diff options
author | Mark Stapp <mstapp@nvidia.com> | 2021-10-28 17:23:31 +0200 |
---|---|---|
committer | Mark Stapp <mstapp@nvidia.com> | 2022-02-25 16:18:32 +0100 |
commit | cd787a8a45ea3c94a689d5ff01ddf62467373550 (patch) | |
tree | 6d33a836729d423443dd004ca2eda91933c44ea6 | |
parent | zebra: add dplane type for NETCONF data (diff) | |
download | frr-cd787a8a45ea3c94a689d5ff01ddf62467373550.tar.xz frr-cd787a8a45ea3c94a689d5ff01ddf62467373550.zip |
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 <mstapp@nvidia.com>
-rw-r--r-- | zebra/if_netlink.c | 4 | ||||
-rw-r--r-- | zebra/interface.c | 50 | ||||
-rw-r--r-- | zebra/interface.h | 1 | ||||
-rw-r--r-- | zebra/kernel_netlink.c | 16 | ||||
-rw-r--r-- | zebra/netconf_netlink.c | 104 | ||||
-rw-r--r-- | zebra/netconf_netlink.h | 7 | ||||
-rw-r--r-- | zebra/zebra_dplane.c | 96 | ||||
-rw-r--r-- | 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 b915d4720..db8ee3236 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 7dd7e4947..c30f43456 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 c00e1fba6..85617961a 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 44389ae01..031ac0733 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 e43685b79..587f6c749 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 0eae2119d..3f2e7af76 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 a062ad0cb..6de2be3ab 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, @@ -2385,13 +2387,29 @@ uint32_t dplane_get_in_queue_len(void) } /* + * 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. */ 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 bfcbe645d..af159da3c 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); |