How to get LINKMODES using <ethtool_netlink.h>

31 Views Asked by At

How to use the netlink interface for ethtool to get linkmodes (speed,duplex,...)

I've tried this:

#include <errno.h>
#include <linux/ethtool_netlink.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include <netlink/netlink.h>
#include <stdio.h>

static int parse_cb(struct nl_msg* msg, void* arg __attribute__((unused))) {
    int err                    = 0;
    struct genlmsghdr* genlhdr = nlmsg_data(nlmsg_hdr(msg));
    struct nlattr* tb[ETHTOOL_A_LINKMODES_MAX + 1];

    err = nla_parse(tb, ETHTOOL_A_LINKMODES_MAX, genlmsg_attrdata(genlhdr, 0), genlmsg_attrlen(genlhdr, 0), NULL);
    if (0 != err) {
        nl_perror(err, "Failed parsing attributes");
        return NL_SKIP;
    }

    if (!tb[ETHTOOL_A_LINKMODES_SPEED]) {
        fprintf(stderr, "Attribute not found\n");
        return NL_SKIP;
    }

    printf("Link speed: %d\n", nla_get_u32(tb[ETHTOOL_A_LINKMODES_SPEED]));

    return NL_OK;
}

static int send_request(struct nl_sock* sk, int fam) {
    void* hdr          = NULL;
    int err            = 0;
    struct nl_msg* msg = NULL;

    msg = nlmsg_alloc();
    if (NULL == msg) {
        fprintf(stderr, "Failed to create message\n");
        return -ENOMEM;
    }

    hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, fam, 0, NLM_F_DUMP, ETHTOOL_MSG_LINKMODES_GET, ETHTOOL_GENL_VERSION);
    if (NULL == hdr) {
        fprintf(stderr, "Failed to put message\n");
        return -EMSGSIZE;
    }

    // Optionally set the interface
    // err = nla_put_string(msg, ETHTOOL_A_HEADER_DEV_NAME, "enp0s0");
    // if (err < 0) {
    //  return -err;
    // }

    err = nl_send_auto(sk, msg);
    err = err >= 0 ? 0 : err;

    nlmsg_free(msg);

    return err;
}

int main(void) {
    struct nl_sock* sock = NULL;
    int err              = 0;
    int fam              = 0;

    sock = nl_socket_alloc();
    if (NULL == sock) {
        fprintf(stderr, "Failed to allocate unicast nl_sock\n");
        return -1;
    }

    err = nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
    if (0 != err) {
        nl_perror(err, "Failed to add custom cb");
    }

    err = genl_connect(sock);
    if (0 != err) {
        nl_perror(err, "Failed to connect socket");
        goto free_socket;
    }

    fam = genl_ctrl_resolve(sock, ETHTOOL_GENL_NAME);
    if (fam < 0) {
        nl_perror(err, "failed to resolve generic netlink family");
        goto free_socket;
    }

    err = send_request(sock, fam);
    if (0 != err) {
        nl_perror(err, "failed to send message");
    }

    err = nl_recvmsgs_default(sock);
    if (err < 0 && err != -NLE_INTR && err != -NLE_AGAIN) {
        nl_perror(err, "Failed to receive messages");
    }

free_socket:
    nl_close(sock);
    nl_socket_free(sock);

    return err;
}

But I get the error message Failed to receive messages: Invalid input data or parameter.

Same thing if I specify the interface (commented code).

It looks like something could be wrong with the message I am sending. I cannot seem to find good examples of how to use the ethtool netlink interface

0

There are 0 best solutions below