diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h new file mode 100644 index 000000000000..4f1d0234d60c --- /dev/null +++ b/include/linux/ethtool_netlink.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * include/uapi/linux/ethtool_netlink.h - netlink interface for ethtool + * + * See Documentation/networking/ethtool-netlink.rst in kernel source tree for + * documentation of the interface. + */ + +#ifndef _LINUX_ETHTOOL_NETLINK_H_ +#define _LINUX_ETHTOOL_NETLINK_H_ + +/* message types - userspace to kernel */ +enum { + ETHTOOL_MSG_USER_NONE, + ETHTOOL_MSG_STRSET_GET, + ETHTOOL_MSG_LINKINFO_GET, + ETHTOOL_MSG_LINKINFO_SET, + ETHTOOL_MSG_LINKMODES_GET, + ETHTOOL_MSG_LINKMODES_SET, + ETHTOOL_MSG_LINKSTATE_GET, + ETHTOOL_MSG_DEBUG_GET, + ETHTOOL_MSG_DEBUG_SET, + ETHTOOL_MSG_WOL_GET, + ETHTOOL_MSG_WOL_SET, + ETHTOOL_MSG_FEATURES_GET, + ETHTOOL_MSG_FEATURES_SET, + ETHTOOL_MSG_PRIVFLAGS_GET, + ETHTOOL_MSG_PRIVFLAGS_SET, + ETHTOOL_MSG_RINGS_GET, + ETHTOOL_MSG_RINGS_SET, + ETHTOOL_MSG_CHANNELS_GET, + ETHTOOL_MSG_CHANNELS_SET, + ETHTOOL_MSG_COALESCE_GET, + ETHTOOL_MSG_COALESCE_SET, + ETHTOOL_MSG_PAUSE_GET, + ETHTOOL_MSG_PAUSE_SET, + ETHTOOL_MSG_EEE_GET, + ETHTOOL_MSG_EEE_SET, + ETHTOOL_MSG_TSINFO_GET, + ETHTOOL_MSG_CABLE_TEST_ACT, + ETHTOOL_MSG_CABLE_TEST_TDR_ACT, + ETHTOOL_MSG_TUNNEL_INFO_GET, + ETHTOOL_MSG_FEC_GET, + ETHTOOL_MSG_FEC_SET, + ETHTOOL_MSG_MODULE_EEPROM_GET, + ETHTOOL_MSG_STATS_GET, + ETHTOOL_MSG_PHC_VCLOCKS_GET, + ETHTOOL_MSG_MODULE_GET, + ETHTOOL_MSG_MODULE_SET, + ETHTOOL_MSG_PSE_GET, + ETHTOOL_MSG_PSE_SET, + ETHTOOL_MSG_RSS_GET, + ETHTOOL_MSG_PLCA_GET_CFG, + ETHTOOL_MSG_PLCA_SET_CFG, + ETHTOOL_MSG_PLCA_GET_STATUS, + ETHTOOL_MSG_MM_GET, + ETHTOOL_MSG_MM_SET, + + /* add new constants above here */ + __ETHTOOL_MSG_USER_CNT, + ETHTOOL_MSG_USER_MAX = __ETHTOOL_MSG_USER_CNT - 1 +}; + +/* message types - kernel to userspace */ +enum { + ETHTOOL_MSG_KERNEL_NONE, + ETHTOOL_MSG_STRSET_GET_REPLY, + ETHTOOL_MSG_LINKINFO_GET_REPLY, + ETHTOOL_MSG_LINKINFO_NTF, + ETHTOOL_MSG_LINKMODES_GET_REPLY, + ETHTOOL_MSG_LINKMODES_NTF, + ETHTOOL_MSG_LINKSTATE_GET_REPLY, + ETHTOOL_MSG_DEBUG_GET_REPLY, + ETHTOOL_MSG_DEBUG_NTF, + ETHTOOL_MSG_WOL_GET_REPLY, + ETHTOOL_MSG_WOL_NTF, + ETHTOOL_MSG_FEATURES_GET_REPLY, + ETHTOOL_MSG_FEATURES_SET_REPLY, + ETHTOOL_MSG_FEATURES_NTF, + ETHTOOL_MSG_PRIVFLAGS_GET_REPLY, + ETHTOOL_MSG_PRIVFLAGS_NTF, + ETHTOOL_MSG_RINGS_GET_REPLY, + ETHTOOL_MSG_RINGS_NTF, + ETHTOOL_MSG_CHANNELS_GET_REPLY, + ETHTOOL_MSG_CHANNELS_NTF, + ETHTOOL_MSG_COALESCE_GET_REPLY, + ETHTOOL_MSG_COALESCE_NTF, + ETHTOOL_MSG_PAUSE_GET_REPLY, + ETHTOOL_MSG_PAUSE_NTF, + ETHTOOL_MSG_EEE_GET_REPLY, + ETHTOOL_MSG_EEE_NTF, + ETHTOOL_MSG_TSINFO_GET_REPLY, + ETHTOOL_MSG_CABLE_TEST_NTF, + ETHTOOL_MSG_CABLE_TEST_TDR_NTF, + ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY, + ETHTOOL_MSG_FEC_GET_REPLY, + ETHTOOL_MSG_FEC_NTF, + ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, + ETHTOOL_MSG_STATS_GET_REPLY, + ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY, + ETHTOOL_MSG_MODULE_GET_REPLY, + ETHTOOL_MSG_MODULE_NTF, + ETHTOOL_MSG_PSE_GET_REPLY, + ETHTOOL_MSG_RSS_GET_REPLY, + ETHTOOL_MSG_PLCA_GET_CFG_REPLY, + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY, + ETHTOOL_MSG_PLCA_NTF, + ETHTOOL_MSG_MM_GET_REPLY, + ETHTOOL_MSG_MM_NTF, + + /* add new constants above here */ + __ETHTOOL_MSG_KERNEL_CNT, + ETHTOOL_MSG_KERNEL_MAX = __ETHTOOL_MSG_KERNEL_CNT - 1 +}; + +/* request header */ + +enum { + ETHTOOL_A_HEADER_UNSPEC, + ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */ + ETHTOOL_A_HEADER_DEV_NAME, /* string */ + ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */ + + /* add new constants above here */ + __ETHTOOL_A_HEADER_CNT, + ETHTOOL_A_HEADER_MAX = __ETHTOOL_A_HEADER_CNT - 1 +}; + +/* LINKMODES */ + +enum { + ETHTOOL_A_LINKMODES_UNSPEC, + ETHTOOL_A_LINKMODES_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_LINKMODES_AUTONEG, /* u8 */ + ETHTOOL_A_LINKMODES_OURS, /* bitset */ + ETHTOOL_A_LINKMODES_PEER, /* bitset */ + ETHTOOL_A_LINKMODES_SPEED, /* u32 */ + ETHTOOL_A_LINKMODES_DUPLEX, /* u8 */ + ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, /* u8 */ + ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, /* u8 */ + ETHTOOL_A_LINKMODES_LANES, /* u32 */ + ETHTOOL_A_LINKMODES_RATE_MATCHING, /* u8 */ + + /* add new constants above here */ + __ETHTOOL_A_LINKMODES_CNT, + ETHTOOL_A_LINKMODES_MAX = __ETHTOOL_A_LINKMODES_CNT - 1 +}; + +/* generic netlink info */ +#define ETHTOOL_GENL_NAME "ethtool" +#define ETHTOOL_GENL_VERSION 1 + +#endif /* _LINUX_ETHTOOL_NETLINK_H_ */ diff --git a/include/subdir.am b/include/subdir.am index bcf3ef7b9bf8..6988e9c3b249 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -1,6 +1,7 @@ noinst_HEADERS += \ include/linux/compiler_types.h \ include/linux/libc-compat.h \ + include/linux/ethtool_netlink.h \ include/linux/if.h \ include/linux/if_addr.h \ include/linux/if_bridge.h \ diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 2fa061f105ea..8e120837097f 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1102,6 +1102,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_TC_QDISC_INSTALL: case DPLANE_OP_TC_QDISC_UNINSTALL: case DPLANE_OP_TC_CLASS_ADD: diff --git a/zebra/ge_netlink.c b/zebra/ge_netlink.c index 72598584d86b..3fb370229ec2 100644 --- a/zebra/ge_netlink.c +++ b/zebra/ge_netlink.c @@ -18,15 +18,18 @@ #include #include #include +#include #include "lib/ns.h" #include "zebra/ge_netlink.h" #include "zebra/debug.h" +#include "zebra/interface.h" #include "zebra/zebra_errors.h" #include "zebra/kernel_netlink.h" #include "zebra/zebra_router.h" #include "zebra/zebra_srv6.h" #include "zebra/zebra_dplane.h" +#include "zebra/zebra_trace.h" #include "lib/netlink_parser.h" #include "lib/lib_errors.h" @@ -55,7 +58,12 @@ */ static int16_t seg6_genl_family = -1; -static int genl_parse_getfamily(struct nlmsghdr *h, ns_id_t ns_id, int startup) +/* + * Numeric family identifier used to query ethtool information through Generic Netlink. + */ +static int16_t ethtool_genl_family = -1; + +static int genl_parse_getfamily(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct rtattr *tb[CTRL_ATTR_MAX + 1]; @@ -101,6 +109,8 @@ static int genl_parse_getfamily(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (strmatch(family, "SEG6")) seg6_genl_family = *(int16_t *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]); + else if (strmatch(family, ETHTOOL_GENL_NAME)) + ethtool_genl_family = *(int16_t *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]); else { if (IS_ZEBRA_DEBUG_KERNEL) flog_err(EC_ZEBRA_NETLINK_INVALID_AF, @@ -133,7 +143,7 @@ int genl_resolve_family(const char *family) strlen(family) + 1)) return -1; - return ge_netlink_talk(genl_parse_getfamily, &req.n, zns, false); + return ge_netlink_talk(genl_parse_getfamily, &req.n, zns, false, NULL, NULL); } /* @@ -234,7 +244,7 @@ netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx zns = zebra_ns_lookup(dplane_ctx_get_ns_sock(ctx)); - return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false); + return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false, NULL, NULL); } /** @@ -246,7 +256,7 @@ netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx * * Return: Result status */ -int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct genlmsghdr *ghdr; @@ -340,14 +350,144 @@ int netlink_sr_tunsrc_read(struct zebra_ns *zns) ret = netlink_request_sr_tunsrc(zns); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_sr_tunsrc_reply_read, - &zns->ge_netlink_cmd, &dp_info, 0, true); + ret = netlink_parse_info(netlink_sr_tunsrc_reply_read, &zns->ge_netlink_cmd, &dp_info, 0, + true, NULL, NULL); if (ret < 0) return ret; return 0; } +struct ethtool_speed_result { + uint32_t speed; + bool speed_set; + int nl_err; /* kernel-reported errno from NLMSG_ERROR, 0 if none */ +}; + +static int netlink_ethtool_linkmodes_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup, + void *arg) +{ + struct ethtool_speed_result *res = arg; + int len; + struct genlmsghdr *ghdr; + struct rtattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {}; + struct rtattr *attrs; + + res->speed_set = false; + + if (h->nlmsg_type != ethtool_genl_family) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) { + zlog_warn("%s: Message received from netlink is of a broken size %d %zu", __func__, + h->nlmsg_len, (size_t)NLMSG_LENGTH(GENL_HDRLEN)); + return -1; + } + + ghdr = NLMSG_DATA(h); + + if (ghdr->cmd != ETHTOOL_MSG_LINKMODES_GET_REPLY) + return 0; + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + netlink_parse_rtattr(tb, ETHTOOL_A_LINKMODES_MAX, attrs, len); + + if (tb[ETHTOOL_A_LINKMODES_SPEED] == NULL) + return 0; + + res->speed = *(uint32_t *)RTA_DATA(tb[ETHTOOL_A_LINKMODES_SPEED]); + res->speed_set = true; + + return 0; +} + +/** + * netlink_get_interface_speed() - Query interface speed via ethtool over netlink + * @zns: Per-namespace netlink sockets holder (uses zns->ge_netlink_cmd) + * @ifname: Interface name + * @error: Out param, set to 0 on success, INTERFACE_SPEED_ERROR_* otherwise + * + * Sends ETHTOOL_MSG_LINKMODES_GET on the per-ns generic netlink command socket + * and parses the reply. The socket is pinned to the right namespace at zns + * creation time, so no setns is required from the caller. + * + * Returns the link speed in Mbps, or 0 with *error set on failure. + */ +uint32_t netlink_get_interface_speed(struct zebra_ns *zns, const char *ifname, int *error) +{ + struct ethtool_speed_result res = {}; + struct genl_request req = {}; + struct rtattr *header; + int ret; + + if (error) + *error = 0; + + if (zns == NULL || zns->ge_netlink_cmd.sock < 0) { + if (error) + *error = INTERFACE_SPEED_ERROR_READ; + return 0; + } + + if (ethtool_genl_family < 0) { + /* Kernel < 5.5 or ethtool family not registered: permanent, + * retrying will not help. + */ + if (error) + *error = INTERFACE_SPEED_ERROR_READ; + return 0; + } + + req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = ethtool_genl_family; + req.n.nlmsg_pid = zns->ge_netlink_cmd.snl.nl_pid; + + req.g.cmd = ETHTOOL_MSG_LINKMODES_GET; + req.g.version = ETHTOOL_GENL_VERSION; + + header = nl_attr_nest(&req.n, sizeof(req), ETHTOOL_A_LINKMODES_HEADER); + if (!header) { + if (error) + *error = INTERFACE_SPEED_ERROR_READ; + return 0; + } + if (!nl_attr_put(&req.n, sizeof(req), ETHTOOL_A_HEADER_DEV_NAME, ifname, + strlen(ifname) + 1)) { + if (error) + *error = INTERFACE_SPEED_ERROR_READ; + return 0; + } + nl_attr_nest_end(&req.n, header); + + ret = ge_netlink_talk(netlink_ethtool_linkmodes_reply_read, &req.n, zns, false, &res, + &res.nl_err); + if (ret < 0) { + int nl_errno = res.nl_err ? -res.nl_err : errno; + + if (error) + *error = (res.nl_err == -ENODEV || + res.nl_err == -EOPNOTSUPP) + ? INTERFACE_SPEED_ERROR_READ + : INTERFACE_SPEED_ERROR_UNKNOWN; + + if (nl_errno != EOPNOTSUPP) + frrtrace(4, frr_zebra, get_iflink_speed, ifname, + nl_errno, safe_strerror(nl_errno), 1); + + return 0; + } + + if (!res.speed_set || res.speed == UINT32_MAX) { + if (error) + *error = INTERFACE_SPEED_ERROR_UNKNOWN; + return 0; + } + + return res.speed; +} + void ge_netlink_init(struct zebra_ns *zns) { if (zns->ge_netlink_cmd.sock < 0) @@ -363,6 +503,15 @@ void ge_netlink_init(struct zebra_ns *zns) zlog_warn( "Kernel does not support 'SEG6' Generic Netlink family. Any attempt to set the encapsulation parameters under the SRv6 configuration will fail"); + /* + * Resolve the 'ethtool' Generic Netlink family. Available since Linux + * 5.5. On older kernels netlink_get_interface_speed() will report the + * speed as unknown. + */ + if (genl_resolve_family(ETHTOOL_GENL_NAME)) + zlog_warn("Kernel does not support '%s' Generic Netlink family; interface speed will be reported as unknown", + ETHTOOL_GENL_NAME); + /** * Retrieve the actual SRv6 encap source address from the kernel * (default namespace) and save it to zebra SRv6 config diff --git a/zebra/ge_netlink.h b/zebra/ge_netlink.h index 567bcd2eca00..3bfa83cededd 100644 --- a/zebra/ge_netlink.h +++ b/zebra/ge_netlink.h @@ -42,9 +42,11 @@ extern enum netlink_msg_status netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); -int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup); +int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); int netlink_sr_tunsrc_read(struct zebra_ns *zns); +extern uint32_t netlink_get_interface_speed(struct zebra_ns *zns, const char *ifname, int *error); + extern void ge_netlink_init(struct zebra_ns *zns); #ifdef __cplusplus diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index c7ee4b180006..2e169905bdb6 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -269,80 +269,36 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, ctx, *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE])); } -static uint32_t get_iflink_speed(struct interface *interface, int *error) +void kernel_read_intf_speed(struct zebra_dplane_ctx *ctx) { - struct ifreq ifdata; - struct ethtool_cmd ecmd; - int sd; - int rc; - const char *ifname = interface->name; - uint32_t ret; - - if (error) - *error = 0; - /* initialize struct */ - memset(&ifdata, 0, sizeof(ifdata)); - - /* set interface name */ - strlcpy(ifdata.ifr_name, ifname, sizeof(ifdata.ifr_name)); - - /* initialize ethtool interface */ - memset(&ecmd, 0, sizeof(ecmd)); - ecmd.cmd = ETHTOOL_GSET; /* ETHTOOL_GLINK */ - ifdata.ifr_data = (caddr_t)&ecmd; - - /* use ioctl to get speed of an interface */ - frr_with_privs(&zserv_privs) { - sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP, - interface->vrf->vrf_id, NULL); - if (sd < 0) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Failure to read interface %s speed: %d %s", - ifname, errno, safe_strerror(errno)); - /* no vrf socket creation may probably mean vrf issue */ - if (error) - *error = INTERFACE_SPEED_ERROR_READ; - - frrtrace(4, frr_zebra, get_iflink_speed, ifname, errno, - safe_strerror(errno), 1); - - return 0; - } - /* Get the current link state for the interface */ - rc = vrf_ioctl(interface->vrf->vrf_id, sd, SIOCETHTOOL, - (char *)&ifdata); - } - if (rc < 0) { - if (errno != EOPNOTSUPP && IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "IOCTL failure to read interface %s speed: %d %s", - ifname, errno, safe_strerror(errno)); - /* no device means interface unreachable */ - if (errno == ENODEV && error) - *error = INTERFACE_SPEED_ERROR_READ; - - if (errno != EOPNOTSUPP) - frrtrace(4, frr_zebra, get_iflink_speed, ifname, errno, - safe_strerror(errno), 2); - - ecmd.speed_hi = 0; - ecmd.speed = 0; - } - - close(sd); - - ret = ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed; - if (ret == UINT32_MAX) { - if (error) - *error = INTERFACE_SPEED_ERROR_UNKNOWN; - ret = 0; + const char *ifname = dplane_ctx_get_ifname(ctx); + struct zebra_ns *zns = zebra_ns_lookup(dplane_ctx_get_ns_id(ctx)); + uint32_t speed; + int error = 0; + + speed = netlink_get_interface_speed(zns, ifname, &error); + switch (error) { + case 0: + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + dplane_ctx_set_ifp_speed(ctx, speed); + dplane_ctx_set_ifp_speed_set(ctx, true); + break; + case INTERFACE_SPEED_ERROR_UNKNOWN: + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + dplane_ctx_set_ifp_speed_set(ctx, false); + break; + case INTERFACE_SPEED_ERROR_READ: + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_set_ifp_speed_set(ctx, false); + break; + default: + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_set_ifp_speed_set(ctx, false); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("netlink_get_interface_speed returned an unknown error %d", + error); + break; } - return ret; -} - -uint32_t kernel_get_speed(struct interface *ifp, int *error) -{ - return get_iflink_speed(ifp, error); } static ssize_t @@ -907,8 +863,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) ret = netlink_request_intf_addr(netlink_cmd, AF_PACKET, RTM_GETLINK, 0); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, - true); + ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true, NULL, NULL); if (ret < 0) return ret; @@ -917,8 +872,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) RTEXT_FILTER_BRVLAN); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, - true); + ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true, NULL, NULL); if (ret < 0) return ret; @@ -966,8 +920,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, - &dp_info, 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, &dp_info, 0, true, + NULL, NULL); if (ret < 0) return ret; @@ -975,8 +929,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) ret = netlink_request_intf_addr(netlink_cmd, AF_INET6, RTM_GETADDR, 0); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, - &dp_info, 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, &dp_info, 0, true, + NULL, NULL); if (ret < 0) return ret; @@ -1012,8 +966,7 @@ int kernel_interface_set_master(struct interface *master, return -1; } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - false); + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false, NULL, NULL); } /* Interface address modification. */ @@ -1133,8 +1086,8 @@ netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) * This runs in the dplane pthread; the context is enqueued to the * main pthread for processing. */ -int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, - int startup /*ignored*/) +int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, int startup /*ignored*/, + void *arg) { int len; struct ifaddrmsg *ifa; @@ -1369,7 +1322,7 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, return 0; } -int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct ifinfomsg *ifi; @@ -1389,6 +1342,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) uint8_t bypass = 0; uint32_t txqlen = 0; uint32_t cchanges = 0; + int speed_err = 0; + uint32_t speed = 0; frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); @@ -1549,8 +1504,22 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } + + vrf_id_t ifp_vrf_id = vrf_is_backend_netns() ? ns_id : vrf_id; + + if (startup) { + speed = netlink_get_interface_speed(zebra_ns_lookup(ifp_vrf_id), + name, &speed_err); + if (speed_err == 0) { + dplane_ctx_set_ifp_speed(ctx, speed); + dplane_ctx_set_ifp_speed_set(ctx, true); + } else + dplane_ctx_set_ifp_speed_set(ctx, false); + } else + dplane_ctx_set_ifp_speed_set(ctx, false); + dplane_ctx_set_ifp_zif_slave_type(ctx, zif_slave_type); - dplane_ctx_set_ifp_vrf_id(ctx, vrf_id); + dplane_ctx_set_ifp_vrf_id(ctx, ifp_vrf_id); dplane_ctx_set_ifp_master_ifindex(ctx, master_infindex); dplane_ctx_set_ifp_bridge_ifindex(ctx, bridge_ifindex); dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); @@ -1558,9 +1527,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) dplane_ctx_set_ifp_zltype( ctx, netlink_to_zebra_link_type(ifi->ifi_type)); - if (vrf_is_backend_netns()) - dplane_ctx_set_ifp_vrf_id(ctx, ns_id); - dplane_ctx_set_ifp_flags(ctx, ifi->ifi_flags & 0x0000fffff); dplane_ctx_set_ifp_change_flags(ctx, ifi->ifi_change & 0x0000fffff); @@ -1763,8 +1729,8 @@ static int tunneldump_walk_cb(struct interface *ifp, void *arg) return NS_WALK_STOP; } - ret = netlink_parse_info(netlink_link_change, &(ctx->zns->netlink_cmd), - ctx->dp_info, 0, true); + ret = netlink_parse_info(netlink_link_change, &(ctx->zns->netlink_cmd), ctx->dp_info, 0, + true, NULL, NULL); if (ret < 0) { ctx->ret = ret; @@ -1798,7 +1764,7 @@ static uint8_t netlink_get_dplane_vlan_state(uint8_t state) * * Return: Result status */ -int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len, rem; struct br_vlan_msg *bvm; @@ -1958,8 +1924,7 @@ int netlink_vlan_read(struct zebra_ns *zns) if (ret < 0) return ret; - ret = netlink_parse_info(netlink_vlan_change, &zns->netlink_cmd, - &dp_info, 0, 1); + ret = netlink_parse_info(netlink_vlan_change, &zns->netlink_cmd, &dp_info, 0, 1, NULL, NULL); return ret; } diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index dc1f71cb7769..603d803f7d52 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -16,13 +16,12 @@ extern "C" { * Parse an incoming interface address change message, generate a dplane * context object for processing. */ -int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, - int startup); +int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); -extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); +extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); extern int interface_lookup_netlink(struct zebra_ns *zns); -extern int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); +extern int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); extern int netlink_vlan_read(struct zebra_ns *zns); extern ssize_t netlink_intf_msg_encode(uint16_t cmd, diff --git a/zebra/interface.c b/zebra/interface.c index 6ff1791b76ec..b4017b6923ee 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -66,22 +66,40 @@ static const char *if_zebra_data_state(uint8_t state) static void if_zebra_speed_update(struct event *event) { struct interface *ifp = EVENT_ARG(event); - struct zebra_if *zif = ifp->info; + + dplane_intf_speed_get(ifp); +} + +static void zebra_if_schedule_speed_update(struct zebra_if *zif, int timeout) +{ + event_add_timer(zrouter.master, if_zebra_speed_update, zif->ifp, timeout, + &zif->speed_update); + event_ignore_late_timer(zif->speed_update); +} + +static void zebra_if_speed_update_ctx(struct zebra_dplane_ctx *ctx, struct interface *ifp) +{ + enum zebra_dplane_result dp_res; + bool speed_set, changed = false; + struct zebra_if *zif; uint32_t new_speed; - bool changed = false; - int error = 0; - zif->speed_checked++; + if (!ifp) + return; - new_speed = kernel_get_speed(ifp, &error); + zif = ifp->info; + zif->speed_checked++; + dp_res = dplane_ctx_get_status(ctx); /* error may indicate vrf not available or * interfaces not available. * note that loopback & virtual interfaces can return 0 as speed */ - if (error == INTERFACE_SPEED_ERROR_READ) + if (dp_res == ZEBRA_DPLANE_REQUEST_FAILURE) return; + speed_set = dplane_ctx_get_ifp_speed_set(ctx); + new_speed = speed_set ? dplane_ctx_get_ifp_speed(ctx) : 0; if (new_speed != ifp->speed) { zlog_info("%s: %s old speed: %u new speed: %u", __func__, ifp->name, ifp->speed, new_speed); @@ -90,7 +108,7 @@ static void if_zebra_speed_update(struct event *event) changed = true; } - if (changed || error == INTERFACE_SPEED_ERROR_UNKNOWN) { + if (changed || !speed_set) { #define SPEED_UPDATE_SLEEP_TIME 5 #define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME) /* @@ -105,14 +123,11 @@ static void if_zebra_speed_update(struct event *event) * to not update the system to keep track of that. This * is far simpler to just stop trying after 4 minutes */ - if (error == INTERFACE_SPEED_ERROR_UNKNOWN && - zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) + if (!speed_set && zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) return; zif->speed_update_count++; - event_add_timer(zrouter.master, if_zebra_speed_update, ifp, - SPEED_UPDATE_SLEEP_TIME, &zif->speed_update); - event_ignore_late_timer(zif->speed_update); + zebra_if_schedule_speed_update(zif, SPEED_UPDATE_SLEEP_TIME); } } @@ -161,19 +176,6 @@ static int if_zebra_new_hook(struct interface *ifp) ifp->info = zebra_if; - /* - * Some platforms are telling us that the interface is - * up and ready to go. When we check the speed we - * sometimes get the wrong value. Wait a couple - * of seconds and ask again. Hopefully it's all settled - * down upon startup. - */ - zebra_if->speed_update_count = 0; - zebra_if->speed_checked = 0; - event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, - &zebra_if->speed_update); - event_ignore_late_timer(zebra_if->speed_update); - return 0; } @@ -950,9 +952,7 @@ static void if_handle_bond_speed_change(struct interface *ifp) if (part_of_bond->bond_if) { zif = part_of_bond->bond_if->info; - if (!event_is_scheduled(zif->speed_update)) - event_add_timer(zrouter.master, if_zebra_speed_update, part_of_bond->bond_if, 1, - &zif->speed_update); + zebra_if_schedule_speed_update(zif, 1); } } @@ -1014,9 +1014,8 @@ void if_up(struct interface *ifp, bool install_connected) if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) zebra_evpn_mh_uplink_oper_update(zif); - event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0, - &zif->speed_update); - event_ignore_late_timer(zif->speed_update); + event_cancel(&zif->speed_update); + dplane_intf_speed_get(ifp); if_addr_wakeup(ifp); @@ -2036,8 +2035,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) uint32_t mtu; ns_id_t link_nsid; struct zebra_if *zif; - bool protodown, protodown_set, startup; - uint32_t rc_bitfield; + bool protodown, protodown_set, startup, speed_set; + uint32_t rc_bitfield, speed; uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; char *desc; uint8_t family; @@ -2069,6 +2068,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) family = dplane_ctx_get_ifp_family(ctx); change_flags = dplane_ctx_get_ifp_change_flags(ctx); cchanges = dplane_ctx_get_intf_carrier_changes(ctx); + speed_set = dplane_ctx_get_ifp_speed_set(ctx); + speed = dplane_ctx_get_ifp_speed(ctx); #ifndef AF_BRIDGE /* @@ -2107,7 +2108,24 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) if_update_state_mtu(ifp, mtu); if_update_state_mtu6(ifp, mtu); if_update_state_metric(ifp, 0); - if_update_state_speed(ifp, kernel_get_speed(ifp, NULL)); + if (!speed_set) { + speed = 0; + /* Query initial speed if not provided by dplane */ + dplane_intf_speed_get(ifp); + + /* + * Some platforms are telling us that the interface is + * up and ready to go. When we check the speed we + * sometimes get the wrong value. Wait a couple + * of seconds and ask again. Hopefully it's all settled + * down upon startup. + */ + zif->speed_update_count = 0; + zif->speed_checked = 0; + zebra_if_schedule_speed_update(zif, 15); + } else + zif->speed_checked++; + if_update_state_speed(ifp, speed); ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); @@ -2211,6 +2229,10 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) if_update_state_mtu(ifp, mtu); if_update_state_mtu6(ifp, mtu); if_update_state_metric(ifp, 0); + if (speed_set) { + zif->speed_checked++; + if_update_state_speed(ifp, speed); + } ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); /* @@ -2420,6 +2442,8 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) zebra_if_update_ctx(ctx, ifp); } else if (op == DPLANE_OP_INTF_NETCONFIG) { zebra_if_netconf_update_ctx(ctx, ifp, ifindex); + } else if (op == DPLANE_OP_INTF_SPEED_GET) { + zebra_if_speed_update_ctx(ctx, ifp); } } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 06e3276d61bf..563fb6c4abb0 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -231,7 +231,7 @@ void netlink_set_batch_buffer_size(uint32_t size, uint32_t threshold, bool set) memory_order_relaxed); } -int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { /* * This is an error condition that must be handled during @@ -379,8 +379,7 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, * Dispatch an incoming netlink message; used by the zebra main pthread's * netlink event reader. */ -static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, - int startup) +static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { /* * When we handle new message types here @@ -393,17 +392,17 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, */ switch (h->nlmsg_type) { case RTM_NEWROUTE: - return netlink_route_change(h, ns_id, startup); + return netlink_route_change(h, ns_id, startup, arg); case RTM_DELROUTE: - return netlink_route_change(h, ns_id, startup); + return netlink_route_change(h, ns_id, startup, arg); case RTM_NEWRULE: - return netlink_rule_change(h, ns_id, startup); + return netlink_rule_change(h, ns_id, startup, arg); case RTM_DELRULE: - return netlink_rule_change(h, ns_id, startup); + return netlink_rule_change(h, ns_id, startup, arg); case RTM_NEWNEXTHOP: - return netlink_nexthop_change(h, ns_id, startup); + return netlink_nexthop_change(h, ns_id, startup, arg); case RTM_DELNEXTHOP: - return netlink_nexthop_change(h, ns_id, startup); + return netlink_nexthop_change(h, ns_id, startup, arg); /* Messages we may receive, but ignore */ case RTM_NEWCHAIN: @@ -454,8 +453,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, * Dispatch an incoming netlink message; used by the dataplane pthread's * netlink event reader code. */ -static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, - int startup) +static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, int startup, + void *arg) { /* * Dispatch the incoming messages that the dplane pthread handles @@ -463,21 +462,21 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, switch (h->nlmsg_type) { case RTM_NEWADDR: case RTM_DELADDR: - return netlink_interface_addr_dplane(h, ns_id, startup); + return netlink_interface_addr_dplane(h, ns_id, startup, arg); case RTM_NEWNETCONF: case RTM_DELNETCONF: - return netlink_netconf_change(h, ns_id, startup); + return netlink_netconf_change(h, ns_id, startup, arg); /* TODO -- other messages for the dplane socket and pthread */ case RTM_NEWLINK: case RTM_DELLINK: - return netlink_link_change(h, ns_id, startup); + return netlink_link_change(h, ns_id, startup, arg); case RTM_NEWVLAN: case RTM_DELVLAN: - return netlink_vlan_change(h, ns_id, startup); + return netlink_vlan_change(h, ns_id, startup, arg); case RTM_NEWNEIGH: case RTM_DELNEIGH: @@ -486,13 +485,13 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWQDISC: case RTM_DELQDISC: - return netlink_qdisc_change(h, ns_id, startup); + return netlink_qdisc_change(h, ns_id, startup, arg); case RTM_NEWTCLASS: case RTM_DELTCLASS: - return netlink_tclass_change(h, ns_id, startup); + return netlink_tclass_change(h, ns_id, startup, arg); case RTM_NEWTFILTER: case RTM_DELTFILTER: - return netlink_tfilter_change(h, ns_id, startup); + return netlink_tfilter_change(h, ns_id, startup, arg); default: break; @@ -509,8 +508,7 @@ static void kernel_read(struct event *event) /* Capture key info from ns struct */ zebra_dplane_info_from_zns(&dp_info, zns, false); - netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, - 5, false); + netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, 5, false, NULL, NULL); event_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); @@ -523,8 +521,7 @@ int kernel_dplane_read(struct zebra_dplane_info *info) { struct nlsock *nl = kernel_netlink_nlsock_lookup(info->sock); - netlink_parse_info(dplane_netlink_information_fetch, nl, info, 5, - false); + netlink_parse_info(dplane_netlink_information_fetch, nl, info, 5, false, NULL, NULL); return 0; } @@ -928,9 +925,9 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, * startup -> Are we reading in under startup conditions? passed to * the filter. */ -int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), - struct nlsock *nl, const struct zebra_dplane_info *zns, - int count, bool startup) +int netlink_parse_info(netlink_parse_filter_t filter, struct nlsock *nl, + const struct zebra_dplane_info *zns, int count, bool startup, void *arg, + int *nl_err) { int status; int ret = 0; @@ -969,8 +966,18 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), if (!(h->nlmsg_flags & NLM_F_MULTI)) return 0; continue; - } else - return err; + } + /* + * Real error: expose the kernel-reported code + * to the caller if requested, then bail out. + */ + if (nl_err && + h->nlmsg_len >= NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + struct nlmsgerr *nlerr = NLMSG_DATA(h); + + *nl_err = nlerr->error; + } + return err; } /* @@ -1004,7 +1011,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), continue; } - error = (*filter)(h, zns->ns_id, startup); + error = (*filter)(h, zns->ns_id, startup, arg); if (error < 0) { zlog_debug("%s filter function error", nl->name); @@ -1040,10 +1047,9 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), * startup -> Are we reading in under startup conditions * This is passed through eventually to filter. */ -static int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, - int startup), - struct nlmsghdr *n, - struct zebra_dplane_info *dp_info, bool startup) +static int netlink_talk_info(netlink_parse_filter_t filter, struct nlmsghdr *n, + struct zebra_dplane_info *dp_info, bool startup, void *arg, + int *nl_err) { struct nlsock *nl; @@ -1065,16 +1071,15 @@ static int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, * Get reply from netlink socket. * The reply should either be an acknowledgement or an error. */ - return netlink_parse_info(filter, nl, dp_info, 0, startup); + return netlink_parse_info(filter, nl, dp_info, 0, startup, arg, nl_err); } /* * Synchronous version of netlink_talk_info. Converts args to suit the * common version, which is suitable for both sync and async use. */ -int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), - struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, - bool startup) +int netlink_talk(netlink_parse_filter_t filter, struct nlmsghdr *n, struct nlsock *nl, + struct zebra_ns *zns, bool startup, void *arg, int *nl_err) { struct zebra_dplane_info dp_info; @@ -1086,15 +1091,15 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), /* Capture info in intermediate info struct */ zebra_dplane_info_from_zns(&dp_info, zns, (nl == &(zns->netlink_cmd))); - return netlink_talk_info(filter, n, &dp_info, startup); + return netlink_talk_info(filter, n, &dp_info, startup, arg, nl_err); } /* * Synchronous version of netlink_talk_info. Converts args to suit the * common version, which is suitable for both sync and async use. */ -int ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), - struct nlmsghdr *n, struct zebra_ns *zns, bool startup) +int ge_netlink_talk(netlink_parse_filter_t filter, struct nlmsghdr *n, struct zebra_ns *zns, + bool startup, void *arg, int *nl_err) { struct zebra_dplane_info dp_info; @@ -1113,7 +1118,7 @@ int ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), dp_info.sock = zns->ge_netlink_cmd.sock; dp_info.seq = zns->ge_netlink_cmd.seq; - return netlink_talk_info(filter, n, &dp_info, startup); + return netlink_talk_info(filter, n, &dp_info, startup, arg, nl_err); } /* Issue request message to kernel via netlink socket. GET messages @@ -1472,6 +1477,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_BR_PORT_UPDATE: return FRR_NETLINK_SUCCESS; + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: case DPLANE_OP_IPSET_ADD: diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 6a5141ca7095..d920d2581093 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -43,14 +43,16 @@ extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); extern const char *nl_rttype_to_str(uint8_t rttype); -extern int netlink_parse_info(int (*filter)(struct nlmsghdr *h, ns_id_t ns_id, int startup), - struct nlsock *nl, const struct zebra_dplane_info *dp_info, - int count, bool startup); -extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup); -extern int netlink_talk(int (*filter)(struct nlmsghdr *h, ns_id_t ns_id, int startup), - struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, bool startup); -extern int ge_netlink_talk(int (*filter)(struct nlmsghdr *h, ns_id_t ns_id, int startup), - struct nlmsghdr *n, struct zebra_ns *zns, bool startup); +typedef int (*netlink_parse_filter_t)(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); + +extern int netlink_parse_info(netlink_parse_filter_t filter, struct nlsock *nl, + const struct zebra_dplane_info *dp_info, int count, bool startup, + void *arg, int *nl_err); +extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup, void *arg); +extern int netlink_talk(netlink_parse_filter_t filter, struct nlmsghdr *n, struct nlsock *nl, + struct zebra_ns *zns, bool startup, void *arg, int *nl_err); +extern int ge_netlink_talk(netlink_parse_filter_t filter, struct nlmsghdr *n, struct zebra_ns *zns, + bool startup, void *arg, int *nl_err); extern int netlink_request(struct nlsock *nl, void *req); enum netlink_msg_status { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 80b5a3828f1d..5d508ce50f53 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1692,6 +1692,7 @@ void kernel_update_multi(struct dplane_ctx_list_head *ctx_list) case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_STARTUP_STAGE: case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_VLAN_INSTALL: diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c index 8b4966def76a..7cbe42f03abf 100644 --- a/zebra/netconf_netlink.c +++ b/zebra/netconf_netlink.c @@ -62,7 +62,7 @@ netlink_netconf_dplane_update(ns_id_t ns_id, afi_t afi, ifindex_t ifindex, /* * Parse and process an incoming netlink netconf update. */ -int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { struct netconfmsg *ncm; struct rtattr *tb[NETCONFA_MAX + 1] = {}; diff --git a/zebra/netconf_netlink.h b/zebra/netconf_netlink.h index 3abc72e2fbbc..795998e52552 100644 --- a/zebra/netconf_netlink.h +++ b/zebra/netconf_netlink.h @@ -17,8 +17,7 @@ extern "C" { #endif /* Parse and handle a NETCONF message. */ -extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, - int startup); +extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); /* Request info from the host OS. */ int netlink_request_netconf(int sockfd); diff --git a/zebra/rt.h b/zebra/rt.h index f8feb1ea1a54..6eaeba04400c 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -77,7 +77,6 @@ extern int mpls_kernel_init(void); void kernel_router_init(void); void kernel_router_terminate(void); -extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); /* @@ -92,6 +91,7 @@ extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void kernel_read_macfdb(struct zebra_dplane_ctx *ctx); extern void kernel_read_neigh(struct zebra_dplane_ctx *ctx); extern void kernel_read_tc_qdisc(struct zebra_dplane_ctx *ctx); +extern void kernel_read_intf_speed(struct zebra_dplane_ctx *ctx); extern void route_read(struct zebra_ns *zns); extern int kernel_upd_mac_nh(uint32_t nh_id, struct ipaddr *vtep_ip); extern int kernel_del_mac_nh(uint32_t nh_id); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 81a1d653d426..e396f29fe4f9 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1391,16 +1391,16 @@ static int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, return ret; } -static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, - int startup) +static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, int startup, + void *arg) { return netlink_route_change_read_unicast_internal(h, ns_id, startup); } static struct mcast_route_data *mroute = NULL; -static int netlink_route_change_read_multicast(struct nlmsghdr *h, - ns_id_t ns_id, int startup) +static int netlink_route_change_read_multicast(struct nlmsghdr *h, ns_id_t ns_id, int startup, + void *arg) { int len; struct rtmsg *rtm; @@ -1512,7 +1512,7 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, return 0; } -int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct rtmsg *rtm; @@ -1571,7 +1571,7 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (rtm->rtm_type == RTN_MULTICAST) return 0; - netlink_route_change_read_unicast(h, ns_id, startup); + netlink_route_change_read_unicast(h, ns_id, startup, arg); return 0; } @@ -1606,8 +1606,8 @@ int netlink_route_read(struct zebra_ns *zns) ret = netlink_request_route(zns, AF_INET, RTM_GETROUTE); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_route_change_read_unicast, - &zns->netlink_cmd, &dp_info, 0, true); + ret = netlink_parse_info(netlink_route_change_read_unicast, &zns->netlink_cmd, &dp_info, 0, + true, NULL, NULL); if (ret < 0) return ret; @@ -1615,8 +1615,8 @@ int netlink_route_read(struct zebra_ns *zns) ret = netlink_request_route(zns, AF_INET6, RTM_GETROUTE); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_route_change_read_unicast, - &zns->netlink_cmd, &dp_info, 0, true); + ret = netlink_parse_info(netlink_route_change_read_unicast, &zns->netlink_cmd, &dp_info, 0, + true, NULL, NULL); if (ret < 0) return ret; @@ -2501,8 +2501,7 @@ static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla, ifp->vrf->vrf_id); } } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - false); + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false, NULL, NULL); } static bool nexthop_set_src(const struct nexthop *nexthop, int family, @@ -2986,8 +2985,8 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return 0; } - suc = netlink_talk(netlink_route_change_read_multicast, &req.n, - &zns->netlink_cmd, zns, false); + suc = netlink_talk(netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, + false, NULL, NULL); mroute = NULL; return suc; @@ -3663,7 +3662,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, * * Return: Result status */ -int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; /* nexthop group id */ @@ -3831,8 +3830,8 @@ int netlink_nexthop_read(struct zebra_ns *zns) ret = netlink_request_nexthop(zns, AF_UNSPEC, RTM_GETNEXTHOP); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd, - &dp_info, 0, true); + ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd, &dp_info, 0, true, + NULL, NULL); if (!ret) /* If we successfully read in nexthop objects, @@ -4175,7 +4174,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; } -static int netlink_macfdb_table(struct nlmsghdr *h, ns_id_t ns_id, int startup) +static int netlink_macfdb_table(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct ndmsg *ndm; @@ -4235,7 +4234,7 @@ static int netlink_macfdb_read(struct nlsock *nl, const struct zebra_dplane_info return ret; /* We are reading entire table. */ filter_vlan = 0; - ret = netlink_parse_info(netlink_macfdb_table, nl, dp_info, 0, true); + ret = netlink_parse_info(netlink_macfdb_table, nl, dp_info, 0, true, NULL, NULL); return ret; } @@ -4261,7 +4260,7 @@ static int netlink_macfdb_read_for_bridge(struct nlsock *nl, if (ret < 0) goto done; - ret = netlink_parse_info(netlink_macfdb_table, nl, dp_info, 0, false); + ret = netlink_parse_info(netlink_macfdb_table, nl, dp_info, 0, false, NULL, NULL); done: /* Reset VLAN filter. */ @@ -4338,7 +4337,7 @@ static int netlink_macfdb_read_specific_mac(struct nlsock *nl, if (ret < 0) return ret; - return netlink_parse_info(netlink_macfdb_table, nl, dp_info, 1, false); + return netlink_parse_info(netlink_macfdb_table, nl, dp_info, 1, false, NULL, NULL); } static int netlink_macfdb_read_mcast_for_vni(struct nlsock *nl, @@ -4354,7 +4353,7 @@ static int netlink_macfdb_read_mcast_for_vni(struct nlsock *nl, if (ret < 0) return ret; - return netlink_parse_info(netlink_macfdb_table, nl, dp_info, 1, false); + return netlink_parse_info(netlink_macfdb_table, nl, dp_info, 1, false, NULL, NULL); } void kernel_read_macfdb(struct zebra_dplane_ctx *ctx) @@ -4637,7 +4636,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; } -static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup) +static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { int len; struct ndmsg *ndm; @@ -4747,15 +4746,15 @@ void kernel_read_neigh(struct zebra_dplane_ctx *ctx) if (ip->ipa_type != IPADDR_NONE) { ret = netlink_request_specific_neigh_in_vlan(nl, RTM_GETNEIGH, ip, ifindex); if (ret >= 0) - netlink_parse_info(netlink_neigh_table, nl, dp_info, 1, false); + netlink_parse_info(netlink_neigh_table, nl, dp_info, 1, false, NULL, NULL); } else if (ifindex) { ret = netlink_request_neigh(nl, AF_UNSPEC, RTM_GETNEIGH, ifindex); if (ret >= 0) - netlink_parse_info(netlink_neigh_table, nl, dp_info, 0, false); + netlink_parse_info(netlink_neigh_table, nl, dp_info, 0, false, NULL, NULL); } else { ret = netlink_request_neigh(nl, AF_UNSPEC, RTM_GETNEIGH, 0); if (ret >= 0) - netlink_parse_info(netlink_neigh_table, nl, dp_info, 0, true); + netlink_parse_info(netlink_neigh_table, nl, dp_info, 0, true, NULL, NULL); } dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); @@ -5172,8 +5171,7 @@ static int netlink_fdb_nh_update(uint32_t nh_id, struct ipaddr *vtep_ip) if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) zlog_debug("Tx %s fdb-nh 0x%x %pIA", nl_msg_type_to_str(cmd), nh_id, vtep_ip); - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - false); + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false, NULL, NULL); } static int netlink_fdb_nh_del(uint32_t nh_id) @@ -5205,8 +5203,7 @@ static int netlink_fdb_nh_del(uint32_t nh_id) nl_msg_type_to_str(cmd), nh_id); } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - false); + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false, NULL, NULL); } static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt, @@ -5263,8 +5260,7 @@ static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt, nl_msg_type_to_str(cmd), nhg_id, vtep_str); } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - false); + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false, NULL, NULL); } static int netlink_fdb_nhg_del(uint32_t nhg_id) diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index dc883cd891d9..15f762ad1fd0 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -61,7 +61,7 @@ extern ssize_t netlink_route_multipath_msg_encode(int cmd, extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, size_t datalen); -extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); +extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); extern int netlink_route_read(struct zebra_ns *zns); /* @@ -73,8 +73,7 @@ extern int netlink_route_read(struct zebra_ns *zns); int netlink_route_notify_read_ctx(struct nlmsghdr *h, ns_id_t ns_id, struct zebra_dplane_ctx *ctx); -extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, - int startup); +extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); extern int netlink_nexthop_read(struct zebra_ns *zns); extern ssize_t netlink_nexthop_msg_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 3f7b052e8eb9..591cdcd67a50 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -383,9 +383,10 @@ extern int kernel_interface_set_master(struct interface *master, return 0; } -uint32_t kernel_get_speed(struct interface *ifp, int *error) +void kernel_read_intf_speed(struct zebra_dplane_ctx *ctx) { - return ifp->speed; + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_set_ifp_speed_set(ctx, false); } int kernel_upd_mac_nh(uint32_t nh_id, struct ipaddr *vtep_ip) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 1d6e9ebe1fc4..9747af6ccb78 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -245,7 +245,7 @@ netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) * from a previous instance and should have been removed on shutdown. * */ -int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { struct zebra_ns *zns; struct fib_rule_hdr *frh; @@ -416,8 +416,7 @@ int netlink_rules_read(struct zebra_ns *zns) if (ret < 0) return ret; - ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, - &dp_info, 0, true); + ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, &dp_info, 0, true, NULL, NULL); if (ret < 0) return ret; @@ -425,8 +424,7 @@ int netlink_rules_read(struct zebra_ns *zns) if (ret < 0) return ret; - ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, - &dp_info, 0, true); + ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, &dp_info, 0, true, NULL, NULL); return ret; } diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h index 8ffca49b6f0d..04ac038d4936 100644 --- a/zebra/rule_netlink.h +++ b/zebra/rule_netlink.h @@ -17,7 +17,7 @@ extern "C" { /* * Handle netlink notification informing a rule add or delete. */ -extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); +extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); /* * Get to know existing PBR rules in the kernel - typically called at startup. diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index da433cbbb1a2..67b2018295b0 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -705,7 +705,7 @@ static int netlink_request_qdiscs(struct nlsock *nl, int family, int type) return netlink_request(nl, &req); } -int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { struct tcmsg *tcm; enum tc_qdisc_kind kind = TC_QDISC_UNSPEC; @@ -747,7 +747,7 @@ int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } -int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { struct tcmsg *tcm; @@ -782,7 +782,7 @@ int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } -int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg) { struct tcmsg *tcm; @@ -822,7 +822,7 @@ void kernel_read_tc_qdisc(struct zebra_dplane_ctx *ctx) ret = netlink_request_qdiscs(nl, AF_UNSPEC, RTM_GETQDISC); if (ret >= 0) - netlink_parse_info(netlink_qdisc_change, nl, dp_info, 0, true); + netlink_parse_info(netlink_qdisc_change, nl, dp_info, 0, true, NULL, NULL); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); diff --git a/zebra/tc_netlink.h b/zebra/tc_netlink.h index b23ef3cf02b9..afdd4f5e8c46 100644 --- a/zebra/tc_netlink.h +++ b/zebra/tc_netlink.h @@ -49,11 +49,9 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, * the sake of consistency with kernel message types (RTM_NEWTFILTER etc.) */ -extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, - int startup); -extern int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, - int startup); -extern int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); +extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); +extern int netlink_tclass_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); +extern int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup, void *arg); #ifdef __cplusplus diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 90e2b37fdc06..d301e45c5b16 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -240,6 +240,9 @@ struct dplane_intf_info { uint32_t flags; uint32_t change_flags; + bool speed_set; + uint32_t speed; + bool protodown; bool protodown_set; bool pd_reason_val; @@ -688,6 +691,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_intfs_in; _Atomic uint32_t dg_intf_errors; + _Atomic uint32_t dg_intf_speed_get_in; + _Atomic uint32_t dg_intf_speed_get_errors; + _Atomic uint32_t dg_tcs_in; _Atomic uint32_t dg_tcs_errors; @@ -966,6 +972,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) break; case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_NETCONFIG: + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_STARTUP_STAGE: case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: break; @@ -1255,6 +1262,9 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_INTF_DELETE: return "INTF_DELETE"; + case DPLANE_OP_INTF_SPEED_GET: + return "INTF_SPEED_GET"; + case DPLANE_OP_TC_QDISC_INSTALL: return "TC_QDISC_INSTALL"; case DPLANE_OP_TC_QDISC_UNINSTALL: @@ -1882,6 +1892,34 @@ void dplane_ctx_set_ifp_zif_type(struct zebra_dplane_ctx *ctx, ctx->u.intf.zif_type = zif_type; } +void dplane_ctx_set_ifp_speed_set(struct zebra_dplane_ctx *ctx, bool set) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.speed_set = set; +} + +bool dplane_ctx_get_ifp_speed_set(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.speed_set; +} + +void dplane_ctx_set_ifp_speed(struct zebra_dplane_ctx *ctx, uint32_t speed) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.speed = speed; +} + +uint32_t dplane_ctx_get_ifp_speed(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.speed; +} + void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname) { DPLANE_CTX_VALID(ctx); @@ -5675,6 +5713,45 @@ enum zebra_dplane_result dplane_intf_update(const struct interface *ifp) return ret; } +/* + * Enqueue a interface speed query for the dataplane. + */ +enum zebra_dplane_result dplane_intf_speed_get(const struct interface *ifp) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx = NULL; + struct zebra_ns *zns; + int ret; + + ctx = dplane_ctx_alloc(); + + ctx->zd_op = DPLANE_OP_INTF_SPEED_GET; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + ctx->zd_vrf_id = ifp->vrf->vrf_id; + + strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); + ctx->zd_ifindex = ifp->ifindex; + + zns = zebra_ns_lookup(ifp->vrf->vrf_id); + dplane_ctx_ns_init(ctx, zns, false); + + ret = dplane_update_enqueue(ctx); + + /* Increment counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_intf_speed_get_in, 1, memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_intf_speed_get_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + /* * Enqueue vxlan/evpn mac add (or update). */ @@ -6685,6 +6762,11 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Intf change updates: %" PRIu64 "\n", incoming); vty_out(vty, "Intf change errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_intf_speed_get_in, memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_intf_speed_get_errors, memory_order_relaxed); + vty_out(vty, "Intf speed query: %" PRIu64 "\n", incoming); + vty_out(vty, "Intf speed errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_macs_in, memory_order_relaxed); errs = atomic_load_explicit(&zdplane_info.dg_mac_errors, @@ -7328,6 +7410,10 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifindex(ctx), dplane_ctx_intf_is_protodown(ctx)); break; + case DPLANE_OP_INTF_SPEED_GET: + zlog_debug("Dplane intf %s, idx %u", dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifindex(ctx)); + break; /* TODO: more detailed log */ case DPLANE_OP_TC_QDISC_INSTALL: @@ -7547,6 +7633,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_INTF_NETCONFIG: + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_VLAN_INSTALL: break; @@ -7615,6 +7702,14 @@ static void kernel_dplane_process_tc_qdisc_read(struct zebra_dplane_provider *pr dplane_provider_enqueue_out_ctx(prov, ctx); } +/* Runs in the dplane pthread. */ +static void kernel_dplane_process_if_speed(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + kernel_read_intf_speed(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + /* * Kernel provider callback */ @@ -7679,6 +7774,8 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) kernel_dplane_process_neigh_read(prov, ctx); else if (dplane_ctx_get_op(ctx) == DPLANE_OP_TC_QDISC_READ) kernel_dplane_process_tc_qdisc_read(prov, ctx); + else if (dplane_ctx_get_op(ctx) == DPLANE_OP_INTF_SPEED_GET) + kernel_dplane_process_if_speed(prov, ctx); else dplane_ctx_list_add_tail(&work_list, ctx); } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 15417b8e29bd..b1585065a225 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -193,6 +193,7 @@ enum dplane_op_e { /* Incoming interface config events */ DPLANE_OP_INTF_NETCONFIG, + DPLANE_OP_INTF_SPEED_GET, /* Interface update */ DPLANE_OP_INTF_INSTALL, @@ -459,6 +460,10 @@ uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx); struct zebra_vxlan_vni_array; void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, struct zebra_vxlan_vni_array *vniarray); +void dplane_ctx_set_ifp_speed_set(struct zebra_dplane_ctx *ctx, bool set); +bool dplane_ctx_get_ifp_speed_set(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_speed(struct zebra_dplane_ctx *ctx, uint32_t speed); +uint32_t dplane_ctx_get_ifp_speed(const struct zebra_dplane_ctx *ctx); /* * These defines mirror the values for bridge values in linux @@ -1016,6 +1021,7 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp, */ enum zebra_dplane_result dplane_intf_add(const struct interface *ifp); enum zebra_dplane_result dplane_intf_update(const struct interface *ifp); +enum zebra_dplane_result dplane_intf_speed_get(const struct interface *ifp); /* * Enqueue tc link changes for the dataplane. diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 64d8f154ab16..da7a0ae80896 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -5279,6 +5279,7 @@ static void rib_process_dplane_results(struct event *event) case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: case DPLANE_OP_INTF_NETCONFIG: + case DPLANE_OP_INTF_SPEED_GET: zebra_if_dplane_result(ctx); break; diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index a3e92d18bc82..08fa3c7f925d 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -424,6 +424,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_UPDATE: /* Not currently handled */ case DPLANE_OP_INTF_NETCONFIG: /*NYI*/ + case DPLANE_OP_INTF_SPEED_GET: case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: