From ebb61fcaf5b94c4cafac1016625200e9bafe5ab9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 4 May 2021 08:50:00 -0400 Subject: [PATCH 1/8] zebra: Start of work to get data about mpls from kernel a) We'll need to pass the info up via some dataplane control method (This way bsd and linux can both be zebra agnostic of each other) b) We'll need to modify `struct interface *` to track this data and when it changes to notify upper level protocols about it. c) Work is needed to dump the entire mpls state at the start so we can gather interface state. This should be done after interface data gathering from the kernel. Signed-off-by: Donald Sharp Signed-off-by: Mark Stapp --- include/linux/netconf.h | 30 +++++++++ include/subdir.am | 1 + zebra/if_netlink.c | 6 ++ zebra/kernel_netlink.c | 11 +++- zebra/netconf_netlink.c | 139 ++++++++++++++++++++++++++++++++++++++++ zebra/netconf_netlink.h | 45 +++++++++++++ zebra/subdir.am | 2 + 7 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 include/linux/netconf.h create mode 100644 zebra/netconf_netlink.c create mode 100644 zebra/netconf_netlink.h diff --git a/include/linux/netconf.h b/include/linux/netconf.h new file mode 100644 index 0000000000..fac4edd553 --- /dev/null +++ b/include/linux/netconf.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_NETCONF_H_ +#define _UAPI_LINUX_NETCONF_H_ + +#include +#include + +struct netconfmsg { + __u8 ncm_family; +}; + +enum { + NETCONFA_UNSPEC, + NETCONFA_IFINDEX, + NETCONFA_FORWARDING, + NETCONFA_RP_FILTER, + NETCONFA_MC_FORWARDING, + NETCONFA_PROXY_NEIGH, + NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + NETCONFA_INPUT, + NETCONFA_BC_FORWARDING, + __NETCONFA_MAX +}; +#define NETCONFA_MAX (__NETCONFA_MAX - 1) +#define NETCONFA_ALL -1 + +#define NETCONFA_IFINDEX_ALL -1 +#define NETCONFA_IFINDEX_DEFAULT -2 + +#endif /* _UAPI_LINUX_NETCONF_H_ */ diff --git a/include/subdir.am b/include/subdir.am index 86129c4d68..a06a8e5649 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -5,6 +5,7 @@ noinst_HEADERS += \ include/linux/lwtunnel.h \ include/linux/mpls_iptunnel.h \ include/linux/neighbour.h \ + include/linux/netconf.h \ include/linux/netlink.h \ include/linux/nexthop.h \ include/linux/rtnetlink.h \ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 141e4074d5..b915d4720a 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -74,6 +74,7 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_l2.h" +#include "zebra/netconf_netlink.h" extern struct zebra_privs_t zserv_privs; @@ -1001,6 +1002,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Hardware type and address. */ ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type); + netlink_interface_update_hw_addr(tb, ifp); if_add_update(ifp); @@ -2078,6 +2080,10 @@ void interface_list(struct zebra_ns *zns) netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); + + /* Read some other properties via the 'netconf' apis */ + netconf_lookup_netlink(zns); + } #endif /* GNU_LINUX */ diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 23e7098d04..0cd69e6c2c 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -48,6 +48,7 @@ #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" #include "zebra/rule_netlink.h" +#include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" #ifndef SO_RCVBUFFORCE @@ -108,6 +109,8 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, + {RTM_NEWNETCONF, "RTM_NEWNETCONF"}, + {RTM_DELNETCONF, "RTM_DELNETCONF"}, {0}}; static const struct message rtproto_str[] = { @@ -370,6 +373,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELNEXTHOP: return netlink_nexthop_change(h, ns_id, startup); + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + return netlink_netconf_change(h, ns_id, startup); + /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: @@ -1593,7 +1600,9 @@ void kernel_init(struct zebra_ns *zns) RTMGRP_NEIGH | ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) | ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | - ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)); + ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)) | + ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1)); dplane_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c new file mode 100644 index 0000000000..e43685b794 --- /dev/null +++ b/zebra/netconf_netlink.c @@ -0,0 +1,139 @@ +/* + * netconf_netlink.c - netconf interaction with the kernel using + * netlink + * Copyright (C) 2021 Nvidia, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include + +#ifdef HAVE_NETLINK /* Netlink OSes only */ + +#include + +#include "linux/netconf.h" + +#include "zebra/zebra_ns.h" +#include "zebra/zebra_dplane.h" +#include "zebra/kernel_netlink.h" +#include "zebra/netconf_netlink.h" +#include "zebra/debug.h" + +static struct rtattr *netconf_rta(struct netconfmsg *ncm) +{ + return (struct rtattr *)((char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); +} + +int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + struct netconfmsg *ncm; + struct rtattr *tb[NETCONFA_MAX + 1] = {}; + int len; + ifindex_t ifindex; + bool mpls_on = false; + bool mc_on = false; + + if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg)); + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + __func__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg))); + return -1; + } + + ncm = NLMSG_DATA(h); + + netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len); + + if (!tb[NETCONFA_IFINDEX]) { + zlog_err("%s: Message received from netlink that we expected to receive an interface on", + __func__); + return 0; + } + + ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]); + + switch (ifindex) { + case NETCONFA_IFINDEX_ALL: + case NETCONFA_IFINDEX_DEFAULT: + /* + * We need the ability to handle netlink messages intended + * for all and default interfaces. I am not 100% sure + * what that is yet, or where we would store it. + */ + return 0; + default: + break; + } + if (tb[NETCONFA_INPUT]) { + mpls_on = *(bool *)RTA_DATA(tb[NETCONFA_INPUT]); + /* Create a context and pass it up for processing */ + } + + if (tb[NETCONFA_MC_FORWARDING]) { + mc_on = *(bool *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]); + /* Create a context and pass it up for processing */ + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Interface %u is mpls on: %d multicast on: %d", + ifindex, mpls_on, mc_on); + + return 0; +} + +static int netlink_request_netconf(struct nlsock *netlink_cmd) +{ + struct { + struct nlmsghdr n; + struct netconfmsg ncm; + char buf[1024]; + } req; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); + req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETNETCONF; + req.ncm.ncm_family = AF_UNSPEC; + + return netlink_request(netlink_cmd, &req); +} + +int netconf_lookup_netlink(struct zebra_ns *zns) +{ + int ret; + struct zebra_dplane_info dp_info; + struct nlsock *netlink_cmd = &zns->netlink_cmd; + + zebra_dplane_info_from_zns(&dp_info, zns, true); + + ret = netlink_request_netconf(netlink_cmd); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_netconf_change, netlink_cmd, &dp_info, + 0, 1); + return ret; +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/netconf_netlink.h b/zebra/netconf_netlink.h new file mode 100644 index 0000000000..0eae2119dd --- /dev/null +++ b/zebra/netconf_netlink.h @@ -0,0 +1,45 @@ +/* + * netconf_netlink.h - netconf interaction with the kernel using + * netlink + * Copyright (C) 2021 Nvidia, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef __NETCONF_NETLINK_H__ +#define __NETCONF_NETLINK_H__ + +#ifdef HAVE_NETLINK /* Netlink-only module */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, + int startup); + +extern int netconf_lookup_netlink(struct zebra_ns *zns); + + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_NETLINK */ + +#endif /* NETCONF_NETLINK_H */ diff --git a/zebra/subdir.am b/zebra/subdir.am index f0cc6ce71b..77e0898d81 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -69,6 +69,7 @@ zebra_zebra_SOURCES = \ zebra/kernel_socket.c \ zebra/label_manager.c \ zebra/main.c \ + zebra/netconf_netlink.c \ zebra/redistribute.c \ zebra/router-id.c \ zebra/rt_netlink.c \ @@ -148,6 +149,7 @@ noinst_HEADERS += \ zebra/kernel_netlink.h \ zebra/kernel_socket.h \ zebra/label_manager.h \ + zebra/netconf_netlink.h \ zebra/redistribute.h \ zebra/rib.h \ zebra/router-id.h \ From c9781f524c3ca17584c86c0e1f4d68dd8b8d4348 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 17 Sep 2021 16:30:23 -0400 Subject: [PATCH 2/8] build: correct help output about netlink debug The configure flag _disables_ netlink debug; make the help text match that. Signed-off-by: Mark Stapp --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bdddf4b846..ae773fbaa9 100644 --- a/configure.ac +++ b/configure.ac @@ -765,7 +765,7 @@ AC_ARG_ENABLE([scripting], AS_HELP_STRING([--enable-scripting], [Build with scripting support])) AC_ARG_ENABLE([netlink-debug], - AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages])) + AS_HELP_STRING([--disable-netlink-debug], [don't pretty print netlink debug messages])) if test "$enable_netlink_debug" != "no" ; then AC_DEFINE([NETLINK_DEBUG], [1], [Netlink extra debugging code]) From b6beb70047f008a956f2e30cd581211d0e2d6672 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 17 Sep 2021 16:32:27 -0400 Subject: [PATCH 3/8] zebra: include mpls enabled status in interface output Add mpls status to the zebra interface struct; include mpls status in show interface output. Signed-off-by: Mark Stapp --- zebra/interface.c | 5 +++++ zebra/interface.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/zebra/interface.c b/zebra/interface.c index 5d1080fd72..7dd7e49479 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1670,6 +1670,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) vty_out(vty, "mtu6 %d ", ifp->mtu6); vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags)); + if (zebra_if->mpls) + vty_out(vty, " MPLS enabled\n"); + /* Hardware address. */ vty_out(vty, " Type: %s\n", if_link_type_str(ifp->ll_type)); if (ifp->hw_addr_len != 0) { @@ -1990,6 +1993,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_string_add(json_if, "OsDescription", zebra_if->desc); + json_object_boolean_add(json_if, "mplsEnabled", zebra_if->mpls); + if (ifp->ifindex == IFINDEX_INTERNAL) { json_object_boolean_add(json_if, "pseudoInterface", true); return; diff --git a/zebra/interface.h b/zebra/interface.h index 413a67469a..c00e1fba69 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -329,6 +329,9 @@ struct zebra_if { /* Multicast configuration. */ uint8_t multicast; + /* MPLS status. */ + bool mpls; + /* Router advertise configuration. */ uint8_t rtadv_enable; From 777f96503e434f3d466ecf97b374cd10ed27d944 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 17 Sep 2021 16:38:16 -0400 Subject: [PATCH 4/8] zebra: add netlink debug dump for netconf messages Add the RTM_NETCONF messages to the detailed netlink message dump module. Signed-off-by: Mark Stapp --- zebra/debug_nl.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index 825497fff3..260ba30b3c 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -90,6 +91,11 @@ const char *nlmsg_type2str(uint16_t type) case RTM_GETNEXTHOP: return "GETNEXTHOP"; + case RTM_NEWNETCONF: + return "RTM_NEWNETCONF"; + case RTM_DELNETCONF: + return "RTM_DELNETCONF"; + default: return "UNKNOWN"; } @@ -657,6 +663,37 @@ const char *frh_action2str(uint8_t action) } } +static const char *ncm_rta2str(int type) +{ + switch (type) { + case NETCONFA_UNSPEC: + return "UNSPEC"; + case NETCONFA_IFINDEX: + return "IFINDEX"; + case NETCONFA_FORWARDING: + return "FORWARDING"; + case NETCONFA_RP_FILTER: + return "RP_FILTER"; + case NETCONFA_MC_FORWARDING: + return "MCAST"; + case NETCONFA_PROXY_NEIGH: + return "PROXY_NEIGH"; + case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN: + return "IGNORE_LINKDOWN"; + case NETCONFA_INPUT: + return "MPLS"; + case NETCONFA_BC_FORWARDING: + return "BCAST"; + default: + return "UNKNOWN"; + } +} + +static void dump_on_off(uint32_t ival, const char *prefix) +{ + zlog_debug("%s%s", prefix, (ival != 0) ? "on" : "off"); +} + static inline void flag_write(int flags, int flag, const char *flagstr, char *buf, size_t buflen) { @@ -1118,6 +1155,7 @@ static void nlnh_dump(struct nhmsg *nhm, size_t msglen) struct nexthop_grp *nhgrp; rta = RTM_NHA(nhm); + next_rta: /* Check the header for valid length and for outbound access. */ if (RTA_OK(rta, msglen) == 0) @@ -1296,6 +1334,52 @@ next_rta: goto next_rta; } +static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen) +{ + const struct rtattr *rta; + size_t plen; + uint32_t ival; + + rta = (void *)((const char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); + +next_rta: + /* Check the attr header for valid length. */ + if (RTA_OK(rta, msglen) == 0) + return; + + plen = RTA_PAYLOAD(rta); + + zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, + plen, rta->rta_type, ncm_rta2str(rta->rta_type)); + + switch (rta->rta_type) { + case NETCONFA_IFINDEX: + ival = *(uint32_t *)RTA_DATA(rta); + zlog_debug(" %d", (int32_t)ival); + break; + + /* Most attrs are just on/off. */ + case NETCONFA_FORWARDING: + case NETCONFA_RP_FILTER: + case NETCONFA_MC_FORWARDING: + case NETCONFA_PROXY_NEIGH: + case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN: + case NETCONFA_INPUT: + case NETCONFA_BC_FORWARDING: + ival = *(uint32_t *)RTA_DATA(rta); + dump_on_off(ival, " "); + break; + default: + /* NOTHING: unhandled. */ + break; + } + + /* Get next pointer and start iteration again. */ + rta = RTA_NEXT(rta, msglen); + goto next_rta; +} + void nl_dump(void *msg, size_t msglen) { struct nlmsghdr *nlmsg = msg; @@ -1305,6 +1389,7 @@ void nl_dump(void *msg, size_t msglen) struct ndmsg *ndm; struct rtmsg *rtm; struct nhmsg *nhm; + struct netconfmsg *ncm; struct ifinfomsg *ifi; struct fib_rule_hdr *frh; char fbuf[128]; @@ -1422,6 +1507,14 @@ next_header: nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm))); break; + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + ncm = NLMSG_DATA(nlmsg); + zlog_debug(" ncm [family=%s (%d)]", + af_type2str(ncm->ncm_family), ncm->ncm_family); + nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm))); + break; + default: break; } From 9f3f1486c8add83ee71a7dd73096e77dfd357a1f Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Mon, 18 Oct 2021 11:55:24 -0400 Subject: [PATCH 5/8] zebra: add xxxNETCONF messages to the netlink BPF filter Allow self-produced xxxNETCONF netlink messages through the BPF filter we use. Just like address-configuration actions, we'll process NETCONF changes in one path, whether the changes were generated by zebra or by something else in the host OS. Signed-off-by: Mark Stapp --- zebra/kernel_netlink.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 0cd69e6c2c..8e472b4728 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -38,7 +38,6 @@ #include "lib_errors.h" #include "hash.h" -//#include "zebra/zserv.h" #include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" @@ -414,7 +413,12 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELADDR: return netlink_interface_addr_dplane(h, ns_id, startup); - /* TODO */ + case RTM_NEWNETCONF: + case RTM_DELNETCONF: + return netlink_netconf_change(h, ns_id, startup); + + /* TODO -- other messages for the dplane socket and pthread */ + case RTM_NEWLINK: case RTM_DELLINK: @@ -463,8 +467,8 @@ int kernel_dplane_read(struct zebra_dplane_info *info) * then the normal course of operations). We are intentionally * allowing some messages from ourselves through * ( I'm looking at you Interface based netlink messages ) - * so that we only had to write one way to handle incoming - * address add/delete changes. + * so that we only have to write one way to handle incoming + * address add/delete and xxxNETCONF changes. */ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) { @@ -480,7 +484,8 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) * if (nlmsg_pid == pid || * nlmsg_pid == dplane_pid) { * if (the incoming nlmsg_type == - * RTM_NEWADDR | RTM_DELADDR) + * RTM_NEWADDR || RTM_DELADDR || RTM_NEWNETCONF || + * RTM_DELNETCONF) * keep this message * else * skip this message @@ -499,7 +504,7 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 2: Compare to dplane pid */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 4), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(dplane_pid), 0, 6), /* * 3: Load the nlmsg_type into BPF register */ @@ -508,17 +513,27 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) /* * 4: Compare to RTM_NEWADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 4, 0), /* * 5: Compare to RTM_DELADDR */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 3, 0), /* - * 6: This is the end state of we want to skip the + * 6: Compare to RTM_NEWNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWNETCONF), 2, + 0), + /* + * 7: Compare to RTM_DELNETCONF + */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELNETCONF), 1, + 0), + /* + * 8: This is the end state of we want to skip the * message */ BPF_STMT(BPF_RET | BPF_K, 0), - /* 7: This is the end state of we want to keep + /* 9: This is the end state of we want to keep * the message */ BPF_STMT(BPF_RET | BPF_K, 0xffff), From d4bcd88d8a3a84b2933d1ddb6db5556f8e1614dc Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Wed, 27 Oct 2021 13:56:06 -0400 Subject: [PATCH 6/8] zebra: avoid default clause in FPM switch Avoid default clause in a switch in the FPM module that handles dplane op codes - include all the codes. Signed-off-by: Mark Stapp --- zebra/dplane_fpm_nl.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index ce3c8d4b11..0baef5bdb5 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -780,6 +780,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) nl_buf_len += (size_t)rv; break; + /* Un-handled by FPM at this time. */ case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: case DPLANE_OP_ADDR_INSTALL: @@ -793,15 +794,26 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_SYS_ROUTE_DELETE: case DPLANE_OP_ROUTE_NOTIFY: case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_RULE_ADD: + case DPLANE_OP_RULE_DELETE: + case DPLANE_OP_RULE_UPDATE: + case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_NONE: break; - default: - if (IS_ZEBRA_DEBUG_FPM) - zlog_debug("%s: unhandled data plane message (%d) %s", - __func__, dplane_ctx_get_op(ctx), - dplane_op2str(dplane_ctx_get_op(ctx))); - break; } /* Skip empty enqueues. */ From 728f2017ae285aea6f7e8bda369eaae7a3083899 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Thu, 28 Oct 2021 11:19:32 -0400 Subject: [PATCH 7/8] zebra: add dplane type for NETCONF data Add a new dplane op for interface NETCONF data; add the new enum value to several switch statements. Signed-off-by: Mark Stapp --- zebra/dplane_fpm_nl.c | 1 + zebra/kernel_netlink.c | 1 + zebra/zebra_dplane.c | 94 ++++++++++++++++++++++++++++++++++++++++-- zebra/zebra_dplane.h | 34 +++++++++++++++ zebra/zebra_nhg.c | 1 + zebra/zebra_rib.c | 1 + zebra/zebra_script.c | 2 + 7 files changed, 131 insertions(+), 3 deletions(-) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 0baef5bdb5..8c8004190b 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -811,6 +811,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: break; diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8e472b4728..44389ae011 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1492,6 +1492,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 1967345d22..a062ad0cb6 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -290,6 +290,19 @@ struct dplane_gre_ctx { unsigned int mtu; struct zebra_l2info_gre info; }; + + +/* + * Network interface configuration info - aligned with netlink's NETCONF + * info. The flags values are public, in the dplane.h file... + */ +struct dplane_netconf_info { + ns_id_t ns_id; + ifindex_t ifindex; + enum dplane_netconf_status_e mpls_val; + enum dplane_netconf_status_e mcast_val; +}; + /* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the @@ -347,6 +360,7 @@ struct zebra_dplane_ctx { } ipset_entry; struct dplane_neigh_table neightable; struct dplane_gre_ctx gre; + struct dplane_netconf_info netconf; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -769,6 +783,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) } break; case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_NETCONFIG: break; } } @@ -1053,6 +1068,9 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_INTF_ADDR_DEL: return "INTF_ADDR_DEL"; + + case DPLANE_OP_INTF_NETCONFIG: + return "INTF_NETCONFIG"; } return ret; @@ -2239,6 +2257,10 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr) return ptr->status; } +/* + * End of interface extra info accessors + */ + uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2270,9 +2292,66 @@ dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx) return ctx->u.neightable.mcast_probes; } -/* - * End of interface extra info accessors - */ +ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.ifindex; +} + +ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.ns_id; +} + +void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.ifindex = ifindex; +} + +void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.ns_id = ns_id; +} + +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.mpls_val; +} + +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.netconf.mcast_val; +} + +void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.mpls_val = val; +} + +void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.netconf.mcast_val = val; +} /* * Retrieve the limit on the number of pending, unprocessed updates. @@ -5113,6 +5192,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifname(ctx), dplane_ctx_get_intf_addr(ctx)); break; + + case DPLANE_OP_INTF_NETCONFIG: + zlog_debug("%s: ifindex %d, mpls %d, mcast %d", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_netconf_ifindex(ctx), + dplane_ctx_get_netconf_mpls(ctx), + dplane_ctx_get_netconf_mcast(ctx)); + break; } } @@ -5258,6 +5345,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) /* TODO -- error counters for incoming events? */ case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: break; case DPLANE_OP_NONE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index a7a5f99e45..29555d5b56 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -185,6 +185,9 @@ enum dplane_op_e { /* Incoming interface address events */ DPLANE_OP_INTF_ADDR_ADD, DPLANE_OP_INTF_ADDR_DEL, + + /* Incoming interface config events */ + DPLANE_OP_INTF_NETCONFIG, }; /* @@ -222,6 +225,22 @@ enum dplane_op_e { #define DPLANE_BR_PORT_NON_DF (1 << 0) +/* Definitions for the dplane 'netconf' apis, corresponding to the netlink + * NETCONF api. + * Sadly, netlink sends incremental updates, so its messages may contain + * just a single changed attribute, and not necessarily + * a complete snapshot of the attributes. + */ +enum dplane_netconf_status_e { + DPLANE_NETCONF_STATUS_UNKNOWN = 0, + DPLANE_NETCONF_STATUS_ENABLED, + DPLANE_NETCONF_STATUS_DISABLED +}; + +/* Some special ifindex values that may be part of the dplane netconf api. */ +#define DPLANE_NETCONF_IFINDEX_ALL -1 +#define DPLANE_NETCONF_IFINDEX_DEFAULT -2 + /* Enable system route notifications */ void dplane_enable_sys_route_notifs(void); @@ -564,6 +583,21 @@ dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx); const struct zebra_l2info_gre * dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx); +/* Interface netconf info */ +ifindex_t dplane_ctx_get_netconf_ifindex(const struct zebra_dplane_ctx *ctx); +ns_id_t dplane_ctx_get_netconf_ns_id(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_netconf_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex); +void dplane_ctx_set_netconf_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t ns_id); +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx); +enum dplane_netconf_status_e +dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val); +void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx, + enum dplane_netconf_status_e val); + /* Namespace fd info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c1b104aec7..858309f3e7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2989,6 +2989,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_NETCONFIG: break; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c386fc4871..bfcbe645dd 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4334,6 +4334,7 @@ static void rib_process_dplane_results(struct thread *thread) case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index 0e19376abe..4087749fd7 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -412,6 +412,8 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) lua_setfield(L, -2, "mtu"); } lua_setfield(L, -2, "gre"); + + case DPLANE_OP_INTF_NETCONFIG: /*NYI*/ case DPLANE_OP_NONE: break; } /* Dispatch by op code */ From cd787a8a45ea3c94a689d5ff01ddf62467373550 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Thu, 28 Oct 2021 11:23:31 -0400 Subject: [PATCH 8/8] zebra: use dataplane to read interface NETCONF info Use the dataplane to query and read interface NETCONF data; add netconf-oriented data to the dplane context object, and add accessors for it. Add handler for incoming update processing. Signed-off-by: Mark Stapp --- zebra/if_netlink.c | 4 -- zebra/interface.c | 50 +++++++++++++++++++ zebra/interface.h | 1 + zebra/kernel_netlink.c | 16 +++---- zebra/netconf_netlink.c | 104 +++++++++++++++++++++++++++------------- zebra/netconf_netlink.h | 7 ++- zebra/zebra_dplane.c | 96 +++++++++++++++++++++++++++---------- zebra/zebra_rib.c | 5 +- 8 files changed, 208 insertions(+), 75 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index b915d4720a..db8ee3236c 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -2080,10 +2080,6 @@ void interface_list(struct zebra_ns *zns) netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); - - /* Read some other properties via the 'netconf' apis */ - netconf_lookup_netlink(zns); - } #endif /* GNU_LINUX */ diff --git a/zebra/interface.c b/zebra/interface.c index 7dd7e49479..c30f43456c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1318,6 +1318,56 @@ done: dplane_ctx_fini(&ctx); } +/* + * Handle netconf change from a dplane context object; runs in the main + * pthread so it can update zebra data structs. + */ +int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx) +{ + struct zebra_ns *zns; + struct interface *ifp; + struct zebra_if *zif; + enum dplane_netconf_status_e mpls; + int ret = 0; + + zns = zebra_ns_lookup(dplane_ctx_get_netconf_ns_id(ctx)); + if (zns == NULL) { + ret = -1; + goto done; + } + + ifp = if_lookup_by_index_per_ns(zns, + dplane_ctx_get_netconf_ifindex(ctx)); + if (ifp == NULL) { + ret = -1; + goto done; + } + + zif = ifp->info; + if (zif == NULL) { + ret = -1; + goto done; + } + + mpls = dplane_ctx_get_netconf_mpls(ctx); + + if (mpls == DPLANE_NETCONF_STATUS_ENABLED) + zif->mpls = true; + else if (mpls == DPLANE_NETCONF_STATUS_DISABLED) + zif->mpls = false; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: if %s, ifindex %d, mpls %s", + __func__, ifp->name, ifp->ifindex, + (zif->mpls ? "ON" : "OFF")); + +done: + /* Free the context */ + dplane_ctx_fini(&ctx); + + return ret; +} + /* Dump if address information to vty. */ static void connected_dump_vty(struct vty *vty, json_object *json, struct connected *connected) diff --git a/zebra/interface.h b/zebra/interface.h index c00e1fba69..85617961af 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -523,6 +523,7 @@ extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, char *pd_buf, uint32_t pd_buf_len); void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx); +int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx); #ifdef HAVE_PROC_NET_DEV extern void ifstat_update_proc(void); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 44389ae011..031ac0733c 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -372,13 +372,11 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELNEXTHOP: return netlink_nexthop_change(h, ns_id, startup); - case RTM_NEWNETCONF: - case RTM_DELNETCONF: - return netlink_netconf_change(h, ns_id, startup); - /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: + case RTM_NEWNETCONF: + case RTM_DELNETCONF: return 0; default: @@ -1616,13 +1614,15 @@ void kernel_init(struct zebra_ns *zns) RTMGRP_NEIGH | ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) | ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | - ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)) | - ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) | - ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1)); + ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)); dplane_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_IFADDR); + RTMGRP_IPV6_IFADDR | + ((uint32_t) 1 << (RTNLGRP_IPV4_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_IPV6_NETCONF - 1)) | + ((uint32_t) 1 << (RTNLGRP_MPLS_NETCONF - 1))); + snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c index e43685b794..587f6c749e 100644 --- a/zebra/netconf_netlink.c +++ b/zebra/netconf_netlink.c @@ -37,25 +37,53 @@ static struct rtattr *netconf_rta(struct netconfmsg *ncm) { - return (struct rtattr *)((char *)ncm - + NLMSG_ALIGN(sizeof(struct netconfmsg))); + return (struct rtattr *)((char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); } +/* + * Handle netconf update about a single interface: create dplane + * context, and enqueue for processing in the main zebra pthread. + */ +static int netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex, + enum dplane_netconf_status_e mpls_on, + enum dplane_netconf_status_e mcast_on) +{ + struct zebra_dplane_ctx *ctx; + + ctx = dplane_ctx_alloc(); + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG); + dplane_ctx_set_netconf_ns_id(ctx, ns_id); + dplane_ctx_set_netconf_ifindex(ctx, ifindex); + + dplane_ctx_set_netconf_mpls(ctx, mpls_on); + dplane_ctx_set_netconf_mcast(ctx, mcast_on); + + /* Enqueue ctx for main pthread to process */ + dplane_provider_enqueue_to_zebra(ctx); + + return 0; +} + +/* + * Parse and process an incoming netlink netconf update. + */ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { struct netconfmsg *ncm; struct rtattr *tb[NETCONFA_MAX + 1] = {}; int len; ifindex_t ifindex; - bool mpls_on = false; - bool mc_on = false; + uint32_t ival; + enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN; + enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN; if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg)); if (len < 0) { - zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu", __func__, h->nlmsg_len, (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg))); return -1; @@ -66,8 +94,7 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len); if (!tb[NETCONFA_IFINDEX]) { - zlog_err("%s: Message received from netlink that we expected to receive an interface on", - __func__); + zlog_err("NETCONF message received from netlink without an ifindex"); return 0; } @@ -81,59 +108,68 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) * for all and default interfaces. I am not 100% sure * what that is yet, or where we would store it. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Ignoring global ifindex %d", + __func__, ifindex); + return 0; default: break; } + if (tb[NETCONFA_INPUT]) { - mpls_on = *(bool *)RTA_DATA(tb[NETCONFA_INPUT]); - /* Create a context and pass it up for processing */ + ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]); + if (ival != 0) + mpls_on = DPLANE_NETCONF_STATUS_ENABLED; + else + mpls_on = DPLANE_NETCONF_STATUS_DISABLED; } if (tb[NETCONFA_MC_FORWARDING]) { - mc_on = *(bool *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]); - /* Create a context and pass it up for processing */ + ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]); + if (ival != 0) + mcast_on = DPLANE_NETCONF_STATUS_ENABLED; + else + mcast_on = DPLANE_NETCONF_STATUS_DISABLED; } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Interface %u is mpls on: %d multicast on: %d", - ifindex, mpls_on, mc_on); + zlog_debug("%s: interface %u is mpls on: %d multicast on: %d", + __func__, ifindex, mpls_on, mcast_on); + + /* Create a dplane context and pass it along for processing */ + netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on); return 0; } -static int netlink_request_netconf(struct nlsock *netlink_cmd) +/* + * Request info from the host OS. This only sends the request; any replies + * are processed asynchronously. + */ +int netlink_request_netconf(int sockfd) { + struct nlsock *nls; struct { struct nlmsghdr n; struct netconfmsg ncm; char buf[1024]; - } req; + } req = {}; + + nls = kernel_netlink_nlsock_lookup(sockfd); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL"); + + if (nls == NULL) + return -1; - memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETNETCONF; req.ncm.ncm_family = AF_UNSPEC; - return netlink_request(netlink_cmd, &req); -} - -int netconf_lookup_netlink(struct zebra_ns *zns) -{ - int ret; - struct zebra_dplane_info dp_info; - struct nlsock *netlink_cmd = &zns->netlink_cmd; - - zebra_dplane_info_from_zns(&dp_info, zns, true); - - ret = netlink_request_netconf(netlink_cmd); - if (ret < 0) - return ret; - - ret = netlink_parse_info(netlink_netconf_change, netlink_cmd, &dp_info, - 0, 1); - return ret; + return netlink_request(nls, &req); } #endif /* HAVE_NETLINK */ diff --git a/zebra/netconf_netlink.h b/zebra/netconf_netlink.h index 0eae2119dd..3f2e7af768 100644 --- a/zebra/netconf_netlink.h +++ b/zebra/netconf_netlink.h @@ -26,14 +26,17 @@ #ifdef HAVE_NETLINK /* Netlink-only module */ +#include "zebra/zebra_ns.h" + #ifdef __cplusplus 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 netconf_lookup_netlink(struct zebra_ns *zns); +/* Request info from the host OS. */ +int netlink_request_netconf(int sockfd); #ifdef __cplusplus diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index a062ad0cb6..6de2be3ab8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -28,6 +28,7 @@ #include "lib/memory.h" #include "lib/queue.h" #include "lib/zebra.h" +#include "zebra/netconf_netlink.h" #include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_vxlan_private.h" @@ -430,6 +431,9 @@ PREDECL_DLIST(zns_info_list); struct dplane_zns_info { struct zebra_dplane_info info; + /* Request data from the OS */ + struct thread *t_request; + /* Read event */ struct thread *t_read; @@ -554,8 +558,6 @@ DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link); /* Prototypes */ static void dplane_thread_loop(struct thread *event); -static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, - struct zebra_ns *zns); static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp, enum dplane_op_e op); static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, @@ -2384,6 +2386,22 @@ uint32_t dplane_get_in_queue_len(void) memory_order_seq_cst); } +/* + * Internal helper that copies information from a zebra ns object; this is + * called in the zebra main pthread context as part of dplane ctx init. + */ +static void ctx_info_from_zns(struct zebra_dplane_info *ns_info, + struct zebra_ns *zns) +{ + ns_info->ns_id = zns->ns_id; + +#if defined(HAVE_NETLINK) + ns_info->is_cmd = true; + ns_info->sock = zns->netlink_dplane_out.sock; + ns_info->seq = zns->netlink_dplane_out.seq; +#endif /* NETLINK */ +} + /* * Common dataplane context init with zebra namespace info. */ @@ -2391,7 +2409,7 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, struct zebra_ns *zns, bool is_update) { - dplane_info_from_zns(&(ctx->zd_ns_info), zns); + ctx_info_from_zns(&(ctx->zd_ns_info), zns); /* */ ctx->zd_is_update = is_update; @@ -4923,21 +4941,6 @@ bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov) return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED); } -/* - * Internal helper that copies information from a zebra ns object; this is - * called in the zebra main pthread context as part of dplane ctx init. - */ -static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, - struct zebra_ns *zns) -{ - ns_info->ns_id = zns->ns_id; - -#if defined(HAVE_NETLINK) - ns_info->is_cmd = true; - ns_info->sock = zns->netlink_dplane_out.sock; -#endif /* NETLINK */ -} - #ifdef HAVE_NETLINK /* * Callback when an OS (netlink) incoming event read is ready. This runs @@ -4953,6 +4956,40 @@ static void dplane_incoming_read(struct thread *event) thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, zi->info.sock, &zi->t_read); } + +/* + * Callback in the dataplane pthread that requests info from the OS and + * initiates netlink reads. + */ +static void dplane_incoming_request(struct thread *event) +{ + struct dplane_zns_info *zi = THREAD_ARG(event); + + /* Start read task */ + thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, + zi->info.sock, &zi->t_read); + + /* Send requests */ + netlink_request_netconf(zi->info.sock); +} + +/* + * Initiate requests for existing info from the OS. This is called by the + * main pthread, but we want all activity on the dplane netlink socket to + * take place on the dplane pthread, so we schedule an event to accomplish + * that. + */ +static void dplane_kernel_info_request(struct dplane_zns_info *zi) +{ + /* If we happen to encounter an enabled zns before the dplane + * pthread is running, we'll initiate this later on. + */ + if (zdplane_info.dg_master) + thread_add_event(zdplane_info.dg_master, + dplane_incoming_request, zi, 0, + &zi->t_request); +} + #endif /* HAVE_NETLINK */ /* @@ -4996,11 +5033,10 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled) zi->info.is_cmd = false; zi->info.sock = zns->netlink_dplane_in.sock; - /* Start read task for the dplane pthread. */ - if (zdplane_info.dg_master) - thread_add_read(zdplane_info.dg_master, - dplane_incoming_read, zi, zi->info.sock, - &zi->t_read); + /* Initiate requests for existing info from the OS, and + * begin reading from the netlink socket. + */ + dplane_kernel_info_request(zi); #endif } else if (zi) { if (IS_ZEBRA_DEBUG_DPLANE) @@ -5010,9 +5046,14 @@ void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled) /* Stop reading, free memory */ zns_info_list_del(&zdplane_info.dg_zns_list, zi); - if (zdplane_info.dg_master) + /* Stop any outstanding tasks */ + if (zdplane_info.dg_master) { + thread_cancel_async(zdplane_info.dg_master, + &zi->t_request, NULL); + thread_cancel_async(zdplane_info.dg_master, &zi->t_read, NULL); + } XFREE(MTYPE_DP_NS, zi); } @@ -5692,8 +5733,10 @@ static void dplane_check_shutdown_status(struct thread *event) frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) { zns_info_list_del(&zdplane_info.dg_zns_list, zi); - if (zdplane_info.dg_master) + if (zdplane_info.dg_master) { thread_cancel(&zi->t_read); + thread_cancel(&zi->t_request); + } XFREE(MTYPE_DP_NS, zi); } @@ -6023,11 +6066,12 @@ void zebra_dplane_start(void) thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0, &zdplane_info.dg_t_update); - /* Enqueue reads if necessary */ + /* Enqueue requests and reads if necessary */ frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) { #if defined(HAVE_NETLINK) thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, zi->info.sock, &zi->t_read); + dplane_kernel_info_request(zi); #endif } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index bfcbe645dd..af159da3cc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4320,6 +4320,10 @@ static void rib_process_dplane_results(struct thread *thread) zebra_if_addr_update_ctx(ctx); break; + case DPLANE_OP_INTF_NETCONFIG: + zebra_if_netconf_update_ctx(ctx); + break; + /* Some op codes not handled here */ case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: @@ -4334,7 +4338,6 @@ static void rib_process_dplane_results(struct thread *thread) case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx);