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