Add functions to get/set link flags, MAC address, and MTU using netlink RTM_GETLINK/RTM_SETLINK messages instead of ioctl.
These will be used in the next commits for a more robust solution that does not rely on interface names. Signed-off-by: Robin Jarry <[email protected]> --- drivers/net/tap/tap_netlink.c | 291 ++++++++++++++++++++++++++++++++++ drivers/net/tap/tap_netlink.h | 10 +- 2 files changed, 299 insertions(+), 2 deletions(-) diff --git a/drivers/net/tap/tap_netlink.c b/drivers/net/tap/tap_netlink.c index 5ff60f41d426..0682ba87e0da 100644 --- a/drivers/net/tap/tap_netlink.c +++ b/drivers/net/tap/tap_netlink.c @@ -6,6 +6,7 @@ #include <errno.h> #include <inttypes.h> #include <linux/netlink.h> +#include <net/if.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> @@ -411,3 +412,293 @@ tap_nlattr_nested_finish(struct tap_nlmsg *msg) rte_free(tail); } + +/** + * Helper structure to pass data between netlink request and callback + */ +struct link_info_ctx { + struct ifinfomsg *info; + struct rte_ether_addr *mac; + unsigned int *flags; + unsigned int ifindex; + int found; +}; + +/** + * Callback to extract link information from RTM_GETLINK response + */ +static int +tap_nl_link_cb(struct nlmsghdr *nh, void *arg) +{ + struct link_info_ctx *ctx = arg; + struct ifinfomsg *ifi = NLMSG_DATA(nh); + struct rtattr *rta; + int rta_len; + + if (nh->nlmsg_type != RTM_NEWLINK) + return 0; + + /* Check if this is the interface we're looking for */ + if (ifi->ifi_index != (int)ctx->ifindex) + return 0; + + ctx->found = 1; + + /* Copy basic info if requested */ + if (ctx->info) + *ctx->info = *ifi; + + /* Extract flags if requested */ + if (ctx->flags) + *ctx->flags = ifi->ifi_flags; + + /* Parse attributes for MAC address if requested */ + if (ctx->mac) { + rta = IFLA_RTA(ifi); + rta_len = IFLA_PAYLOAD(nh); + + for (; RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) { + if (rta->rta_type == IFLA_ADDRESS) { + if (RTA_PAYLOAD(rta) >= RTE_ETHER_ADDR_LEN) + memcpy(ctx->mac, RTA_DATA(rta), + RTE_ETHER_ADDR_LEN); + break; + } + } + } + + return 0; +} + +/** + * Get interface flags by ifindex + * + * @param nlsk_fd + * Netlink socket file descriptor + * @param ifindex + * Interface index + * @param flags + * Pointer to store interface flags + * + * @return + * 0 on success, -1 on error + */ +int +tap_nl_get_flags(int nlsk_fd, unsigned int ifindex, unsigned int *flags) +{ + struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_GETLINK, + .nlmsg_flags = NLM_F_REQUEST, + }, + .ifi = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + }, + }; + struct link_info_ctx ctx = { + .flags = flags, + .ifindex = ifindex, + .found = 0, + }; + + if (tap_nl_send(nlsk_fd, &req.nh) < 0) + return -1; + + if (tap_nl_recv(nlsk_fd, tap_nl_link_cb, &ctx) < 0) + return -1; + + if (!ctx.found) { + errno = ENODEV; + return -1; + } + + return 0; +} + +/** + * Set interface flags by ifindex + * + * @param nlsk_fd + * Netlink socket file descriptor + * @param ifindex + * Interface index + * @param flags + * Flags to set/unset + * @param set + * 1 to set flags, 0 to unset them + * + * @return + * 0 on success, -1 on error + */ +int +tap_nl_set_flags(int nlsk_fd, unsigned int ifindex, unsigned int flags, int set) +{ + struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_SETLINK, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }, + .ifi = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + .ifi_flags = set ? flags : 0, + .ifi_change = flags, /* mask of flags to change */ + }, + }; + + if (tap_nl_send(nlsk_fd, &req.nh) < 0) + return -1; + + return tap_nl_recv_ack(nlsk_fd); +} + +/** + * Set interface MTU by ifindex + * + * @param nlsk_fd + * Netlink socket file descriptor + * @param ifindex + * Interface index + * @param mtu + * New MTU value + * + * @return + * 0 on success, -1 on error + */ +int +tap_nl_set_mtu(int nlsk_fd, unsigned int ifindex, unsigned int mtu) +{ + struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + char buf[64]; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_SETLINK, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }, + .ifi = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + }, + }; + struct rtattr *rta; + + /* Add MTU attribute */ + rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len)); + rta->rta_type = IFLA_MTU; + rta->rta_len = RTA_LENGTH(sizeof(mtu)); + memcpy(RTA_DATA(rta), &mtu, sizeof(mtu)); + req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_ALIGN(rta->rta_len); + + if (tap_nl_send(nlsk_fd, &req.nh) < 0) + return -1; + + return tap_nl_recv_ack(nlsk_fd); +} + +/** + * Get interface MAC address by ifindex + * + * @param nlsk_fd + * Netlink socket file descriptor + * @param ifindex + * Interface index + * @param mac + * Pointer to store MAC address + * + * @return + * 0 on success, -1 on error + */ +int +tap_nl_get_mac(int nlsk_fd, unsigned int ifindex, struct rte_ether_addr *mac) +{ + struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_GETLINK, + .nlmsg_flags = NLM_F_REQUEST, + }, + .ifi = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + }, + }; + struct link_info_ctx ctx = { + .mac = mac, + .ifindex = ifindex, + .found = 0, + }; + + if (tap_nl_send(nlsk_fd, &req.nh) < 0) + return -1; + + if (tap_nl_recv(nlsk_fd, tap_nl_link_cb, &ctx) < 0) + return -1; + + if (!ctx.found) { + errno = ENODEV; + return -1; + } + + return 0; +} + +/** + * Set interface MAC address by ifindex + * + * @param nlsk_fd + * Netlink socket file descriptor + * @param ifindex + * Interface index + * @param mac + * New MAC address + * + * @return + * 0 on success, -1 on error + */ +int +tap_nl_set_mac(int nlsk_fd, unsigned int ifindex, const struct rte_ether_addr *mac) +{ + struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + char buf[64]; + } req = { + .nh = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_SETLINK, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }, + .ifi = { + .ifi_family = AF_UNSPEC, + .ifi_index = ifindex, + }, + }; + struct rtattr *rta; + + /* Add MAC address attribute */ + rta = (struct rtattr *)((char *)&req + NLMSG_ALIGN(req.nh.nlmsg_len)); + rta->rta_type = IFLA_ADDRESS; + rta->rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN); + memcpy(RTA_DATA(rta), mac, RTE_ETHER_ADDR_LEN); + req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_ALIGN(rta->rta_len); + + if (tap_nl_send(nlsk_fd, &req.nh) < 0) + return -1; + + return tap_nl_recv_ack(nlsk_fd); +} diff --git a/drivers/net/tap/tap_netlink.h b/drivers/net/tap/tap_netlink.h index 5eff6edbb1cd..b85be166245e 100644 --- a/drivers/net/tap/tap_netlink.h +++ b/drivers/net/tap/tap_netlink.h @@ -6,12 +6,11 @@ #ifndef _TAP_NETLINK_H_ #define _TAP_NETLINK_H_ -#include <ctype.h> #include <inttypes.h> #include <linux/rtnetlink.h> #include <linux/netlink.h> -#include <stdio.h> +#include <rte_ether.h> #include <rte_log.h> #define NLMSG_BUF 512 @@ -39,4 +38,11 @@ void tap_nlattr_add32(struct tap_nlmsg *msg, unsigned short type, uint32_t data) int tap_nlattr_nested_start(struct tap_nlmsg *msg, uint16_t type); void tap_nlattr_nested_finish(struct tap_nlmsg *msg); +/* Link management functions using netlink */ +int tap_nl_get_flags(int nlsk_fd, unsigned int ifindex, unsigned int *flags); +int tap_nl_set_flags(int nlsk_fd, unsigned int ifindex, unsigned int flags, int set); +int tap_nl_set_mtu(int nlsk_fd, unsigned int ifindex, unsigned int mtu); +int tap_nl_set_mac(int nlsk_fd, unsigned int ifindex, const struct rte_ether_addr *mac); +int tap_nl_get_mac(int nlsk_fd, unsigned int ifindex, struct rte_ether_addr *mac); + #endif /* _TAP_NETLINK_H_ */ -- 2.51.1

