diff options
author | Mark Stapp <mjs@cisco.com> | 2024-11-21 21:12:42 +0100 |
---|---|---|
committer | Mark Stapp <mjs@cisco.com> | 2024-12-05 15:23:53 +0100 |
commit | 29122bc9b8d5317f6f486f9fe61a92a854948cc5 (patch) | |
tree | e825fccf277a0db175f3d63bb996c1ea2a0b0197 | |
parent | zebra: add more dataplane route apis (diff) | |
download | frr-29122bc9b8d5317f6f486f9fe61a92a854948cc5.tar.xz frr-29122bc9b8d5317f6f486f9fe61a92a854948cc5.zip |
zebra: refactor netlink route message parsing
Separate core netlink route message parsing into a new api that
uses a dplane ctx to hold the parsed attribute data. Use the new
api in two paths: the normal netlink update message parsing path,
and in the FPM plugin, which also uses netlink encoding. The FPM
route-notificatin code runs in its own pthread, and only needs
a subset of the route info that zebra ordinarily develops. This
change stops that pthread from accessing zebra's internal
data, such as vrfs and ifps, that are not thread-safe.
Signed-off-by: Mark Stapp <mjs@cisco.com>
-rw-r--r-- | zebra/dplane_fpm_nl.c | 20 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 414 | ||||
-rw-r--r-- | zebra/rt_netlink.h | 13 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 32 | ||||
-rw-r--r-- | zebra/zebra_vrf.c | 19 | ||||
-rw-r--r-- | zebra/zebra_vrf.h | 3 |
6 files changed, 397 insertions, 104 deletions
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 3ec1c9d65..b8dbabb60 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -587,6 +587,7 @@ static void fpm_read(struct event *t) struct zebra_dplane_ctx *ctx; size_t available_bytes; size_t hdr_available_bytes; + int ival; /* Let's ignore the input at the moment. */ rv = stream_read_try(fnc->ibuf, fnc->socket, @@ -715,17 +716,28 @@ static void fpm_read(struct event *t) break; } + /* Parse the route data into a dplane ctx, then + * enqueue it to zebra for processing. + */ ctx = dplane_ctx_alloc(); dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL, NULL); - if (netlink_route_change_read_unicast_internal( - hdr, 0, false, ctx) != 1) { - dplane_ctx_fini(&ctx); - stream_pulldown(fnc->ibuf); + + if (netlink_route_notify_read_ctx(hdr, 0, ctx) >= 0) { + /* In the FPM encoding, the vrfid is present */ + ival = dplane_ctx_get_table(ctx); + dplane_ctx_set_vrf(ctx, ival); + dplane_ctx_set_table(ctx, + ZEBRA_ROUTE_TABLE_UNKNOWN); + + dplane_provider_enqueue_to_zebra(ctx); + } else { /* * Let's continue to read other messages * Even if we ignore this one. */ + dplane_ctx_fini(&ctx); + stream_pulldown(fnc->ibuf); } break; default: diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 492fe5288..f88c70cc5 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -723,44 +723,52 @@ static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_g return nhop_num; } -/* Looking up routing table by netlink interface. */ -int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, - ns_id_t ns_id, int startup, - struct zebra_dplane_ctx *ctx) +/* + * Parse netlink route message and capture info into a dplane ctx. + * Returns <0 if the message is to be skipped (might be an error) + */ +static int netlink_route_read_unicast_ctx(struct nlmsghdr *h, ns_id_t ns_id, + struct rtattr **tb_in, + struct zebra_dplane_ctx *ctx) { + int ret = 0; int len; struct rtmsg *rtm; - struct rtattr *tb[RTA_MAX + 1]; + struct rtattr **tb, *tb_array[RTA_MAX + 1]; uint32_t flags = 0; struct prefix p; - struct prefix_ipv6 src_p = {}; - vrf_id_t vrf_id; + struct prefix src_p = {}; bool selfroute; - - char anyaddr[16] = {0}; - + char anyaddr[16] = {}; int proto = ZEBRA_ROUTE_KERNEL; int index = 0; - int table; + int tableid; int metric = 0; uint32_t mtu = 0; uint8_t distance = 0; route_tag_t tag = 0; - uint32_t nhe_id = 0; - + uint32_t nhg_id = 0; void *dest = NULL; void *gate = NULL; + int gate_len; void *prefsrc = NULL; /* IPv4 preferred source host address */ + int prefsrc_len; void *src = NULL; /* IPv6 srcdest source prefix */ enum blackhole_type bh_type = BLACKHOLE_UNSPEC; + afi_t afi = AFI_IP; + struct ipaddr addr = {}; - frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id, - startup); + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + if (len < 0) { + zlog_err( + "%s: Netlink route message received with invalid size %d %zu", + __func__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct rtmsg))); + return -1; + } rtm = NLMSG_DATA(h); - if (startup && h->nlmsg_type != RTM_NEWROUTE) - return 0; switch (rtm->rtm_type) { case RTN_UNICAST: break; @@ -778,54 +786,42 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_debug("Route rtm_type: %s(%d) intentionally ignoring", nl_rttype_to_str(rtm->rtm_type), rtm->rtm_type); - return 0; + ret = -1; + goto done; } - len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); - 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 rtmsg))); - return -1; + if ((rtm->rtm_flags & RTM_F_CLONED) || + (rtm->rtm_protocol == RTPROT_REDIRECT)) { + ret = -1; + goto done; } - netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); - - if (rtm->rtm_flags & RTM_F_CLONED) - return 0; - if (rtm->rtm_protocol == RTPROT_REDIRECT) - return 0; + /* We don't care about change notifications for the MPLS table. */ + /* TODO: Revisit this. */ + if (rtm->rtm_family == AF_MPLS) { + ret = -1; + goto done; + } - selfroute = is_selfroute(rtm->rtm_protocol); + dplane_ctx_set_ns_id(ctx, ns_id); - if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE && - !zrouter.asic_offloaded && !ctx) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Route type: %d Received that we think we have originated, ignoring", - rtm->rtm_protocol); - return 0; + /* Parse attrs if necessary */ + if (tb_in != NULL) { + tb = tb_in; + } else { + netlink_parse_rtattr(tb_array, RTA_MAX, RTM_RTA(rtm), len); + tb = tb_array; } - /* We don't care about change notifications for the MPLS table. */ - /* TODO: Revisit this. */ - if (rtm->rtm_family == AF_MPLS) - return 0; + selfroute = is_selfroute(rtm->rtm_protocol); /* Table corresponding to route. */ if (tb[RTA_TABLE]) - table = *(int *)RTA_DATA(tb[RTA_TABLE]); + tableid = *(int *)RTA_DATA(tb[RTA_TABLE]); else - table = rtm->rtm_table; - - /* Map to VRF */ - vrf_id = zebra_vrf_lookup_by_table(table, ns_id); - if (vrf_id == VRF_DEFAULT) { - if (!is_zebra_valid_kernel_table(table) - && !is_zebra_main_routing_table(table)) - return 0; - } + tableid = rtm->rtm_table; + /* Map flags values */ if (rtm->rtm_flags & RTM_F_TRAP) flags |= ZEBRA_FLAG_TRAPPED; if (rtm->rtm_flags & RTM_F_OFFLOAD) @@ -836,7 +832,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, if (h->nlmsg_flags & NLM_F_APPEND) flags |= ZEBRA_FLAG_OUTOFSYNC; - /* Route which inserted by Zebra. */ + /* Route which was inserted by Zebra. */ if (selfroute) { flags |= ZEBRA_FLAG_SELFROUTE; proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false); @@ -854,14 +850,18 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, else src = anyaddr; - if (tb[RTA_PREFSRC]) + if (tb[RTA_PREFSRC]) { prefsrc = RTA_DATA(tb[RTA_PREFSRC]); + prefsrc_len = RTA_PAYLOAD(tb[RTA_PREFSRC]); + } - if (tb[RTA_GATEWAY]) + if (tb[RTA_GATEWAY]) { gate = RTA_DATA(tb[RTA_GATEWAY]); + gate_len = RTA_PAYLOAD(tb[RTA_GATEWAY]); + } if (tb[RTA_NH_ID]) - nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]); + nhg_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]); if (tb[RTA_PRIORITY]) metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]); @@ -887,7 +887,8 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "Invalid destination prefix length: %u received from kernel route change", rtm->rtm_dst_len); - return -1; + ret = -1; + goto done; } memcpy(&p.u.prefix4, dest, 4); p.prefixlen = rtm->rtm_dst_len; @@ -895,14 +896,16 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, if (rtm->rtm_src_len != 0) { flog_warn( EC_ZEBRA_UNSUPPORTED_V4_SRCDEST, - "unsupported IPv4 sourcedest route (dest %pFX vrf %u)", - &p, vrf_id); - return 0; + "unsupported IPv4 sourcedest route (dest %pFX table %u)", + &p, tableid); + ret = -1; + goto done; } /* Force debug below to not display anything for source */ src_p.prefixlen = 0; } else if (rtm->rtm_family == AF_INET6) { + afi = AFI_IP6; p.family = AF_INET6; if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) { zlog_err( @@ -920,14 +923,15 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, rtm->rtm_src_len); return -1; } - memcpy(&src_p.prefix, src, 16); + memcpy(&src_p.u.prefix6, src, 16); src_p.prefixlen = rtm->rtm_src_len; } else { /* We only handle the AFs we handle... */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: unknown address-family %u", __func__, rtm->rtm_family); - return 0; + ret = -1; + goto done; } /* @@ -956,6 +960,249 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, char buf2[PREFIX_STRLEN]; zlog_debug( + "%s %pFX%s%s nsid: %u table_id: %u metric: %d Admin Distance: %d", + nl_msg_type_to_str(h->nlmsg_type), &p, + src_p.prefixlen ? " from " : "", + src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) + : "", + ns_id, tableid, metric, distance); + } + + /* Set values in ctx. Note that vrf is not set, because we can only + * resolve the FRR vrf info in the main pthread. + */ + dplane_ctx_set_afi(ctx, afi); + dplane_ctx_set_safi(ctx, SAFI_UNICAST); + dplane_ctx_set_table(ctx, tableid); + dplane_ctx_set_vrf(ctx, VRF_UNKNOWN); + dplane_ctx_set_ns_id(ctx, ns_id); + dplane_ctx_set_dest(ctx, &p); + if (src_p.prefixlen > 0) + dplane_ctx_set_src(ctx, &src_p); + else + dplane_ctx_set_src(ctx, NULL); + dplane_ctx_set_type(ctx, proto); + dplane_ctx_set_flags(ctx, flags); + dplane_ctx_set_route_metric(ctx, metric); + dplane_ctx_set_route_mtu(ctx, mtu); + dplane_ctx_set_distance(ctx, distance); + dplane_ctx_set_tag(ctx, tag); + + dplane_ctx_set_ifindex(ctx, index); + dplane_ctx_set_route_bhtype(ctx, bh_type); + if (prefsrc) { + /* Convert to ipaddr */ + memset(&addr, 0, sizeof(addr)); + + if (afi == AFI_IP) { + SET_IPADDR_V4(&addr); + memcpy(&addr.ipaddr_v4, prefsrc, prefsrc_len); + } else { + SET_IPADDR_V6(&addr); + memcpy(&addr.ipaddr_v6, prefsrc, prefsrc_len); + } + + dplane_ctx_set_route_prefsrc(ctx, &addr); + } else { + dplane_ctx_set_route_prefsrc(ctx, NULL); + } + + if (gate) { + /* Convert to ipaddr */ + memset(&addr, 0, sizeof(addr)); + + if (afi == AFI_IP) { + SET_IPADDR_V4(&addr); + memcpy(&addr.ipaddr_v4, gate, gate_len); + } else { + SET_IPADDR_V6(&addr); + memcpy(&addr.ipaddr_v6, gate, gate_len); + } + + dplane_ctx_set_route_gw(ctx, &addr); + } + + if (nhg_id > 0) + dplane_ctx_set_nhg_id(ctx, nhg_id); + +done: + + return ret; +} + +/* + * Public api for use parsing a route notification message: this notification + * only parses the top-level route attributes, and doesn't include nexthops. + */ +int netlink_route_notify_read_ctx(struct nlmsghdr *h, ns_id_t ns_id, + struct zebra_dplane_ctx *ctx) +{ + /* Use the common parser for route-level netlink message info; + * we expect the caller to have set the context up with the correct + * dplane opcode, and we expect the caller to submit the resulting ctx + * for processing in zebra. + */ + return netlink_route_read_unicast_ctx(h, ns_id, NULL, ctx); +} + +/* + * Parse a route update netlink message, extract and validate its data, + * call into zebra with an update. + */ +static int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, + ns_id_t ns_id, int startup) +{ + int len; + struct rtmsg *rtm; + struct rtattr *tb[RTA_MAX + 1]; + uint32_t flags = 0; + struct prefix p; + struct prefix src_p = {}; + vrf_id_t vrf_id; + bool selfroute; + + int proto = ZEBRA_ROUTE_KERNEL; + int index = 0; + int table; + int metric = 0; + uint32_t mtu = 0; + uint8_t distance = 0; + route_tag_t tag = 0; + uint32_t nhe_id = 0; + void *gate = NULL; + const struct ipaddr *gate_addr; + void *prefsrc = NULL; /* IPv4 preferred source host address */ + const struct ipaddr *prefsrc_addr; + enum blackhole_type bh_type = BLACKHOLE_UNSPEC; + afi_t afi; + struct zebra_dplane_ctx *ctx = NULL; + int ret; + + frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id, + startup); + + rtm = NLMSG_DATA(h); + + if (startup && h->nlmsg_type != RTM_NEWROUTE) + return 0; + + switch (rtm->rtm_type) { + case RTN_UNICAST: + case RTN_BLACKHOLE: + case RTN_UNREACHABLE: + case RTN_PROHIBIT: + break; + default: + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Route rtm_type: %s(%d) intentionally ignoring", + nl_rttype_to_str(rtm->rtm_type), + rtm->rtm_type); + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + 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 rtmsg))); + return -1; + } + + if (rtm->rtm_flags & RTM_F_CLONED) + return 0; + if (rtm->rtm_protocol == RTPROT_REDIRECT) + return 0; + + /* We don't care about change notifications for the MPLS table. */ + /* TODO: Revisit this. */ + if (rtm->rtm_family == AF_MPLS) + return 0; + + netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); + + /* + * Allocate a context object and parse the core parts of the route + * message. + * After this point, note that we need to 'goto done' to exit, + * so that the ctx gets cleaned-up. + */ + ctx = dplane_ctx_alloc(); + + dplane_ctx_route_init(ctx, + h->nlmsg_type == RTM_NEWROUTE ? + DPLANE_OP_ROUTE_INSTALL : + DPLANE_OP_ROUTE_DELETE, NULL, NULL); + + /* Finish parsing the core route info */ + ret = netlink_route_read_unicast_ctx(h, ns_id, tb, ctx); + if (ret < 0) { + ret = 0; + goto done; + } + + flags = dplane_ctx_get_flags(ctx); + + selfroute = CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE); + + if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE && + !zrouter.asic_offloaded) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Route type: %d Received that we think we have originated, ignoring", + rtm->rtm_protocol); + ret = 0; + goto done; + } + + /* Table corresponding to route. */ + table = dplane_ctx_get_table(ctx); + + /* Map to VRF: note that this can _only_ be done in the main pthread */ + vrf_id = zebra_vrf_lookup_by_table(table, ns_id); + if (vrf_id == VRF_DEFAULT) { + if (!is_zebra_valid_kernel_table(table) + && !is_zebra_main_routing_table(table)) { + ret = 0; + goto done; + } + } + + /* Route which inserted by Zebra. */ + if (selfroute) + proto = dplane_ctx_get_type(ctx); + + index = dplane_ctx_get_ifindex(ctx); + + p = *(dplane_ctx_get_dest(ctx)); + + if (dplane_ctx_get_src(ctx) == NULL) + src_p.prefixlen = 0; + else + src_p = *(dplane_ctx_get_src(ctx)); + + prefsrc_addr = dplane_ctx_get_route_prefsrc(ctx); + if (prefsrc_addr) + prefsrc = (void *)&(prefsrc_addr->ip.addr); + + gate_addr = dplane_ctx_get_route_gw(ctx); + if (!IS_IPADDR_NONE(gate_addr)) + gate = (void *)&(gate_addr->ip.addr); + + nhe_id = dplane_ctx_get_nhe_id(ctx); + + metric = dplane_ctx_get_metric(ctx); + distance = dplane_ctx_get_distance(ctx); + tag = dplane_ctx_get_tag(ctx); + mtu = dplane_ctx_get_mtu(ctx); + + afi = dplane_ctx_get_afi(ctx); + + bh_type = dplane_ctx_get_route_bhtype(ctx); + + if (IS_ZEBRA_DEBUG_KERNEL) { + char buf2[PREFIX_STRLEN]; + + zlog_debug( "%s %pFX%s%s vrf %s(%u) table_id: %u metric: %d Admin Distance: %d", nl_msg_type_to_str(h->nlmsg_type), &p, src_p.prefixlen ? " from " : "", @@ -965,10 +1212,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, distance); } - afi_t afi = AFI_IP; - if (rtm->rtm_family == AF_INET6) - afi = AFI_IP6; - if (h->nlmsg_type == RTM_NEWROUTE) { struct route_entry *re; struct nexthop_group *ng = NULL; @@ -1018,12 +1261,11 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, } } if (nhe_id || ng) { - dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, - re, ng, startup, ctx); + rib_add_multipath(afi, SAFI_UNICAST, &p, + (struct prefix_ipv6 *)&src_p, + re, ng, startup); if (ng) nexthop_group_delete(&ng); - if (ctx) - zebra_rib_route_entry_free(re); } else { /* * I really don't see how this is possible @@ -1038,17 +1280,10 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zebra_rib_route_entry_free(re); } } else { - if (ctx) { - zlog_err( - "%s: %pFX RTM_DELROUTE received but received a context as well", - __func__, &p); - return 0; - } - if (nhe_id) { rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, &src_p, NULL, nhe_id, table, metric, - distance, true); + &p, (struct prefix_ipv6 *)&src_p, NULL, + nhe_id, table, metric, distance, true); } else { if (!tb[RTA_MULTIPATH]) { struct nexthop nh; @@ -1057,26 +1292,33 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, ns_id, rtm, tb, bh_type, index, prefsrc, gate, afi, vrf_id); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, - flags, &p, &src_p, &nh, 0, table, - metric, distance, true); + flags, &p, + (struct prefix_ipv6 *)&src_p, &nh, 0, + table, metric, distance, true); } else { /* XXX: need to compare the entire list of * nexthops here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, - flags, &p, &src_p, NULL, 0, table, - metric, distance, true); + flags, &p, + (struct prefix_ipv6 *)&src_p, NULL, 0, + table, metric, distance, true); } } } - return 1; + ret = 1; + +done: + if (ctx) + dplane_ctx_fini(&ctx); + + return ret; } static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, int startup) { - return netlink_route_change_read_unicast_internal(h, ns_id, startup, - NULL); + return netlink_route_change_read_unicast_internal(h, ns_id, startup); } static struct mcast_route_data *mroute = NULL; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index d51944f1a..1c113baee 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -64,6 +64,15 @@ extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_route_read(struct zebra_ns *zns); +/* + * Public api for parsing a route notification message: this notification + * only parses the top-level route attributes, and doesn't include nexthops. + * FPM, for example, is a user. + * Returns <0 if the message should be ignored/skipped. + */ +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_read(struct zebra_ns *zns); @@ -109,10 +118,6 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); extern enum netlink_msg_status netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); -int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, - ns_id_t ns_id, int startup, - struct zebra_dplane_ctx *ctx); - #ifdef NETLINK_DEBUG const char *nlmsg_type2str(uint16_t type); const char *af_type2str(int type); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b2543ca0e..8e4550846 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2279,8 +2279,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) bool fib_changed = false; bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB; int start_count, end_count; + vrf_id_t vrf_id; + int tableid; + + /* Locate vrf and route table - we must have one or the other */ + tableid = dplane_ctx_get_table(ctx); + vrf_id = dplane_ctx_get_vrf(ctx); + if (vrf_id == VRF_UNKNOWN) + vrf_id = zebra_vrf_lookup_by_table(tableid, + dplane_ctx_get_ns_id(ctx)); + else if (tableid == ZEBRA_ROUTE_TABLE_UNKNOWN) + tableid = zebra_vrf_lookup_tableid(vrf_id, + dplane_ctx_get_ns_id(ctx)); - vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + vrf = vrf_lookup_by_id(vrf_id); /* Locate rn and re(s) from ctx */ rn = rib_find_rn_from_ctx(ctx); @@ -2289,7 +2301,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) zlog_debug( "Failed to process dplane notification: no routes for %s(%u:%u):%pRN", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + tableid, rn); } goto done; } @@ -2299,7 +2311,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (debug_p) zlog_debug("%s(%u:%u):%pRN Processing dplane notif ctx %p", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn, ctx); + tableid, rn, ctx); /* * Take a pass through the routes, look for matches with the context @@ -2316,7 +2328,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) zlog_debug( "%s(%u:%u):%pRN Unable to process dplane notification: no entry for type %s", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn, + tableid, rn, zebra_route_string(dplane_ctx_get_type(ctx))); goto done; @@ -2352,7 +2364,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) "%s(%u:%u):%pRN dplane notif, uninstalled type %s route", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn, + tableid, rn, zebra_route_string( dplane_ctx_get_type(ctx))); } else { @@ -2362,7 +2374,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) "%s(%u:%u):%pRN dplane notif, but type %s not selected_fib", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn, + tableid, rn, zebra_route_string( dplane_ctx_get_type(ctx))); } @@ -2401,7 +2413,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) zlog_debug( "%s(%u:%u):%pRN dplane notification: rib_update returns FALSE", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + tableid, rn); } /* @@ -2420,7 +2432,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) "%s(%u:%u):%pRN applied nexthop changes from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + tableid, rn); /* Changed nexthops - update kernel/others */ dplane_route_notif_update(rn, re, @@ -2432,7 +2444,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) "%s(%u:%u):%pRN installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + tableid, rn); /* We expect this to be the selected route, so we want * to tell others about this transition. @@ -2452,7 +2464,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) "%s(%u:%u):%pRN un-installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + tableid, rn); /* Transition from _something_ installed to _nothing_ * installed. diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 2b3cfc876..c7781e86d 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -417,6 +417,25 @@ vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) return VRF_DEFAULT; } +/* + * Lookup tableid by vrfid; handle vrf-lite and vrf-netns cases + */ +int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id) +{ + struct zebra_vrf *zvrf; + + /* Handle vrf-lite and vrf-netns */ + if (vrf_is_backend_netns()) + zvrf = vrf_info_lookup(ns_id); + else + zvrf = vrf_info_lookup(vrf_id); + + if (zvrf) + return zvrf->table_id; + else + return ZEBRA_ROUTE_TABLE_UNKNOWN; +} + /* Lookup VRF by identifier. */ struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) { diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index f97138c81..334bb9368 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -24,6 +24,8 @@ FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT, { .val_bool = false }, ); +#define ZEBRA_ROUTE_TABLE_UNKNOWN 0 + /* MPLS (Segment Routing) global block */ struct mpls_srgb { uint32_t start_label; @@ -247,6 +249,7 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); extern vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); extern struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf); extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t); +int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id); /* * API to associate a VRF with a NETNS. |