diff options
Diffstat (limited to 'zebra')
106 files changed, 13764 insertions, 8831 deletions
diff --git a/zebra/.gitignore b/zebra/.gitignore index 41a86e7d75..f10240db43 100644 --- a/zebra/.gitignore +++ b/zebra/.gitignore @@ -1,3 +1,4 @@ zebra zebra.conf client +fpm_listener diff --git a/zebra/connected.c b/zebra/connected.c index ee0823f56f..404f892f6e 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -48,7 +48,7 @@ static void connected_withdraw(struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { - listnode_delete(ifc->ifp->connected, ifc); + if_connected_del(ifc->ifp->connected, ifc); connected_free(&ifc); } } @@ -65,7 +65,7 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED); } - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); /* Update interface address information to protocol daemon. */ if (ifc->address->family == AF_INET) @@ -84,9 +84,8 @@ struct connected *connected_check(struct interface *ifp, { const struct prefix *p = pu.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + frr_each (if_connected, ifp->connected, ifc) if (prefix_same(ifc->address, p)) return ifc; @@ -101,9 +100,8 @@ struct connected *connected_check_ptp(struct interface *ifp, const struct prefix *p = pu.p; const struct prefix *d = du.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (!prefix_same(ifc->address, p)) continue; if (!CONNECTED_PEER(ifc) && !d) @@ -182,7 +180,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc) void connected_up(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, @@ -192,8 +190,8 @@ void connected_up(struct interface *ifp, struct connected *ifc) uint32_t metric; uint32_t flags = 0; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool install_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -210,6 +208,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN); prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -224,6 +223,8 @@ void connected_up(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: #ifndef GNU_LINUX @@ -231,6 +232,11 @@ void connected_up(struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; #endif + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + install_local = false; + + plocal.prefixlen = IPV6_MAX_BITLEN; break; case AFI_UNSPEC: case AFI_L2VPN: @@ -262,7 +268,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) * for all the addresses on an interface that * resolve to the same network and mask */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -276,13 +282,24 @@ void connected_up(struct interface *ifp, struct connected *ifc) return; } - rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); - rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); + } + + if (install_local) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_LOCAL, + 0, flags, &plocal, NULL, &nh, 0, zvrf->table_id, 0, 0, + 0, 0, false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, flags, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -368,7 +385,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, void connected_down(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, @@ -376,8 +393,8 @@ void connected_down(struct interface *ifp, struct connected *ifc) }; struct zebra_vrf *zvrf; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool remove_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -403,6 +420,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) } prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -417,10 +435,18 @@ void connected_down(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; + + plocal.prefixlen = IPV6_MAX_BITLEN; + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + remove_local = false; + break; case AFI_UNSPEC: case AFI_L2VPN: @@ -439,7 +465,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) * allow the deletion when are removing the last * one. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -457,11 +483,25 @@ void connected_down(struct interface *ifp, struct connected *ifc) * Same logic as for connected_up(): push the changes into the * head. */ - rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } + + if (remove_local) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); - rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -616,9 +656,8 @@ void connected_delete_ipv6(struct interface *ifp, int connected_is_unnumbered(struct interface *ifp) { struct connected *connected; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) && connected->address->family == AF_INET) return CHECK_FLAG(connected->flags, diff --git a/zebra/debug.c b/zebra/debug.c index 68bedaf057..cf1701be19 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -7,6 +7,7 @@ #include <zebra.h> #include "command.h" #include "debug.h" +#include "mgmt_be_client.h" #include "zebra/debug_clippy.c" @@ -846,4 +847,7 @@ void zebra_debug_init(void) install_element(CONFIG_NODE, &no_debug_zebra_pbr_cmd); install_element(CONFIG_NODE, &debug_zebra_mlag_cmd); install_element(CONFIG_NODE, &debug_zebra_evpn_mh_cmd); + + /* Init mgmtd backend client debug commands. */ + mgmt_be_client_lib_vty_init(); } diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index df0b5aae7b..a7cccdb98f 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -983,6 +983,7 @@ next_rta: zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, plen, rta_type, rta_type2str(rta_type)); switch (rta_type) { + case IFLA_IFNAME: case IFLA_IFALIAS: if (plen == 0) { zlog_debug(" invalid length"); diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index fc140b07a3..7a5388c57b 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -105,8 +105,7 @@ static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg) ifp = if_lookup_by_name_vrf(rule->ifname, vrf); if (ifp) - zd_dpdk_flow_stat_show(vty, ifp->ifindex, - zaction->dp_flow_ptr); + zd_dpdk_flow_stat_show(vty, ifp->ifindex, zaction->dp_flow_ptr); } return HASHWALK_CONTINUE; } @@ -153,8 +152,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, in_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, in_ifindex); return; } @@ -163,8 +161,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, out_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, out_ifindex); return; } @@ -180,7 +177,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) memset(&ip, 0, sizeof(ip)); memset(&ip_mask, 0, sizeof(ip_mask)); - if (filter_bm & PBR_FILTER_SRC_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP)) { const struct prefix *src_ip; src_ip = dplane_ctx_rule_get_src_ip(ctx); @@ -188,7 +185,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(src_ip->prefixlen, &tmp_mask); ip_mask.hdr.src_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_DST_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP)) { const struct prefix *dst_ip; dst_ip = dplane_ctx_rule_get_dst_ip(ctx); @@ -196,7 +193,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(dst_ip->prefixlen, &tmp_mask); ip_mask.hdr.dst_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_IP_PROTOCOL) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_IP_PROTOCOL)) { ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx); ip_mask.hdr.next_proto_id = UINT8_MAX; } @@ -206,17 +203,15 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) items[item_cnt].last = NULL; ++item_cnt; - if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { + if (CHECK_FLAG(filter_bm, (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { memset(&udp, 0, sizeof(udp)); memset(&udp_mask, 0, sizeof(udp_mask)); - if (filter_bm & PBR_FILTER_SRC_PORT) { - udp.hdr.src_port = - RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_PORT)) { + udp.hdr.src_port = RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); udp_mask.hdr.src_port = UINT16_MAX; } - if (filter_bm & PBR_FILTER_DST_PORT) { - udp.hdr.dst_port = - RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_PORT)) { + udp.hdr.dst_port = RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); udp_mask.hdr.dst_port = UINT16_MAX; } items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP; @@ -273,8 +268,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) } else { zlog_warn( "PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, - error.type); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, error.type); } } @@ -562,7 +556,7 @@ void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail) for (count = 0; count < RTE_MAX_ETHPORTS; ++count) { dport = &dpdk_ctx->dpdk_ports[count]; - if (dport->flags & ZD_DPDK_PORT_FLAG_INITED) + if (CHECK_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED)) zd_dpdk_port_show_entry(dport, vty, detail); } } @@ -592,14 +586,14 @@ static void zd_dpdk_port_init(void) dport = &dpdk_ctx->dpdk_ports[count]; count++; dport->port_id = port_id; - dport->flags |= ZD_DPDK_PORT_FLAG_PROBED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_PROBED); dev_info = &dport->dev_info; if (rte_eth_dev_info_get(port_id, dev_info) < 0) { zlog_warn("failed to get dev info for %u, %s", port_id, rte_strerror(rte_errno)); continue; } - dport->flags |= ZD_DPDK_PORT_FLAG_INITED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED); if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( "port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u", @@ -611,12 +605,10 @@ static void zd_dpdk_port_init(void) if (rte_flow_isolate(port_id, 1, &error)) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( - "Flow isolate on port %u failed %d\n", - port_id, error.type); + "Flow isolate on port %u failed %d", port_id, error.type); } else { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("Flow isolate on port %u\n", - port_id); + zlog_debug("Flow isolate on port %u", port_id); } rc = rte_eth_dev_start(port_id); if (rc) { @@ -625,8 +617,7 @@ static void zd_dpdk_port_init(void) continue; } if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("DPDK port %d started in promiscuous mode ", - port_id); + zlog_debug("DPDK port %d started in promiscuous mode ", port_id); } if (!count) { @@ -639,8 +630,7 @@ static void zd_dpdk_port_init(void) static int zd_dpdk_init(void) { int rc; - static const char *argv[] = {(char *)"/usr/lib/frr/zebra", - (char *)"--"}; + static const char *argv[] = {(char *)"/usr/lib/frr/zebra", (char *)"--"}; zd_dpdk_vty_init(); @@ -674,8 +664,7 @@ static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early) if (early) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("%s early finish", - dplane_provider_get_name(prov)); + zlog_debug("%s early finish", dplane_provider_get_name(prov)); return 0; } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index be2f55120c..245b799a91 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -19,6 +19,9 @@ #include <string.h> #include "lib/zebra.h" + +#include <linux/rtnetlink.h> + #include "lib/json.h" #include "lib/libfrr.h" #include "lib/frratomic.h" @@ -27,6 +30,7 @@ #include "lib/network.h" #include "lib/ns.h" #include "lib/frr_pthread.h" +#include "lib/termtable.h" #include "zebra/debug.h" #include "zebra/interface.h" #include "zebra/zebra_dplane.h" @@ -41,8 +45,15 @@ #include "zebra/debug.h" #include "fpm/fpm.h" +#include "zebra/dplane_fpm_nl_clippy.c" + #define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK -#define SOUTHBOUND_DEFAULT_PORT 2620 + +/* + * Time in seconds that if the other end is not responding + * something terrible has gone wrong. Let's fix that. + */ +#define DPLANE_FPM_NL_WEDGIE_TIME 15 /** * FPM header: @@ -65,6 +76,7 @@ struct fpm_nl_ctx { bool disabled; bool connecting; bool use_nhg; + bool use_route_replace; struct sockaddr_storage addr; /* data plane buffers. */ @@ -89,6 +101,7 @@ struct fpm_nl_ctx { struct event *t_event; struct event *t_nhg; struct event *t_dequeue; + struct event *t_wedged; /* zebra events. */ struct event *t_lspreset; @@ -206,7 +219,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd, memset(sin, 0, sizeof(*sin)); sin->sin_family = AF_INET; sin->sin_port = - port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT); + port ? htons(port) : htons(FPM_DEFAULT_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin->sin_len = sizeof(*sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ @@ -224,7 +237,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd, sin6 = (struct sockaddr_in6 *)&gfnc->addr; memset(sin6, 0, sizeof(*sin6)); sin6->sin6_family = AF_INET6; - sin6->sin6_port = port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT); + sin6->sin6_port = port ? htons(port) : htons(FPM_DEFAULT_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6->sin6_len = sizeof(*sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ @@ -282,6 +295,25 @@ DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd, return CMD_SUCCESS; } +DEFUN(fpm_use_route_replace, fpm_use_route_replace_cmd, + "fpm use-route-replace", + FPM_STR + "Use netlink route replace semantics\n") +{ + gfnc->use_route_replace = true; + return CMD_SUCCESS; +} + +DEFUN(no_fpm_use_route_replace, no_fpm_use_route_replace_cmd, + "no fpm use-route-replace", + NO_STR + FPM_STR + "Use netlink route replace semantics\n") +{ + gfnc->use_route_replace = false; + return CMD_SUCCESS; +} + DEFUN(fpm_reset_counters, fpm_reset_counters_cmd, "clear fpm counters", CLEAR_STR @@ -293,6 +325,74 @@ DEFUN(fpm_reset_counters, fpm_reset_counters_cmd, return CMD_SUCCESS; } +DEFPY(fpm_show_status, + fpm_show_status_cmd, + "show fpm status [json]$json", + SHOW_STR FPM_STR "FPM status\n" JSON_STR) +{ + struct json_object *j; + bool connected; + uint16_t port; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + char buf[BUFSIZ]; + + connected = gfnc->socket > 0 ? true : false; + + switch (gfnc->addr.ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)&gfnc->addr; + snprintfrr(buf, sizeof(buf), "%pI4", &sin->sin_addr); + port = ntohs(sin->sin_port); + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&gfnc->addr; + snprintfrr(buf, sizeof(buf), "%pI6", &sin6->sin6_addr); + port = ntohs(sin6->sin6_port); + break; + default: + strlcpy(buf, "Unknown", sizeof(buf)); + port = FPM_DEFAULT_PORT; + break; + } + + if (json) { + j = json_object_new_object(); + + json_object_boolean_add(j, "connected", connected); + json_object_boolean_add(j, "useNHG", gfnc->use_nhg); + json_object_boolean_add(j, "useRouteReplace", + gfnc->use_route_replace); + json_object_boolean_add(j, "disabled", gfnc->disabled); + json_object_string_add(j, "address", buf); + json_object_int_add(j, "port", port); + + vty_json(vty, j); + } else { + struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + char *out; + + ttable_rowseps(table, 0, BOTTOM, true, '-'); + ttable_add_row(table, "Address to connect to|%s", buf); + ttable_add_row(table, "Port|%u", port); + ttable_add_row(table, "Connected|%s", connected ? "Yes" : "No"); + ttable_add_row(table, "Use Nexthop Groups|%s", + gfnc->use_nhg ? "Yes" : "No"); + ttable_add_row(table, "Use Route Replace Semantics|%s", + gfnc->use_route_replace ? "Yes" : "No"); + ttable_add_row(table, "Disabled|%s", + gfnc->disabled ? "Yes" : "No"); + + out = ttable_dump(table, "\n"); + vty_out(vty, "%s\n", out); + XFREE(MTYPE_TMP, out); + + ttable_del(table); + } + + return CMD_SUCCESS; +} + DEFUN(fpm_show_counters, fpm_show_counters_cmd, "show fpm counters", SHOW_STR @@ -372,7 +472,7 @@ static int fpm_write_config(struct vty *vty) written = 1; sin = (struct sockaddr_in *)&gfnc->addr; vty_out(vty, "fpm address %pI4", &sin->sin_addr); - if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT)) + if (sin->sin_port != htons(FPM_DEFAULT_PORT)) vty_out(vty, " port %d", ntohs(sin->sin_port)); vty_out(vty, "\n"); @@ -381,7 +481,7 @@ static int fpm_write_config(struct vty *vty) written = 1; sin6 = (struct sockaddr_in6 *)&gfnc->addr; vty_out(vty, "fpm address %pI6", &sin6->sin6_addr); - if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT)) + if (sin6->sin6_port != htons(FPM_DEFAULT_PORT)) vty_out(vty, " port %d", ntohs(sin6->sin6_port)); vty_out(vty, "\n"); @@ -396,6 +496,11 @@ static int fpm_write_config(struct vty *vty) written = 1; } + if (!gfnc->use_route_replace) { + vty_out(vty, "no fpm use-route-replace\n"); + written = 1; + } + return written; } @@ -587,7 +692,8 @@ static void fpm_read(struct event *t) switch (hdr->nlmsg_type) { case RTM_NEWROUTE: ctx = dplane_ctx_alloc(); - dplane_ctx_set_op(ctx, DPLANE_OP_ROUTE_NOTIFY); + 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); @@ -806,12 +912,20 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) frr_mutex_lock_autounlock(&fnc->obuf_mutex); + /* + * If route replace is enabled then directly encode the install which + * is going to use `NLM_F_REPLACE` (instead of delete/add operations). + */ + if (fnc->use_route_replace && op == DPLANE_OP_ROUTE_UPDATE) + op = DPLANE_OP_ROUTE_INSTALL; + switch (op) { case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: rv = netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, nl_buf, sizeof(nl_buf), - true, fnc->use_nhg); + true, fnc->use_nhg, + false); if (rv <= 0) { zlog_err( "%s: netlink_route_multipath_msg_encode failed", @@ -825,11 +939,14 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) if (op == DPLANE_OP_ROUTE_DELETE) break; - /* FALL THROUGH */ + fallthrough; case DPLANE_OP_ROUTE_INSTALL: - rv = netlink_route_multipath_msg_encode( - RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len], - sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg); + rv = netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, + &nl_buf[nl_buf_len], + sizeof(nl_buf) - + nl_buf_len, + true, fnc->use_nhg, + fnc->use_route_replace); if (rv <= 0) { zlog_err( "%s: netlink_route_multipath_msg_encode failed", @@ -932,7 +1049,9 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_ADD: case DPLANE_OP_TC_FILTER_DELETE: case DPLANE_OP_TC_FILTER_UPDATE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: + case DPLANE_OP_STARTUP_STAGE: break; } @@ -1326,6 +1445,18 @@ static void fpm_rmac_reset(struct event *t) &fnc->t_rmacwalk); } +static void fpm_process_wedged(struct event *t) +{ + struct fpm_nl_ctx *fnc = EVENT_ARG(t); + + zlog_warn("%s: Connection unable to write to peer for over %u seconds, resetting", + __func__, DPLANE_FPM_NL_WEDGIE_TIME); + + atomic_fetch_add_explicit(&fnc->counters.connection_errors, 1, + memory_order_relaxed); + FPM_RECONNECT(fnc); +} + static void fpm_process_queue(struct event *t) { struct fpm_nl_ctx *fnc = EVENT_ARG(t); @@ -1334,8 +1465,14 @@ static void fpm_process_queue(struct event *t) uint64_t processed_contexts = 0; while (true) { + size_t writeable_amount; + + frr_with_mutex (&fnc->obuf_mutex) { + writeable_amount = STREAM_WRITEABLE(fnc->obuf); + } + /* No space available yet. */ - if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE) { + if (writeable_amount < NL_PKT_BUF_SIZE) { no_bufs = true; break; } @@ -1370,9 +1507,13 @@ static void fpm_process_queue(struct event *t) processed_contexts, memory_order_relaxed); /* Re-schedule if we ran out of buffer space */ - if (no_bufs) - event_add_timer(fnc->fthread->master, fpm_process_queue, fnc, 0, + if (no_bufs) { + event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); + event_add_timer(fnc->fthread->master, fpm_process_wedged, fnc, + DPLANE_FPM_NL_WEDGIE_TIME, &fnc->t_wedged); + } else + EVENT_OFF(fnc->t_wedged); /* * Let the dataplane thread know if there are items in the @@ -1467,6 +1608,7 @@ static int fpm_nl_start(struct zebra_dplane_provider *prov) /* Set default values. */ fnc->use_nhg = true; + fnc->use_route_replace = true; return 0; } @@ -1575,7 +1717,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) if (atomic_load_explicit(&fnc->counters.ctxqueue_len, memory_order_relaxed) > 0) - event_add_timer(fnc->fthread->master, fpm_process_queue, fnc, 0, + event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); /* Ensure dataplane thread is rescheduled if we hit the work limit */ @@ -1600,6 +1742,7 @@ static int fpm_nl_new(struct event_loop *tm) zlog_debug("%s register status: %d", prov_name, rv); install_node(&fpm_node); + install_element(ENABLE_NODE, &fpm_show_status_cmd); install_element(ENABLE_NODE, &fpm_show_counters_cmd); install_element(ENABLE_NODE, &fpm_show_counters_json_cmd); install_element(ENABLE_NODE, &fpm_reset_counters_cmd); @@ -1607,6 +1750,8 @@ static int fpm_nl_new(struct event_loop *tm) install_element(CONFIG_NODE, &no_fpm_set_address_cmd); install_element(CONFIG_NODE, &fpm_use_nhg_cmd); install_element(CONFIG_NODE, &no_fpm_use_nhg_cmd); + install_element(CONFIG_NODE, &fpm_use_route_replace_cmd); + install_element(CONFIG_NODE, &no_fpm_use_route_replace_cmd); return 0; } diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c new file mode 100644 index 0000000000..5ffc0561bb --- /dev/null +++ b/zebra/fpm_listener.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef GNU_LINUX +#include <stdint.h> +#include <memory.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <errno.h> +#include <assert.h> +#include <err.h> +#include <sys/types.h> + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include "rt_netlink.h" +#include "fpm/fpm.h" +#include "lib/libfrr.h" + +struct glob { + int server_sock; + int sock; + bool reflect; +}; + +struct glob glob_space; +struct glob *glob = &glob_space; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* + * get_print_buf + */ +static char * +get_print_buf(size_t *buf_len) +{ + static char print_bufs[16][128]; + static int counter; + + counter++; + if (counter >= 16) + counter = 0; + + *buf_len = 128; + return &print_bufs[counter][0]; +} + +/* + * create_listen_sock + */ +static int create_listen_sock(int port, int *sock_p) +{ + int sock; + struct sockaddr_in addr; + int reuse; + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + fprintf(stderr, "Failed to create socket: %s\n", strerror(errno)); + return 0; + } + + reuse = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < + 0) { + fprintf(stderr, "Failed to set reuse addr option: %s\n", + strerror(errno)); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "Failed to bind to port %d: %s\n", port, strerror(errno)); + close(sock); + return 0; + } + + if (listen(sock, 5)) { + fprintf(stderr, "Failed to listen on socket: %s\n", strerror(errno)); + close(sock); + return 0; + } + + *sock_p = sock; + return 1; +} + +/* + * accept_conn + */ +static int accept_conn(int listen_sock) +{ + int sock; + struct sockaddr_in client_addr = { 0 }; + unsigned int client_len; + + while (1) { + char buf[120]; + + fprintf(stdout, "Waiting for client connection...\n"); + client_len = sizeof(client_addr); + sock = accept(listen_sock, (struct sockaddr *)&client_addr, + &client_len); + + if (sock >= 0) { + fprintf(stdout, "Accepted client %s\n", + inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf))); + return sock; + } + fprintf(stderr, "Failed to accept socket: %s\n", strerror(errno)); + } +} + +/* + * read_fpm_msg + */ +static fpm_msg_hdr_t * +read_fpm_msg(char *buf, size_t buf_len) +{ + char *cur, *end; + long need_len, bytes_read, have_len; + fpm_msg_hdr_t *hdr; + int reading_full_msg; + + end = buf + buf_len; + cur = buf; + hdr = (fpm_msg_hdr_t *)buf; + + while (1) { + reading_full_msg = 0; + + have_len = cur - buf; + + if (have_len < (long)FPM_MSG_HDR_LEN) { + need_len = FPM_MSG_HDR_LEN - have_len; + } else { + need_len = fpm_msg_len(hdr) - have_len; + assert(need_len >= 0 && need_len <= (end - cur)); + + if (!need_len) + return hdr; + + reading_full_msg = 1; + } + + bytes_read = read(glob->sock, cur, need_len); + + if (bytes_read == 0) { + fprintf(stdout, + "Socket closed as that read returned 0\n"); + return NULL; + } + + if (bytes_read < 0) { + fprintf(stderr, "Error reading from socket: %s\n", + strerror(errno)); + return NULL; + } + + cur += bytes_read; + + if (bytes_read < need_len) { + fprintf(stderr, + "Read %lu bytes but expected to read %lu bytes instead\n", + bytes_read, need_len); + return NULL; + } + + if (reading_full_msg) + return hdr; + + if (!fpm_msg_ok(hdr, buf_len)) { + assert(0); + fprintf(stderr, "Malformed fpm message\n"); + return NULL; + } + } +} + +/* + * netlink_msg_type_to_s + */ +static const char * +netlink_msg_type_to_s(uint16_t type) +{ + switch (type) { + + case RTM_NEWROUTE: + return "New route"; + + case RTM_DELROUTE: + return "Del route"; + + case RTM_NEWNEXTHOP: + return "New Nexthop Group"; + + case RTM_DELNEXTHOP: + return "Del Nexthop Group"; + + default: + return "Unknown"; + } +} + +/* + * netlink_prot_to_s + */ +static const char * +netlink_prot_to_s(unsigned char prot) +{ + switch (prot) { + + case RTPROT_KERNEL: + return "Kernel"; + + case RTPROT_BOOT: + return "Boot"; + + case RTPROT_STATIC: + return "Static"; + + case RTPROT_ZEBRA: + return "Zebra"; + + case RTPROT_DHCP: + return "Dhcp"; + + case RTPROT_BGP: + return "BGP"; + + case RTPROT_ISIS: + return "ISIS"; + + case RTPROT_OSPF: + return "OSPF"; + + case RTPROT_RIP: + return "RIP"; + + case RTPROT_RIPNG: + return "RIPNG"; + + case RTPROT_BABEL: + return "BABEL"; + + case RTPROT_NHRP: + return "NHRP"; + + case RTPROT_EIGRP: + return "EIGRP"; + + case RTPROT_SHARP: + return "SHARP"; + + case RTPROT_PBR: + return "PBR"; + + case RTPROT_ZSTATIC: + return "Static"; + + default: + return "Unknown"; + } +} + +#define MAX_NHS 16 + +struct netlink_nh { + struct rtattr *gateway; + int if_index; +}; + +struct netlink_msg_ctx { + struct nlmsghdr *hdr; + + /* + * Stuff pertaining to route messages. + */ + struct rtmsg *rtmsg; + struct rtattr *rtattrs[RTA_MAX + 1]; + + /* + * Nexthops. + */ + struct netlink_nh nhs[MAX_NHS]; + unsigned long num_nhs; + + struct rtattr *dest; + struct rtattr *src; + int *metric; + unsigned int *nhgid; + + const char *err_msg; +}; + +/* + * netlink_msg_ctx_init + */ +static inline void netlink_msg_ctx_init(struct netlink_msg_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * netlink_msg_ctx_set_err + */ +static inline void netlink_msg_ctx_set_err(struct netlink_msg_ctx *ctx, + const char *err_msg) +{ + if (ctx->err_msg) + return; + + ctx->err_msg = err_msg; +} + +/* + * parse_rtattrs_ + */ +static int parse_rtattrs_(struct rtattr *rta, size_t len, struct rtattr **rtas, + int num_rtas, const char **err_msg) +{ + memset(rtas, 0, num_rtas * sizeof(rtas[0])); + + for (; len > 0; rta = RTA_NEXT(rta, len)) { + if (!RTA_OK(rta, len)) { + *err_msg = "Malformed rta"; + return 0; + } + + if (rta->rta_type >= num_rtas) { + warn("Unknown rtattr type %d", rta->rta_type); + continue; + } + + rtas[rta->rta_type] = rta; + } + + return 1; +} + +/* + * parse_rtattrs + */ +static int parse_rtattrs(struct netlink_msg_ctx *ctx, struct rtattr *rta, + size_t len) +{ + const char *err_msg; + + err_msg = NULL; + + if (!parse_rtattrs_(rta, len, ctx->rtattrs, ARRAY_SIZE(ctx->rtattrs), + &err_msg)) { + netlink_msg_ctx_set_err(ctx, err_msg); + return 0; + } + + return 1; +} + +/* + * netlink_msg_ctx_add_nh + */ +static int netlink_msg_ctx_add_nh(struct netlink_msg_ctx *ctx, int if_index, + struct rtattr *gateway) +{ + struct netlink_nh *nh; + + if (ctx->num_nhs + 1 >= ARRAY_SIZE(ctx->nhs)) { + warn("Too many next hops"); + return 0; + } + nh = &ctx->nhs[ctx->num_nhs]; + ctx->num_nhs++; + + nh->gateway = gateway; + nh->if_index = if_index; + return 1; +} + +/* + * parse_multipath_attr + */ +static int parse_multipath_attr(struct netlink_msg_ctx *ctx, + struct rtattr *mpath_rtattr) +{ + size_t len; + struct rtnexthop *rtnh; + struct rtattr *rtattrs[RTA_MAX + 1]; + struct rtattr *gateway; + const char *err_msg; + + rtnh = RTA_DATA(mpath_rtattr); + len = RTA_PAYLOAD(mpath_rtattr); + + for (; len > 0; + len -= NLMSG_ALIGN(rtnh->rtnh_len), rtnh = RTNH_NEXT(rtnh)) { + + if (!RTNH_OK(rtnh, len)) { + netlink_msg_ctx_set_err(ctx, "Malformed nh"); + return 0; + } + + if (rtnh->rtnh_len <= sizeof(*rtnh)) { + netlink_msg_ctx_set_err(ctx, "NH len too small"); + return 0; + } + + /* + * Parse attributes included in the nexthop. + */ + err_msg = NULL; + if (!parse_rtattrs_(RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh), rtattrs, + ARRAY_SIZE(rtattrs), &err_msg)) { + netlink_msg_ctx_set_err(ctx, err_msg); + return 0; + } + + gateway = rtattrs[RTA_GATEWAY]; + netlink_msg_ctx_add_nh(ctx, rtnh->rtnh_ifindex, gateway); + } + + return 1; +} + +/* + * parse_route_msg + */ +static int parse_route_msg(struct netlink_msg_ctx *ctx) +{ + int len; + struct rtattr **rtattrs, *rtattr, *gateway, *oif; + int if_index; + + ctx->rtmsg = NLMSG_DATA(ctx->hdr); + + len = ctx->hdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + if (len < 0) { + netlink_msg_ctx_set_err(ctx, "Bad message length"); + return 0; + } + + if (!parse_rtattrs(ctx, RTM_RTA(ctx->rtmsg), len)) + return 0; + + rtattrs = ctx->rtattrs; + + ctx->dest = rtattrs[RTA_DST]; + ctx->src = rtattrs[RTA_PREFSRC]; + + rtattr = rtattrs[RTA_PRIORITY]; + if (rtattr) + ctx->metric = (int *)RTA_DATA(rtattr); + + rtattr = rtattrs[RTA_NH_ID]; + if (rtattr) + ctx->nhgid = (unsigned int *)RTA_DATA(rtattr); + + gateway = rtattrs[RTA_GATEWAY]; + oif = rtattrs[RTA_OIF]; + if (gateway || oif) { + if_index = 0; + if (oif) + if_index = *((int *)RTA_DATA(oif)); + + netlink_msg_ctx_add_nh(ctx, if_index, gateway); + } + + rtattr = rtattrs[RTA_MULTIPATH]; + if (rtattr) + parse_multipath_attr(ctx, rtattr); + + return 1; +} + +/* + * addr_to_s + */ +static const char * +addr_to_s(unsigned char family, void *addr) +{ + size_t buf_len; + char *buf; + + buf = get_print_buf(&buf_len); + + return inet_ntop(family, addr, buf, buf_len); +} + +/* + * netlink_msg_ctx_print + */ +static int netlink_msg_ctx_snprint(struct netlink_msg_ctx *ctx, char *buf, + size_t buf_len) +{ + struct nlmsghdr *hdr; + struct rtmsg *rtmsg; + struct netlink_nh *nh; + char *cur, *end; + unsigned long i; + + hdr = ctx->hdr; + rtmsg = ctx->rtmsg; + + cur = buf; + end = buf + buf_len; + + cur += snprintf(cur, end - cur, "%s %s/%d, Prot: %s(%u)", + netlink_msg_type_to_s(hdr->nlmsg_type), + addr_to_s(rtmsg->rtm_family, RTA_DATA(ctx->dest)), + rtmsg->rtm_dst_len, + netlink_prot_to_s(rtmsg->rtm_protocol), + rtmsg->rtm_protocol); + + if (ctx->metric) + cur += snprintf(cur, end - cur, ", Metric: %d", *ctx->metric); + + if (ctx->nhgid) + cur += snprintf(cur, end - cur, ", nhgid: %u", *ctx->nhgid); + for (i = 0; i < ctx->num_nhs; i++) { + cur += snprintf(cur, end - cur, "\n "); + nh = &ctx->nhs[i]; + + if (nh->gateway) { + cur += snprintf(cur, end - cur, " %s", + addr_to_s(rtmsg->rtm_family, + RTA_DATA(nh->gateway))); + } + + if (nh->if_index) { + cur += snprintf(cur, end - cur, " via interface %d", + nh->if_index); + } + } + + return cur - buf; +} + +/* + * print_netlink_msg_ctx + */ +static void print_netlink_msg_ctx(struct netlink_msg_ctx *ctx) +{ + char buf[1024]; + + netlink_msg_ctx_snprint(ctx, buf, sizeof(buf)); + printf("%s\n", buf); +} + +/* + * parse_netlink_msg + */ +static void parse_netlink_msg(char *buf, size_t buf_len, fpm_msg_hdr_t *fpm) +{ + struct netlink_msg_ctx ctx_space, *ctx; + struct nlmsghdr *hdr; + unsigned int len; + + ctx = &ctx_space; + + hdr = (struct nlmsghdr *)buf; + len = buf_len; + for (; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) { + + netlink_msg_ctx_init(ctx); + ctx->hdr = (struct nlmsghdr *)buf; + + switch (hdr->nlmsg_type) { + + case RTM_DELROUTE: + case RTM_NEWROUTE: + + parse_route_msg(ctx); + if (ctx->err_msg) { + fprintf(stderr, + "Error parsing route message: %s\n", + ctx->err_msg); + } + + print_netlink_msg_ctx(ctx); + + if (glob->reflect && hdr->nlmsg_type == RTM_NEWROUTE && + ctx->rtmsg->rtm_protocol > RTPROT_STATIC) { + printf(" Route %s(%u) reflecting back\n", + netlink_prot_to_s( + ctx->rtmsg->rtm_protocol), + ctx->rtmsg->rtm_protocol); + ctx->rtmsg->rtm_flags |= RTM_F_OFFLOAD; + write(glob->sock, fpm, fpm_msg_len(fpm)); + } + break; + + default: + fprintf(stdout, + "Ignoring netlink message - Type: %s(%d)\n", + netlink_msg_type_to_s(hdr->nlmsg_type), + hdr->nlmsg_type); + } + } +} + +/* + * process_fpm_msg + */ +static void process_fpm_msg(fpm_msg_hdr_t *hdr) +{ + fprintf(stdout, "FPM message - Type: %d, Length %d\n", hdr->msg_type, + ntohs(hdr->msg_len)); + + if (hdr->msg_type != FPM_MSG_TYPE_NETLINK) { + fprintf(stderr, "Unknown fpm message type %u\n", hdr->msg_type); + return; + } + + parse_netlink_msg(fpm_msg_data(hdr), fpm_msg_data_len(hdr), hdr); +} + +/* + * fpm_serve + */ +static void fpm_serve(void) +{ + char buf[FPM_MAX_MSG_LEN * 4]; + fpm_msg_hdr_t *hdr; + + while (1) { + + hdr = read_fpm_msg(buf, sizeof(buf)); + if (!hdr) + return; + + process_fpm_msg(hdr); + } +} + +int main(int argc, char **argv) +{ + pid_t daemon; + int r; + bool fork_daemon = false; + + memset(glob, 0, sizeof(*glob)); + + while ((r = getopt(argc, argv, "rd")) != -1) { + switch (r) { + case 'r': + glob->reflect = true; + break; + case 'd': + fork_daemon = true; + break; + } + } + + if (fork_daemon) { + daemon = fork(); + + if (daemon) + exit(0); + } + + if (!create_listen_sock(FPM_DEFAULT_PORT, &glob->server_sock)) + exit(1); + + /* + * Server forever. + */ + while (1) { + glob->sock = accept_conn(glob->server_sock); + fpm_serve(); + fprintf(stdout, "Done serving client"); + } +} +#else + +int main(int argc, char **argv) +{ + fprintf(stderr, "This program only works on linux"); + exit(-1); +} +#endif diff --git a/zebra/ge_netlink.c b/zebra/ge_netlink.c new file mode 100644 index 0000000000..e7d2e6b12a --- /dev/null +++ b/zebra/ge_netlink.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Generic Netlink functions. + * Copyright (C) 2022, Carmine Scarpitta + */ + +#include <zebra.h> + +#ifdef HAVE_NETLINK + +/* The following definition is to workaround an issue in the Linux kernel + * header files with redefinition of 'struct in6_addr' in both + * netinet/in.h and linux/in6.h. + * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html + */ +#define _LINUX_IN6_H + +#include <linux/genetlink.h> +#include <linux/rtnetlink.h> +#include <linux/seg6_genl.h> + +#include "lib/ns.h" +#include "zebra/ge_netlink.h" +#include "zebra/debug.h" +#include "zebra/kernel_netlink.h" +#include "zebra/zebra_router.h" +#include "zebra/zebra_srv6.h" + + +/** + * This file provides an implementation of the functionality exposed by the + * kernel through the Generic Netlink mechanism. + * + * Supported features include the ability to configure the source address used + * for SRv6 encapsulation ('sr tunsrc' in kernel terminology). + * + * At the time of writing this code, the kernel does not send us any asynchronous + * notifications when someone changes the 'sr tunsrc' under us. As a result, we + * are currently unable to detect when the source address changes and update the + * SRv6 encapsulation source address configured in zebra. + * + * In the future, when the kernel supports async notifications, the implementation + * can be improved by listening on the Generic Netlink socket and adding a handler + * to process/parse incoming 'sr tunsrc' change messages and update the SRv6 zebra + * configuration with the new encap source address. + */ + + +/* + * Numeric family identifier used to configure SRv6 internal parameters through Generic Netlink. + */ +static int16_t seg6_genl_family = -1; + +static int genl_parse_getfamily(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + int len; + struct rtattr *tb[CTRL_ATTR_MAX + 1]; + struct genlmsghdr *ghdr = NLMSG_DATA(h); + struct rtattr *attrs; + const char *family; + + if (h->nlmsg_type != GENL_ID_CTRL) { + zlog_err( + "Not a controller message, nlmsg_len=%d nlmsg_type=0x%x", + h->nlmsg_len, h->nlmsg_type); + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) { + zlog_err( + "Message received from netlink is of a broken size %d %zu", + h->nlmsg_len, (size_t)NLMSG_LENGTH(GENL_HDRLEN)); + return -1; + } + + if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { + zlog_err("Unknown controller command %d", ghdr->cmd); + return -1; + } + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + netlink_parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); + + if (tb[CTRL_ATTR_FAMILY_ID] == NULL) { + zlog_err("Missing family id TLV"); + return -1; + } + + if (tb[CTRL_ATTR_FAMILY_NAME] == NULL) { + zlog_err("Missing family name TLV"); + return -1; + } + + family = (char *)RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]); + + if (strmatch(family, "SEG6")) + seg6_genl_family = + *(int16_t *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]); + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_err("Unsupported Generic Netlink family '%s'", + family); + return -1; + } + + return 0; +} + +int genl_resolve_family(const char *family) +{ + struct zebra_ns *zns; + struct genl_request req; + + memset(&req, 0, sizeof(req)); + + zns = zebra_ns_lookup(NS_DEFAULT); + + req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = GENL_ID_CTRL; + + req.n.nlmsg_pid = zns->ge_netlink_cmd.snl.nl_pid; + + req.g.cmd = CTRL_CMD_GETFAMILY; + req.g.version = 0; + + if (!nl_attr_put(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, family, + strlen(family) + 1)) + return -1; + + return ge_netlink_talk(genl_parse_getfamily, &req.n, zns, false); +} + +/* + * sr tunsrc change via netlink interface, using a dataplane context object + * + * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer + * otherwise the number of bytes written to buf. + */ +ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + struct nlsock *nl; + const struct in6_addr *tunsrc_addr; + struct genl_request *req = buf; + + if (seg6_genl_family < 0) { + zlog_err( + "Failed to set SRv6 source address: kernel does not support 'SEG6' Generic Netlink family."); + return -1; + } + + tunsrc_addr = dplane_ctx_get_srv6_encap_srcaddr(ctx); + if (!tunsrc_addr) + return -1; + + if (buflen < sizeof(*req)) + return 0; + + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + /* Prepare Netlink request to set tunsrc addr */ + req->n.nlmsg_type = seg6_genl_family; + req->n.nlmsg_pid = nl->snl.nl_pid; + + req->g.cmd = cmd; + req->g.version = SEG6_GENL_VERSION; + + switch (cmd) { + case SEG6_CMD_SET_TUNSRC: + if (!nl_attr_put(&req->n, buflen, SEG6_ATTR_DST, tunsrc_addr, + sizeof(struct in6_addr))) + return 0; + break; + default: + zlog_err("Unsupported command (%u)", cmd); + return -1; + } + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + enum dplane_op_e op; + int cmd = 0; + + op = dplane_ctx_get_op(ctx); + + /* Call to netlink layer based on type of operation */ + if (op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET) { + /* Validate */ + if (dplane_ctx_get_srv6_encap_srcaddr(ctx) == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "sr tunsrc set failed: SRv6 encap source address not set"); + return -1; + } + + cmd = SEG6_CMD_SET_TUNSRC; + } else { + /* Invalid op */ + zlog_err("Context received for kernel sr tunsrc update with incorrect OP code (%u)", + op); + return -1; + } + + return netlink_sr_tunsrc_set_msg_encode(cmd, ctx, buf, buflen); +} + +enum netlink_msg_status +netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + struct zebra_ns *zns; + struct genl_request req; + + op = dplane_ctx_get_op(ctx); + assert(op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET); + + netlink_sr_tunsrc_set_msg_encoder(ctx, &req, sizeof(req)); + + zns = zebra_ns_lookup(dplane_ctx_get_ns_sock(ctx)); + + return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false); +} + +/** + * netlink_sr_tunsrc_reply_read() - Read in SR tunsrc reply from the kernel + * + * @h: Netlink message header + * @ns_id: Namspace id + * @startup: Are we reading under startup conditions? + * + * Return: Result status + */ +int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + int len; + struct genlmsghdr *ghdr; + struct rtattr *tb[SEG6_ATTR_MAX + 1] = {}; + struct rtattr *attrs; + + if (h->nlmsg_type != seg6_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 != SEG6_CMD_GET_TUNSRC) + return 0; + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + netlink_parse_rtattr(tb, SEG6_ATTR_MAX, attrs, len); + + if (tb[SEG6_ATTR_DST] == NULL) { + zlog_err("Missing tunsrc addr"); + return -1; + } + + zebra_srv6_encap_src_addr_set( + (struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST])); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: SRv6 encap source address received from kernel: '%pI6'", + __func__, + (struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST])); + + return 0; +} + +/** + * netlink_request_sr_tunsrc() - Request SR tunsrc from the kernel + * @zns: Zebra namespace + * + * Return: Result status + */ +static int netlink_request_sr_tunsrc(struct zebra_ns *zns) +{ + struct genl_request req; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + if (seg6_genl_family < 0) { + zlog_err( + "Failed to get SRv6 encap source address: kernel does not support 'SEG6' Generic Netlink family."); + return -1; + } + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = seg6_genl_family; + req.g.cmd = SEG6_CMD_GET_TUNSRC; + req.g.version = SEG6_GENL_VERSION; + + return netlink_request(&zns->ge_netlink_cmd, &req); +} + +/** + * SR tunsrc read function using netlink interface. Only called + * on bootstrap time. + */ +int netlink_sr_tunsrc_read(struct zebra_ns *zns) +{ + int ret; + struct zebra_dplane_info dp_info; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + /* Capture info in intermediate info struct */ + dp_info.ns_id = zns->ns_id; + dp_info.is_cmd = true; + dp_info.sock = zns->ge_netlink_cmd.sock; + dp_info.seq = zns->ge_netlink_cmd.seq; + + /* Get SR tunsrc. */ + 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); + if (ret < 0) + return ret; + + return 0; +} + +void ge_netlink_init(struct zebra_ns *zns) +{ + if (zns->ge_netlink_cmd.sock < 0) + return; + + /* + * Resolves the 'seg6' Generic Netlink family name to the corresponding numeric family identifier. + * This will give us the numeric family identifier required to send 'seg6' commands to the kernel + * over the Generic Netlink socket. 'seg6' commands are used to configure SRv6 internal parameters + * such as the address to use as source for encapsulated packets. + */ + if (genl_resolve_family("SEG6")) + zlog_warn( + "Kernel does not support 'SEG6' Generic Netlink family. Any attempt to set the encapsulation parameters under the SRv6 configuration will fail"); + + /** + * Retrieve the actual SRv6 encap source address from the kernel + * (default namespace) and save it to zebra SRv6 config + */ + if (zns->ns_id == NS_DEFAULT) + netlink_sr_tunsrc_read(zns); +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/ge_netlink.h b/zebra/ge_netlink.h new file mode 100644 index 0000000000..20d09116c0 --- /dev/null +++ b/zebra/ge_netlink.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Header file exported by ge_netlink.c to zebra. + * Copyright (C) 2022, Carmine Scarpitta + */ + +#ifndef _ZEBRA_GE_NETLINK_H +#define _ZEBRA_GE_NETLINK_H + +#include "zebra_dplane.h" + +#ifdef HAVE_NETLINK + +#include <linux/genetlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Generic Netlink request message */ +struct genl_request { + struct nlmsghdr n; + struct genlmsghdr g; + char buf[1024]; +}; + +extern int genl_resolve_family(const char *family); +extern ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd, + struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); +extern ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); +struct nl_batch; +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_read(struct zebra_ns *zns); + +extern void ge_netlink_init(struct zebra_ns *zns); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_NETLINK */ + +#endif /* _ZEBRA_GE_NETLINK_H */ diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index b3cf865122..d0aa2167fe 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -5,6 +5,7 @@ */ #include <zebra.h> +#include <sys/ioctl.h> #ifdef OPEN_BSD diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 3a325df06c..5f096e3039 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -17,6 +17,8 @@ #define _LINUX_IF_H #define _LINUX_IP_H +#include <linux/netlink.h> +#include <linux/rtnetlink.h> #include <netinet/if_ether.h> #include <linux/if_bridge.h> #include <linux/if_link.h> @@ -63,66 +65,22 @@ #include "zebra/zebra_trace.h" extern struct zebra_privs_t zserv_privs; -uint8_t frr_protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; - -/* Note: on netlink systems, there should be a 1-to-1 mapping between interface - names and ifindex values. */ -static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, - struct zebra_ns *zns) -{ - struct interface *oifp; - - if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL) - && (oifp != ifp)) { - if (ifi_index == IFINDEX_INTERNAL) - flog_err( - EC_LIB_INTERFACE, - "Netlink is setting interface %s ifindex to reserved internal value %u", - ifp->name, ifi_index); - else { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "interface index %d was renamed from %s to %s", - ifi_index, oifp->name, ifp->name); - if (if_is_up(oifp)) - flog_err( - EC_LIB_INTERFACE, - "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", - ifi_index, oifp->name, ifp->name); - if_delete_update(&oifp); - } - } - if_set_index(ifp, ifi_index); -} /* Utility function to parse hardware link-layer address and update ifp */ static void netlink_interface_update_hw_addr(struct rtattr **tb, - struct interface *ifp) + struct zebra_dplane_ctx *ctx) { - int i; - if (tb[IFLA_ADDRESS]) { int hw_addr_len; hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); if (hw_addr_len > INTERFACE_HWADDR_MAX) - zlog_debug("Hardware address is too large: %d", - hw_addr_len); - else { - ifp->hw_addr_len = hw_addr_len; - memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), - hw_addr_len); - - for (i = 0; i < hw_addr_len; i++) - if (ifp->hw_addr[i] != 0) - break; - - if (i == hw_addr_len) - ifp->hw_addr_len = 0; - else - ifp->hw_addr_len = hw_addr_len; - } + zlog_warn("Hardware address is too large: %d", + hw_addr_len); + else + dplane_ctx_set_ifp_hw_addr(ctx, hw_addr_len, + RTA_DATA(tb[IFLA_ADDRESS])); } } @@ -237,26 +195,6 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt) } } -static inline void zebra_if_set_ziftype(struct interface *ifp, - enum zebra_iftype zif_type, - enum zebra_slave_iftype zif_slave_type) -{ - struct zebra_if *zif; - - zif = (struct zebra_if *)ifp->info; - zif->zif_slave_type = zif_slave_type; - - if (zif->zif_type != zif_type) { - zif->zif_type = zif_type; - /* If the if_type has been set to bond initialize ES info - * against it. XXX - note that we don't handle the case where - * a zif changes from bond to non-bond; it is really - * an unexpected/error condition. - */ - zebra_evpn_if_init(zif); - } -} - static void netlink_determine_zebra_iftype(const char *kind, enum zebra_iftype *zif_type) { @@ -279,23 +217,18 @@ static void netlink_determine_zebra_iftype(const char *kind, *zif_type = ZEBRA_IF_VETH; else if (strcmp(kind, "bond") == 0) *zif_type = ZEBRA_IF_BOND; - else if (strcmp(kind, "bond_slave") == 0) - *zif_type = ZEBRA_IF_BOND_SLAVE; + else if (strcmp(kind, "team") == 0) + *zif_type = ZEBRA_IF_BOND; else if (strcmp(kind, "gre") == 0) *zif_type = ZEBRA_IF_GRE; } static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, - uint32_t ns_id, const char *name) + uint32_t ns_id, const char *name, + struct zebra_dplane_ctx *ctx) { - struct ifinfomsg *ifi; struct rtattr *linkinfo[IFLA_INFO_MAX + 1]; struct rtattr *attr[IFLA_VRF_MAX + 1]; - struct vrf *vrf = NULL; - struct zebra_vrf *zvrf; - uint32_t nl_table_id; - - ifi = NLMSG_DATA(h); netlink_parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb); @@ -317,74 +250,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, return; } - nl_table_id = *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]); - - if (h->nlmsg_type == RTM_NEWLINK) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_NEWLINK for VRF %s(%u) table %u", name, - ifi->ifi_index, nl_table_id); - - if (!vrf_lookup_by_id((vrf_id_t)ifi->ifi_index)) { - vrf_id_t exist_id; - - exist_id = vrf_lookup_by_table(nl_table_id, ns_id); - if (exist_id != VRF_DEFAULT) { - vrf = vrf_lookup_by_id(exist_id); - - flog_err( - EC_ZEBRA_VRF_MISCONFIGURED, - "VRF %s id %u table id overlaps existing vrf %s, misconfiguration exiting", - name, ifi->ifi_index, vrf->name); - exit(-1); - } - } - - vrf = vrf_update((vrf_id_t)ifi->ifi_index, name); - if (!vrf) { - flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", - name, ifi->ifi_index); - return; - } - - /* - * This is the only place that we get the actual kernel table_id - * being used. We need it to set the table_id of the routes - * we are passing to the kernel.... And to throw some totally - * awesome parties. that too. - * - * At this point we *must* have a zvrf because the vrf_create - * callback creates one. We *must* set the table id - * before the vrf_enable because of( at the very least ) - * static routes being delayed for installation until - * during the vrf_enable callbacks. - */ - zvrf = (struct zebra_vrf *)vrf->info; - zvrf->table_id = nl_table_id; - - /* Enable the created VRF. */ - if (!vrf_enable(vrf)) { - flog_err(EC_LIB_INTERFACE, - "Failed to enable VRF %s id %u", name, - ifi->ifi_index); - return; - } - - } else // h->nlmsg_type == RTM_DELLINK - { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_DELLINK for VRF %s(%u)", name, - ifi->ifi_index); - - vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index); - - if (!vrf) { - flog_warn(EC_ZEBRA_VRF_NOT_FOUND, "%s: vrf not found", - __func__); - return; - } - - vrf_delete(vrf); - } + dplane_ctx_set_ifp_table_id( + ctx, *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE])); } static uint32_t get_iflink_speed(struct interface *interface, int *error) @@ -394,6 +261,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) int sd; int rc; const char *ifname = interface->name; + uint32_t ret; if (error) *error = 0; @@ -418,7 +286,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) ifname, errno, safe_strerror(errno)); /* no vrf socket creation may probably mean vrf issue */ if (error) - *error = -1; + *error = INTERFACE_SPEED_ERROR_READ; return 0; } /* Get the current link state for the interface */ @@ -432,14 +300,20 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) ifname, errno, safe_strerror(errno)); /* no device means interface unreachable */ if (errno == ENODEV && error) - *error = -1; + *error = INTERFACE_SPEED_ERROR_READ; ecmd.speed_hi = 0; ecmd.speed = 0; } close(sd); - return ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed; + ret = ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed; + if (ret == UINT32_MAX) { + if (error) + *error = INTERFACE_SPEED_ERROR_UNKNOWN; + ret = 0; + } + return ret; } uint32_t kernel_get_speed(struct interface *ifp, int *error) @@ -665,62 +539,59 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data, * bridge interface is added or updated, take further actions to map * its members. Likewise, for VxLAN interface. */ -static void netlink_interface_update_l2info(struct interface *ifp, +static void netlink_interface_update_l2info(struct zebra_dplane_ctx *ctx, + enum zebra_iftype zif_type, struct rtattr *link_data, int add, ns_id_t link_nsid) { + struct zebra_l2info_bridge bridge_info; + struct zebra_l2info_vlan vlan_info; + struct zebra_l2info_vxlan vxlan_info; + struct zebra_l2info_gre gre_info; + if (!link_data) return; - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - struct zebra_l2info_bridge bridge_info; - + switch (zif_type) { + case ZEBRA_IF_BRIDGE: netlink_extract_bridge_info(link_data, &bridge_info); - zebra_l2_bridge_add_update(ifp, &bridge_info, add); - } else if (IS_ZEBRA_IF_VLAN(ifp)) { - struct zebra_l2info_vlan vlan_info; - + dplane_ctx_set_ifp_bridge_info(ctx, &bridge_info); + break; + case ZEBRA_IF_VLAN: netlink_extract_vlan_info(link_data, &vlan_info); - zebra_l2_vlanif_update(ifp, &vlan_info); - zebra_evpn_acc_bd_svi_set(ifp->info, NULL, - !!if_is_operative(ifp)); - } else if (IS_ZEBRA_IF_VXLAN(ifp)) { - struct zebra_l2info_vxlan vxlan_info; - + dplane_ctx_set_ifp_vlan_info(ctx, &vlan_info); + break; + case ZEBRA_IF_VXLAN: netlink_extract_vxlan_info(link_data, &vxlan_info); vxlan_info.link_nsid = link_nsid; - zebra_l2_vxlanif_add_update(ifp, &vxlan_info, add); - if (link_nsid != NS_UNKNOWN && - vxlan_info.ifindex_link) - zebra_if_update_link(ifp, vxlan_info.ifindex_link, - link_nsid); - } else if (IS_ZEBRA_IF_GRE(ifp)) { - struct zebra_l2info_gre gre_info; - + dplane_ctx_set_ifp_vxlan_info(ctx, &vxlan_info); + break; + case ZEBRA_IF_GRE: netlink_extract_gre_info(link_data, &gre_info); gre_info.link_nsid = link_nsid; - zebra_l2_greif_add_update(ifp, &gre_info, add); - if (link_nsid != NS_UNKNOWN && - gre_info.ifindex_link) - zebra_if_update_link(ifp, gre_info.ifindex_link, - link_nsid); + dplane_ctx_set_ifp_gre_info(ctx, &gre_info); + break; + case ZEBRA_IF_OTHER: + case ZEBRA_IF_VRF: + case ZEBRA_IF_MACVLAN: + case ZEBRA_IF_VETH: + case ZEBRA_IF_BOND: + break; } } -static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp, - struct rtattr *af_spec) +static int +netlink_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { int rem; - vni_t vni_id; - vlanid_t vid; uint16_t flags; struct rtattr *i; - struct zebra_vxlan_vni vni; - struct zebra_vxlan_vni *vnip; - struct hash *vni_table = NULL; + struct zebra_vxlan_vni_array *vniarray = NULL; struct zebra_vxlan_vni vni_end; struct zebra_vxlan_vni vni_start; struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1]; + int32_t count = 0; memset(&vni_start, 0, sizeof(vni_start)); memset(&vni_end, 0, sizeof(vni_end)); @@ -739,204 +610,126 @@ static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp, /* vlan-vni info missing */ return 0; + count++; flags = 0; - memset(&vni, 0, sizeof(vni)); + vniarray = XREALLOC( + MTYPE_TMP, vniarray, + sizeof(struct zebra_vxlan_vni_array) + + count * sizeof(struct zebra_vxlan_vni)); - vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); - vni.access_vlan = *(vlanid_t *)RTA_DATA( + memset(&vniarray->vnis[count - 1], 0, + sizeof(struct zebra_vxlan_vni)); + + vniarray->vnis[count - 1].vni = + *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); + vniarray->vnis[count - 1].access_vlan = *(vlanid_t *)RTA_DATA( aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]); if (aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]) flags = *(uint16_t *)RTA_DATA( aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]); - if (flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - vni_start = vni; - continue; - } - - if (flags & BRIDGE_VLAN_INFO_RANGE_END) - vni_end = vni; - - if (!(flags & BRIDGE_VLAN_INFO_RANGE_END)) { - vni_start = vni; - vni_end = vni; - } - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)", - vni_start.access_vlan, vni_end.access_vlan, - vni_start.vni, vni_end.vni, ifp->name, - ifp->ifindex); - - if (!vni_table) { - vni_table = zebra_vxlan_vni_table_create(); - if (!vni_table) - return 0; - } - - for (vid = vni_start.access_vlan, vni_id = vni_start.vni; - vid <= vni_end.access_vlan; vid++, vni_id++) { - - memset(&vni, 0, sizeof(vni)); - vni.vni = vni_id; - vni.access_vlan = vid; - vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc); - if (!vnip) - return 0; - } - - memset(&vni_start, 0, sizeof(vni_start)); - memset(&vni_end, 0, sizeof(vni_end)); + vniarray->vnis[count - 1].flags = flags; } - if (vni_table) - zebra_vxlan_if_vni_table_add_update(ifp, vni_table); - + if (count) { + vniarray->count = count; + dplane_ctx_set_ifp_vxlan_vni_array(ctx, vniarray); + } return 0; } -static int netlink_bridge_vxlan_update(struct interface *ifp, - struct rtattr *af_spec) +static int netlink_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { struct rtattr *aftb[IFLA_BRIDGE_MAX + 1]; struct bridge_vlan_info *vinfo; - struct zebra_if *zif; - vlanid_t access_vlan; + struct zebra_dplane_bridge_vlan_info bvinfo; - if (!af_spec) + if (!af_spec) { + dplane_ctx_set_ifp_no_afspec(ctx); return 0; + } - zif = (struct zebra_if *)ifp->info; - - /* Single vxlan devices has vni-vlan range to update */ - if (IS_ZEBRA_VXLAN_IF_SVD(zif)) - return netlink_bridge_vxlan_vlan_vni_map_update(ifp, af_spec); + netlink_bridge_vxlan_vlan_vni_map_update(ctx, af_spec); /* There is a 1-to-1 mapping of VLAN to VxLAN - hence * only 1 access VLAN is accepted. */ netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, af_spec); - if (!aftb[IFLA_BRIDGE_VLAN_INFO]) + if (!aftb[IFLA_BRIDGE_VLAN_INFO]) { + dplane_ctx_set_ifp_no_bridge_vlan_info(ctx); return 0; + } vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]); - if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID)) - return 0; + bvinfo.flags = vinfo->flags; + bvinfo.vid = vinfo->vid; - access_vlan = (vlanid_t)vinfo->vid; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan, - ifp->name, ifp->ifindex); - zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan); + dplane_ctx_set_ifp_bridge_vlan_info(ctx, &bvinfo); return 0; } -static void netlink_bridge_vlan_update(struct interface *ifp, - struct rtattr *af_spec) +static void netlink_bridge_vlan_update(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec) { struct rtattr *i; int rem; - uint16_t vid_range_start = 0; - struct zebra_if *zif; - bitfield_t old_vlan_bitmap; struct bridge_vlan_info *vinfo; - - zif = (struct zebra_if *)ifp->info; - - /* cache the old bitmap addrs */ - old_vlan_bitmap = zif->vlan_bitmap; - /* create a new bitmap space for re-eval */ - bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); + struct zebra_dplane_bridge_vlan_info_array *bvarray = NULL; + int32_t count = 0; if (af_spec) { for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { - if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; - vinfo = RTA_DATA(i); - - if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - vid_range_start = vinfo->vid; - continue; - } - - if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) - vid_range_start = vinfo->vid; + count++; + bvarray = XREALLOC( + MTYPE_TMP, bvarray, + sizeof(struct + zebra_dplane_bridge_vlan_info_array) + + count * sizeof(struct + zebra_dplane_bridge_vlan_info)); - zebra_vlan_bitmap_compute(ifp, vid_range_start, - vinfo->vid); + vinfo = RTA_DATA(i); + bvarray->array[count - 1].flags = vinfo->flags; + bvarray->array[count - 1].vid = vinfo->vid; } } - zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); - - bf_free(old_vlan_bitmap); + if (count) { + bvarray->count = count; + dplane_ctx_set_ifp_bridge_vlan_info_array(ctx, bvarray); + } } -static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id, - int startup) +static int netlink_bridge_interface(struct zebra_dplane_ctx *ctx, + struct rtattr *af_spec, int startup) { - char *name = NULL; - struct ifinfomsg *ifi; - struct rtattr *tb[IFLA_MAX + 1]; - struct interface *ifp; - struct zebra_if *zif; - struct rtattr *af_spec; - - /* Fetch name and ifindex */ - ifi = NLMSG_DATA(h); - netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - - if (tb[IFLA_IFNAME] == NULL) - return -1; - name = (char *)RTA_DATA(tb[IFLA_IFNAME]); - - /* The interface should already be known, if not discard. */ - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ifi->ifi_index); - if (!ifp) { - zlog_debug("Cannot find bridge IF %s(%u)", name, - ifi->ifi_index); - return 0; - } - /* We are only interested in the access VLAN i.e., AF_SPEC */ - af_spec = tb[IFLA_AF_SPEC]; - - if (IS_ZEBRA_IF_VXLAN(ifp)) - return netlink_bridge_vxlan_update(ifp, af_spec); + netlink_bridge_vxlan_update(ctx, af_spec); /* build vlan bitmap associated with this interface if that * device type is interested in the vlans */ - zif = (struct zebra_if *)ifp->info; - if (bf_is_inited(zif->vlan_bitmap)) - netlink_bridge_vlan_update(ifp, af_spec); + netlink_bridge_vlan_update(ctx, af_spec); + dplane_provider_enqueue_to_zebra(ctx); return 0; } -static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield) -{ - /* This shouldn't be possible */ - assert(frr_protodown_r_bit < 32); - return (rc_bitfield == (((uint32_t)1) << frr_protodown_r_bit)); -} - /* * Process interface protodown dplane update. * * If the interface is an es bond member then it must follow EVPN's * protodown setting. */ -static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, +static void netlink_proc_dplane_if_protodown(struct zebra_dplane_ctx *ctx, struct rtattr **tb) { bool protodown; - bool old_protodown; uint32_t rc_bitfield = 0; struct rtattr *pd_reason_info[IFLA_MAX + 1]; @@ -951,59 +744,9 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, pd_reason_info[IFLA_PROTO_DOWN_REASON_VALUE]); } - /* - * Set our reason code to note it wasn't us. - * If the reason we got from the kernel is ONLY frr though, don't - * set it. - */ - COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL, - protodown && rc_bitfield && - !is_if_protodown_reason_only_frr(rc_bitfield)); - - - old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); - if (protodown == old_protodown) - return; - - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s dplane change, protdown %s", - zif->ifp->name, protodown ? "on" : "off"); - - /* Set protodown, respectively */ - COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); - - if (zebra_evpn_is_es_bond_member(zif->ifp)) { - /* Check it's not already being sent to the dplane first */ - if (protodown && - CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s protodown on recv'd but already sent protodown on to the dplane", - zif->ifp->name); - return; - } - - if (!protodown && - CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s protodown off recv'd but already sent protodown off to the dplane", - zif->ifp->name); - return; - } - - if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "bond mbr %s reinstate protodown %s in the dplane", - zif->ifp->name, old_protodown ? "on" : "off"); - - if (old_protodown) - SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); - else - SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN); - - dplane_intf_update(zif->ifp); - } + dplane_ctx_set_ifp_rc_bitfield(ctx, rc_bitfield); + dplane_ctx_set_ifp_protodown(ctx, protodown); + dplane_ctx_set_ifp_protodown_set(ctx, true); } static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) @@ -1020,201 +763,6 @@ static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) return bypass; } -/* - * Only called at startup to cleanup leftover protodown reasons we may - * have not cleaned up. We leave protodown set though. - */ -static void if_sweep_protodown(struct zebra_if *zif) -{ - bool protodown; - - protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); - - if (!protodown) - return; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s sweeping protodown %s reason 0x%x", - zif->ifp->name, protodown ? "on" : "off", - zif->protodown_rc); - - /* Only clear our reason codes, leave external if it was set */ - UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL); - dplane_intf_update(zif->ifp); -} - -/* - * Called from interface_lookup_netlink(). This function is only used - * during bootstrap. - */ -static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) -{ - int len; - struct ifinfomsg *ifi; - struct rtattr *tb[IFLA_MAX + 1]; - struct rtattr *linkinfo[IFLA_MAX + 1]; - struct interface *ifp; - char *name = NULL; - char *kind = NULL; - char *desc = NULL; - char *slave_kind = NULL; - struct zebra_ns *zns = NULL; - vrf_id_t vrf_id = VRF_DEFAULT; - enum zebra_iftype zif_type = ZEBRA_IF_OTHER; - enum zebra_slave_iftype zif_slave_type = ZEBRA_IF_SLAVE_NONE; - ifindex_t bridge_ifindex = IFINDEX_INTERNAL; - ifindex_t link_ifindex = IFINDEX_INTERNAL; - ifindex_t bond_ifindex = IFINDEX_INTERNAL; - struct zebra_if *zif; - ns_id_t link_nsid = ns_id; - uint8_t bypass = 0; - - frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); - - zns = zebra_ns_lookup(ns_id); - ifi = NLMSG_DATA(h); - - if (h->nlmsg_type != RTM_NEWLINK) - return 0; - - len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); - 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 ifinfomsg))); - return -1; - } - - /* We are interested in some AF_BRIDGE notifications. */ - if (ifi->ifi_family == AF_BRIDGE) - return netlink_bridge_interface(h, len, ns_id, startup); - - /* Looking up interface name. */ - memset(linkinfo, 0, sizeof(linkinfo)); - netlink_parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, - NLA_F_NESTED); - - /* check for wireless messages to ignore */ - if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: ignoring IFLA_WIRELESS message", - __func__); - return 0; - } - - if (tb[IFLA_IFNAME] == NULL) - return -1; - name = (char *)RTA_DATA(tb[IFLA_IFNAME]); - - if (tb[IFLA_IFALIAS]) - desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); - - if (tb[IFLA_LINKINFO]) { - netlink_parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, - tb[IFLA_LINKINFO]); - - if (linkinfo[IFLA_INFO_KIND]) - kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]); - - if (linkinfo[IFLA_INFO_SLAVE_KIND]) - slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]); - - if ((slave_kind != NULL) && strcmp(slave_kind, "bond") == 0) - netlink_determine_zebra_iftype("bond_slave", &zif_type); - else - netlink_determine_zebra_iftype(kind, &zif_type); - } - - /* If VRF, create the VRF structure itself. */ - if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); - vrf_id = (vrf_id_t)ifi->ifi_index; - } - - if (tb[IFLA_MASTER]) { - if (slave_kind && (strcmp(slave_kind, "vrf") == 0) - && !vrf_is_backend_netns()) { - zif_slave_type = ZEBRA_IF_SLAVE_VRF; - vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]); - } else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) { - zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE; - bridge_ifindex = - *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); - } else if (slave_kind && (strcmp(slave_kind, "bond") == 0)) { - zif_slave_type = ZEBRA_IF_SLAVE_BOND; - bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); - bypass = netlink_parse_lacp_bypass(linkinfo); - } else - zif_slave_type = ZEBRA_IF_SLAVE_OTHER; - } - if (vrf_is_backend_netns()) - vrf_id = (vrf_id_t)ns_id; - - /* If linking to another interface, note it. */ - if (tb[IFLA_LINK]) - link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); - - if (tb[IFLA_LINK_NETNSID]) { - link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]); - link_nsid = ns_id_get_absolute(ns_id, link_nsid); - } - - ifp = if_get_by_name(name, vrf_id, NULL); - set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */ - - ifp->flags = ifi->ifi_flags & 0x0000fffff; - ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); - ifp->metric = 0; - ifp->speed = get_iflink_speed(ifp, NULL); - ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; - - /* Set zebra interface type */ - zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); - if (IS_ZEBRA_IF_VRF(ifp)) - SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); - - /* - * Just set the @link/lower-device ifindex. During nldump interfaces are - * not ordered in any fashion so we may end up getting upper devices - * before lower devices. We will setup the real linkage once the dump - * is complete. - */ - zif = (struct zebra_if *)ifp->info; - zif->link_ifindex = link_ifindex; - - if (desc) { - XFREE(MTYPE_ZIF_DESC, zif->desc); - zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); - } - - /* 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); - - /* Extract and save L2 interface information, take additional actions. - */ - netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], - 1, link_nsid); - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, true); - if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id, - ZEBRA_BRIDGE_NO_ACTION); - else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); - - if (tb[IFLA_PROTO_DOWN]) { - netlink_proc_dplane_if_protodown(zif, tb); - if_sweep_protodown(zif); - } - - return 0; -} - /* Request for specific interface or address information from the kernel */ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, int type, uint32_t filter_mask) @@ -1261,7 +809,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) { int ret; struct zebra_dplane_info dp_info; - struct nlsock *netlink_cmd = &zns->netlink_cmd; + struct nlsock *netlink_cmd = &zns->netlink_dplane_out; /* Capture key info from ns struct */ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); @@ -1270,7 +818,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_interface, netlink_cmd, &dp_info, 0, + ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true); if (ret < 0) return ret; @@ -1280,11 +828,18 @@ int interface_lookup_netlink(struct zebra_ns *zns) RTEXT_FILTER_BRVLAN); if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0, + ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true); if (ret < 0) return ret; + return ret; +} + +void interface_list_tunneldump(struct zebra_ns *zns) +{ + int ret; + /* * So netlink_tunneldump_read will initiate a request * per tunnel to get data. If we are on a kernel that @@ -1297,13 +852,12 @@ int interface_lookup_netlink(struct zebra_ns *zns) */ ret = netlink_tunneldump_read(zns); if (ret < 0) - return ret; + return; - /* fixup linkages */ - zebra_if_update_all_links(zns); - return 0; + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ); } + /** * interface_addr_lookup_netlink() - Look up interface addresses * @@ -1323,8 +877,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, netlink_cmd, &dp_info, - 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, + &dp_info, 0, true); if (ret < 0) return ret; @@ -1332,8 +886,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, netlink_cmd, &dp_info, - 0, true); + ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, + &dp_info, 0, true); if (ret < 0) return ret; @@ -1455,67 +1009,13 @@ static ssize_t netlink_intf_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, op = dplane_ctx_get_op(ctx); - switch (op) { - case DPLANE_OP_INTF_UPDATE: + if (op == DPLANE_OP_INTF_UPDATE) cmd = RTM_SETLINK; - break; - case DPLANE_OP_INTF_INSTALL: + else if (op == DPLANE_OP_INTF_INSTALL) cmd = RTM_NEWLINK; - break; - case DPLANE_OP_INTF_DELETE: + else if (op == DPLANE_OP_INTF_DELETE) cmd = RTM_DELLINK; - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - 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_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_IPSET_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_INTF_NETCONFIG: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: + else { flog_err( EC_ZEBRA_NHG_FIB_UPDATE, "Context received for kernel interface update with incorrect OP code (%u)", @@ -1930,6 +1430,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, if (kernel_flags & IFA_F_SECONDARY) dplane_ctx_intf_set_secondary(ctx); + if (kernel_flags & IFA_F_NOPREFIXROUTE) + dplane_ctx_intf_set_noprefixroute(ctx); + /* Label */ if (tb[IFA_LABEL]) { label = (char *)RTA_DATA(tb[IFA_LABEL]); @@ -1943,7 +1446,6 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, /* Enqueue ctx for main pthread to process */ dplane_provider_enqueue_to_zebra(ctx); - return 0; } @@ -1953,25 +1455,22 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_MAX + 1]; - struct interface *ifp; char *name = NULL; char *kind = NULL; - char *desc = NULL; char *slave_kind = NULL; - struct zebra_ns *zns; vrf_id_t vrf_id = VRF_DEFAULT; enum zebra_iftype zif_type = ZEBRA_IF_OTHER; enum zebra_slave_iftype zif_slave_type = ZEBRA_IF_SLAVE_NONE; ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; - uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; - struct zebra_if *zif; ns_id_t link_nsid = ns_id; ifindex_t master_infindex = IFINDEX_INTERNAL; uint8_t bypass = 0; + uint32_t txqlen = 0; + + frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup); - zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); /* assume if not default zns, then new VRF */ @@ -2000,10 +1499,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } - /* We are interested in some AF_BRIDGE notifications. */ - if (ifi->ifi_family == AF_BRIDGE) - return netlink_bridge_interface(h, len, ns_id, startup); - /* Looking up interface name. */ memset(linkinfo, 0, sizeof(linkinfo)); netlink_parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, @@ -2050,18 +1545,52 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]); link_nsid = ns_id_get_absolute(ns_id, link_nsid); } - if (tb[IFLA_IFALIAS]) { - desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); - } - /* See if interface is present. */ - ifp = if_lookup_by_name_per_ns(zns, name); + if (tb[IFLA_TXQLEN]) + txqlen = *(uint32_t *)RTA_DATA(tb[IFLA_TXQLEN]); + + struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); + dplane_ctx_set_ns_id(ctx, ns_id); + dplane_ctx_set_ifp_link_nsid(ctx, link_nsid); + dplane_ctx_set_ifp_zif_type(ctx, zif_type); + dplane_ctx_set_ifindex(ctx, ifi->ifi_index); + dplane_ctx_set_ifname(ctx, name); + dplane_ctx_set_ifp_startup(ctx, startup); + dplane_ctx_set_ifp_family(ctx, ifi->ifi_family); + dplane_ctx_set_intf_txqlen(ctx, txqlen); + + /* We are interested in some AF_BRIDGE notifications. */ +#ifndef AF_BRIDGE +#define AF_BRIDGE 7 +#endif + if (ifi->ifi_family == AF_BRIDGE) { + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); + return netlink_bridge_interface(ctx, tb[IFLA_AF_SPEC], startup); + } if (h->nlmsg_type == RTM_NEWLINK) { + dplane_ctx_set_ifp_link_ifindex(ctx, link_ifindex); + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); + if (tb[IFLA_IFALIAS]) { + dplane_ctx_set_ifp_desc(ctx, + RTA_DATA(tb[IFLA_IFALIAS])); + } + if (!tb[IFLA_MTU]) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + dplane_ctx_fini(&ctx); + return 0; + } + dplane_ctx_set_ifp_mtu(ctx, *(int *)RTA_DATA(tb[IFLA_MTU])); + /* If VRF, create or update the VRF structure itself. */ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); - vrf_id = (vrf_id_t)ifi->ifi_index; + netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name, + ctx); + vrf_id = ifi->ifi_index; } if (tb[IFLA_MASTER]) { @@ -2084,264 +1613,45 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } + dplane_ctx_set_ifp_zif_slave_type(ctx, zif_slave_type); + dplane_ctx_set_ifp_vrf_id(ctx, 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); + dplane_ctx_set_ifp_bypass(ctx, bypass); + dplane_ctx_set_ifp_zltype( + ctx, netlink_to_zebra_link_type(ifi->ifi_type)); + if (vrf_is_backend_netns()) - vrf_id = (vrf_id_t)ns_id; - if (ifp == NULL - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - /* Add interface notification from kernel */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u flags 0x%x", - name, ifi->ifi_index, vrf_id, zif_type, - zif_slave_type, master_infindex, - ifi->ifi_flags); - - if (ifp == NULL) { - /* unknown interface */ - ifp = if_get_by_name(name, vrf_id, NULL); - } else { - /* pre-configured interface, learnt now */ - if (ifp->vrf->vrf_id != vrf_id) - if_update_to_new_vrf(ifp, vrf_id); - } - - /* Update interface information. */ - set_ifindex(ifp, ifi->ifi_index, zns); - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!tb[IFLA_MTU]) { - zlog_debug( - "RTM_NEWLINK for interface %s(%u) without MTU set", - name, ifi->ifi_index); - return 0; - } - ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); - ifp->metric = 0; - ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; - - /* Set interface type */ - zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); - if (IS_ZEBRA_IF_VRF(ifp)) - SET_FLAG(ifp->status, - ZEBRA_INTERFACE_VRF_LOOPBACK); - - /* Update link. */ - zebra_if_update_link(ifp, link_ifindex, link_nsid); - - ifp->ll_type = - netlink_to_zebra_link_type(ifi->ifi_type); - netlink_interface_update_hw_addr(tb, ifp); - - /* Inform clients, install any configured addresses. */ - if_add_update(ifp); - - /* Extract and save L2 interface information, take - * additional actions. */ - netlink_interface_update_l2info( - ifp, linkinfo[IFLA_INFO_DATA], - 1, link_nsid); - if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave( - ifp, bridge_ifindex, ns_id, - ZEBRA_BRIDGE_NO_ACTION); - else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, - !!bypass); - - if (tb[IFLA_PROTO_DOWN]) - netlink_proc_dplane_if_protodown(ifp->info, tb); - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - zif = ifp->info; - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", - name, ifp->ifindex, - IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( - zif)); - } - } else if (ifp->vrf->vrf_id != vrf_id) { - /* VRF change for an interface. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u flags 0x%x", - name, ifp->ifindex, ifp->vrf->vrf_id, - vrf_id, ifi->ifi_flags); + dplane_ctx_set_ifp_vrf_id(ctx, ns_id); - if_handle_vrf_change(ifp, vrf_id); - } else { - bool was_bridge_slave, was_bond_slave; - uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; - zif = ifp->info; + dplane_ctx_set_ifp_flags(ctx, ifi->ifi_flags & 0x0000fffff); - /* Interface update. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK update for %s(%u) sl_type %d master %u flags 0x%x", - name, ifp->ifindex, zif_slave_type, - master_infindex, ifi->ifi_flags); + if (tb[IFLA_PROTO_DOWN]) { + dplane_ctx_set_ifp_protodown_set(ctx, true); + netlink_proc_dplane_if_protodown(ctx, tb); + } else + dplane_ctx_set_ifp_protodown_set(ctx, false); - set_ifindex(ifp, ifi->ifi_index, zns); - if (!tb[IFLA_MTU]) { - zlog_debug( - "RTM_NEWLINK for interface %s(%u) without MTU set", - name, ifi->ifi_index); - return 0; - } - ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); - ifp->metric = 0; - - /* Update interface type - NOTE: Only slave_type can - * change. */ - was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); - was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); - zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); - - memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); - - /* Update link. */ - zebra_if_update_link(ifp, link_ifindex, link_nsid); - - ifp->ll_type = - netlink_to_zebra_link_type(ifi->ifi_type); - netlink_interface_update_hw_addr(tb, ifp); - - if (tb[IFLA_PROTO_DOWN]) - netlink_proc_dplane_if_protodown(ifp->info, tb); - - if (if_is_no_ptm_operative(ifp)) { - bool is_up = if_is_operative(ifp); - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!if_is_no_ptm_operative(ifp) || - CHECK_FLAG(zif->flags, - ZIF_FLAG_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has gone DOWN", - name, ifp->ifindex); - if_down(ifp); - rib_update(RIB_UPDATE_KERNEL); - } else if (if_is_operative(ifp)) { - bool mac_updated = false; - - /* Must notify client daemons of new - * interface status. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) PTM up, notifying clients", - name, ifp->ifindex); - if_up(ifp, !is_up); - - /* Update EVPN VNI when SVI MAC change - */ - if (memcmp(old_hw_addr, ifp->hw_addr, - INTERFACE_HWADDR_MAX)) - mac_updated = true; - if (IS_ZEBRA_IF_VLAN(ifp) - && mac_updated) { - struct interface *link_if; - - link_if = - if_lookup_by_index_per_ns( - zebra_ns_lookup(NS_DEFAULT), - link_ifindex); - if (link_if) - zebra_vxlan_svi_up(ifp, - link_if); - } else if (mac_updated - && IS_ZEBRA_IF_BRIDGE(ifp)) { - zlog_debug( - "Intf %s(%u) bridge changed MAC address", - name, ifp->ifindex); - chgflags = - ZEBRA_BRIDGE_MASTER_MAC_CHANGE; - } - } - } else { - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_operative(ifp) && - !CHECK_FLAG(zif->flags, - ZIF_FLAG_PROTODOWN)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has come UP", - name, ifp->ifindex); - if_up(ifp, true); - if (IS_ZEBRA_IF_BRIDGE(ifp)) - chgflags = - ZEBRA_BRIDGE_MASTER_UP; - } else { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Intf %s(%u) has gone DOWN", - name, ifp->ifindex); - if_down(ifp); - rib_update(RIB_UPDATE_KERNEL); - } - } - - /* Extract and save L2 interface information, take - * additional actions. */ - netlink_interface_update_l2info( - ifp, linkinfo[IFLA_INFO_DATA], - 0, link_nsid); - if (IS_ZEBRA_IF_BRIDGE(ifp)) - zebra_l2if_update_bridge(ifp, chgflags); - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, true); - if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) - zebra_l2if_update_bridge_slave( - ifp, bridge_ifindex, ns_id, chgflags); - else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, - !!bypass); - if (IS_ZEBRA_IF_BRIDGE(ifp)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_NEWLINK update for %s(%u), vlan-aware %d", - name, ifp->ifindex, - IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( - zif)); - } - } + netlink_interface_update_hw_addr(tb, ctx); - zif = ifp->info; - if (zif) { - XFREE(MTYPE_ZIF_DESC, zif->desc); - if (desc) - zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); - } + /* Extract and save L2 interface information, take + * additional actions. */ + netlink_interface_update_l2info( + ctx, zif_type, linkinfo[IFLA_INFO_DATA], 1, link_nsid); } else { - /* Delete interface notification from kernel */ - if (ifp == NULL) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "RTM_DELLINK for unknown interface %s(%u)", - name, ifi->ifi_index); - return 0; - } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("RTM_DELLINK for %s(%u)", name, - ifp->ifindex); - - UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); - - if (IS_ZEBRA_IF_BOND(ifp)) - zebra_l2if_update_bond(ifp, false); - if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); - /* Special handling for bridge or VxLAN interfaces. */ - if (IS_ZEBRA_IF_BRIDGE(ifp)) - zebra_l2_bridge_del(ifp); - else if (IS_ZEBRA_IF_VXLAN(ifp)) - zebra_l2_vxlanif_del(ifp); - - if_delete_update(&ifp); - - /* If VRF, delete the VRF structure itself. */ - if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); + zlog_debug("RTM_DELLINK for %s(%u), enqueuing to zebra", + name, ifi->ifi_index); + + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_DELETE); + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); + + dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); } + dplane_provider_enqueue_to_zebra(ctx); + return 0; } @@ -2399,9 +1709,10 @@ ssize_t netlink_intf_msg_encode(uint16_t cmd, return -1; nl_attr_put32(&req->n, buflen, IFLA_PROTO_DOWN_REASON_MASK, - (1 << frr_protodown_r_bit)); + (1 << if_netlink_get_frr_protodown_r_bit())); nl_attr_put32(&req->n, buflen, IFLA_PROTO_DOWN_REASON_VALUE, - ((int)pd_reason_val) << frr_protodown_r_bit); + ((int)pd_reason_val) + << if_netlink_get_frr_protodown_r_bit()); nl_attr_nest_end(&req->n, nest_protodown_reason); @@ -2417,6 +1728,13 @@ ssize_t netlink_intf_msg_encode(uint16_t cmd, void interface_list(struct zebra_ns *zns) { interface_lookup_netlink(zns); + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); +} + +void interface_list_second(struct zebra_ns *zns) +{ + zebra_if_update_all_links(zns); /* We add routes for interface address, * so we need to get the nexthop info * from the kernel before we can do that @@ -2424,37 +1742,8 @@ void interface_list(struct zebra_ns *zns) netlink_nexthop_read(zns); interface_addr_lookup_netlink(zns); -} - -void if_netlink_set_frr_protodown_r_bit(uint8_t bit) -{ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Protodown reason bit index changed: bit-index %u -> bit-index %u", - frr_protodown_r_bit, bit); - - frr_protodown_r_bit = bit; -} -void if_netlink_unset_frr_protodown_r_bit(void) -{ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "Protodown reason bit index changed: bit-index %u -> bit-index %u", - frr_protodown_r_bit, FRR_PROTODOWN_REASON_DEFAULT_BIT); - - frr_protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; -} - - -bool if_netlink_frr_protodown_r_bit_is_set(void) -{ - return (frr_protodown_r_bit != FRR_PROTODOWN_REASON_DEFAULT_BIT); -} - -uint8_t if_netlink_get_frr_protodown_r_bit(void) -{ - return frr_protodown_r_bit; + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ); } /** @@ -2514,7 +1803,7 @@ int netlink_tunneldump_read(struct zebra_ns *zns) if (ret < 0) return ret; - ret = netlink_parse_info(netlink_interface, netlink_cmd, + ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true); if (ret < 0) diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index ede6224188..9b31906a17 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -42,17 +42,6 @@ extern int netlink_tunneldump_read(struct zebra_ns *zns); extern enum netlink_msg_status netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); -#define FRR_PROTODOWN_REASON_DEFAULT_BIT 7 -/* Protodown bit setter/getter - * - * Allow users to change the bit if it conflicts with another - * on their system. - */ -extern void if_netlink_set_frr_protodown_r_bit(uint8_t bit); -extern void if_netlink_unset_frr_protodown_r_bit(void); -extern bool if_netlink_frr_protodown_r_bit_is_set(void); -extern uint8_t if_netlink_get_frr_protodown_r_bit(void); - #ifdef __cplusplus } #endif diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index ae292689ed..9db959896e 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -6,6 +6,8 @@ #include <zebra.h> +#include <net/route.h> + #if !defined(GNU_LINUX) && !defined(OPEN_BSD) #include "if.h" diff --git a/zebra/interface.c b/zebra/interface.c index 496a85e676..b824977f9e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -18,7 +18,6 @@ #include "log.h" #include "zclient.h" #include "vrf.h" -#include "lib/northbound_cli.h" #include "zebra/rtadv.h" #include "zebra_ns.h" @@ -44,8 +43,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information"); DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), (vty, ifp)); -DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)); DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc"); @@ -65,7 +62,7 @@ static void if_zebra_speed_update(struct event *thread) * interfaces not available. * note that loopback & virtual interfaces can return 0 as speed */ - if (error < 0) + if (error == INTERFACE_SPEED_ERROR_READ) return; if (new_speed != ifp->speed) { @@ -76,7 +73,7 @@ static void if_zebra_speed_update(struct event *thread) changed = true; } - if (changed || new_speed == UINT32_MAX) { + if (changed || error == INTERFACE_SPEED_ERROR_UNKNOWN) { #define SPEED_UPDATE_SLEEP_TIME 5 #define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME) /* @@ -91,7 +88,7 @@ static void if_zebra_speed_update(struct event *thread) * to not update the system to keep track of that. This * is far simpler to just stop trying after 4 minutes */ - if (new_speed == UINT32_MAX && + if (error == INTERFACE_SPEED_ERROR_UNKNOWN && zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) return; @@ -111,17 +108,6 @@ static void zebra_if_node_destroy(route_table_delegate_t *delegate, route_node_destroy(delegate, table, node); } -static void zebra_if_nhg_dependents_free(struct zebra_if *zebra_if) -{ - nhg_connected_tree_free(&zebra_if->nhg_dependents); -} - -static void zebra_if_nhg_dependents_init(struct zebra_if *zebra_if) -{ - nhg_connected_tree_init(&zebra_if->nhg_dependents); -} - - route_table_delegate_t zebra_if_table_delegate = { .create_node = route_node_create, .destroy_node = zebra_if_node_destroy}; @@ -135,11 +121,12 @@ static int if_zebra_new_hook(struct interface *ifp) zebra_if->ifp = ifp; zebra_if->multicast = IF_ZEBRA_DATA_UNSPEC; - zebra_if->shutdown = IF_ZEBRA_DATA_OFF; + zebra_if->mpls_config = IF_ZEBRA_DATA_UNSPEC; + zebra_if->shutdown = IF_ZEBRA_DATA_UNSPEC; zebra_if->link_nsid = NS_UNKNOWN; - zebra_if_nhg_dependents_init(zebra_if); + nhg_connected_tree_init(&zebra_if->nhg_dependents); zebra_ptm_if_init(zebra_if); @@ -147,6 +134,8 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv_if_init(zebra_if); + zebra_evpn_mh_if_init(zebra_if); + memset(&zebra_if->neigh_mac[0], 0, 6); /* Initialize installed address chains tree. */ @@ -170,18 +159,13 @@ static int if_zebra_new_hook(struct interface *ifp) return 0; } -static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe) -{ - zebra_nhg_check_valid(nhe); -} - static void if_down_nhg_dependents(const struct interface *ifp) { struct nhg_connected *rb_node_dep = NULL; struct zebra_if *zif = (struct zebra_if *)ifp->info; frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) - if_nhg_dependents_check_valid(rb_node_dep->nhe); + zebra_nhg_check_valid(rb_node_dep->nhe); } static void if_nhg_dependents_release(const struct interface *ifp) @@ -191,7 +175,11 @@ static void if_nhg_dependents_release(const struct interface *ifp) frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) { rb_node_dep->nhe->ifp = NULL; /* Null it out */ - if_nhg_dependents_check_valid(rb_node_dep->nhe); + zebra_nhg_check_valid(rb_node_dep->nhe); + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_KEEP_AROUND) && + rb_node_dep->nhe->refcnt == 1) + zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -199,6 +187,7 @@ static void if_nhg_dependents_release(const struct interface *ifp) static int if_zebra_delete_hook(struct interface *ifp) { struct zebra_if *zebra_if; + struct zebra_l2info_bond *bond; if (ifp->info) { zebra_if = ifp->info; @@ -216,12 +205,16 @@ static int if_zebra_delete_hook(struct interface *ifp) rtadv_if_fini(zebra_if); + bond = &zebra_if->bond_info; + if (bond && bond->mbr_zifs) + list_delete(&bond->mbr_zifs); + zebra_l2_bridge_if_cleanup(ifp); zebra_evpn_if_cleanup(zebra_if); zebra_evpn_mac_ifp_del(ifp); if_nhg_dependents_release(ifp); - zebra_if_nhg_dependents_free(zebra_if); + nhg_connected_tree_free(&zebra_if->nhg_dependents); XFREE(MTYPE_ZIF_DESC, zebra_if->desc); @@ -267,6 +260,9 @@ struct interface *if_link_per_ns(struct zebra_ns *ns, struct interface *ifp) /* Delete a VRF. This is called in vrf_terminate(). */ void if_unlink_per_ns(struct interface *ifp) { + if (!ifp->node) + return; + ifp->node->info = NULL; route_unlock_node(ifp->node); ifp->node = NULL; @@ -480,12 +476,11 @@ void if_flags_update(struct interface *ifp, uint64_t newflags) address. */ void if_addr_wakeup(struct interface *ifp) { - struct listnode *node, *nnode; struct connected *ifc; struct prefix *p; enum zebra_dplane_result dplane_res; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { + frr_each_safe (if_connected, ifp->connected, ifc) { p = ifc->address; if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED) @@ -606,6 +601,11 @@ void if_add_update(struct interface *ifp) if_addr_wakeup(ifp); + if (if_data->mpls_config == IF_ZEBRA_DATA_ON) + dplane_intf_mpls_modify_state(ifp, true); + else if (if_data->mpls_config == IF_ZEBRA_DATA_OFF) + dplane_intf_mpls_modify_state(ifp, false); + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "interface %s vrf %s(%u) index %d becomes active.", @@ -623,32 +623,24 @@ void if_add_update(struct interface *ifp) /* Install connected routes corresponding to an interface. */ static void if_install_connected(struct interface *ifp) { - struct listnode *node; - struct listnode *next; struct connected *ifc; - if (ifp->connected) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { - if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) - zebra_interface_address_add_update(ifp, ifc); + frr_each (if_connected, ifp->connected, ifc) { + if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) + zebra_interface_address_add_update(ifp, ifc); - connected_up(ifp, ifc); - } + connected_up(ifp, ifc); } } /* Uninstall connected routes corresponding to an interface. */ static void if_uninstall_connected(struct interface *ifp) { - struct listnode *node; - struct listnode *next; struct connected *ifc; - if (ifp->connected) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { - zebra_interface_address_delete_update(ifp, ifc); - connected_down(ifp, ifc); - } + frr_each_safe (if_connected, ifp->connected, ifc) { + zebra_interface_address_delete_update(ifp, ifc); + connected_down(ifp, ifc); } } @@ -656,20 +648,15 @@ static void if_uninstall_connected(struct interface *ifp) /* TODO - Check why IPv4 handling here is different from install or if_down */ static void if_delete_connected(struct interface *ifp) { - struct connected *ifc; + struct connected *ifc, *ifc_next; struct prefix cp; struct route_node *rn; struct zebra_if *zebra_if; - struct listnode *node; - struct listnode *last = NULL; zebra_if = ifp->info; - if (!ifp->connected) - return; - - while ((node = (last ? last->next : listhead(ifp->connected)))) { - ifc = listgetdata(node); + for (ifc = if_connected_first(ifp->connected); ifc; ifc = ifc_next) { + ifc_next = if_connected_next(ifp->connected, ifc); cp = *CONNECTED_PREFIX(ifc); apply_mask(&cp); @@ -718,11 +705,15 @@ static void if_delete_connected(struct interface *ifp) * (unconditionally). */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { - listnode_delete(ifp->connected, + if (ifc == ifc_next) + ifc_next = if_connected_next( + ifp->connected, ifc); + + if_connected_del(ifp->connected, + ifc); connected_free(&ifc); - } else - last = node; + } } /* Free chain list and respective route node. */ @@ -737,14 +728,10 @@ static void if_delete_connected(struct interface *ifp) UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL); UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - last = node; - else { - listnode_delete(ifp->connected, ifc); + if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { + if_connected_del(ifp->connected, ifc); connected_free(&ifc); } - } else { - last = node; } } } @@ -778,6 +765,15 @@ void if_delete_update(struct interface **pifp) /* Delete connected routes from the kernel. */ if_delete_connected(ifp); + /* if the ifp is in a vrf, move it to default so vrf can be deleted if + * desired. This operation is not done for netns implementation to avoid + * collision with interface with the same name in the default vrf (can + * occur with this implementation whereas it is not possible with + * vrf-lite). + */ + if (ifp->vrf->vrf_id && !vrf_is_backend_netns()) + if_handle_vrf_change(ifp, VRF_DEFAULT); + /* Send out notification on interface delete. */ zebra_interface_delete_update(ifp); @@ -791,14 +787,7 @@ void if_delete_update(struct interface **pifp) if_set_index(ifp, IFINDEX_INTERNAL); ifp->node = NULL; - /* if the ifp is in a vrf, move it to default so vrf can be deleted if - * desired. This operation is not done for netns implementation to avoid - * collision with interface with the same name in the default vrf (can - * occur with this implementation whereas it is not possible with - * vrf-lite). - */ - if (ifp->vrf->vrf_id && !vrf_is_backend_netns()) - if_handle_vrf_change(ifp, VRF_DEFAULT); + UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); /* Reset some zebra interface params to default values. */ zif = ifp->info; @@ -837,9 +826,12 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) if_down_del_nbr_connected(ifp); /* Send out notification on interface VRF change. */ - /* This is to issue an UPDATE or a DELETE, as appropriate. */ + /* This is to issue a DELETE, as appropriate. */ zebra_interface_vrf_update_del(ifp, vrf_id); + if (if_is_vrf(ifp)) + return; + /* update VRF */ if_update_to_new_vrf(ifp, vrf_id); @@ -955,47 +947,6 @@ static void if_down_del_nbr_connected(struct interface *ifp) } } -void if_nhg_dependents_add(struct interface *ifp, struct nhg_hash_entry *nhe) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe); - } -} - -void if_nhg_dependents_del(struct interface *ifp, struct nhg_hash_entry *nhe) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe); - } -} - -unsigned int if_nhg_dependents_count(const struct interface *ifp) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - return nhg_connected_tree_count(&zif->nhg_dependents); - } - - return 0; -} - - -bool if_nhg_dependents_is_empty(const struct interface *ifp) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - return nhg_connected_tree_is_empty(&zif->nhg_dependents); - } - - return false; -} - /* Interface is up. */ void if_up(struct interface *ifp, bool install_connected) { @@ -1023,6 +974,14 @@ void if_up(struct interface *ifp, bool install_connected) if (install_connected) if_install_connected(ifp); + /* + * Interface associated NHG's have been deleted on + * interface down events, now that this interface + * is coming back up, let's resync the zebra -> dplane + * nhg's so that they can be continued to be used. + */ + zebra_interface_nhg_reinstall(ifp); + /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed * on them for ARP suppression. @@ -1049,6 +1008,8 @@ void if_up(struct interface *ifp, bool install_connected) event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0, &zif->speed_update); event_ignore_late_timer(zif->speed_update); + + if_addr_wakeup(ifp); } /* Interface goes down. We have to manage different behavior of based @@ -1112,8 +1073,6 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, { struct zebra_if *zif; - if (IS_ZEBRA_IF_VETH(ifp)) - return; zif = (struct zebra_if *)ifp->info; zif->link_nsid = ns_id; zif->link_ifindex = link_ifindex; @@ -1176,6 +1135,12 @@ static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down, zif = ifp->info; + /* + * FRR does not have enough data to make this request + */ + if (ifp->ifindex == IFINDEX_INTERNAL) + return true; + /* Current state as we know it */ old_down = !!(ZEBRA_IF_IS_PROTODOWN(zif)); old_set_down = !!CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); @@ -1285,6 +1250,9 @@ static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, const struct prefix *addr, *dest = NULL; enum dplane_op_e op; + if (!ifp) + return; + op = dplane_ctx_get_op(ctx); addr = dplane_ctx_get_intf_addr(ctx); @@ -1305,6 +1273,9 @@ static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, if (dplane_ctx_intf_is_secondary(ctx)) SET_FLAG(flags, ZEBRA_IFA_SECONDARY); + if (dplane_ctx_intf_is_noprefixroute(ctx)) + SET_FLAG(flags, ZEBRA_IFA_NOPREFIXROUTE); + /* Label? */ if (dplane_ctx_intf_has_label(ctx)) label = dplane_ctx_get_intf_label(ctx); @@ -1356,6 +1327,13 @@ static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx, bool pd_reason_val; bool down; + if (!ifp) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Can't find ifp", __func__); + + return; + } + dp_res = dplane_ctx_get_status(ctx); pd_reason_val = dplane_ctx_get_intf_pd_reason_val(ctx); down = dplane_ctx_intf_is_protodown(ctx); @@ -1403,6 +1381,13 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, enum dplane_netconf_status_e mpls, mcast_on, linkdown; bool *mcast_set, *linkdown_set; + if (!ifp && ifindex != -1 && ifindex != -2) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Can't find ifp(%u)", __func__, ifindex); + + return; + } + afi = dplane_ctx_get_afi(ctx); mpls = dplane_ctx_get_netconf_mpls(ctx); linkdown = dplane_ctx_get_netconf_linkdown(ctx); @@ -1425,7 +1410,7 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, linkdown_set = &zrouter.default_linkdownv6; } } else { - zif = ifp ? ifp->info : NULL; + zif = ifp->info; if (!zif) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -1472,6 +1457,762 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, (*linkdown_set ? "ON" : "OFF")); } +static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, + const char *name, uint32_t tableid, + ns_id_t ns_id) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf = NULL; + + if (op == DPLANE_OP_INTF_DELETE) { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("DPLANE_OP_INTF_DELETE for VRF %s(%u)", name, + ifindex); + + vrf = vrf_lookup_by_id((vrf_id_t)ifindex); + if (!vrf) { + flog_warn(EC_ZEBRA_VRF_NOT_FOUND, + "%s(%u): vrf not found", name, ifindex); + return; + } + + vrf_delete(vrf); + } else { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug( + "DPLANE_OP_INTF_UPDATE for VRF %s(%u) table %u", + name, ifindex, tableid); + + if (!vrf_lookup_by_id((vrf_id_t)ifindex)) { + vrf_id_t exist_id; + + exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); + if (exist_id != VRF_DEFAULT) { + vrf = vrf_lookup_by_id(exist_id); + + if (vrf) + flog_err(EC_ZEBRA_VRF_MISCONFIGURED, + "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", + name, ifindex, vrf->name, + vrf->vrf_id); + else + flog_err(EC_ZEBRA_VRF_NOT_FOUND, + "VRF %s id %u does not exist", + name, ifindex); + + exit(-1); + } + } + + vrf = vrf_update((vrf_id_t)ifindex, name); + if (!vrf) { + flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", + name, ifindex); + return; + } + + /* + * This is the only place that we get the actual kernel table_id + * being used. We need it to set the table_id of the routes + * we are passing to the kernel.... And to throw some totally + * awesome parties. that too. + * + * At this point we *must* have a zvrf because the vrf_create + * callback creates one. We *must* set the table id + * before the vrf_enable because of( at the very least ) + * static routes being delayed for installation until + * during the vrf_enable callbacks. + */ + zvrf = (struct zebra_vrf *)vrf->info; + zvrf->table_id = tableid; + + /* Enable the created VRF. */ + if (!vrf_enable(vrf)) { + flog_err(EC_LIB_INTERFACE, + "Failed to enable VRF %s id %u", name, + ifindex); + return; + } + } +} + +/* + * Note: on netlink systems, there should be a 1-to-1 mapping + * between interface names and ifindex values. + */ +static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, + struct zebra_ns *zns) +{ + struct interface *oifp; + + oifp = if_lookup_by_index_per_ns(zns, ifi_index); + if ((oifp != NULL) && (oifp != ifp)) { + if (ifi_index == IFINDEX_INTERNAL) + flog_err( + EC_LIB_INTERFACE, + "Netlink is setting interface %s ifindex to reserved internal value %u", + ifp->name, ifi_index); + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "interface index %d was renamed from %s to %s", + ifi_index, oifp->name, ifp->name); + if (if_is_up(oifp)) + flog_err( + EC_LIB_INTERFACE, + "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", + ifi_index, oifp->name, ifp->name); + if_delete_update(&oifp); + } + } + if_set_index(ifp, ifi_index); +} + +static inline void zebra_if_set_ziftype(struct interface *ifp, + enum zebra_iftype zif_type, + enum zebra_slave_iftype zif_slave_type) +{ + struct zebra_if *zif; + + zif = (struct zebra_if *)ifp->info; + zif->zif_slave_type = zif_slave_type; + + if (zif->zif_type != zif_type) { + zif->zif_type = zif_type; + /* If the if_type has been set to bond initialize ES info + * against it. XXX - note that we don't handle the case where + * a zif changes from bond to non-bond; it is really + * an unexpected/error condition. + */ + zebra_evpn_if_init(zif); + } +} + +static void interface_update_hw_addr(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + int i; + + ifp->hw_addr_len = dplane_ctx_get_ifp_hw_addr_len(ctx); + memcpy(ifp->hw_addr, dplane_ctx_get_ifp_hw_addr(ctx), ifp->hw_addr_len); + + for (i = 0; i < ifp->hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == ifp->hw_addr_len) + ifp->hw_addr_len = 0; +} + +static void interface_update_l2info(struct zebra_dplane_ctx *ctx, + struct interface *ifp, + enum zebra_iftype zif_type, int add, + ns_id_t link_nsid) +{ + const struct zebra_l2info_vxlan *vxlan_info; + const struct zebra_l2info_gre *gre_info; + + switch (zif_type) { + case ZEBRA_IF_BRIDGE: + zebra_l2_bridge_add_update(ifp, + dplane_ctx_get_ifp_bridge_info(ctx)); + break; + case ZEBRA_IF_VLAN: + zebra_l2_vlanif_update(ifp, dplane_ctx_get_ifp_vlan_info(ctx)); + zebra_evpn_acc_bd_svi_set(ifp->info, NULL, + !!if_is_operative(ifp)); + break; + case ZEBRA_IF_VXLAN: + vxlan_info = dplane_ctx_get_ifp_vxlan_info(ctx); + zebra_l2_vxlanif_add_update(ifp, vxlan_info, add); + if (link_nsid != NS_UNKNOWN && vxlan_info->ifindex_link) + zebra_if_update_link(ifp, vxlan_info->ifindex_link, + link_nsid); + break; + case ZEBRA_IF_GRE: + gre_info = dplane_ctx_get_ifp_gre_info(ctx); + zebra_l2_greif_add_update(ifp, gre_info, add); + if (link_nsid != NS_UNKNOWN && gre_info->ifindex_link) + zebra_if_update_link(ifp, gre_info->ifindex_link, + link_nsid); + break; + case ZEBRA_IF_OTHER: + case ZEBRA_IF_VRF: + case ZEBRA_IF_MACVLAN: + case ZEBRA_IF_VETH: + case ZEBRA_IF_BOND: + break; + } +} + +static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield) +{ + uint8_t frr_protodown_r_bit = if_netlink_get_frr_protodown_r_bit(); + + return (rc_bitfield == (((uint32_t)1) << frr_protodown_r_bit)); +} + +static void interface_if_protodown(struct interface *ifp, bool protodown, + uint32_t rc_bitfield) +{ + struct zebra_if *zif = ifp->info; + bool old_protodown; + + /* + * Set our reason code to note it wasn't us. + * If the reason we got from the kernel is ONLY frr though, don't + * set it. + */ + COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL, + protodown && rc_bitfield && + !is_if_protodown_reason_only_frr(rc_bitfield)); + + + old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); + if (protodown == old_protodown) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("interface %s dplane change, protodown %s", + ifp->name, protodown ? "on" : "off"); + + /* Set protodown, respectively */ + COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); + + if (zebra_evpn_is_es_bond_member(ifp)) { + /* Check it's not already being sent to the dplane first */ + if (protodown && + CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s protodown on recv'd but already sent protodown on to the dplane", + ifp->name); + return; + } + + if (!protodown && + CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s protodown off recv'd but already sent protodown off to the dplane", + ifp->name); + return; + } + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "bond mbr %s reinstate protodown %s in the dplane", + ifp->name, old_protodown ? "on" : "off"); + + if (old_protodown) + SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); + else + SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN); + + dplane_intf_update(zif->ifp); + } +} + +static void if_sweep_protodown(struct zebra_if *zif) +{ + bool protodown; + + protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); + + if (!protodown) + return; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("interface %s sweeping protodown %s reason 0x%x", + zif->ifp->name, protodown ? "on" : "off", + zif->protodown_rc); + + /* Only clear our reason codes, leave external if it was set */ + UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL); + dplane_intf_update(zif->ifp); +} + +static void +interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + const struct zebra_vxlan_vni_array *vniarray = + dplane_ctx_get_ifp_vxlan_vni_array(ctx); + struct zebra_vxlan_vni vni_start, vni_end; + struct hash *vni_table = NULL; + struct zebra_vxlan_vni vni, *vnip; + vni_t vni_id; + vlanid_t vid; + int i; + + if (vniarray == NULL) + return; + + memset(&vni_start, 0, sizeof(vni_start)); + memset(&vni_end, 0, sizeof(vni_end)); + + for (i = 0; i < vniarray->count; i++) { + uint16_t flags = vniarray->vnis[i].flags; + + if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) { + vni_start = vniarray->vnis[i]; + continue; + } + + if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END) + vni_end = vniarray->vnis[i]; + + if (!(flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) { + vni_start = vniarray->vnis[i]; + vni_end = vniarray->vnis[i]; + } + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug( + "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)", + vni_start.access_vlan, vni_end.access_vlan, + vni_start.vni, vni_end.vni, ifp->name, + ifp->ifindex); + + if (!vni_table) { + vni_table = zebra_vxlan_vni_table_create(); + if (!vni_table) + return; + } + + for (vid = vni_start.access_vlan, vni_id = vni_start.vni; + vid <= vni_end.access_vlan; vid++, vni_id++) { + + memset(&vni, 0, sizeof(vni)); + vni.vni = vni_id; + vni.access_vlan = vid; + vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc); + if (!vnip) + return; + } + + memset(&vni_start, 0, sizeof(vni_start)); + memset(&vni_end, 0, sizeof(vni_end)); + } + + if (vni_table) + zebra_vxlan_if_vni_table_add_update(ifp, vni_table); +} + +static void interface_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + const struct zebra_dplane_bridge_vlan_info *bvinfo; + + if (dplane_ctx_get_ifp_no_afspec(ctx)) + return; + + if (IS_ZEBRA_VXLAN_IF_SVD(zif)) + interface_bridge_vxlan_vlan_vni_map_update(ctx, ifp); + + if (dplane_ctx_get_ifp_no_bridge_vlan_info(ctx)) + return; + + bvinfo = dplane_ctx_get_ifp_bridge_vlan_info(ctx); + + if (!(bvinfo->flags & DPLANE_BRIDGE_VLAN_INFO_PVID)) + return; + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", bvinfo->vid, + ifp->name, ifp->ifindex); + + zebra_l2_vxlanif_update_access_vlan(ifp, bvinfo->vid); +} + +static void interface_bridge_vlan_update(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + const struct zebra_dplane_bridge_vlan_info_array *bvarray; + struct zebra_dplane_bridge_vlan_info bvinfo; + bitfield_t old_vlan_bitmap; + uint16_t vid_range_start = 0; + int32_t i; + + /* cache the old bitmap addrs */ + old_vlan_bitmap = zif->vlan_bitmap; + /* create a new bitmap space for re-eval */ + bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); + + /* Could we have multiple bridge vlan infos? */ + bvarray = dplane_ctx_get_ifp_bridge_vlan_info_array(ctx); + if (!bvarray) + return; + + for (i = 0; i < bvarray->count; i++) { + bvinfo = bvarray->array[i]; + + if (bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) { + vid_range_start = bvinfo.vid; + continue; + } + + if (!(bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) + vid_range_start = bvinfo.vid; + + zebra_vlan_bitmap_compute(ifp, vid_range_start, bvinfo.vid); + } + + zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); + bf_free(old_vlan_bitmap); +} + +static void interface_bridge_handling(struct zebra_dplane_ctx *ctx, + struct interface *ifp, + enum zebra_iftype zif_type) +{ + struct zebra_if *zif; + + if (!ifp) { + zlog_warn("Cannot find bridge if %s(%u)", + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx)); + return; + } + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return interface_bridge_vxlan_update(ctx, ifp); + + /* + * build vlan bitmap associated with this interface if that + * device type is interested in the vlans + */ + zif = ifp->info; + if (bf_is_inited(zif->vlan_bitmap)) + interface_bridge_vlan_update(ctx, ifp); +} + +static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op = dplane_ctx_get_op(ctx); + const char *name = dplane_ctx_get_ifname(ctx); + ns_id_t ns_id = dplane_ctx_get_ns_id(ctx); + ifindex_t ifindex = dplane_ctx_get_ifindex(ctx); + ifindex_t bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); + uint32_t tableid = dplane_ctx_get_ifp_table_id(ctx); + enum zebra_iftype zif_type = dplane_ctx_get_ifp_zif_type(ctx); + struct interface *ifp; + struct zebra_ns *zns; + + zns = zebra_ns_lookup(ns_id); + if (!zns) { + zlog_err("Where is our namespace?"); + return; + } + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("%s for %s(%u)", dplane_op2str(op), name, ifindex); + + ifp = if_lookup_by_name_per_ns(zns, name); + if (op == DPLANE_OP_INTF_DELETE) { + /* Delete interface notification from kernel */ + if (ifp == NULL) { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug( + "Delete LINK received for unknown interface %s(%u)", + name, ifindex); + return; + } + + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, false); + if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); + /* Special handling for bridge or VxLAN interfaces. */ + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2_bridge_del(ifp); + else if (IS_ZEBRA_IF_VXLAN(ifp)) + zebra_l2_vxlanif_del(ifp); + + if_delete_update(&ifp); + + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) + interface_vrf_change(op, ifindex, name, tableid, ns_id); + } else { + ifindex_t master_ifindex, bridge_ifindex, bond_ifindex, + link_ifindex; + enum zebra_slave_iftype zif_slave_type; + uint8_t bypass; + uint64_t flags; + vrf_id_t vrf_id; + uint32_t mtu; + ns_id_t link_nsid; + struct zebra_if *zif; + bool protodown, protodown_set, startup; + uint32_t rc_bitfield; + uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; + char *desc; + uint8_t family; + + /* If VRF, create or update the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) + interface_vrf_change(op, ifindex, name, tableid, ns_id); + + master_ifindex = dplane_ctx_get_ifp_master_ifindex(ctx); + zif_slave_type = dplane_ctx_get_ifp_zif_slave_type(ctx); + bridge_ifindex = dplane_ctx_get_ifp_bridge_ifindex(ctx); + bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); + bypass = dplane_ctx_get_ifp_bypass(ctx); + flags = dplane_ctx_get_ifp_flags(ctx); + vrf_id = dplane_ctx_get_ifp_vrf_id(ctx); + mtu = dplane_ctx_get_ifp_mtu(ctx); + link_ifindex = dplane_ctx_get_ifp_link_ifindex(ctx); + link_nsid = dplane_ctx_get_ifp_link_nsid(ctx); + protodown_set = dplane_ctx_get_ifp_protodown_set(ctx); + protodown = dplane_ctx_get_ifp_protodown(ctx); + rc_bitfield = dplane_ctx_get_ifp_rc_bitfield(ctx); + startup = dplane_ctx_get_ifp_startup(ctx); + desc = dplane_ctx_get_ifp_desc(ctx); + family = dplane_ctx_get_ifp_family(ctx); + +#ifndef AF_BRIDGE + /* + * Work around to make free bsd happy at the moment + */ +#define AF_BRIDGE 7 +#endif + if (family == AF_BRIDGE) + return interface_bridge_handling(ctx, ifp, zif_type); + + if (ifp == NULL || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { + /* Add interface notification from kernel */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u", + name, ifindex, vrf_id, zif_type, + zif_slave_type, master_ifindex); + + if (ifp == NULL) { + /* unknown interface */ + ifp = if_get_by_name(name, vrf_id, NULL); + } else { + /* pre-configured interface, learnt now */ + if (ifp->vrf->vrf_id != vrf_id) + if_update_to_new_vrf(ifp, vrf_id); + } + + zif = ifp->info; + + /* Update interface information. */ + set_ifindex(ifp, ifindex, zns); + ifp->flags = flags; + ifp->mtu6 = ifp->mtu = mtu; + ifp->metric = 0; + ifp->speed = kernel_get_speed(ifp, NULL); + ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); + + /* Set interface type */ + zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + if (IS_ZEBRA_IF_VRF(ifp)) + SET_FLAG(ifp->status, + ZEBRA_INTERFACE_VRF_LOOPBACK); + + /* Update link. */ + zebra_if_update_link(ifp, link_ifindex, link_nsid); + + ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); + interface_update_hw_addr(ctx, ifp); + + /* Inform clients, install any configured addresses. */ + if_add_update(ifp); + + /* + * Extract and save L2 interface information, take + * additional actions. + */ + interface_update_l2info(ctx, ifp, zif_type, 1, + link_nsid); + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, true); + if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); + else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); + + if (protodown_set) { + interface_if_protodown(ifp, protodown, + rc_bitfield); + if (startup) + if_sweep_protodown(zif); + } + + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } + } else if (ifp->vrf->vrf_id != vrf_id) { + /* VRF change for an interface. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u", + name, ifp->ifindex, ifp->vrf->vrf_id, + vrf_id); + + if_handle_vrf_change(ifp, vrf_id); + } else { + bool was_bridge_slave, was_bond_slave; + uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; + + zif = ifp->info; + + /* Interface update. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK update for %s(%u) sl_type %d master %u", + name, ifp->ifindex, zif_slave_type, + master_ifindex); + + set_ifindex(ifp, ifindex, zns); + ifp->mtu6 = ifp->mtu = mtu; + ifp->metric = 0; + ifp->txqlen = dplane_ctx_get_intf_txqlen(ctx); + + /* + * Update interface type - NOTE: Only slave_type can + * change. + */ + was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); + was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); + zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + + memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); + + /* Update link. */ + zebra_if_update_link(ifp, link_ifindex, link_nsid); + + ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); + interface_update_hw_addr(ctx, ifp); + + if (protodown_set) + interface_if_protodown(ifp, protodown, + rc_bitfield); + + if (if_is_no_ptm_operative(ifp)) { + bool is_up = if_is_operative(ifp); + + ifp->flags = flags; + if (!if_is_no_ptm_operative(ifp) || + CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); + rib_update(RIB_UPDATE_KERNEL); + } else if (if_is_operative(ifp)) { + bool mac_updated = false; + + /* + * Must notify client daemons of new + * interface status. + */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) PTM up, notifying clients", + name, ifp->ifindex); + if_up(ifp, !is_up); + + /* + * Update EVPN VNI when SVI MAC change + */ + if (memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) + mac_updated = true; + if (IS_ZEBRA_IF_VLAN(ifp) && + mac_updated) { + struct interface *link_if; + + link_if = if_lookup_by_index_per_ns( + zebra_ns_lookup( + NS_DEFAULT), + link_ifindex); + if (link_if) + zebra_vxlan_svi_up( + ifp, link_if); + } else if (mac_updated && + IS_ZEBRA_IF_BRIDGE(ifp)) { + zlog_debug( + "Intf %s(%u) bridge changed MAC address", + name, ifp->ifindex); + chgflags = + ZEBRA_BRIDGE_MASTER_MAC_CHANGE; + } + } + } else { + ifp->flags = flags; + if (if_is_operative(ifp) && + !CHECK_FLAG(zif->flags, + ZIF_FLAG_PROTODOWN)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has come UP", + name, ifp->ifindex); + if_up(ifp, true); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + chgflags = + ZEBRA_BRIDGE_MASTER_UP; + } else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); + rib_update(RIB_UPDATE_KERNEL); + } + } + + /* + * Extract and save L2 interface information, take + * additional actions. + */ + interface_update_l2info(ctx, ifp, zif_type, 0, + link_nsid); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2if_update_bridge(ifp, chgflags); + if (IS_ZEBRA_IF_BOND(ifp)) + zebra_l2if_update_bond(ifp, true); + if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, chgflags); + else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); + if (IS_ZEBRA_IF_BRIDGE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "RTM_NEWLINK update for %s(%u), vlan-aware %d", + name, ifp->ifindex, + IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( + zif)); + } + } + + zif = ifp->info; + if (zif) { + XFREE(MTYPE_ZIF_DESC, zif->desc); + if (desc[0]) + zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); + } + } +} + void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) { struct zebra_ns *zns; @@ -1501,83 +2242,22 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) } ifp = if_lookup_by_index_per_ns(zns, ifindex); - if (ifp == NULL) { - if (op != DPLANE_OP_INTF_NETCONFIG || - (ifindex != -1 && ifindex != -2)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "%s: can't find ifp at nsid %u index %d", - __func__, ns_id, ifindex); - - return; - } - } - switch (op) { - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: + if (op == DPLANE_OP_INTF_ADDR_ADD || op == DPLANE_OP_INTF_ADDR_DEL) { zebra_if_addr_update_ctx(ctx, ifp); - break; - - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - zebra_if_update_ctx(ctx, ifp); - break; - - case DPLANE_OP_INTF_NETCONFIG: + } else if (op == DPLANE_OP_INTF_INSTALL || + op == DPLANE_OP_INTF_UPDATE || op == DPLANE_OP_INTF_DELETE) { + /* + * Queued from the dplane means it is something + * that we need to handle( create/delete the + * interface as needed ) + */ + if (dp_res == ZEBRA_DPLANE_REQUEST_QUEUED) + zebra_if_dplane_ifp_handling(ctx); + else + zebra_if_update_ctx(ctx, ifp); + } else if (op == DPLANE_OP_INTF_NETCONFIG) { zebra_if_netconf_update_ctx(ctx, ifp, ifindex); - break; - - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_NONE: - 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_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - break; /* should never hit here */ } } @@ -1617,6 +2297,12 @@ static void connected_dump_vty(struct vty *vty, json_object *json, vty_out(vty, " secondary"); if (json) + json_object_boolean_add(json_addr, "noPrefixRoute", + CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)); + else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)) + vty_out(vty, " noprefixroute"); + + if (json) json_object_boolean_add( json_addr, "unnumbered", CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED)); @@ -1692,9 +2378,6 @@ static const char *zebra_ziftype_2str(enum zebra_iftype zif_type) case ZEBRA_IF_BOND: return "bond"; - case ZEBRA_IF_BOND_SLAVE: - return "bond_slave"; - case ZEBRA_IF_MACVLAN: return "macvlan"; @@ -1768,34 +2451,27 @@ static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf) } uint32_t v6_list_size = 0; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) && (connected->address->family == AF_INET6)) v6_list_size++; } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && !CHECK_FLAG(connected->flags, - ZEBRA_IFA_SECONDARY) - && (connected->address->family == AF_INET6)) { + frr_each (if_connected, ifp->connected, connected) { + if (!CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY) && + (connected->address->family == AF_INET6)) { p = connected->address; - /* Don't print link local pfx */ - if (!IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) { - if (first_pfx_printed) { - /* padding to prepare row only - * for ip addr */ - vty_out(vty, "%-40s", ""); - if (v6_list_size > 1) - vty_out(vty, "+ "); - vty_out(vty, "%pFX\n", p); - } else { - if (v6_list_size > 1) - vty_out(vty, "+ "); - vty_out(vty, "%pFX\n", p); - } - first_pfx_printed = true; - break; + if (first_pfx_printed) { + vty_out(vty, "%-40s", ""); + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%pFX\n", p); + } else { + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%pFX\n", p); } + first_pfx_printed = true; + break; } } if (!first_pfx_printed) @@ -1807,7 +2483,6 @@ static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf) static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf) { struct connected *connected; - struct listnode *node; struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) { @@ -1823,13 +2498,8 @@ static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf) json_addrs = json_object_new_array(); json_object_object_add(json_if, "addresses", json_addrs); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && !CHECK_FLAG(connected->flags, - ZEBRA_IFA_SECONDARY) - && !(connected->address->family == AF_INET6 - && IN6_IS_ADDR_LINKLOCAL( - &connected->address->u.prefix6))) { + frr_each (if_connected, ifp->connected, connected) { + if (!CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) { char buf[PREFIX2STR_BUFFER]; json_array_string_add( @@ -1990,8 +2660,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) return; } - vty_out(vty, " index %d metric %d mtu %d speed %u ", ifp->ifindex, - ifp->metric, ifp->mtu, ifp->speed); + vty_out(vty, " index %d metric %d mtu %d speed %u txqlen %u", + ifp->ifindex, ifp->metric, ifp->mtu, ifp->speed, ifp->txqlen); if (ifp->mtu6 != ifp->mtu) vty_out(vty, "mtu6 %d ", ifp->mtu6); vty_out(vty, "\n flags: %s\n", if_flag_dump(ifp->flags)); @@ -2036,9 +2706,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) connected_dump_vty(vty, NULL, connected); } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) + frr_each (if_connected, ifp->connected, connected) { + if (connected->address->family == AF_INET6) connected_dump_vty(vty, NULL, connected); } @@ -2170,8 +2839,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) " Link Delay Variation %u (micro-sec.)\n", iflp->delay_var); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) - vty_out(vty, " Link Packet Loss %g (in %%)\n", - iflp->pkt_loss); + vty_out(vty, " Link Packet Loss %f (in %%)\n", + (double)iflp->pkt_loss * LOSS_PRECISION); if (IS_PARAM_SET(iflp, LP_AVA_BW)) vty_out(vty, " Available Bandwidth %g (Byte/s)\n", iflp->ava_bw); @@ -2345,7 +3014,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_string_add(json_if, "lastLinkDown", zebra_if->down_last); - zebra_ptm_show_status(vty, json, ifp); + zebra_ptm_show_status(vty, json_if, ifp); json_object_string_add(json_if, "vrfName", ifp->vrf->name); @@ -2378,6 +3047,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, if (ifp->mtu6 != ifp->mtu) json_object_int_add(json_if, "mtu6", ifp->mtu6); json_object_int_add(json_if, "speed", ifp->speed); + json_object_int_add(json_if, "txqlen", ifp->txqlen); json_object_string_add(json_if, "flags", if_flag_dump(ifp->flags)); /* Hardware address. */ @@ -2412,9 +3082,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, connected_dump_vty(vty, json_addrs, connected); } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) + frr_each (if_connected, ifp->connected, connected) { + if (connected->address->family == AF_INET6) connected_dump_vty(vty, json_addrs, connected); } @@ -2571,7 +3240,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, iflp->delay_var); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) json_object_double_add(json_te, "linkPacketLoss", - iflp->pkt_loss); + (double)iflp->pkt_loss * + LOSS_PRECISION); if (IS_PARAM_SET(iflp, LP_AVA_BW)) json_object_double_add(json_te, "availableBandwidth", iflp->ava_bw); @@ -2955,66 +3625,43 @@ DEFUN (show_interface_desc_vrf_all, return CMD_SUCCESS; } -int if_multicast_set(struct interface *ifp) +void if_arp(struct interface *ifp, bool enable) { - struct zebra_if *if_data; + int ret; - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - if (if_set_flags(ifp, IFF_MULTICAST) < 0) { - zlog_debug("Can't set multicast flag on interface %s", - ifp->name); - return -1; - } - if_refresh(ifp); + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) + return; + + if (enable) + ret = if_unset_flags(ifp, IFF_NOARP); + else + ret = if_set_flags(ifp, IFF_NOARP); + + if (ret < 0) { + zlog_debug("Can't %sset noarp flag on interface %s", + enable ? "" : "un", ifp->name); + return; } - if_data = ifp->info; - if_data->multicast = IF_ZEBRA_DATA_ON; - return 0; + if_refresh(ifp); } -DEFUN (multicast, - multicast_cmd, - "multicast", - "Set multicast flag to interface\n") +int if_multicast_set(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; struct zebra_if *if_data; if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - ret = if_set_flags(ifp, IFF_MULTICAST); - if (ret < 0) { - vty_out(vty, "Can't set multicast flag\n"); - return CMD_WARNING_CONFIG_FAILED; + if (if_set_flags(ifp, IFF_MULTICAST) < 0) { + zlog_debug("Can't set multicast flag on interface %s", + ifp->name); + return -1; } if_refresh(ifp); } if_data = ifp->info; if_data->multicast = IF_ZEBRA_DATA_ON; - return CMD_SUCCESS; -} - -DEFPY (mpls, - mpls_cmd, - "[no] mpls enable", - NO_STR - MPLS_STR - "Set mpls to be on for the interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *if_data = ifp->info; - - if (no) { - dplane_intf_mpls_modify_state(ifp, false); - if_data->mpls = IF_ZEBRA_DATA_UNSPEC; - } else { - dplane_intf_mpls_modify_state(ifp, true); - if_data->mpls = IF_ZEBRA_DATA_ON; - } - - return CMD_SUCCESS; + return 0; } int if_multicast_unset(struct interface *ifp) @@ -3035,30 +3682,6 @@ int if_multicast_unset(struct interface *ifp) return 0; } -DEFUN (no_multicast, - no_multicast_cmd, - "no multicast", - NO_STR - "Unset multicast flag to interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - ret = if_unset_flags(ifp, IFF_MULTICAST); - if (ret < 0) { - vty_out(vty, "Can't unset multicast flag\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - } - if_data = ifp->info; - if_data->multicast = IF_ZEBRA_DATA_OFF; - - return CMD_SUCCESS; -} - int if_linkdetect(struct interface *ifp, bool detect) { int if_was_operative; @@ -3082,30 +3705,6 @@ int if_linkdetect(struct interface *ifp, bool detect) return 0; } -DEFUN(linkdetect, linkdetect_cmd, "link-detect", - "Enable link detection on interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - if_linkdetect(ifp, true); - - return CMD_SUCCESS; -} - - -DEFUN (no_linkdetect, - no_linkdetect_cmd, - "no link-detect", - NO_STR - "Disable link detection on interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - if_linkdetect(ifp, false); - - return CMD_SUCCESS; -} - int if_shutdown(struct interface *ifp) { struct zebra_if *if_data; @@ -3125,31 +3724,6 @@ int if_shutdown(struct interface *ifp) return 0; } -DEFUN (shutdown_if, - shutdown_if_cmd, - "shutdown", - "Shutdown the selected interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (ifp->ifindex != IFINDEX_INTERNAL) { - /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ - rtadv_stop_ra(ifp); - ret = if_unset_flags(ifp, IFF_UP); - if (ret < 0) { - vty_out(vty, "Can't shutdown interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - } - if_data = ifp->info; - if_data->shutdown = IF_ZEBRA_DATA_ON; - - return CMD_SUCCESS; -} - int if_no_shutdown(struct interface *ifp) { struct zebra_if *if_data; @@ -3174,984 +3748,56 @@ int if_no_shutdown(struct interface *ifp) return 0; } -DEFUN (no_shutdown_if, - no_shutdown_if_cmd, - "no shutdown", - NO_STR - "Shutdown the selected interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (ifp->ifindex != IFINDEX_INTERNAL) { - ret = if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if (ret < 0) { - vty_out(vty, "Can't up interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - - /* Some addresses (in particular, IPv6 addresses on Linux) get - * removed when the interface goes down. They need to be - * readded. - */ - if_addr_wakeup(ifp); - } - - if_data = ifp->info; - if_data->shutdown = IF_ZEBRA_DATA_OFF; - - return CMD_SUCCESS; -} - -DEFUN (bandwidth_if, - bandwidth_if_cmd, - "bandwidth (1-100000)", - "Set bandwidth informational parameter\n" - "Bandwidth in megabits\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned int bandwidth; - - bandwidth = strtol(argv[idx_number]->arg, NULL, 10); - - /* bandwidth range is <1-100000> */ - if (bandwidth < 1 || bandwidth > 100000) { - vty_out(vty, "Bandwidth is invalid\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ifp->bandwidth = bandwidth; - - /* force protocols to recalculate routes due to cost change */ - if (if_is_operative(ifp)) - zebra_interface_up_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_bandwidth_if, - no_bandwidth_if_cmd, - "no bandwidth [(1-100000)]", - NO_STR - "Set bandwidth informational parameter\n" - "Bandwidth in megabits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - ifp->bandwidth = 0; - - /* force protocols to recalculate routes due to cost change */ - if (if_is_operative(ifp)) - zebra_interface_up_update(ifp); - - return CMD_SUCCESS; -} - - -struct cmd_node link_params_node = { - .name = "link-params", - .node = LINK_PARAMS_NODE, - .parent_node = INTERFACE_NODE, - .prompt = "%s(config-link-params)# ", - .no_xpath = true, -}; - -static void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, - uint32_t type, uint32_t value) +void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value) { /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); } } -static void link_param_cmd_set_float(struct interface *ifp, float *field, - uint32_t type, float value) -{ +void link_param_cmd_set_float(struct interface *ifp, float *field, + uint32_t type, float value) +{ /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); } } -static void link_param_cmd_unset(struct interface *ifp, uint32_t type) +void link_param_cmd_unset(struct interface *ifp, uint32_t type) { if (ifp->link_params == NULL) return; /* Unset field */ UNSET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); -} - -DEFUN_NOSH (link_params, - link_params_cmd, - "link-params", - LINK_PARAMS_STR) -{ - /* vty->qobj_index stays the same @ interface pointer */ - vty->node = LINK_PARAMS_NODE; - - return CMD_SUCCESS; -} - -DEFUN_NOSH (exit_link_params, - exit_link_params_cmd, - "exit-link-params", - "Exit from Link Params configuration mode\n") -{ - if (vty->node == LINK_PARAMS_NODE) - vty->node = INTERFACE_NODE; - return CMD_SUCCESS; -} - -/* Specific Traffic Engineering parameters commands */ -DEFUN (link_params_enable, - link_params_enable_cmd, - "enable", - "Activate link parameters on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* This command could be issue at startup, when activate MPLS TE */ - /* on a new interface or after a ON / OFF / ON toggle */ - /* In all case, TE parameters are reset to their default factory */ - if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "Link-params: enable TE link parameters on interface %s", - ifp->name); - - if (!if_link_params_get(ifp)) - if_link_params_enable(ifp); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_enable, - no_link_params_enable_cmd, - "no enable", - NO_STR - "Disable link parameters on this interface\n") -{ - char xpath[XPATH_MAXLEN]; - int ret; - VTY_DECLVAR_CONTEXT(interface, ifp); - - if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) - zlog_debug("MPLS-TE: disable TE link parameters on interface %s", - ifp->name); - - if_link_params_free(ifp); - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - ret = nb_cli_apply_changes(vty, NULL); - - if (ret != CMD_SUCCESS) - return ret; - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; } -/* STANDARD TE metrics */ -DEFUN (link_params_metric, - link_params_metric_cmd, - "metric (0-4294967295)", - "Link metric for MPLS-TE purpose\n" - "Metric value in decimal\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint32_t metric; - - metric = strtoul(argv[idx_number]->arg, NULL, 10); - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update TE metric if needed */ - link_param_cmd_set_uint32(ifp, &iflp->te_metric, LP_TE_METRIC, metric); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_metric, - no_link_params_metric_cmd, - "no metric", - NO_STR - "Disable Link Metric on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset TE Metric */ - link_param_cmd_unset(ifp, LP_TE_METRIC); - - return CMD_SUCCESS; -} - -DEFUN (link_params_maxbw, - link_params_maxbw_cmd, - "max-bw BANDWIDTH", - "Maximum bandwidth that can be used\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_maxbw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that Maximum bandwidth is not lower than other bandwidth - * parameters */ - if (iflp && ((bw <= iflp->max_rsv_bw) || (bw <= iflp->unrsv_bw[0]) || - (bw <= iflp->unrsv_bw[1]) || (bw <= iflp->unrsv_bw[2]) || - (bw <= iflp->unrsv_bw[3]) || (bw <= iflp->unrsv_bw[4]) || - (bw <= iflp->unrsv_bw[5]) || (bw <= iflp->unrsv_bw[6]) || - (bw <= iflp->unrsv_bw[7]) || (bw <= iflp->ava_bw) || - (bw <= iflp->res_bw) || (bw <= iflp->use_bw))) { - vty_out(vty, - "Maximum Bandwidth could not be lower than others bandwidth\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Maximum Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->max_bw, LP_MAX_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (link_params_max_rsv_bw, - link_params_max_rsv_bw_cmd, - "max-rsv-bw BANDWIDTH", - "Maximum bandwidth that may be reserved\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_max_rsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Maximum Reservable Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (link_params_unrsv_bw, - link_params_unrsv_bw_cmd, - "unrsv-bw (0-7) BANDWIDTH", - "Unreserved bandwidth at each priority level\n" - "Priority\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_number = 1; - int idx_bandwidth = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - int priority; - float bw; - - /* We don't have to consider about range check here. */ - if (sscanf(argv[idx_number]->arg, "%d", &priority) != 1) { - vty_out(vty, "link_params_unrsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_unrsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Unreserved Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, - bw); - - return CMD_SUCCESS; -} - -DEFPY_YANG(link_params_admin_grp, link_params_admin_grp_cmd, - "admin-grp BITPATTERN", - "Administrative group membership\n" - "32-bit Hexadecimal value (e.g. 0xa1)\n") -{ - char xpath[XPATH_MAXLEN]; - int idx_bitpattern = 1; - unsigned long value; - char value_str[11]; - - VTY_DECLVAR_CONTEXT(interface, ifp); - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) { - vty_out(vty, - "cannot use the admin-grp command when affinity is set\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (sscanf(argv[idx_bitpattern]->arg, "0x%lx", &value) != 1) { - vty_out(vty, "link_params_admin_grp: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (value > 0xFFFFFFFF) { - vty_out(vty, "value must be not be superior to 0xFFFFFFFF\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - snprintf(value_str, sizeof(value_str), "%ld", value); - - nb_cli_enqueue_change( - vty, "./frr-zebra:zebra/link-params/legacy-admin-group", - NB_OP_MODIFY, value_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG(no_link_params_admin_grp, no_link_params_admin_grp_cmd, - "no admin-grp", - NO_STR "Disable Administrative group membership on this interface\n") -{ - nb_cli_enqueue_change( - vty, "./frr-zebra:zebra/link-params/legacy-admin-group", - NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -/* RFC5392 & RFC5316: INTER-AS */ -DEFUN (link_params_inter_as, - link_params_inter_as_cmd, - "neighbor A.B.C.D as (1-4294967295)", - "Configure remote ASBR information (Neighbor IP address and AS number)\n" - "Remote IP address in dot decimal A.B.C.D\n" - "Remote AS number\n" - "AS number in the range <1-4294967295>\n") -{ - int idx_ipv4 = 1; - int idx_number = 3; - - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - struct in_addr addr; - uint32_t as; - - if (!inet_aton(argv[idx_ipv4]->arg, &addr)) { - vty_out(vty, "Please specify Router-Addr by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - as = strtoul(argv[idx_number]->arg, NULL, 10); - - /* Update Remote IP and Remote AS fields if needed */ - if (IS_PARAM_UNSET(iflp, LP_RMT_AS) || iflp->rmt_as != as - || iflp->rmt_ip.s_addr != addr.s_addr) { - - iflp->rmt_as = as; - iflp->rmt_ip.s_addr = addr.s_addr; - SET_PARAM(iflp, LP_RMT_AS); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - } - return CMD_SUCCESS; -} - -DEFUN (no_link_params_inter_as, - no_link_params_inter_as_cmd, - "no neighbor", - NO_STR - "Remove Neighbor IP address and AS number for Inter-AS TE\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - if (!iflp) - return CMD_SUCCESS; - - /* Reset Remote IP and AS neighbor */ - iflp->rmt_as = 0; - iflp->rmt_ip.s_addr = 0; - UNSET_PARAM(iflp, LP_RMT_AS); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -/* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & - * draft-ietf-isis-metric-extensions-07.txt */ -DEFUN (link_params_delay, - link_params_delay_cmd, - "delay (0-16777215) [min (0-16777215) max (0-16777215)]", - "Unidirectional Average Link Delay\n" - "Average delay in micro-second as decimal (0...16777215)\n" - "Minimum delay\n" - "Minimum delay in micro-second as decimal (0...16777215)\n" - "Maximum delay\n" - "Maximum delay in micro-second as decimal (0...16777215)\n") -{ - /* Get and Check new delay values */ - uint32_t delay = 0, low = 0, high = 0; - delay = strtoul(argv[1]->arg, NULL, 10); - if (argc == 6) { - low = strtoul(argv[3]->arg, NULL, 10); - high = strtoul(argv[5]->arg, NULL, 10); - } - - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint8_t update = 0; - - if (argc == 2) { - /* - * Check new delay value against old Min and Max delays if set - * - * RFC 7471 Section 4.2.7: - * It is possible for min delay and max delay to be - * the same value. - * - * Therefore, it is also allowed that the average - * delay be equal to the min delay or max delay. - */ - if (iflp && IS_PARAM_SET(iflp, LP_MM_DELAY) && - (delay < iflp->min_delay || delay > iflp->max_delay)) { - vty_out(vty, - "Average delay should be in range Min (%d) - Max (%d) delay\n", - iflp->min_delay, iflp->max_delay); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update delay if value is not set or change */ - if (IS_PARAM_UNSET(iflp, LP_DELAY) || iflp->av_delay != delay) { - iflp->av_delay = delay; - SET_PARAM(iflp, LP_DELAY); - update = 1; - } - /* Unset Min and Max delays if already set */ - if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { - iflp->min_delay = 0; - iflp->max_delay = 0; - UNSET_PARAM(iflp, LP_MM_DELAY); - update = 1; - } - } else { - /* - * Check new delays value coherency. See above note - * regarding average delay equal to min/max allowed - */ - if (delay < low || delay > high) { - vty_out(vty, - "Average delay should be in range Min (%d) - Max (%d) delay\n", - low, high); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Delays if needed */ - if (IS_PARAM_UNSET(iflp, LP_DELAY) - || IS_PARAM_UNSET(iflp, LP_MM_DELAY) - || iflp->av_delay != delay || iflp->min_delay != low - || iflp->max_delay != high) { - iflp->av_delay = delay; - SET_PARAM(iflp, LP_DELAY); - iflp->min_delay = low; - iflp->max_delay = high; - SET_PARAM(iflp, LP_MM_DELAY); - update = 1; - } - } - - /* force protocols to update LINK STATE due to parameters change */ - if (update == 1 && if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_delay, - no_link_params_delay_cmd, - "no delay", - NO_STR - "Disable Unidirectional Average, Min & Max Link Delay on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - if (!iflp) - return CMD_SUCCESS; - - /* Unset Delays */ - iflp->av_delay = 0; - UNSET_PARAM(iflp, LP_DELAY); - iflp->min_delay = 0; - iflp->max_delay = 0; - UNSET_PARAM(iflp, LP_MM_DELAY); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (link_params_delay_var, - link_params_delay_var_cmd, - "delay-variation (0-16777215)", - "Unidirectional Link Delay Variation\n" - "delay variation in micro-second as decimal (0...16777215)\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint32_t value; - - value = strtoul(argv[idx_number]->arg, NULL, 10); - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Delay Variation if needed */ - link_param_cmd_set_uint32(ifp, &iflp->delay_var, LP_DELAY_VAR, value); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_delay_var, - no_link_params_delay_var_cmd, - "no delay-variation", - NO_STR - "Disable Unidirectional Delay Variation on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Delay Variation */ - link_param_cmd_unset(ifp, LP_DELAY_VAR); - - return CMD_SUCCESS; -} - -DEFUN (link_params_pkt_loss, - link_params_pkt_loss_cmd, - "packet-loss PERCENTAGE", - "Unidirectional Link Packet Loss\n" - "percentage of total traffic by 0.000003% step and less than 50.331642%\n") -{ - int idx_percentage = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float fval; - - if (sscanf(argv[idx_percentage]->arg, "%g", &fval) != 1) { - vty_out(vty, "link_params_pkt_loss: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (fval > MAX_PKT_LOSS) - fval = MAX_PKT_LOSS; - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Packet Loss if needed */ - link_param_cmd_set_float(ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_pkt_loss, - no_link_params_pkt_loss_cmd, - "no packet-loss", - NO_STR - "Disable Unidirectional Link Packet Loss on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Packet Loss */ - link_param_cmd_unset(ifp, LP_PKT_LOSS); - - return CMD_SUCCESS; -} - -DEFUN (link_params_res_bw, - link_params_res_bw_cmd, - "res-bw BANDWIDTH", - "Unidirectional Residual Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_res_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Residual Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->res_bw, LP_RES_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_res_bw, - no_link_params_res_bw_cmd, - "no res-bw", - NO_STR - "Disable Unidirectional Residual Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Residual Bandwidth */ - link_param_cmd_unset(ifp, LP_RES_BW); - - return CMD_SUCCESS; -} - -DEFUN (link_params_ava_bw, - link_params_ava_bw_cmd, - "ava-bw BANDWIDTH", - "Unidirectional Available Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_ava_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Available Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Residual Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->ava_bw, LP_AVA_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_ava_bw, - no_link_params_ava_bw_cmd, - "no ava-bw", - NO_STR - "Disable Unidirectional Available Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Available Bandwidth */ - link_param_cmd_unset(ifp, LP_AVA_BW); - - return CMD_SUCCESS; -} - -DEFUN (link_params_use_bw, - link_params_use_bw_cmd, - "use-bw BANDWIDTH", - "Unidirectional Utilised Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_use_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Utilized Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->use_bw, LP_USE_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_use_bw, - no_link_params_use_bw_cmd, - "no use-bw", - NO_STR - "Disable Unidirectional Utilised Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Utilised Bandwidth */ - link_param_cmd_unset(ifp, LP_USE_BW); - - return CMD_SUCCESS; -} - -static int ag_change(struct vty *vty, int argc, struct cmd_token **argv, - const char *xpath, bool no, int start_idx) -{ - for (int i = start_idx; i < argc; i++) - nb_cli_enqueue_change(vty, xpath, - no ? NB_OP_DESTROY : NB_OP_CREATE, - argv[i]->arg); - return nb_cli_apply_changes(vty, NULL); -} - -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity - */ -DEFPY_YANG(link_params_affinity, link_params_affinity_cmd, - "[no] affinity NAME...", - NO_STR - "Interface affinities\n" - "Affinity names\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - char xpath[XPATH_MAXLEN]; - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/legacy-admin-group", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) { - vty_out(vty, - "cannot use the affinity command when admin-grp is set\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return ag_change(vty, argc, argv, - "./frr-zebra:zebra/link-params/affinities/affinity", - no, no ? 2 : 1); -} - - -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity-mode - */ -DEFPY_YANG(link_params_affinity_mode, link_params_affinity_mode_cmd, - "affinity-mode <standard|extended|both>$affmode", - "Interface affinity mode\n" - "Standard Admin-Group only RFC3630,5305,5329 (default)\n" - "Extended Admin-Group only RFC7308\n" - "Standard and extended Admin-Group format\n") -{ - const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, affmode); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG(no_link_params_affinity_mode, no_link_params_affinity_mode_cmd, - "no affinity-mode [<standard|extended|both>]", - NO_STR - "Interface affinity mode\n" - "Standard Admin-Group only RFC3630,5305,5329 (default)\n" - "Extended Admin-Group only RFC7308\n" - "Standard and extended Admin-Group format\n") -{ - const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "standard"); - - return nb_cli_apply_changes(vty, NULL); -} - -static int ag_iter_cb(const struct lyd_node *dnode, void *arg) -{ - struct vty *vty = (struct vty *)arg; - - vty_out(vty, " %s", yang_dnode_get_string(dnode, ".")); - return YANG_ITER_CONTINUE; -} - -void cli_show_legacy_admin_group(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - if (!yang_dnode_exists(dnode, "./legacy-admin-group")) - return; - - vty_out(vty, " admin-group 0x%x\n", - yang_dnode_get_uint32(dnode, "./legacy-admin-group")); -} - -void cli_show_affinity_mode(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - enum affinity_mode affinity_mode = yang_dnode_get_enum(dnode, "."); - - if (affinity_mode == AFFINITY_MODE_STANDARD) - vty_out(vty, " affinity-mode standard\n"); - else if (affinity_mode == AFFINITY_MODE_BOTH) - vty_out(vty, " affinity-mode both\n"); -} - -void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - if (!yang_dnode_exists(dnode, "./affinity")) - return; - - vty_out(vty, " affinity"); - yang_dnode_iterate(ag_iter_cb, vty, dnode, "./affinity"); - vty_out(vty, "\n"); -} - -int if_ip_address_install(struct interface *ifp, struct prefix *prefix, - const char *label, struct prefix *pp) +void if_ip_address_install(struct interface *ifp, struct prefix *prefix, + const char *label, struct prefix *pp) { struct zebra_if *if_data; - struct prefix_ipv4 lp; - struct prefix_ipv4 *p; struct connected *ifc; - enum zebra_dplane_result dplane_res; if_data = ifp->info; - lp.family = prefix->family; - lp.prefix = prefix->u.prefix4; - lp.prefixlen = prefix->prefixlen; - apply_mask_ipv4(&lp); - - ifc = connected_check_ptp(ifp, &lp, pp ? pp : NULL); + ifc = connected_check_ptp(ifp, prefix, pp); if (!ifc) { ifc = connected_new(); ifc->ifp = ifp; /* Address. */ - p = prefix_ipv4_new(); - *p = lp; - ifc->address = (struct prefix *)p; + ifc->address = prefix_new(); + prefix_copy(ifc->address, prefix); if (pp) { SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); - p = prefix_ipv4_new(); - *p = *(struct prefix_ipv4 *)pp; - ifc->destination = (struct prefix *)p; + ifc->destination = prefix_new(); + prefix_copy(ifc->destination, pp); } /* Label. */ @@ -4159,7 +3805,7 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix, ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); /* Add to linked list. */ - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); } /* This address is configured from zebra. */ @@ -4176,13 +3822,7 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix, if_refresh(ifp); } - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug( - "dplane can't set interface IP address: %s.", - dplane_res2str(dplane_res)); - return NB_ERR; - } + dplane_intf_addr_set(ifp, ifc); SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the @@ -4190,407 +3830,50 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix, * from the kernel has been received. * It will also be added to the subnet chain list, then. */ } - - return 0; } -static int ip_address_install(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) +void if_ip_address_uninstall(struct interface *ifp, struct prefix *prefix, + struct prefix *pp) { - struct zebra_if *if_data; - struct prefix_ipv4 lp, pp; struct connected *ifc; - struct prefix_ipv4 *p; - int ret; - enum zebra_dplane_result dplane_res; - - if_data = ifp->info; - - ret = str2prefix_ipv4(addr_str, &lp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ipv4_martian(&lp.prefix)) { - vty_out(vty, "%% Invalid address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (peer_str) { - if (lp.prefixlen != IPV4_MAX_BITLEN) { - vty_out(vty, - "%% Local prefix length for P-t-P address must be /32\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = str2prefix_ipv4(peer_str, &pp); - if (ret <= 0) { - vty_out(vty, "%% Malformed peer address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); - if (!ifc) { - ifc = connected_new(); - ifc->ifp = ifp; - - /* Address. */ - p = prefix_ipv4_new(); - *p = lp; - ifc->address = (struct prefix *)p; - - if (peer_str) { - SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); - p = prefix_ipv4_new(); - *p = pp; - ifc->destination = (struct prefix *)p; - } - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - - /* Add to linked list. */ - listnode_add(ifp->connected, ifc); - } - - /* This address is configured from zebra. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* In case of this route need to install kernel. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) && - CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && - !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) { - /* Some system need to up the interface to set IP address. */ - if (!if_is_up(ifp)) { - if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if_refresh(ifp); - } - - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't set interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } - - SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* The address will be advertised to zebra clients when the - * notification - * from the kernel has been received. - * It will also be added to the subnet chain list, then. */ - } - - return CMD_SUCCESS; -} - -int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix) -{ - struct connected *ifc = NULL; - enum zebra_dplane_result dplane_res; - - if (prefix->family == AF_INET) { - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, prefix, NULL); - if (!ifc) { - zlog_debug("interface %s Can't find address", - ifp->name); - return -1; - } - } else if (prefix->family == AF_INET6) { - /* Check current interface address. */ - ifc = connected_check(ifp, prefix); - } + ifc = connected_check_ptp(ifp, prefix, pp); + assert(ifc); - if (!ifc) { - zlog_debug("interface %s Can't find address", ifp->name); - return -1; - } UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); + if_connected_del(ifp->connected, ifc); connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; + return; } /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug("Can't unset interface IP address: %s.", - dplane_res2str(dplane_res)); - return -1; - } - UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - - return 0; -} - -static int ip_address_uninstall(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) -{ - struct prefix_ipv4 lp, pp; - struct connected *ifc; - int ret; - enum zebra_dplane_result dplane_res; - - /* Convert to prefix structure. */ - ret = str2prefix_ipv4(addr_str, &lp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (peer_str) { - if (lp.prefixlen != IPV4_MAX_BITLEN) { - vty_out(vty, - "%% Local prefix length for P-t-P address must be /32\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = str2prefix_ipv4(peer_str, &pp); - if (ret <= 0) { - vty_out(vty, "%% Malformed peer address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); - if (!ifc) { - vty_out(vty, "%% Can't find address\n"); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_unset(ifp, ifc); - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - return CMD_WARNING_CONFIG_FAILED; - - UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* This is not real address or interface is not active. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); - connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; - } - - /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't unset interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* we will receive a kernel notification about this route being removed. - * this will trigger its removal from the connected list. */ - return CMD_SUCCESS; -} - -DEFUN (ip_address, - ip_address_cmd, - "ip address A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n") -{ - int idx_ipv4_prefixlen = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[idx_ipv4_prefixlen]->arg, NULL, - NULL); -} - -DEFUN (no_ip_address, - no_ip_address_cmd, - "no ip address A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP Address (e.g. 10.0.0.1/8)\n") -{ - int idx_ipv4_prefixlen = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[idx_ipv4_prefixlen]->arg, - NULL, NULL); -} - -DEFUN(ip_address_peer, - ip_address_peer_cmd, - "ip address A.B.C.D peer A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "Local IP (e.g. 10.0.0.1) for P-t-P address\n" - "Specify P-t-P address\n" - "Peer IP address (e.g. 10.0.0.1/8)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[2]->arg, argv[4]->arg, NULL); -} - -DEFUN(no_ip_address_peer, - no_ip_address_peer_cmd, - "no ip address A.B.C.D peer A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "Local IP (e.g. 10.0.0.1) for P-t-P address\n" - "Specify P-t-P address\n" - "Peer IP address (e.g. 10.0.0.1/8)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[3]->arg, argv[5]->arg, NULL); -} - -#ifdef HAVE_NETLINK -DEFUN (ip_address_label, - ip_address_label_cmd, - "ip address A.B.C.D/M label LINE", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n" - "Label of this address\n" - "Label\n") -{ - int idx_ipv4_prefixlen = 2; - int idx_line = 4; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[idx_ipv4_prefixlen]->arg, NULL, - argv[idx_line]->arg); -} - -DEFUN (no_ip_address_label, - no_ip_address_label_cmd, - "no ip address A.B.C.D/M label LINE", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n" - "Label of this address\n" - "Label\n") -{ - int idx_ipv4_prefixlen = 3; - int idx_line = 5; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[idx_ipv4_prefixlen]->arg, - NULL, argv[idx_line]->arg); } -#endif /* HAVE_NETLINK */ -int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix, - const char *label) +void if_ipv6_address_install(struct interface *ifp, struct prefix *prefix) { struct zebra_if *if_data; - struct prefix_ipv6 cp; struct connected *ifc; - struct prefix_ipv6 *p; - enum zebra_dplane_result dplane_res; - - if_data = ifp->info; - - cp.family = prefix->family; - cp.prefixlen = prefix->prefixlen; - cp.prefix = prefix->u.prefix6; - apply_mask_ipv6(&cp); - - ifc = connected_check(ifp, (struct prefix *)&cp); - if (!ifc) { - ifc = connected_new(); - ifc->ifp = ifp; - - /* Address. */ - p = prefix_ipv6_new(); - *p = cp; - ifc->address = (struct prefix *)p; - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - - /* Add to linked list. */ - listnode_add(ifp->connected, ifc); - } - - /* This address is configured from zebra. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* In case of this route need to install kernel. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) && - CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && - !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) { - /* Some system need to up the interface to set IP address. */ - if (!if_is_up(ifp)) { - if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if_refresh(ifp); - } - - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug( - "dplane can't set interface IP address: %s.", - dplane_res2str(dplane_res)); - return NB_ERR; - } - - SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* The address will be advertised to zebra clients when the - * notification - * from the kernel has been received. */ - } - - return 0; -} - -static int ipv6_address_install(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) -{ - struct zebra_if *if_data; - struct prefix_ipv6 cp; - struct connected *ifc; - struct prefix_ipv6 *p; - int ret; - enum zebra_dplane_result dplane_res; if_data = ifp->info; - ret = str2prefix_ipv6(addr_str, &cp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ipv6_martian(&cp.prefix)) { - vty_out(vty, "%% Invalid address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ifc = connected_check(ifp, (struct prefix *)&cp); + ifc = connected_check(ifp, prefix); if (!ifc) { ifc = connected_new(); ifc->ifp = ifp; /* Address. */ - p = prefix_ipv6_new(); - *p = cp; - ifc->address = (struct prefix *)p; - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); + ifc->address = prefix_new(); + prefix_copy(ifc->address, prefix); /* Add to linked list. */ - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); } /* This address is configured from zebra. */ @@ -4607,261 +3890,36 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp, if_refresh(ifp); } - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't set interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_set(ifp, ifc); SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the * notification * from the kernel has been received. */ } - - return CMD_SUCCESS; -} - -/* Return true if an ipv6 address is configured on ifp */ -int ipv6_address_configured(struct interface *ifp) -{ - struct connected *connected; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) - return 1; - - return 0; } -static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) +void if_ipv6_address_uninstall(struct interface *ifp, struct prefix *prefix) { - struct prefix_ipv6 cp; struct connected *ifc; - int ret; - enum zebra_dplane_result dplane_res; - - /* Convert to prefix structure. */ - ret = str2prefix_ipv6(addr_str, &cp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* Check current interface address. */ - ifc = connected_check(ifp, (struct prefix *)&cp); - if (!ifc) { - vty_out(vty, "%% Can't find address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - return CMD_WARNING_CONFIG_FAILED; + ifc = connected_check(ifp, prefix); + assert(ifc); UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); + if_connected_del(ifp->connected, ifc); connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; + return; } /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't unset interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_unset(ifp, ifc); UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* This information will be propagated to the zclients when the - * kernel notification is received. */ - return CMD_SUCCESS; -} - -DEFUN (ipv6_address, - ipv6_address_cmd, - "ipv6 address X:X::X:X/M", - "Interface IPv6 config commands\n" - "Set the IP address of an interface\n" - "IPv6 address (e.g. 3ffe:506::1/48)\n") -{ - int idx_ipv6_prefixlen = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ipv6_address_install(vty, ifp, argv[idx_ipv6_prefixlen]->arg, - NULL, NULL); -} - -DEFUN (no_ipv6_address, - no_ipv6_address_cmd, - "no ipv6 address X:X::X:X/M", - NO_STR - "Interface IPv6 config commands\n" - "Set the IP address of an interface\n" - "IPv6 address (e.g. 3ffe:506::1/48)\n") -{ - int idx_ipv6_prefixlen = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ipv6_address_uninstall(vty, ifp, argv[idx_ipv6_prefixlen]->arg, - NULL, NULL); -} - -static int link_params_config_write(struct vty *vty, struct interface *ifp) -{ - const struct lyd_node *dnode; - char xpath[XPATH_MAXLEN]; - int i; - - if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) - return -1; - - struct if_link_params *iflp = ifp->link_params; - - vty_out(vty, " link-params\n"); - vty_out(vty, " enable\n"); - if (IS_PARAM_SET(iflp, LP_TE_METRIC) && iflp->te_metric != ifp->metric) - vty_out(vty, " metric %u\n", iflp->te_metric); - if (IS_PARAM_SET(iflp, LP_MAX_BW) && iflp->max_bw != iflp->default_bw) - vty_out(vty, " max-bw %g\n", iflp->max_bw); - if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW) - && iflp->max_rsv_bw != iflp->default_bw) - vty_out(vty, " max-rsv-bw %g\n", iflp->max_rsv_bw); - if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { - for (i = 0; i < 8; i++) - if (iflp->unrsv_bw[i] != iflp->default_bw) - vty_out(vty, " unrsv-bw %d %g\n", i, - iflp->unrsv_bw[i]); - } - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params", - ifp->name); - dnode = yang_dnode_get(running_config->dnode, xpath); - if (dnode) - nb_cli_show_dnode_cmds(vty, dnode, false); - - if (IS_PARAM_SET(iflp, LP_DELAY)) { - vty_out(vty, " delay %u", iflp->av_delay); - if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { - vty_out(vty, " min %u", iflp->min_delay); - vty_out(vty, " max %u", iflp->max_delay); - } - vty_out(vty, "\n"); - } - if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) - vty_out(vty, " delay-variation %u\n", iflp->delay_var); - if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) - vty_out(vty, " packet-loss %g\n", iflp->pkt_loss); - if (IS_PARAM_SET(iflp, LP_AVA_BW)) - vty_out(vty, " ava-bw %g\n", iflp->ava_bw); - if (IS_PARAM_SET(iflp, LP_RES_BW)) - vty_out(vty, " res-bw %g\n", iflp->res_bw); - if (IS_PARAM_SET(iflp, LP_USE_BW)) - vty_out(vty, " use-bw %g\n", iflp->use_bw); - if (IS_PARAM_SET(iflp, LP_RMT_AS)) - vty_out(vty, " neighbor %pI4 as %u\n", &iflp->rmt_ip, - iflp->rmt_as); - - vty_out(vty, " exit-link-params\n"); - return 0; -} - -static int if_config_write(struct vty *vty) -{ - struct vrf *vrf; - struct interface *ifp; - - zebra_ptm_write(vty); - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - FOR_ALL_INTERFACES (vrf, ifp) { - struct zebra_if *if_data; - struct listnode *addrnode; - struct connected *ifc; - struct prefix *p; - - if_data = ifp->info; - - if_vty_config_start(vty, ifp); - - if (if_data) { - if (if_data->shutdown == IF_ZEBRA_DATA_ON) - vty_out(vty, " shutdown\n"); - - zebra_ptm_if_write(vty, if_data); - } - - if (ifp->desc) - vty_out(vty, " description %s\n", ifp->desc); - - /* Assign bandwidth here to avoid unnecessary interface - flap - while processing config script */ - if (ifp->bandwidth != 0) - vty_out(vty, " bandwidth %u\n", ifp->bandwidth); - - if (!CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION)) - vty_out(vty, " no link-detect\n"); - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, addrnode, - ifc)) { - if (CHECK_FLAG(ifc->conf, - ZEBRA_IFC_CONFIGURED)) { - char buf[INET6_ADDRSTRLEN]; - p = ifc->address; - vty_out(vty, " ip%s address %s", - p->family == AF_INET ? "" - : "v6", - inet_ntop(p->family, - &p->u.prefix, buf, - sizeof(buf))); - if (CONNECTED_PEER(ifc)) { - p = ifc->destination; - vty_out(vty, " peer %s", - inet_ntop(p->family, - &p->u.prefix, - buf, - sizeof(buf))); - } - vty_out(vty, "/%d", p->prefixlen); - - if (ifc->label) - vty_out(vty, " label %s", - ifc->label); - - vty_out(vty, "\n"); - } - } - - if (if_data) { - if (if_data->multicast != IF_ZEBRA_DATA_UNSPEC) - vty_out(vty, " %smulticast\n", - if_data->multicast == - IF_ZEBRA_DATA_ON - ? "" - : "no "); - if (if_data->mpls == IF_ZEBRA_DATA_ON) - vty_out(vty, " mpls enable\n"); - } - - hook_call(zebra_if_config_wr, vty, ifp); - zebra_evpn_mh_if_write(vty, ifp); - link_params_config_write(vty, ifp); - - if_vty_config_end(vty); - } - return 0; } /* Allocate and initialize interface vector. */ @@ -4871,15 +3929,6 @@ void zebra_if_init(void) hook_register_prio(if_add, 0, if_zebra_new_hook); hook_register_prio(if_del, 0, if_zebra_delete_hook); - /* Install configuration write function. */ - if_cmd_init(if_config_write); - install_node(&link_params_node); - /* - * This is *intentionally* setting this to NULL, signaling - * that interface creation for zebra acts differently - */ - if_zapi_callbacks(NULL, NULL, NULL, NULL); - install_element(VIEW_NODE, &show_interface_cmd); install_element(VIEW_NODE, &show_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_interface_name_vrf_cmd); @@ -4887,55 +3936,4 @@ void zebra_if_init(void) install_element(ENABLE_NODE, &show_interface_desc_cmd); install_element(ENABLE_NODE, &show_interface_desc_vrf_all_cmd); - install_element(INTERFACE_NODE, &multicast_cmd); - install_element(INTERFACE_NODE, &no_multicast_cmd); - install_element(INTERFACE_NODE, &mpls_cmd); - install_element(INTERFACE_NODE, &linkdetect_cmd); - install_element(INTERFACE_NODE, &no_linkdetect_cmd); - install_element(INTERFACE_NODE, &shutdown_if_cmd); - install_element(INTERFACE_NODE, &no_shutdown_if_cmd); - install_element(INTERFACE_NODE, &bandwidth_if_cmd); - install_element(INTERFACE_NODE, &no_bandwidth_if_cmd); - install_element(INTERFACE_NODE, &ip_address_cmd); - install_element(INTERFACE_NODE, &no_ip_address_cmd); - install_element(INTERFACE_NODE, &ip_address_peer_cmd); - install_element(INTERFACE_NODE, &no_ip_address_peer_cmd); - install_element(INTERFACE_NODE, &ipv6_address_cmd); - install_element(INTERFACE_NODE, &no_ipv6_address_cmd); -#ifdef HAVE_NETLINK - install_element(INTERFACE_NODE, &ip_address_label_cmd); - install_element(INTERFACE_NODE, &no_ip_address_label_cmd); -#endif /* HAVE_NETLINK */ - install_element(INTERFACE_NODE, &link_params_cmd); - install_default(LINK_PARAMS_NODE); - install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); - install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_metric_cmd); - install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_admin_grp_cmd); - install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); - install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_delay_cmd); - install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_delay_var_cmd); - install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_pkt_loss_cmd); - install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_ava_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_affinity_cmd); - install_element(LINK_PARAMS_NODE, &link_params_affinity_mode_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_affinity_mode_cmd); - install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); - - /* setup EVPN MH elements */ - zebra_evpn_interface_init(); } diff --git a/zebra/interface.h b/zebra/interface.h index e5545d6ba0..8d19c1838f 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -39,7 +39,6 @@ enum zebra_iftype { ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/ ZEBRA_IF_VETH, /* VETH interface*/ ZEBRA_IF_BOND, /* Bond */ - ZEBRA_IF_BOND_SLAVE, /* Bond */ ZEBRA_IF_GRE, /* GRE interface */ }; @@ -114,6 +113,9 @@ struct zebra_if { /* MPLS status. */ bool mpls; + /* MPLS configuration */ + uint8_t mpls_config; + /* Linkdown status */ bool linkdown, linkdownv6; @@ -199,6 +201,9 @@ struct zebra_if { ifindex_t link_ifindex; struct interface *link; +#define INTERFACE_SPEED_ERROR_READ -1 +#define INTERFACE_SPEED_ERROR_UNKNOWN -2 + uint8_t speed_update_count; struct event *speed_update; @@ -216,8 +221,6 @@ struct zebra_if { DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), (vty, ifp)); -DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)); #define IS_ZEBRA_IF_VRF(ifp) \ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF) @@ -281,7 +284,6 @@ extern void if_refresh(struct interface *); extern void if_flags_update(struct interface *, uint64_t); extern int if_subnet_add(struct interface *, struct connected *); extern int if_subnet_delete(struct interface *, struct connected *); -extern int ipv6_address_configured(struct interface *ifp); extern void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id); extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, ns_id_t ns_id); @@ -306,24 +308,29 @@ extern void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, */ extern int zebra_if_set_protodown(struct interface *ifp, bool down, enum protodown_reasons new_reason); -extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix, - const char *label, struct prefix *pp); -extern int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix, - const char *label); -extern int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix); +extern void if_ip_address_install(struct interface *ifp, struct prefix *prefix, + const char *label, struct prefix *pp); +extern void if_ip_address_uninstall(struct interface *ifp, + struct prefix *prefix, struct prefix *pp); +extern void if_ipv6_address_install(struct interface *ifp, + struct prefix *prefix); +extern void if_ipv6_address_uninstall(struct interface *ifp, + struct prefix *prefix); extern int if_shutdown(struct interface *ifp); extern int if_no_shutdown(struct interface *ifp); +extern void if_arp(struct interface *ifp, bool enable); extern int if_multicast_set(struct interface *ifp); extern int if_multicast_unset(struct interface *ifp); extern int if_linkdetect(struct interface *ifp, bool detect); extern void if_addr_wakeup(struct interface *ifp); +void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value); +void link_param_cmd_set_float(struct interface *ifp, float *field, + uint32_t type, float value); +void link_param_cmd_unset(struct interface *ifp, uint32_t type); + /* Nexthop group connected functions */ -extern void if_nhg_dependents_add(struct interface *ifp, - struct nhg_hash_entry *nhe); -extern void if_nhg_dependents_del(struct interface *ifp, - struct nhg_hash_entry *nhe); -extern unsigned int if_nhg_dependents_count(const struct interface *ifp); extern bool if_nhg_dependents_is_empty(const struct interface *ifp); extern void vrf_add_update(struct vrf *vrfp); diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 8da1ae37c6..a35784cd36 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -6,6 +6,8 @@ #include <zebra.h> +#include <sys/ioctl.h> + #include "linklist.h" #include "if.h" #include "prefix.h" diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 253e6a8dd6..70f3f57ae0 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -87,12 +87,12 @@ static const char *inet_2a(uint32_t a, char *b, size_t b_len) static struct prefix *irdp_get_prefix(struct interface *ifp) { - struct listnode *node; struct connected *ifc; - if (ifp->connected) - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + frr_each (if_connected, ifp->connected, ifc) { + if (ifc->address->family == AF_INET) return ifc->address; + } return NULL; } @@ -198,7 +198,6 @@ static void irdp_if_start(struct interface *ifp, int multicast, { struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; - struct listnode *node; struct connected *ifc; uint32_t timer, seed; @@ -247,11 +246,12 @@ static void irdp_if_start(struct interface *ifp, int multicast, /* The spec suggests this for randomness */ seed = 0; - if (ifp->connected) - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { + if (ifc->address->family == AF_INET) { seed = ifc->address->u.prefix4.s_addr; break; } + } srandom(seed); timer = (frr_weak_random() % IRDP_DEFAULT_INTERVAL) + 1; @@ -694,7 +694,6 @@ DEFUN (ip_irdp_debug_disable, void irdp_if_init(void) { - hook_register(zebra_if_config_wr, irdp_config_write); hook_register(if_del, irdp_if_delete); install_element(INTERFACE_NODE, &ip_irdp_broadcast_cmd); diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 6548790e9a..349ae1a191 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -197,7 +197,6 @@ void irdp_send_thread(struct event *t_advert) struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; struct prefix *p; - struct listnode *node, *nnode; struct connected *ifc; if (!irdp) @@ -205,16 +204,15 @@ void irdp_send_thread(struct event *t_advert) irdp->flags &= ~IF_SOLICIT; - if (ifp->connected) - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { - p = ifc->address; + frr_each (if_connected, ifp->connected, ifc) { + p = ifc->address; - if (p->family != AF_INET) - continue; + if (p->family != AF_INET) + continue; - irdp_advertisement(ifp, p); - irdp->irdp_sent++; - } + irdp_advertisement(ifp, p); + irdp->irdp_sent++; + } tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval; timer = frr_weak_random() % (tmp + 1); @@ -237,7 +235,6 @@ void irdp_advert_off(struct interface *ifp) { struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; - struct listnode *node, *nnode; int i; struct connected *ifc; struct prefix *p; @@ -247,19 +244,21 @@ void irdp_advert_off(struct interface *ifp) EVENT_OFF(irdp->t_advertise); - if (ifp->connected) - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { - p = ifc->address; + frr_each (if_connected, ifp->connected, ifc) { + p = ifc->address; - /* Output some packets with Lifetime 0 - we should add a wait... - */ + if (p->family != AF_INET) + continue; - for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) { - irdp->irdp_sent++; - irdp_advertisement(ifp, p); - } + /* Output some packets with Lifetime 0 + we should add a wait... + */ + + for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) { + irdp->irdp_sent++; + irdp_advertisement(ifp, p); } + } } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 78b1dfe276..8a64a1ea48 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -4,8 +4,12 @@ */ #include <zebra.h> +#include <fcntl.h> #ifdef HAVE_NETLINK +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/filter.h> #include "linklist.h" #include "if.h" @@ -35,6 +39,7 @@ #include "zebra/tc_netlink.h" #include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" +#include "zebra/ge_netlink.h" #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE (33) @@ -76,43 +81,48 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, - {RTM_DELROUTE, "RTM_DELROUTE"}, - {RTM_GETROUTE, "RTM_GETROUTE"}, - {RTM_NEWLINK, "RTM_NEWLINK"}, - {RTM_SETLINK, "RTM_SETLINK"}, - {RTM_DELLINK, "RTM_DELLINK"}, - {RTM_GETLINK, "RTM_GETLINK"}, - {RTM_NEWADDR, "RTM_NEWADDR"}, - {RTM_DELADDR, "RTM_DELADDR"}, - {RTM_GETADDR, "RTM_GETADDR"}, - {RTM_NEWNEIGH, "RTM_NEWNEIGH"}, - {RTM_DELNEIGH, "RTM_DELNEIGH"}, - {RTM_GETNEIGH, "RTM_GETNEIGH"}, - {RTM_NEWRULE, "RTM_NEWRULE"}, - {RTM_DELRULE, "RTM_DELRULE"}, - {RTM_GETRULE, "RTM_GETRULE"}, - {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, - {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, - {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, - {RTM_NEWNETCONF, "RTM_NEWNETCONF"}, - {RTM_DELNETCONF, "RTM_DELNETCONF"}, - {RTM_NEWTUNNEL, "RTM_NEWTUNNEL"}, - {RTM_DELTUNNEL, "RTM_DELTUNNEL"}, - {RTM_GETTUNNEL, "RTM_GETTUNNEL"}, - {RTM_NEWQDISC, "RTM_NEWQDISC"}, - {RTM_DELQDISC, "RTM_DELQDISC"}, - {RTM_GETQDISC, "RTM_GETQDISC"}, - {RTM_NEWTCLASS, "RTM_NEWTCLASS"}, - {RTM_DELTCLASS, "RTM_DELTCLASS"}, - {RTM_GETTCLASS, "RTM_GETTCLASS"}, - {RTM_NEWTFILTER, "RTM_NEWTFILTER"}, - {RTM_DELTFILTER, "RTM_DELTFILTER"}, - {RTM_GETTFILTER, "RTM_GETTFILTER"}, - {RTM_NEWVLAN, "RTM_NEWVLAN"}, - {RTM_DELVLAN, "RTM_DELVLAN"}, - {RTM_GETVLAN, "RTM_GETVLAN"}, - {0}}; +static const struct message nlmsg_str[] = { + { RTM_NEWROUTE, "RTM_NEWROUTE" }, + { RTM_DELROUTE, "RTM_DELROUTE" }, + { RTM_GETROUTE, "RTM_GETROUTE" }, + { RTM_NEWLINK, "RTM_NEWLINK" }, + { RTM_SETLINK, "RTM_SETLINK" }, + { RTM_DELLINK, "RTM_DELLINK" }, + { RTM_GETLINK, "RTM_GETLINK" }, + { RTM_NEWADDR, "RTM_NEWADDR" }, + { RTM_DELADDR, "RTM_DELADDR" }, + { RTM_GETADDR, "RTM_GETADDR" }, + { RTM_NEWNEIGH, "RTM_NEWNEIGH" }, + { RTM_DELNEIGH, "RTM_DELNEIGH" }, + { RTM_GETNEIGH, "RTM_GETNEIGH" }, + { RTM_NEWRULE, "RTM_NEWRULE" }, + { RTM_DELRULE, "RTM_DELRULE" }, + { RTM_GETRULE, "RTM_GETRULE" }, + { RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP" }, + { RTM_DELNEXTHOP, "RTM_DELNEXTHOP" }, + { RTM_GETNEXTHOP, "RTM_GETNEXTHOP" }, + { RTM_NEWNETCONF, "RTM_NEWNETCONF" }, + { RTM_DELNETCONF, "RTM_DELNETCONF" }, + { RTM_NEWTUNNEL, "RTM_NEWTUNNEL" }, + { RTM_DELTUNNEL, "RTM_DELTUNNEL" }, + { RTM_GETTUNNEL, "RTM_GETTUNNEL" }, + { RTM_NEWQDISC, "RTM_NEWQDISC" }, + { RTM_DELQDISC, "RTM_DELQDISC" }, + { RTM_GETQDISC, "RTM_GETQDISC" }, + { RTM_NEWTCLASS, "RTM_NEWTCLASS" }, + { RTM_DELTCLASS, "RTM_DELTCLASS" }, + { RTM_GETTCLASS, "RTM_GETTCLASS" }, + { RTM_NEWTFILTER, "RTM_NEWTFILTER" }, + { RTM_DELTFILTER, "RTM_DELTFILTER" }, + { RTM_GETTFILTER, "RTM_GETTFILTER" }, + { RTM_NEWVLAN, "RTM_NEWVLAN" }, + { RTM_DELVLAN, "RTM_DELVLAN" }, + { RTM_GETVLAN, "RTM_GETVLAN" }, + { RTM_NEWCHAIN, "RTM_NEWCHAIN" }, + { RTM_DELCHAIN, "RTM_DELCHAIN" }, + { RTM_GETCHAIN, "RTM_GETCHAIN" }, + { 0 } +}; static const struct message rtproto_str[] = { {RTPROT_REDIRECT, "redirect"}, @@ -301,7 +311,7 @@ static const char *group2str(uint32_t group) /* Make socket for Linux netlink interface. */ static int netlink_socket(struct nlsock *nl, unsigned long groups, uint32_t ext_groups[], uint8_t ext_group_size, - ns_id_t ns_id) + ns_id_t ns_id, int nl_family) { int ret; struct sockaddr_nl snl; @@ -309,7 +319,7 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, int namelen; frr_with_privs(&zserv_privs) { - sock = ns_socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id); + sock = ns_socket(AF_NETLINK, SOCK_RAW, nl_family, ns_id); if (sock < 0) { zlog_err("Can't open %s socket: %s", nl->name, safe_strerror(errno)); @@ -398,7 +408,7 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWLINK: return netlink_link_change(h, ns_id, startup); case RTM_DELLINK: - return netlink_link_change(h, ns_id, startup); + return 0; case RTM_NEWNEIGH: case RTM_DELNEIGH: case RTM_GETNEIGH: @@ -425,6 +435,12 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELVLAN: return netlink_vlan_change(h, ns_id, startup); + /* Messages we may receive, but ignore */ + case RTM_NEWCHAIN: + case RTM_DELCHAIN: + case RTM_GETCHAIN: + return 0; + /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: @@ -474,6 +490,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWLINK: case RTM_DELLINK: + return netlink_link_change(h, ns_id, startup); default: break; @@ -740,58 +757,6 @@ void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh) rtnh->rtnh_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)rtnh; } -bool nl_rta_put(struct rtattr *rta, unsigned int maxlen, int type, - const void *data, int alen) -{ - struct rtattr *subrta; - int len = RTA_LENGTH(alen); - - if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { - zlog_err("ERROR max allowed bound %d exceeded for rtattr", - maxlen); - return false; - } - subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); - subrta->rta_type = type; - subrta->rta_len = len; - if (alen) - memcpy(RTA_DATA(subrta), data, alen); - rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); - - return true; -} - -bool nl_rta_put16(struct rtattr *rta, unsigned int maxlen, int type, - uint16_t data) -{ - return nl_rta_put(rta, maxlen, type, &data, sizeof(uint16_t)); -} - -bool nl_rta_put64(struct rtattr *rta, unsigned int maxlen, int type, - uint64_t data) -{ - return nl_rta_put(rta, maxlen, type, &data, sizeof(uint64_t)); -} - -struct rtattr *nl_rta_nest(struct rtattr *rta, unsigned int maxlen, int type) -{ - struct rtattr *nest = RTA_TAIL(rta); - - if (nl_rta_put(rta, maxlen, type, NULL, 0)) - return NULL; - - nest->rta_type |= NLA_F_NESTED; - - return nest; -} - -int nl_rta_nest_end(struct rtattr *rta, struct rtattr *nest) -{ - nest->rta_len = (uint8_t *)RTA_TAIL(rta) - (uint8_t *)nest; - - return rta->rta_len; -} - const char *nl_msg_type_to_str(uint16_t msg_type) { return lookup_msg(nlmsg_str, msg_type, ""); @@ -1169,7 +1134,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), h->nlmsg_type, h->nlmsg_len, h->nlmsg_seq, h->nlmsg_pid); - /* * Ignore messages that maybe sent from * other actors besides the kernel @@ -1265,6 +1229,33 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), return netlink_talk_info(filter, n, &dp_info, startup); } +/* + * 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) +{ + struct zebra_dplane_info dp_info; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + /* Increment sequence number before capturing snapshot of ns socket + * info. + */ + zns->ge_netlink_cmd.seq = zebra_router_get_next_sequence(); + + /* Capture info in intermediate info struct */ + dp_info.ns_id = zns->ns_id; + + dp_info.is_cmd = true; + 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); +} + /* Issue request message to kernel via netlink socket. GET messages * are issued through this interface. */ @@ -1289,18 +1280,15 @@ int netlink_request(struct nlsock *nl, void *req) return 0; } -static int nl_batch_read_resp(struct nl_batch *bth) +static int nl_batch_read_resp(struct nl_batch *bth, struct nlsock *nl) { struct nlmsghdr *h; struct sockaddr_nl snl; struct msghdr msg = {}; int status, seq; - struct nlsock *nl; struct zebra_dplane_ctx *ctx; bool ignore_msg; - nl = kernel_netlink_nlsock_lookup(bth->zns->sock); - msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); @@ -1493,7 +1481,7 @@ static void nl_batch_send(struct nl_batch *bth) err = true; if (!err) { - if (nl_batch_read_resp(bth) == -1) + if (nl_batch_read_resp(bth, nl) == -1) err = true; } } @@ -1631,6 +1619,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_IPSET_DELETE: case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_STARTUP_STAGE: return FRR_NETLINK_ERROR; case DPLANE_OP_GRE_SET: @@ -1660,6 +1649,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_TC_FILTER_DELETE: case DPLANE_OP_TC_FILTER_UPDATE: return netlink_put_tc_filter_update_msg(bth, ctx); + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + return netlink_put_sr_tunsrc_set_msg(bth, ctx); } return FRR_NETLINK_ERROR; @@ -1777,17 +1769,11 @@ void kernel_init(struct zebra_ns *zns) * groups are added further below after SOL_NETLINK is verified to * exist. */ - groups = RTMGRP_LINK | - RTMGRP_IPV4_ROUTE | - RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_ROUTE | - RTMGRP_IPV6_IFADDR | - RTMGRP_IPV4_MROUTE | - 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_TC - 1)); + groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_MROUTE | + 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_TC - 1)); dplane_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | @@ -1802,8 +1788,8 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; - if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id) < - 0) { + if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink.name); exit(-1); @@ -1814,7 +1800,8 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; - if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_cmd.name); exit(-1); @@ -1827,7 +1814,8 @@ void kernel_init(struct zebra_ns *zns) sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", zns->ns_id); zns->netlink_dplane_out.sock = -1; - if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_out.name); exit(-1); @@ -1841,7 +1829,7 @@ void kernel_init(struct zebra_ns *zns) zns->ns_id); zns->netlink_dplane_in.sock = -1; if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, 0, - zns->ns_id) < 0) { + zns->ns_id, NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); exit(-1); @@ -1849,6 +1837,19 @@ void kernel_init(struct zebra_ns *zns) kernel_netlink_nlsock_insert(&zns->netlink_dplane_in); + /* Generic Netlink socket. */ + snprintf(zns->ge_netlink_cmd.name, sizeof(zns->ge_netlink_cmd.name), + "generic-netlink-cmd (NS %u)", zns->ns_id); + zns->ge_netlink_cmd.sock = -1; + if (netlink_socket(&zns->ge_netlink_cmd, 0, 0, 0, zns->ns_id, + NETLINK_GENERIC) < 0) { + zlog_warn("Failure to create %s socket", + zns->ge_netlink_cmd.name); + } + + if (zns->ge_netlink_cmd.sock >= 0) + kernel_netlink_nlsock_insert(&zns->ge_netlink_cmd); + /* * SOL_NETLINK is not available on all platforms yet * apparently. It's in bits/socket.h which I am not @@ -1887,6 +1888,15 @@ void kernel_init(struct zebra_ns *zns) zlog_notice("Registration for extended dp ACK failed : %d %s", errno, safe_strerror(errno)); + if (zns->ge_netlink_cmd.sock >= 0) { + one = 1; + ret = setsockopt(zns->ge_netlink_cmd.sock, SOL_NETLINK, + NETLINK_EXT_ACK, &one, sizeof(one)); + if (ret < 0) + zlog_err("Registration for extended generic netlink cmd ACK failed : %d %s", + errno, safe_strerror(errno)); + } + /* * Trim off the payload of the original netlink message in the * acknowledgment. This option is available since Linux 4.2, so if @@ -1919,12 +1929,22 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane_in.name, safe_strerror(errno), errno); + if (zns->ge_netlink_cmd.sock >= 0) { + if (fcntl(zns->ge_netlink_cmd.sock, F_SETFL, O_NONBLOCK) < 0) + zlog_err("Can't set %s socket error: %s(%d)", + zns->ge_netlink_cmd.name, safe_strerror(errno), + errno); + } + /* Set receive buffer size if it's set from command line */ if (rcvbufsize) { netlink_recvbuf(&zns->netlink, rcvbufsize); netlink_recvbuf(&zns->netlink_cmd, rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize); + + if (zns->ge_netlink_cmd.sock >= 0) + netlink_recvbuf(&zns->ge_netlink_cmd, rcvbufsize); } /* Set filter for inbound sockets, to exclude events we've generated @@ -1943,6 +1963,8 @@ void kernel_init(struct zebra_ns *zns) &zns->t_netlink); rt_netlink_init(); + + ge_netlink_init(zns); } /* Helper to clean up an nlsock */ @@ -1967,11 +1989,16 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) kernel_nlsock_fini(&zns->netlink_dplane_in); + kernel_nlsock_fini(&zns->ge_netlink_cmd); + /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ - if (complete) + if (complete) { kernel_nlsock_fini(&zns->netlink_dplane_out); + + XFREE(MTYPE_NL_BUF, nl_batch_tx_buf); + } } /* diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 446c860327..e37bba0cf6 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -85,35 +85,6 @@ extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max, */ extern bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, const void *data, unsigned int len); -/* - * nl_rta_put - add an additional optional attribute(rtattr) to the - * Netlink message buffer. - * - * Returns true if the attribute could be added to the message (fits into the - * buffer), otherwise false is returned. - */ -extern bool nl_rta_put(struct rtattr *rta, unsigned int maxlen, int type, - const void *data, int alen); -extern bool nl_rta_put16(struct rtattr *rta, unsigned int maxlen, int type, - uint16_t data); -extern bool nl_rta_put64(struct rtattr *rta, unsigned int maxlen, int type, - uint64_t data); -/* - * nl_rta_nest - start an additional optional attribute (rtattr) nest. - * - * Returns a valid pointer to the beginning of the nest if the attribute - * describing the nest could be added to the message (fits into the buffer), - * otherwise NULL is returned. - */ -extern struct rtattr *nl_rta_nest(struct rtattr *rta, unsigned int maxlen, - int type); -/* - * nl_rta_nest_end - finalize nesting of an aditionl optionl attributes. - * - * Updates the length field of the attribute header to include the appeneded - * attributes. Returns a total length of the Netlink message. - */ -extern int nl_rta_nest_end(struct rtattr *rta, struct rtattr *nest); extern const char *nl_msg_type_to_str(uint16_t msg_type); extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); @@ -127,6 +98,9 @@ extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup); extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, bool startup); +extern int +ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), + struct nlmsghdr *n, struct zebra_ns *zns, bool startup); 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 b8dc92b2e9..d50e7de229 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -5,6 +5,8 @@ #include <zebra.h> +#include <net/route.h> + #ifndef HAVE_NETLINK #include <net/if_types.h> @@ -48,11 +50,7 @@ extern struct zebra_privs_t zserv_privs; * 0). We follow this practice without questioning it, but it is a * bug if frr calls ROUNDUP with 0. */ -#ifdef __APPLE__ -#define ROUNDUP_TYPE int -#else -#define ROUNDUP_TYPE long -#endif +#define ROUNDUP_TYPE long /* * Because of these varying conventions, the only sane approach is for @@ -834,12 +832,12 @@ int ifam_read(struct ifa_msghdr *ifam) struct interface *ifp = NULL; union sockunion addr, mask, brd; bool dest_same = false; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; short ifnlen = 0; bool isalias = false; uint32_t flags = 0; - ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; + ifname[0] = ifname[IFNAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg(ifam, &addr, &mask, &brd, ifname, &ifnlen); @@ -851,7 +849,7 @@ int ifam_read(struct ifa_msghdr *ifam) return -1; } - if (ifnlen && strncmp(ifp->name, ifname, INTERFACE_NAMSIZ)) + if (ifnlen && strncmp(ifp->name, ifname, IFNAMSIZ)) isalias = true; /* @@ -995,7 +993,7 @@ void rtm_read(struct rt_msghdr *rtm) int flags; uint32_t zebra_flags; union sockunion dest, mask, gate; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; short ifnlen = 0; struct nexthop nh; struct prefix p; @@ -1100,11 +1098,11 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, zebra_flags, - &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, 0, distance, 0, + &p, NULL, &nh, 0, rt_table_main_id, 0, 0, distance, 0, false); else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, proto, 0, - zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, + zebra_flags, &p, NULL, &nh, 0, rt_table_main_id, 0, distance, true); } @@ -1468,6 +1466,14 @@ static void routing_socket(struct zebra_ns *zns) event_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); } +void interface_list_second(struct zebra_ns *zns) +{ +} + +void interface_list_tunneldump(struct zebra_ns *zns) +{ +} + /* Exported interface function. This function simply calls routing_socket (). */ void kernel_init(struct zebra_ns *zns) @@ -1617,6 +1623,8 @@ 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_STARTUP_STAGE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: zlog_err("Unhandled dplane data for %s", dplane_op2str(dplane_ctx_get_op(ctx))); res = ZEBRA_DPLANE_REQUEST_FAILURE; diff --git a/zebra/label_manager.c b/zebra/label_manager.c index c77470a701..c97beb6af8 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -28,6 +28,8 @@ #include "zebra/zapi_msg.h" #include "zebra/debug.h" +#include "zebra/label_manager_clippy.c" + #define CONNECTION_DELAY 5 struct label_manager lbl_mgr; @@ -49,10 +51,14 @@ DEFINE_HOOK(lm_get_chunk, DEFINE_HOOK(lm_release_chunk, (struct zserv *client, uint32_t start, uint32_t end), (client, start, end)); +/* show running-config needs an API for dynamic-block */ +DEFINE_HOOK(lm_write_label_block_config, + (struct vty *vty, struct zebra_vrf *zvrf), + (vty, zvrf)); DEFINE_HOOK(lm_cbs_inited, (), ()); -/* define wrappers to be called in zapi_msg.c (as hooks must be called in - * source file where they were defined) +/* define wrappers to be called in zapi_msg.c or zebra_mpls_vty.c (as hooks + * must be called in source file where they were defined) */ void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id) { @@ -69,6 +75,11 @@ void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end) hook_call(lm_release_chunk, client, start, end); } +int lm_write_label_block_config_call(struct vty *vty, struct zebra_vrf *zvrf) +{ + return hook_call(lm_write_label_block_config, vty, zvrf); +} + /* forward declarations of the static functions to be used for some hooks */ static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id); static int label_manager_disconnect(struct zserv *client); @@ -78,6 +89,8 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc, vrf_id_t vrf_id); static int label_manager_release_label_chunk(struct zserv *client, uint32_t start, uint32_t end); +static int label_manager_write_label_block_config(struct vty *vty, + struct zebra_vrf *zvrf); void delete_label_chunk(void *val) { @@ -96,7 +109,7 @@ void delete_label_chunk(void *val) */ int release_daemon_label_chunks(struct zserv *client) { - struct listnode *node; + struct listnode *node, *nnode; struct label_manager_chunk *lmc; int count = 0; int ret; @@ -106,7 +119,7 @@ int release_daemon_label_chunks(struct zserv *client) __func__, zebra_route_string(client->proto), client->instance, client->session_id); - for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + for (ALL_LIST_ELEMENTS(lbl_mgr.lc_list, node, nnode, lmc)) { if (lmc->proto == client->proto && lmc->instance == client->instance && lmc->session_id == client->session_id && lmc->keep == 0) { @@ -136,6 +149,8 @@ void lm_hooks_register(void) hook_register(lm_client_disconnect, label_manager_disconnect); hook_register(lm_get_chunk, label_manager_get_chunk); hook_register(lm_release_chunk, label_manager_release_label_chunk); + hook_register(lm_write_label_block_config, + label_manager_write_label_block_config); } void lm_hooks_unregister(void) { @@ -143,6 +158,127 @@ void lm_hooks_unregister(void) hook_unregister(lm_client_disconnect, label_manager_disconnect); hook_unregister(lm_get_chunk, label_manager_get_chunk); hook_unregister(lm_release_chunk, label_manager_release_label_chunk); + hook_unregister(lm_write_label_block_config, + label_manager_write_label_block_config); +} + +static json_object *lmc_json(struct label_manager_chunk *lmc) +{ + json_object *json = json_object_new_object(); + + json_object_string_add(json, "protocol", zebra_route_string(lmc->proto)); + json_object_int_add(json, "instance", lmc->instance); + json_object_int_add(json, "sessionId", lmc->session_id); + json_object_int_add(json, "start", lmc->start); + json_object_int_add(json, "end", lmc->end); + json_object_boolean_add(json, "dynamic", lmc->is_dynamic); + return json; +} + +DEFPY(show_label_table, show_label_table_cmd, "show debugging label-table [json$uj]", + SHOW_STR + DEBUG_STR + "Display allocated label chunks\n" + JSON_STR) +{ + struct label_manager_chunk *lmc; + struct listnode *node; + json_object *json_array = NULL, *json_global = NULL, *json_dyn_block; + + if (uj) { + json_array = json_object_new_array(); + json_global = json_object_new_object(); + json_dyn_block = json_object_new_object(); + json_object_int_add(json_dyn_block, "lowerBound", + lbl_mgr.dynamic_block_start); + json_object_int_add(json_dyn_block, "upperBound", + lbl_mgr.dynamic_block_end); + json_object_object_add(json_global, "dynamicBlock", + json_dyn_block); + } else + vty_out(vty, "Dynamic block: lower-bound %u, upper-bound %u\n", + lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end); + + for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + if (uj) { + json_object_array_add(json_array, lmc_json(lmc)); + continue; + } + vty_out(vty, "Proto %s: [%u/%u]\n", + zebra_route_string(lmc->proto), lmc->start, lmc->end); + } + if (uj) { + json_object_object_add(json_global, "chunks", json_array); + vty_json(vty, json_global); + } + return CMD_SUCCESS; +} + +DEFPY(mpls_label_dynamic_block, mpls_label_dynamic_block_cmd, + "[no$no] mpls label dynamic-block [(16-1048575)$start (16-1048575)$end]", + NO_STR + MPLS_STR + "Label configuration\n" + "Configure dynamic label block\n" + "Start label\n" + "End label\n") +{ + struct listnode *node; + struct label_manager_chunk *lmc; + + /* unset dynamic range */ + if (no || + (start == MPLS_LABEL_UNRESERVED_MIN && end == MPLS_LABEL_MAX)) { + lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN; + lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX; + return CMD_SUCCESS; + } + if (!start || !end) { + vty_out(vty, + "%% label dynamic-block, range missing, aborting\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (start > end) { + vty_out(vty, + "%% label dynamic-block, wrong range (%ld > %ld), aborting\n", + start, end); + return CMD_WARNING_CONFIG_FAILED; + } + + for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + if (lmc->proto == NO_PROTO) + continue; + if (!lmc->is_dynamic && lmc->start >= (uint32_t)start && + lmc->end <= (uint32_t)end) { + vty_out(vty, + "%% Found a static label chunk [%u-%u] for %s in conflict with the dynamic label block\n", + lmc->start, lmc->end, + zebra_route_string(lmc->proto)); + return CMD_WARNING_CONFIG_FAILED; + } else if (lmc->is_dynamic && (lmc->end > (uint32_t)end || + lmc->start < (uint32_t)start)) { + vty_out(vty, + "%% Found a dynamic label chunk [%u-%u] for %s outside the new dynamic label block, consider restart the service\n", + lmc->start, lmc->end, + zebra_route_string(lmc->proto)); + } + } + lbl_mgr.dynamic_block_start = start; + lbl_mgr.dynamic_block_end = end; + return CMD_SUCCESS; +} + +static int label_manager_write_label_block_config(struct vty *vty, + struct zebra_vrf *zvrf) +{ + if (zvrf_id(zvrf) != VRF_DEFAULT) + return 0; + if (lbl_mgr.dynamic_block_start == MPLS_LABEL_UNRESERVED_MIN && + lbl_mgr.dynamic_block_end == MPLS_LABEL_MAX) + return 0; + vty_out(vty, "mpls label dynamic-block %u %u\n", + lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end); + return 1; } /** @@ -152,6 +288,8 @@ void label_manager_init(void) { lbl_mgr.lc_list = list_new(); lbl_mgr.lc_list->del = delete_label_chunk; + lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN; + lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX; hook_register(zserv_client_close, lm_client_disconnect_cb); /* register default hooks for the label manager actions */ @@ -159,12 +297,20 @@ void label_manager_init(void) /* notify any external module that we are done */ hook_call(lm_cbs_inited); + + install_element(VIEW_NODE, &show_label_table_cmd); + install_element(CONFIG_NODE, &mpls_label_dynamic_block_cmd); +} + +void label_manager_terminate(void) +{ + list_delete(&lbl_mgr.lc_list); } /* alloc and fill a label chunk */ struct label_manager_chunk * create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, - uint8_t keep, uint32_t start, uint32_t end) + uint8_t keep, uint32_t start, uint32_t end, bool is_dynamic) { /* alloc chunk, fill it and return it */ struct label_manager_chunk *lmc = @@ -176,6 +322,7 @@ create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, lmc->instance = instance; lmc->session_id = session_id; lmc->keep = keep; + lmc->is_dynamic = is_dynamic; return lmc; } @@ -203,6 +350,15 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, return NULL; } + if ((lbl_mgr.dynamic_block_start != MPLS_LABEL_UNRESERVED_MIN || + lbl_mgr.dynamic_block_end != MPLS_LABEL_MAX) && + base >= lbl_mgr.dynamic_block_start && + end <= lbl_mgr.dynamic_block_end) { + zlog_warn("Invalid LM request arguments: base: %u, size: %u for %s in conflict with the dynamic label block", + base, size, zebra_route_string(proto)); + return NULL; + } + /* Scan the existing chunks to see if the requested range of labels * falls inside any of such chunks */ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { @@ -234,7 +390,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, /* insert chunk between existing chunks */ if (insert_node) { lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); listnode_add_before(lbl_mgr.lc_list, insert_node, lmc); return lmc; } @@ -257,7 +413,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, } lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); if (last_node) listnode_add_before(lbl_mgr.lc_list, last_node, lmc); else @@ -268,7 +424,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, /* create a new chunk past all the existing ones and link at * tail */ lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); listnode_add(lbl_mgr.lc_list, lmc); return lmc; } @@ -293,9 +449,13 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, { struct label_manager_chunk *lmc; struct listnode *node; - uint32_t prev_end = MPLS_LABEL_UNRESERVED_MIN; + uint32_t prev_end = lbl_mgr.dynamic_block_start - 1; + struct label_manager_chunk *lmc_block_last = NULL; - /* handle chunks request with a specific base label */ + /* handle chunks request with a specific base label + * - static label requests: BGP hardset value, Pathd + * - segment routing label requests + */ if (base != MPLS_LABEL_BASE_ANY) return assign_specific_label_chunk(proto, instance, session_id, keep, size, base); @@ -305,37 +465,44 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, /* first check if there's one available */ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { - if (lmc->proto == NO_PROTO - && lmc->end - lmc->start + 1 == size) { + if (lmc->start <= prev_end) + continue; + if (lmc->proto == NO_PROTO && + lmc->end - lmc->start + 1 == size && + lmc->end <= lbl_mgr.dynamic_block_end) { lmc->proto = proto; lmc->instance = instance; lmc->session_id = session_id; lmc->keep = keep; + lmc->is_dynamic = true; return lmc; } /* check if we hadve a "hole" behind us that we can squeeze into */ - if ((lmc->start > prev_end) && (lmc->start - prev_end > size)) { + if (lmc->start - prev_end > size && + prev_end + 1 + size <= lbl_mgr.dynamic_block_end) { lmc = create_label_chunk(proto, instance, session_id, keep, prev_end + 1, - prev_end + size); + prev_end + size, true); listnode_add_before(lbl_mgr.lc_list, node, lmc); return lmc; } prev_end = lmc->end; + + /* check if we have a chunk that goes over the end block */ + if (lmc->end > lbl_mgr.dynamic_block_end) + continue; + lmc_block_last = lmc; } /* otherwise create a new one */ uint32_t start_free; - if (list_isempty(lbl_mgr.lc_list)) - start_free = MPLS_LABEL_UNRESERVED_MIN; + if (lmc_block_last == NULL) + start_free = lbl_mgr.dynamic_block_start; else - start_free = ((struct label_manager_chunk *)listgetdata( - listtail(lbl_mgr.lc_list))) - ->end - + 1; + start_free = lmc_block_last->end + 1; - if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) { + if (start_free > lbl_mgr.dynamic_block_end - size + 1) { flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS, "Reached max labels. Start: %u, size: %u", start_free, size); @@ -344,7 +511,7 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, /* create chunk and link at tail */ lmc = create_label_chunk(proto, instance, session_id, keep, start_free, - start_free + size - 1); + start_free + size - 1, true); listnode_add(lbl_mgr.lc_list, lmc); return lmc; } @@ -399,13 +566,14 @@ int release_label_chunk(uint8_t proto, unsigned short instance, "%s: Daemon mismatch!!", __func__); continue; } - lmc->proto = NO_PROTO; - lmc->instance = 0; - lmc->session_id = 0; - lmc->keep = 0; ret = 0; break; } + if (lmc) { + list_delete_node(lbl_mgr.lc_list, node); + delete_label_chunk(lmc); + } + if (ret != 0) flog_err(EC_ZEBRA_LM_UNRELEASED_CHUNK, "%s: Label chunk not released!!", __func__); @@ -435,7 +603,25 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc, { *lmc = assign_label_chunk(client->proto, client->instance, client->session_id, keep, size, base); - return lm_get_chunk_response(*lmc, client, vrf_id); + /* Respond to a get_chunk request */ + if (!*lmc) { + if (base == MPLS_LABEL_BASE_ANY) + flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, + "Unable to assign Label Chunk size %u to %s instance %u", + size, zebra_route_string(client->proto), + client->instance); + else + flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, + "Unable to assign Label Chunk %u - %u to %s instance %u", + base, base + size - 1, + zebra_route_string(client->proto), + client->instance); + } else if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", + (*lmc)->start, (*lmc)->end, + zebra_route_string(client->proto), client->instance); + + return zsend_assign_label_chunk_response(client, vrf_id, *lmc); } /* Respond to a connect request */ @@ -454,22 +640,6 @@ int lm_client_connect_response(uint8_t proto, uint16_t instance, return zsend_label_manager_connect_response(client, vrf_id, result); } -/* Respond to a get_chunk request */ -int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, - vrf_id_t vrf_id) -{ - if (!lmc) - flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, - "Unable to assign Label Chunk to %s instance %u", - zebra_route_string(client->proto), client->instance); - else if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", - lmc->start, lmc->end, - zebra_route_string(client->proto), client->instance); - - return zsend_assign_label_chunk_response(client, vrf_id, lmc); -} - void label_manager_close(void) { list_delete(&lbl_mgr.lc_list); diff --git a/zebra/label_manager.h b/zebra/label_manager.h index cfbb4bd169..03cf6a6813 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -42,6 +42,7 @@ struct label_manager_chunk { unsigned short instance; uint32_t session_id; uint8_t keep; + uint8_t is_dynamic; /* Tell if chunk is dynamic or static */ uint32_t start; /* First label of the chunk */ uint32_t end; /* Last label of the chunk */ }; @@ -61,11 +62,14 @@ DECLARE_HOOK(lm_get_chunk, DECLARE_HOOK(lm_release_chunk, (struct zserv *client, uint32_t start, uint32_t end), (client, start, end)); +DECLARE_HOOK(lm_write_label_block_config, + (struct vty *vty, struct zebra_vrf *zvrf), + (vty, zvrf)); DECLARE_HOOK(lm_cbs_inited, (), ()); -/* declare wrappers to be called in zapi_msg.c (as hooks must be called in - * source file where they were defined) +/* declare wrappers to be called in zapi_msg.c or zebra_mpls_vty.c (as hooks + * must be called in source file where they were defined) */ void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id); void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, @@ -73,18 +77,17 @@ void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, vrf_id_t vrf_id); void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end); +int lm_write_label_block_config_call(struct vty *vty, struct zebra_vrf *zvrf); /* API for an external LM to return responses for requests */ int lm_client_connect_response(uint8_t proto, uint16_t instance, uint32_t session_id, vrf_id_t vrf_id, uint8_t result); -int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, - vrf_id_t vrf_id); /* convenience function to allocate an lmc to be consumed by the above API */ struct label_manager_chunk * create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, - uint8_t keep, uint32_t start, uint32_t end); + uint8_t keep, uint32_t start, uint32_t end, bool is_dynamic); void delete_label_chunk(void *val); /* register/unregister callbacks for hooks */ @@ -97,9 +100,13 @@ void lm_hooks_unregister(void); */ struct label_manager { struct list *lc_list; + uint32_t dynamic_block_start; + uint32_t dynamic_block_end; }; void label_manager_init(void); +void label_manager_terminate(void); + struct label_manager_chunk * assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, uint8_t keep, uint32_t size, uint32_t base); diff --git a/zebra/main.c b/zebra/main.c index 81a3066445..d83f1d0491 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -5,6 +5,10 @@ #include <zebra.h> +#ifdef GNU_LINUX +#include <linux/rtnetlink.h> +#endif + #include <lib/version.h> #include "getopt.h" #include "command.h" @@ -21,6 +25,7 @@ #include "affinitymap.h" #include "routemap.h" #include "routing_nb.h" +#include "mgmt_be_client.h" #include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" @@ -54,13 +59,13 @@ pid_t pid; /* Pacify zclient.o in libfrr, which expects this variable. */ struct event_loop *master; +struct mgmt_be_client *mgmt_be_client; + /* Route retain mode flag. */ int retain_mode = 0; int graceful_restart; -bool v6_rr_semantics = false; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -69,24 +74,30 @@ uint32_t rcvbufsize = RCVBUFSIZE_MIN; uint32_t rcvbufsize = 128 * 1024; #endif +uint32_t rt_table_main_id = RT_TABLE_MAIN; + #define OPTION_V6_RR_SEMANTICS 2000 #define OPTION_ASIC_OFFLOAD 2001 +#define OPTION_V6_WITH_V4_NEXTHOP 2002 /* Command line options. */ const struct option longopts[] = { - {"batch", no_argument, NULL, 'b'}, - {"allow_delete", no_argument, NULL, 'a'}, - {"socket", required_argument, NULL, 'z'}, - {"ecmp", required_argument, NULL, 'e'}, - {"retain", no_argument, NULL, 'r'}, - {"graceful_restart", required_argument, NULL, 'K'}, - {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD}, + { "batch", no_argument, NULL, 'b' }, + { "allow_delete", no_argument, NULL, 'a' }, + { "socket", required_argument, NULL, 'z' }, + { "ecmp", required_argument, NULL, 'e' }, + { "retain", no_argument, NULL, 'r' }, + { "graceful_restart", required_argument, NULL, 'K' }, + { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, + { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK - {"vrfwnetns", no_argument, NULL, 'n'}, - {"nl-bufsize", required_argument, NULL, 's'}, - {"v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS}, + { "vrfwnetns", no_argument, NULL, 'n' }, + { "nl-bufsize", required_argument, NULL, 's' }, + { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {0}}; + {"routing-table", optional_argument, NULL, 'R'}, + { 0 } +}; zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, @@ -134,6 +145,10 @@ static void sigint(void) zlog_notice("Terminating on signal"); + nb_oper_cancel_all_walks(); + mgmt_be_client_destroy(mgmt_be_client); + mgmt_be_client = NULL; + atomic_store_explicit(&zrouter.in_shutdown, true, memory_order_relaxed); @@ -188,6 +203,13 @@ static void sigint(void) rib_update_finish(); list_delete(&zrouter.client_list); + list_delete(&zrouter.stale_client_list); + + /* + * Besides other clean-ups zebra's vrf_disable() also enqueues installed + * routes for removal from the kernel, unless ZEBRA_VRF_RETAIN is set. + */ + vrf_iterate(vrf_disable); /* Indicate that all new dplane work has been enqueued. When that * work is complete, the dataplane will enqueue an event @@ -206,17 +228,31 @@ void zebra_finalize(struct event *dummy) vrf_terminate(); + /* + * Stop dplane thread and finish any cleanup + * This is before the zebra_ns_early_shutdown call + * because sockets that the dplane depends on are closed + * in those functions + */ + zebra_dplane_shutdown(); + ns_walk_func(zebra_ns_early_shutdown, NULL, NULL); zebra_ns_notify_close(); - /* Stop dplane thread and finish any cleanup */ - zebra_dplane_shutdown(); - /* Final shutdown of ns resources */ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + zebra_rib_terminate(); zebra_router_terminate(); + zebra_mpls_terminate(); + + zebra_pw_terminate(); + + zebra_srv6_terminate(); + + label_manager_terminate(); + ns_terminate(); frr_fini(); exit(0); @@ -260,19 +296,23 @@ static const struct frr_yang_module_info *const zebra_yang_modules[] = { }; /* clang-format on */ -FRR_DAEMON_INFO( - zebra, ZEBRA, .vty_port = ZEBRA_VTY_PORT, .flags = FRR_NO_ZCLIENT, - +/* clang-format off */ +FRR_DAEMON_INFO(zebra, ZEBRA, + .vty_port = ZEBRA_VTY_PORT, .proghelp = "Daemon which manages kernel routing table management and\nredistribution between different routing protocols.", - .signals = zebra_signals, .n_signals = array_size(zebra_signals), + .flags = FRR_NO_ZCLIENT, + + .signals = zebra_signals, + .n_signals = array_size(zebra_signals), .privs = &zserv_privs, .yang_modules = zebra_yang_modules, .n_yang_modules = array_size(zebra_yang_modules), ); +/* clang-format on */ /* Main startup routine. */ int main(int argc, char **argv) @@ -282,6 +322,7 @@ int main(int argc, char **argv) struct sockaddr_storage dummy; socklen_t dummylen; bool asic_offload = false; + bool v6_with_v4_nexthop = false; bool notify_on_ack = true; graceful_restart = 0; @@ -289,27 +330,28 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); - frr_opt_add( - "baz:e:rK:s:" + frr_opt_add("baz:e:rK:s:R:" #ifdef HAVE_NETLINK - "n" + "n" #endif - , - longopts, - " -b, --batch Runs in batch mode\n" - " -a, --allow_delete Allow other processes to delete zebra routes\n" - " -z, --socket Set path of zebra socket\n" - " -e, --ecmp Specify ECMP to use.\n" - " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" - " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + , + longopts, + " -b, --batch Runs in batch mode\n" + " -a, --allow_delete Allow other processes to delete zebra routes\n" + " -z, --socket Set path of zebra socket\n" + " -e, --ecmp Specify ECMP to use.\n" + " -r, --retain When program terminates, retain added route by zebra.\n" + " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" + " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK - " -s, --nl-bufsize Set netlink receive buffer size\n" - " -n, --vrfwnetns Use NetNS as VRF backend\n" - " --v6-rr-semantics Use v6 RR semantics\n" + " -s, --nl-bufsize Set netlink receive buffer size\n" + " -n, --vrfwnetns Use NetNS as VRF backend\n" + " --v6-rr-semantics Use v6 RR semantics\n" #else - " -s, Set kernel socket receive buffer size\n" + " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ + " -R, --routing-table Set kernel routing table\n" ); while (1) { @@ -364,12 +406,15 @@ int main(int argc, char **argv) "Rcvbufsize is smaller than recommended value: %d\n", RCVBUFSIZE_MIN); break; + case 'R': + rt_table_main_id = atoi(optarg); + break; #ifdef HAVE_NETLINK case 'n': vrf_configure_backend(VRF_BACKEND_NETNS); break; case OPTION_V6_RR_SEMANTICS: - v6_rr_semantics = true; + zrouter.v6_rr_semantics = true; break; case OPTION_ASIC_OFFLOAD: if (!strcmp(optarg, "notify_on_offload")) @@ -378,6 +423,9 @@ int main(int argc, char **argv) notify_on_ack = true; asic_offload = true; break; + case OPTION_V6_WITH_V4_NEXTHOP: + v6_with_v4_nexthop = true; + break; #endif /* HAVE_NETLINK */ default: frr_help_exit(1); @@ -387,9 +435,9 @@ int main(int argc, char **argv) zrouter.master = frr_init(); /* Zebra related initialize. */ - zebra_router_init(asic_offload, notify_on_ack); + zebra_router_init(asic_offload, notify_on_ack, v6_with_v4_nexthop); zserv_init(); - rib_init(); + zebra_rib_init(); zebra_if_init(); zebra_debug_init(); @@ -399,8 +447,12 @@ int main(int argc, char **argv) zebra_ns_init(); router_id_cmd_init(); zebra_vty_init(); - access_list_init(); + mgmt_be_client = mgmt_be_client_create("zebra", NULL, 0, + zrouter.master); + access_list_init_new(true); prefix_list_init(); + + rtadv_init(); rtadv_cmd_init(); /* PTM socket */ #ifdef ZEBRA_PTM_SUPPORT diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c index 7352dfb2ee..002d2c7bf6 100644 --- a/zebra/netconf_netlink.c +++ b/zebra/netconf_netlink.c @@ -6,11 +6,14 @@ * Donald Sharp */ #include <zebra.h> +#include <fcntl.h> #ifdef HAVE_NETLINK /* Netlink OSes only */ #include <ns.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> #include "linux/netconf.h" #include "lib/lib_errors.h" diff --git a/zebra/redistribute.c b/zebra/redistribute.c index d2fa85eb64..11c1330398 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -16,6 +16,7 @@ #include "log.h" #include "vrf.h" #include "srcdest_table.h" +#include "frrdistance.h" #include "zebra/rib.h" #include "zebra/zebra_router.h" @@ -28,6 +29,7 @@ #include "zebra/zapi_msg.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_neigh.h" #define ZEBRA_PTM_SUPPORT @@ -60,7 +62,7 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - if (!vrf_bitmap_check(client->redist_default[afi], vrf_id)) + if (!vrf_bitmap_check(&client->redist_default[afi], vrf_id)) continue; /* Lookup table. */ @@ -77,9 +79,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) RNODE_FOREACH_RE (rn, newre) { if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)) - zsend_redistribute_route( - ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, - rn, newre); + zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, + client, rn, newre, false); } route_unlock_node(rn); @@ -88,14 +89,26 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) /* Redistribute routes. */ static void zebra_redistribute(struct zserv *client, int type, - unsigned short instance, vrf_id_t vrf_id, + unsigned short instance, struct zebra_vrf *zvrf, int afi) { struct route_entry *newre; struct route_table *table; struct route_node *rn; + bool is_table_direct = false; + vrf_id_t vrf_id = zvrf_id(zvrf); + + if (type == ZEBRA_ROUTE_TABLE_DIRECT) { + if (vrf_id == VRF_DEFAULT) { + table = zebra_router_find_table(zvrf, instance, afi, + SAFI_UNICAST); + type = ZEBRA_ROUTE_ALL; + is_table_direct = true; + } else + return; + } else + table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); - table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); if (!table) return; @@ -125,11 +138,26 @@ static void zebra_redistribute(struct zserv *client, int type, continue; zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, rn, newre); + client, rn, newre, is_table_direct); } } /* + * Function to return a valid table id value if table-direct is used + * return 0 otherwise + * This function can be called only if zebra_redistribute_check returns TRUE + */ +static bool zebra_redistribute_is_table_direct(const struct route_entry *re) +{ + struct zebra_vrf *zvrf; + + zvrf = zebra_vrf_lookup_by_id(re->vrf_id); + if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) + return true; + return false; +} + +/* * Function to check if prefix is candidate for * redistribute. */ @@ -146,16 +174,27 @@ static bool zebra_redistribute_check(const struct route_node *rn, afi = family2afi(rn->p.family); zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) + if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) { + if (re->table && + redist_check_instance(&client->mi_redist + [afi][ZEBRA_ROUTE_TABLE_DIRECT], + re->table)) { + /* table-direct redistribution only for route entries which + * are on the default vrf, and that have table id different + * from the default table. + */ + return true; + } return false; + } /* If default route and redistributed */ if (is_default_prefix(&rn->p) && - vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) + vrf_bitmap_check(&client->redist_default[afi], re->vrf_id)) return true; /* If redistribute in enabled for zebra route all */ - if (vrf_bitmap_check(client->redist[afi][ZEBRA_ROUTE_ALL], re->vrf_id)) + if (vrf_bitmap_check(&client->redist[afi][ZEBRA_ROUTE_ALL], re->vrf_id)) return true; /* @@ -171,7 +210,7 @@ static bool zebra_redistribute_check(const struct route_node *rn, } /* If redistribution is enabled for give route type. */ - if (vrf_bitmap_check(client->redist[afi][re->type], re->vrf_id)) + if (vrf_bitmap_check(&client->redist[afi][re->type], re->vrf_id)) return true; return false; @@ -185,6 +224,7 @@ void redistribute_update(const struct route_node *rn, { struct listnode *node, *nnode; struct zserv *client; + bool is_table_direct; if (IS_ZEBRA_DEBUG_RIB) zlog_debug( @@ -210,11 +250,16 @@ void redistribute_update(const struct route_node *rn, re->vrf_id, re->table, re->type, re->distance, re->metric); } + is_table_direct = zebra_redistribute_is_table_direct(re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, rn, re); - } else if (zebra_redistribute_check(rn, prev_re, client)) + client, rn, re, + is_table_direct); + } else if (zebra_redistribute_check(rn, prev_re, client)) { + is_table_direct = zebra_redistribute_is_table_direct(prev_re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, rn, prev_re); + client, rn, prev_re, + is_table_direct); + } } } @@ -233,6 +278,7 @@ void redistribute_delete(const struct route_node *rn, struct listnode *node, *nnode; struct zserv *client; vrf_id_t vrfid; + bool is_table_direct; if (old_re) vrfid = old_re->vrf_id; @@ -256,12 +302,11 @@ void redistribute_delete(const struct route_node *rn, table = new_re->table; } - zlog_debug( - "%u:%u%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", - vrfid, table, rn, old_re, old_inst, - old_re ? zebra_route_string(old_re->type) : "None", - new_re, new_inst, - new_re ? zebra_route_string(new_re->type) : "None"); + zlog_debug("(%u:%u):%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", + vrfid, table, rn, old_re, old_inst, + old_re ? zebra_route_string(old_re->type) : "None", + new_re, new_inst, + new_re ? zebra_route_string(new_re->type) : "None"); } /* Skip invalid (e.g. linklocal) prefix */ @@ -286,9 +331,20 @@ void redistribute_delete(const struct route_node *rn, continue; /* Send a delete for the 'old' re to any subscribed client. */ - if (zebra_redistribute_check(rn, old_re, client)) + if (zebra_redistribute_check(rn, old_re, client)) { + /* + * SA is complaining that old_re could be false + * SA is wrong because old_re is checked for NULL + * in zebra_redistribute_check and false is + * returned in that case. Let's just make SA + * happy. + */ + assert(old_re); + is_table_direct = zebra_redistribute_is_table_direct(old_re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, rn, old_re); + client, rn, old_re, + is_table_direct); + } } } @@ -327,20 +383,19 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) instance)) { redist_add_instance(&client->mi_redist[afi][type], instance); - zebra_redistribute(client, type, instance, - zvrf_id(zvrf), afi); + zebra_redistribute(client, type, instance, zvrf, afi); } } else { - if (!vrf_bitmap_check(client->redist[afi][type], + if (!vrf_bitmap_check(&client->redist[afi][type], zvrf_id(zvrf))) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "%s: setting vrf %s(%u) redist bitmap", __func__, VRF_LOGNAME(zvrf->vrf), zvrf_id(zvrf)); - vrf_bitmap_set(client->redist[afi][type], + vrf_bitmap_set(&client->redist[afi][type], zvrf_id(zvrf)); - zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); + zebra_redistribute(client, type, 0, zvrf, afi); } } @@ -387,7 +442,7 @@ void zebra_redistribute_delete(ZAPI_HANDLER_ARGS) if (instance) redist_del_instance(&client->mi_redist[afi][type], instance); else - vrf_bitmap_unset(client->redist[afi][type], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->redist[afi][type], zvrf_id(zvrf)); stream_failure: return; @@ -405,7 +460,7 @@ void zebra_redistribute_default_add(ZAPI_HANDLER_ARGS) return; } - vrf_bitmap_set(client->redist_default[afi], zvrf_id(zvrf)); + vrf_bitmap_set(&client->redist_default[afi], zvrf_id(zvrf)); zebra_redistribute_default(client, zvrf_id(zvrf)); stream_failure: @@ -424,7 +479,7 @@ void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS) return; } - vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->redist_default[afi], zvrf_id(zvrf)); stream_failure: return; @@ -473,6 +528,8 @@ void zebra_interface_down_update(struct interface *ifp) zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); } + + zebra_neigh_del_all(ifp); } /* Interface information update. */ @@ -589,9 +646,8 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", - ifp->name, ifp->vrf->vrf_id, new_vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s VRF Id %u -> %u", + ifp->name, ifp->vrf->vrf_id, new_vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -603,7 +659,6 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); client->ifdel_cnt++; zsend_interface_delete(client, ifp); - zsend_interface_vrf_update(client, ifp, new_vrf_id); } } @@ -616,9 +671,8 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", - ifp->name, old_vrf_id, ifp->vrf->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s VRF Id %u -> %u", + ifp->name, old_vrf_id, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -644,10 +698,9 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, afi = family2afi(rn->p.family); if (rmap_name) - ret = zebra_import_table_route_map_check( - afi, re->type, re->instance, &rn->p, - re->nhe->nhg.nexthop, - zvrf->vrf->vrf_id, re->tag, rmap_name); + ret = zebra_import_table_route_map_check(afi, re, &rn->p, + re->nhe->nhg.nexthop, + rmap_name); if (ret != RMAP_PERMITMATCH) { UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); @@ -661,9 +714,10 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) continue; - if (same->type == re->type && same->instance == re->instance - && same->table == re->table - && same->type != ZEBRA_ROUTE_CONNECT) + if (same->type == re->type && same->instance == re->instance && + same->table == re->table && + (same->type != ZEBRA_ROUTE_CONNECT && + same->type != ZEBRA_ROUTE_LOCAL)) break; } @@ -672,6 +726,8 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, zebra_del_import_table_entry(zvrf, rn, same); } + UNSET_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE); + newre = zebra_rib_route_entry_new( 0, ZEBRA_ROUTE_TABLE, re->table, re->flags, re->nhe_id, zvrf->table_id, re->metric, re->mtu, @@ -681,6 +737,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, copy_nexthops(&ng->nexthop, re->nhe->nhg.nexthop, NULL); rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng, false); + nexthop_group_delete(&ng); return 0; } @@ -712,7 +769,7 @@ int zebra_import_table(afi_t afi, vrf_id_t vrf_id, uint32_t table_id, struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf_id); if (!is_zebra_valid_kernel_table(table_id) - || (table_id == RT_TABLE_MAIN)) + || (table_id == rt_table_main_id)) return -1; if (afi >= AFI_MAX) diff --git a/zebra/rib.h b/zebra/rib.h index a56bb05d68..a721f4bac4 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -85,25 +85,12 @@ struct route_entry { */ struct nhg_hash_entry *nhe; - /* Nexthop group from FIB (optional), reflecting what is actually - * installed in the FIB if that differs. The 'backup' group is used - * when backup nexthops are present in the route's nhg. - */ - struct nexthop_group fib_ng; - struct nexthop_group fib_backup_ng; - /* Nexthop group hash entry IDs. The "installed" id is the id * used in linux/netlink, if available. */ uint32_t nhe_id; uint32_t nhe_installed_id; - /* Tag */ - route_tag_t tag; - - /* Uptime. */ - time_t uptime; - /* Type of this route. */ int type; @@ -160,13 +147,30 @@ struct route_entry { /* Distance. */ uint8_t distance; + /* Tag */ + route_tag_t tag; + + /* Uptime. */ + time_t uptime; + struct re_opaque *opaque; + + /* Nexthop group from FIB (optional), reflecting what is actually + * installed in the FIB if that differs. The 'backup' group is used + * when backup nexthops are present in the route's nhg. + */ + struct nexthop_group fib_ng; + struct nexthop_group fib_backup_ng; }; #define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type) #define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type) +/* Define route types that are equivalent to "connected". */ +#define RIB_CONNECTED_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_CONNECT || (R)->type == ZEBRA_ROUTE_LOCAL || (R)->type == ZEBRA_ROUTE_NHRP) + /* meta-queue structure: * sub-queue 0: nexthop group objects * sub-queue 1: EVPN/VxLAN objects @@ -181,6 +185,10 @@ struct route_entry { * don't generate routes */ #define MQ_SIZE 11 + +/* For checking that an object has already queued in some sub-queue */ +#define MQ_BIT_MASK ((1 << MQ_SIZE) - 1) + struct meta_queue { struct list *subq[MQ_SIZE]; uint32_t size; /* sum of lengths of all subqueues */ @@ -329,14 +337,16 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new_nhghe); /* NHG replace has happend, we have to update route_entry pointers to new one */ -void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, - struct nhg_hash_entry *new_entry); +int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, + struct nhg_hash_entry *new_entry); #define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re) extern void _route_entry_dump(const char *func, union prefixconstptr pp, union prefixconstptr src_pp, const struct route_entry *re); +void zebra_rib_route_entry_free(struct route_entry *re); + struct route_entry * zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, uint8_t instance, uint32_t flags, uint32_t nhe_id, uint32_t table_id, @@ -406,7 +416,8 @@ extern void rib_update_table(struct route_table *table, extern void rib_sweep_route(struct event *t); extern void rib_sweep_table(struct route_table *table); extern void rib_close_table(struct route_table *table); -extern void rib_init(void); +extern void zebra_rib_init(void); +extern void zebra_rib_terminate(void); extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance); extern unsigned long rib_score_proto_table(uint8_t proto, unsigned short instance, @@ -421,6 +432,7 @@ extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx); /* Enqueue incoming nhg from proto daemon for processing */ extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe); +extern int rib_queue_nhe_del(struct nhg_hash_entry *nhe); /* Enqueue evpn route for processing */ int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, @@ -465,6 +477,13 @@ extern uint8_t route_distance(int type); extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, bool rt_delete); +/* + * rib_find_rn_from_ctx + * + * Returns a lock increased route_node for the appropriate + * table and prefix specified by the context. Developer + * should unlock the node when done. + */ extern struct route_node * rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx); @@ -612,7 +631,7 @@ extern void zebra_vty_init(void); extern pid_t pid; -extern bool v6_rr_semantics; +extern uint32_t rt_table_main_id; /* Name of hook calls */ #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" diff --git a/zebra/router-id.c b/zebra/router-id.c index ef87d924fe..2f251a79e5 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -109,7 +109,7 @@ int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) assert(!"Reached end of function we should never hit"); } -static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) +int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) { struct prefix after, before; struct listnode *node; @@ -241,256 +241,6 @@ void router_id_del_address(struct connected *ifc) zsend_router_id_update(client, afi, &after, zvrf_id(zvrf)); } -void router_id_write(struct vty *vty, struct zebra_vrf *zvrf) -{ - char space[2]; - - memset(space, 0, sizeof(space)); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - snprintf(space, sizeof(space), "%s", " "); - - if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY) { - vty_out(vty, "%sip router-id %pI4\n", space, - &zvrf->rid_user_assigned.u.prefix4); - } - if (!router_id_v6_is_any(&zvrf->rid6_user_assigned)) { - vty_out(vty, "%sipv6 router-id %pI6\n", space, - &zvrf->rid_user_assigned.u.prefix6); - } -} - -DEFUN (ip_router_id, - ip_router_id_cmd, - "ip router-id A.B.C.D vrf NAME", - IP_STR - "Manually set the router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; - - argv_find(argv, argc, "A.B.C.D", &idx); - - if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV4_MAX_BITLEN; - rid.family = AF_INET; - - argv_find(argv, argc, "NAME", &idx); - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (ip_router_id, - router_id_cmd, - "router-id A.B.C.D vrf NAME", - "Manually set the router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR); - -DEFUN (ipv6_router_id, - ipv6_router_id_cmd, - "ipv6 router-id X:X::X:X vrf NAME", - IPV6_STR - "Manually set the router-id\n" - "IPv6 address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; - - argv_find(argv, argc, "X:X::X:X", &idx); - - if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV6_MAX_BITLEN; - rid.family = AF_INET6; - - argv_find(argv, argc, "NAME", &idx); - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - - -DEFUN (ip_router_id_in_vrf, - ip_router_id_in_vrf_cmd, - "ip router-id A.B.C.D", - IP_STR - "Manually set the router-id\n" - "IP address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - int idx = 0; - struct prefix rid; - - argv_find(argv, argc, "A.B.C.D", &idx); - - if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV4_MAX_BITLEN; - rid.family = AF_INET; - - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (ip_router_id_in_vrf, - router_id_in_vrf_cmd, - "router-id A.B.C.D", - "Manually set the router-id\n" - "IP address to use for router-id\n"); - -DEFUN (ipv6_router_id_in_vrf, - ipv6_router_id_in_vrf_cmd, - "ipv6 router-id X:X::X:X", - IP6_STR - "Manually set the IPv6 router-id\n" - "IPV6 address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - int idx = 0; - struct prefix rid; - - argv_find(argv, argc, "X:X::X:X", &idx); - - if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV6_MAX_BITLEN; - rid.family = AF_INET6; - - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - -DEFUN (no_ip_router_id, - no_ip_router_id_cmd, - "no ip router-id [A.B.C.D vrf NAME]", - NO_STR - IP_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id = VRF_DEFAULT; - struct zebra_vrf *zvrf; - - rid.u.prefix4.s_addr = 0; - rid.prefixlen = 0; - rid.family = AF_INET; - - if (argv_find(argv, argc, "NAME", &idx)) - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (no_ip_router_id, - no_router_id_cmd, - "no router-id [A.B.C.D vrf NAME]", - NO_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR); - -DEFUN (no_ipv6_router_id, - no_ipv6_router_id_cmd, - "no ipv6 router-id [X:X::X:X vrf NAME]", - NO_STR - IPV6_STR - "Remove the manually configured IPv6 router-id\n" - "IPv6 address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id = VRF_DEFAULT; - struct zebra_vrf *zvrf; - - memset(&rid, 0, sizeof(rid)); - rid.family = AF_INET; - - if (argv_find(argv, argc, "NAME", &idx)) - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - -DEFUN (no_ip_router_id_in_vrf, - no_ip_router_id_in_vrf_cmd, - "no ip router-id [A.B.C.D]", - NO_STR - IP_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - struct prefix rid; - - rid.u.prefix4.s_addr = 0; - rid.prefixlen = 0; - rid.family = AF_INET; - - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (no_ip_router_id_in_vrf, - no_router_id_in_vrf_cmd, - "no router-id [A.B.C.D]", - NO_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n"); - -DEFUN (no_ipv6_router_id_in_vrf, - no_ipv6_router_id_in_vrf_cmd, - "no ipv6 router-id [X:X::X:X]", - NO_STR - IP6_STR - "Remove the manually configured IPv6 router-id\n" - "IPv6 address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - struct prefix rid; - - memset(&rid, 0, sizeof(rid)); - rid.family = AF_INET; - - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - DEFUN (show_ip_router_id, show_ip_router_id_cmd, "show [ip|ipv6] router-id [vrf NAME]", @@ -557,24 +307,6 @@ static int router_id_v6_cmp(void *a, void *b) void router_id_cmd_init(void) { - install_element(CONFIG_NODE, &ip_router_id_cmd); - install_element(CONFIG_NODE, &router_id_cmd); - install_element(CONFIG_NODE, &ipv6_router_id_cmd); - install_element(CONFIG_NODE, &no_ip_router_id_cmd); - install_element(CONFIG_NODE, &no_router_id_cmd); - install_element(CONFIG_NODE, &ip_router_id_in_vrf_cmd); - install_element(VRF_NODE, &ip_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &router_id_in_vrf_cmd); - install_element(VRF_NODE, &router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &ipv6_router_id_in_vrf_cmd); - install_element(VRF_NODE, &ipv6_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_ipv6_router_id_cmd); - install_element(CONFIG_NODE, &no_ip_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_ip_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_ipv6_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_ipv6_router_id_in_vrf_cmd); install_element(VIEW_NODE, &show_ip_router_id_cmd); } diff --git a/zebra/router-id.h b/zebra/router-id.h index 45860d8b7b..09ad4ec65e 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -25,8 +25,8 @@ extern void router_id_add_address(struct connected *c); extern void router_id_del_address(struct connected *c); extern void router_id_init(struct zebra_vrf *zvrf); extern void router_id_cmd_init(void); -extern void router_id_write(struct vty *vty, struct zebra_vrf *zvrf); extern int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf); +extern int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf); #ifdef __cplusplus } diff --git a/zebra/rt.h b/zebra/rt.h index 2e3495a037..e5dc26150a 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -25,7 +25,8 @@ extern "C" { #define RKERNEL_ROUTE(type) ((type) == ZEBRA_ROUTE_KERNEL) #define RSYSTEM_ROUTE(type) \ - ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT) + ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT || \ + (type) == ZEBRA_ROUTE_LOCAL) #ifndef HAVE_NETLINK /* @@ -84,6 +85,8 @@ extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); * state. */ extern void interface_list(struct zebra_ns *zns); +extern void interface_list_tunneldump(struct zebra_ns *zns); +extern void interface_list_second(struct zebra_ns *zns); extern void kernel_init(struct zebra_ns *zns); extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void macfdb_read(struct zebra_ns *zns); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index de01ced411..f092fc5c85 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -66,6 +66,7 @@ #include "zebra/zebra_evpn_mh.h" #include "zebra/zebra_trace.h" #include "zebra/zebra_neigh.h" +#include "lib/srv6.h" #ifndef AF_MPLS #define AF_MPLS 28 @@ -77,6 +78,8 @@ #define BR_SPH_LIST_SIZE 10 #endif +DEFINE_MTYPE_STATIC(LIB, NH_SRV6, "Nexthop srv6"); + static vlanid_t filter_vlan = 0; /* We capture whether the current kernel supports nexthop ids; by @@ -275,6 +278,7 @@ int zebra2proto(int proto) proto = RTPROT_ZEBRA; break; case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_LOCAL: case ZEBRA_ROUTE_KERNEL: proto = RTPROT_KERNEL; break; @@ -363,7 +367,8 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) proto = ZEBRA_ROUTE_NHG; break; } - /* Intentional fall thru */ + proto = ZEBRA_ROUTE_KERNEL; + break; default: /* * When a user adds a new protocol this will show up @@ -380,33 +385,6 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) return proto; } -/* -Pending: create an efficient table_id (in a tree/hash) based lookup) - */ -vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - zvrf = vrf->info; - if (zvrf == NULL) - continue; - /* case vrf with netns : match the netnsid */ - if (vrf_is_backend_netns()) { - if (ns_id == zvrf_id(zvrf)) - return zvrf_id(zvrf); - } else { - /* VRF is VRF_BACKEND_VRF_LITE */ - if (zvrf->table_id != table_id) - continue; - return zvrf_id(zvrf); - } - } - - return VRF_DEFAULT; -} - /** * @parse_encap_mpls() - Parses encapsulated mpls attributes * @tb: Pointer to rtattr to look for nested items in. @@ -434,6 +412,36 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels) return num_labels; } +/** + * @parse_encap_seg6local_flavors() - Parses encapsulated SRv6 flavors + * attributes + * @tb: Pointer to rtattr to look for nested items in. + * @flv: Pointer to store SRv6 flavors info in. + * + * Return: 0 on success, non-zero on error + */ +static int parse_encap_seg6local_flavors(struct rtattr *tb, + struct seg6local_flavors_info *flv) +{ + struct rtattr *tb_encap[SEG6_LOCAL_FLV_MAX + 1] = {}; + + netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_FLV_MAX, tb); + + if (tb_encap[SEG6_LOCAL_FLV_OPERATION]) + flv->flv_ops = *(uint32_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_OPERATION]); + + if (tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]) + flv->lcblock_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCBLOCK_BITS]); + + if (tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]) + flv->lcnode_func_len = *(uint8_t *)RTA_DATA( + tb_encap[SEG6_LOCAL_FLV_LCNODE_FN_BITS]); + + return 0; +} + static enum seg6local_action_t parse_encap_seg6local(struct rtattr *tb, struct seg6local_context *ctx) @@ -461,6 +469,11 @@ parse_encap_seg6local(struct rtattr *tb, ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]); + if (tb_encap[SEG6_LOCAL_FLAVORS]) { + parse_encap_seg6local_flavors(tb_encap[SEG6_LOCAL_FLAVORS], + &ctx->flv); + } + return act; } @@ -468,19 +481,19 @@ static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs) { struct rtattr *tb_encap[SEG6_IPTUNNEL_MAX + 1] = {}; struct seg6_iptunnel_encap *ipt = NULL; - struct in6_addr *segments = NULL; + int i; netlink_parse_rtattr_nested(tb_encap, SEG6_IPTUNNEL_MAX, tb); - /* - * TODO: It's not support multiple SID list. - */ if (tb_encap[SEG6_IPTUNNEL_SRH]) { ipt = (struct seg6_iptunnel_encap *) RTA_DATA(tb_encap[SEG6_IPTUNNEL_SRH]); - segments = ipt->srh[0].segments; - *segs = segments[0]; - return 1; + + for (i = ipt->srh[0].first_segment; i >= 0; i--) + memcpy(&segs[i], &ipt->srh[0].segments[i], + sizeof(struct in6_addr)); + + return ipt->srh[0].first_segment + 1; } return 0; @@ -498,7 +511,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; - struct in6_addr seg6_segs = {}; + struct in6_addr segs[SRV6_MAX_SIDS] = {}; int num_segs = 0; vrf_id_t nh_vrf_id = vrf_id; @@ -547,7 +560,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE] && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE]) == LWTUNNEL_ENCAP_SEG6) { - num_segs = parse_encap_seg6(tb[RTA_ENCAP], &seg6_segs); + num_segs = parse_encap_seg6(tb[RTA_ENCAP], segs); } if (rtm->rtm_flags & RTNH_F_ONLINK) @@ -559,11 +572,21 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx); if (num_segs) - nexthop_add_srv6_seg6(&nh, &seg6_segs); + nexthop_add_srv6_seg6(&nh, segs, num_segs); return nh; } @@ -583,7 +606,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; struct seg6local_context seg6l_ctx = {}; - struct in6_addr seg6_segs = {}; + struct in6_addr segs[SRV6_MAX_SIDS] = {}; int num_segs = 0; struct rtattr *rtnh_tb[RTA_MAX + 1] = {}; @@ -639,7 +662,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE]) == LWTUNNEL_ENCAP_SEG6) { num_segs = parse_encap_seg6(rtnh_tb[RTA_ENCAP], - &seg6_segs); + segs); } } @@ -666,12 +689,23 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + /* Resolve default values for SRv6 flavors */ + if (seg6l_ctx.flv.flv_ops != + ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) { + if (seg6l_ctx.flv.lcblock_len == 0) + seg6l_ctx.flv.lcblock_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCBLOCK_LEN; + if (seg6l_ctx.flv.lcnode_func_len == 0) + seg6l_ctx.flv.lcnode_func_len = + ZEBRA_DEFAULT_SEG6_LOCAL_FLV_LCNODE_FN_LEN; + } + if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) nexthop_add_srv6_seg6local(nh, seg6l_act, &seg6l_ctx); if (num_segs) - nexthop_add_srv6_seg6(nh, &seg6_segs); + nexthop_add_srv6_seg6(nh, segs, num_segs); if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); @@ -790,7 +824,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, table = rtm->rtm_table; /* Map to VRF */ - vrf_id = vrf_lookup_by_table(table, ns_id); + 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)) @@ -993,6 +1027,8 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, re, ng, startup, ctx); if (ng) nexthop_group_delete(&ng); + if (ctx) + zebra_rib_route_entry_free(re); } else { /* * I really don't see how this is possible @@ -1079,7 +1115,7 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, else table = rtm->rtm_table; - vrf = vrf_lookup_by_table(table, ns_id); + vrf = zebra_vrf_lookup_by_table(table, ns_id); if (tb[RTA_IIF]) iif = *(int *)RTA_DATA(tb[RTA_IIF]); @@ -1485,37 +1521,80 @@ static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, } static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen, - const struct in6_addr *seg) + struct seg6_seg_stack *segs) { struct seg6_iptunnel_encap *ipt; struct ipv6_sr_hdr *srh; - const size_t srhlen = 24; + size_t srhlen; + int i; - /* - * Caution: Support only SINGLE-SID, not MULTI-SID - * This function only supports the case where segs represents - * a single SID. If you want to extend the SRv6 functionality, - * you should improve the Boundary Check. - * Ex. In case of set a SID-List include multiple-SIDs as an - * argument of the Transit Behavior, we must support variable - * boundary check for buflen. - */ - if (buflen < (sizeof(struct seg6_iptunnel_encap) + - sizeof(struct ipv6_sr_hdr) + 16)) + if (segs->num_segs > SRV6_MAX_SEGS) { + /* Exceeding maximum supported SIDs */ + return -1; + } + + srhlen = SRH_BASE_HEADER_LENGTH + SRH_SEGMENT_LENGTH * segs->num_segs; + + if (buflen < (sizeof(struct seg6_iptunnel_encap) + srhlen)) return -1; memset(buffer, 0, buflen); ipt = (struct seg6_iptunnel_encap *)buffer; ipt->mode = SEG6_IPTUN_MODE_ENCAP; - srh = ipt->srh; + + srh = (struct ipv6_sr_hdr *)&ipt->srh; srh->hdrlen = (srhlen >> 3) - 1; srh->type = 4; - srh->segments_left = 0; - srh->first_segment = 0; - memcpy(&srh->segments[0], seg, sizeof(struct in6_addr)); + srh->segments_left = segs->num_segs - 1; + srh->first_segment = segs->num_segs - 1; + + for (i = 0; i < segs->num_segs; i++) { + memcpy(&srh->segments[i], &segs->seg[i], + sizeof(struct in6_addr)); + } + + return sizeof(struct seg6_iptunnel_encap) + srhlen; +} + +static bool +_netlink_nexthop_encode_seg6local_flavor(const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, size_t buflen) +{ + struct rtattr *nest; + struct seg6local_flavors_info *flv; + + assert(nexthop); + + if (!nexthop->nh_srv6) + return false; + + flv = &nexthop->nh_srv6->seg6local_ctx.flv; + + if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC) + return true; + + nest = nl_attr_nest(nlmsg, buflen, SEG6_LOCAL_FLAVORS); + if (!nest) + return false; + + if (!nl_attr_put32(nlmsg, buflen, SEG6_LOCAL_FLV_OPERATION, + flv->flv_ops)) + return false; - return srhlen + 4; + if (flv->lcblock_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCBLOCK_BITS, + flv->lcblock_len)) + return false; + + if (flv->lcnode_func_len) + if (!nl_attr_put8(nlmsg, buflen, SEG6_LOCAL_FLV_LCNODE_FN_BITS, + flv->lcnode_func_len)) + return false; + + nl_attr_nest_end(nlmsg, nest); + + return true; } /* This function takes a nexthop as argument and adds @@ -1649,10 +1728,17 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nexthop->nh_srv6->seg6local_action); return false; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nexthop, nlmsg, req_size)) + return false; + nl_attr_nest_end(nlmsg, nest); } - if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) { + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs && + !sid_zero(nexthop->nh_srv6->seg6_segs)) { char tun_buf[4096]; ssize_t tun_len; struct rtattr *nest; @@ -1663,8 +1749,9 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP); if (!nest) return false; - tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), - &nexthop->nh_srv6->seg6_segs); + tun_len = + fill_seg6ipt_encap(tun_buf, sizeof(tun_buf), + nexthop->nh_srv6->seg6_segs); if (tun_len < 0) return false; if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH, @@ -2087,10 +2174,10 @@ static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer * otherwise the number of bytes written to buf. */ -ssize_t netlink_route_multipath_msg_encode(int cmd, - struct zebra_dplane_ctx *ctx, +ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen, - bool fpm, bool force_nhg) + bool fpm, bool force_nhg, + bool force_rr) { int bytelen; struct nexthop *nexthop = NULL; @@ -2124,8 +2211,10 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if ((cmd == RTM_NEWROUTE) && - ((p->family == AF_INET) || v6_rr_semantics)) + if (((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || kernel_nexthops_supported() || + zrouter.v6_rr_semantics)) || + force_rr) req->n.nlmsg_flags |= NLM_F_REPLACE; req->n.nlmsg_type = cmd; @@ -2328,19 +2417,21 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, p, routedesc, bytelen, nexthop, &req->n, &req->r, datalen, cmd)) return 0; + + /* + * Add encapsulation information when + * installing via FPM. + */ + if (fpm) { + if (!netlink_route_nexthop_encap(&req->n, + datalen, + nexthop)) + return 0; + } + nexthop_num++; break; } - - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) { - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) - return 0; - } } if (setsrc) { @@ -2387,6 +2478,16 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, tag)) return 0; + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) { + if (!netlink_route_nexthop_encap( + &req->n, datalen, nexthop)) + return 0; + } + if (!setsrc && src1) { if (p->family == AF_INET) src.ipv4 = src1->ipv4; @@ -2400,23 +2501,6 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, nl_attr_nest_end(&req->n, nest); - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) { - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), - nexthop)) { - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - continue; - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) - return 0; - } - } - - if (setsrc) { if (p->family == AF_INET) { if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, @@ -2503,7 +2587,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) * are trying to give me. So now we have this little hack. */ if (mroute->family == AF_INET) - actual_table = (zvrf->table_id == RT_TABLE_MAIN) + actual_table = (zvrf->table_id == rt_table_main_id) ? RT_TABLE_DEFAULT : zvrf->table_id; else @@ -2543,7 +2627,7 @@ static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, if (IS_ZEBRA_DEBUG_KERNEL) { if (i == 0) - snprintf(buf, sizeof(buf1), "group %u", + snprintf(buf, sizeof(buf), "group %u", grp[i].id); else { snprintf(buf1, sizeof(buf1), "/%u", @@ -2888,10 +2972,17 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, __func__, action); return 0; } + + if (!_netlink_nexthop_encode_seg6local_flavor( + nh, &req->n, buflen)) + return false; + nl_attr_nest_end(&req->n, nest); } - if (!sid_zero(&nh->nh_srv6->seg6_segs)) { + if (nh->nh_srv6->seg6_segs && + nh->nh_srv6->seg6_segs->num_segs && + !sid_zero(nh->nh_srv6->seg6_segs)) { char tun_buf[4096]; ssize_t tun_len; struct rtattr *nest; @@ -2904,9 +2995,9 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, NHA_ENCAP | NLA_F_NESTED); if (!nest) return 0; - tun_len = fill_seg6ipt_encap(tun_buf, - sizeof(tun_buf), - &nh->nh_srv6->seg6_segs); + tun_len = fill_seg6ipt_encap( + tun_buf, sizeof(tun_buf), + nh->nh_srv6->seg6_segs); if (tun_len < 0) return 0; if (!nl_attr_put(&req->n, buflen, @@ -2980,14 +3071,14 @@ static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf, - buflen, false, false); + buflen, false, false, false); } enum netlink_msg_status @@ -3001,8 +3092,8 @@ netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { cmd = RTM_NEWROUTE; } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { - - if (p->family == AF_INET || v6_rr_semantics) { + if (p->family == AF_INET || kernel_nexthops_supported() || + zrouter.v6_rr_semantics) { /* Single 'replace' operation */ /* @@ -4151,11 +4242,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * - struct ethaddr mac; (for NEW) */ if (h->nlmsg_type == RTM_NEWNEIGH) - cmd = ZEBRA_NHRP_NEIGH_ADDED; + cmd = ZEBRA_NEIGH_ADDED; else if (h->nlmsg_type == RTM_GETNEIGH) - cmd = ZEBRA_NHRP_NEIGH_GET; + cmd = ZEBRA_NEIGH_GET; else if (h->nlmsg_type == RTM_DELNEIGH) - cmd = ZEBRA_NHRP_NEIGH_REMOVED; + cmd = ZEBRA_NEIGH_REMOVED; else { zlog_debug("%s(): unknown nlmsg type %u", __func__, h->nlmsg_type); @@ -4165,20 +4256,18 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* copy LLADDR information */ l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]); } - if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) { - union sockunion link_layer_ipv4; - if (l2_len) { - sockunion_family(&link_layer_ipv4) = AF_INET; - memcpy((void *)sockunion_get_addr(&link_layer_ipv4), - RTA_DATA(tb[NDA_LLADDR]), l2_len); - } else - sockunion_family(&link_layer_ipv4) = AF_UNSPEC; - zsend_nhrp_neighbor_notify( - cmd, ifp, &ip, - netlink_nbr_entry_state_to_zclient(ndm->ndm_state), - &link_layer_ipv4); - } + union sockunion link_layer_ipv4; + + if (l2_len) { + sockunion_family(&link_layer_ipv4) = AF_INET; + memcpy((void *)sockunion_get_addr(&link_layer_ipv4), + RTA_DATA(tb[NDA_LLADDR]), l2_len); + } else + sockunion_family(&link_layer_ipv4) = AF_UNSPEC; + zsend_neighbor_notify(cmd, ifp, &ip, + netlink_nbr_entry_state_to_zclient(ndm->ndm_state), + &link_layer_ipv4, l2_len); if (h->nlmsg_type == RTM_GETNEIGH) return 0; @@ -4631,76 +4720,24 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { ssize_t ret = 0; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_NEIGH_IP_INSTALL: + op = dplane_ctx_get_op(ctx); + if (op == DPLANE_OP_NEIGH_INSTALL || op == DPLANE_OP_NEIGH_UPDATE || + op == DPLANE_OP_NEIGH_DISCOVER || op == DPLANE_OP_NEIGH_IP_INSTALL) ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); - break; - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_DELETE: + else if (op == DPLANE_OP_NEIGH_DELETE || op == DPLANE_OP_NEIGH_IP_DELETE) ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); - break; - case DPLANE_OP_VTEP_ADD: + else if (op == DPLANE_OP_VTEP_ADD) ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); - break; - case DPLANE_OP_VTEP_DELETE: + else if (op == DPLANE_OP_VTEP_DELETE) ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); - break; - case DPLANE_OP_NEIGH_TABLE_UPDATE: + else if (op == DPLANE_OP_NEIGH_TABLE_UPDATE) ret = netlink_neigh_table_update_ctx(ctx, buf, buflen); - break; - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - 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_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_NONE: + else ret = -1; - } return ret; } @@ -4785,7 +4822,7 @@ ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, req->n.nlmsg_pid = nl->snl.nl_pid; req->r.rtm_family = AF_MPLS; - req->r.rtm_table = RT_TABLE_MAIN; + req->r.rtm_table = rt_table_main_id; req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS; req->r.rtm_scope = RT_SCOPE_UNIVERSE; req->r.rtm_type = RTN_UNICAST; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 3ca59ce676..d51944f1a4 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -56,7 +56,8 @@ extern ssize_t netlink_mpls_multipath_msg_encode(int cmd, extern ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen, - bool fpm, bool force_nhg); + bool fpm, bool force_nhg, + bool force_rr); extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, size_t datalen); @@ -90,7 +91,6 @@ extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, uint16_t vid); extern int netlink_neigh_read_specific_ip(const struct ipaddr *ip, struct interface *vlan_if); -extern vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); struct nl_batch; extern enum netlink_msg_status diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index f9888b12d4..0bfcd518ca 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -6,6 +6,8 @@ #include <zebra.h> +#include <net/route.h> + #ifndef HAVE_NETLINK #ifdef __OpenBSD__ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9af41cbc39..470391de9b 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -6,6 +6,7 @@ */ #include <zebra.h> +#include <netinet/icmp6.h> #include "memory.h" #include "sockopt.h" @@ -33,6 +34,7 @@ extern struct zebra_privs_t zserv_privs; static uint32_t interfaces_configured_for_ra_from_bgp; +#define RTADV_ADATA_SIZE 1024 #if defined(HAVE_RTADV) @@ -58,7 +60,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface"); /* adv list node */ struct adv_if { - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; struct adv_if_list_item list_item; }; @@ -182,13 +184,14 @@ static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf, static void rtadv_send_packet(int sock, struct interface *ifp, enum ipv6_nd_suppress_ra_status stop) { - struct msghdr msg; - struct iovec iov; + struct msghdr msg = { 0 }; + struct iovec iov = { 0 }; struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; - struct sockaddr_in6 addr; - static void *adata = NULL; - unsigned char buf[RTADV_MSG_SIZE]; + struct sockaddr_in6 addr = { 0 }; + unsigned char buf[RTADV_MSG_SIZE] = { 0 }; + char adata[RTADV_ADATA_SIZE] = { 0 }; + struct nd_router_advert *rtadv; int ret; int len = 0; @@ -199,22 +202,6 @@ static void rtadv_send_packet(int sock, struct interface *ifp, struct listnode *node; uint16_t pkt_RouterLifetime; - /* - * Allocate control message bufffer. This is dynamic because - * CMSG_SPACE is not guaranteed not to call a function. Note that - * the size will be different on different architectures due to - * differing alignment rules. - */ - if (adata == NULL) { - /* XXX Free on shutdown. */ - adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo))); - - if (adata == NULL) { - zlog_debug("%s: can't malloc control data", __func__); - exit(-1); - } - } - /* Logging of packet. */ if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name, @@ -1147,7 +1134,8 @@ static void rtadv_prefix_set_defaults(struct rtadv_prefix *rp) rp->AdvValidLifetime = RTADV_VALID_LIFETIME; } -static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp) +static struct rtadv_prefix *rtadv_prefix_set(struct zebra_if *zif, + struct rtadv_prefix *rp) { struct rtadv_prefix *rprefix; @@ -1180,13 +1168,16 @@ static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp) rtadv_prefix_set_defaults(rprefix); } } + + return rprefix; } -static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) +static void rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp, + struct rtadv_prefix *rprefix) { - struct rtadv_prefix *rprefix; + if (!rprefix) + rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp); - rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp); if (rprefix != NULL) { /* @@ -1200,20 +1191,35 @@ static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO; rtadv_prefix_set_defaults(rprefix); - return 1; + return; } } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) { if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL; - return 1; + return; } } rtadv_prefixes_del(zif->rtadv.prefixes, rprefix); rtadv_prefix_free(rprefix); - return 1; - } else - return 0; + } +} + +struct rtadv_prefix *rtadv_add_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rp) +{ + rp->AdvPrefixCreate = PREFIX_SRC_MANUAL; + return rtadv_prefix_set(zif, rp); +} + +void rtadv_delete_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rprefix) +{ + struct rtadv_prefix rp; + + rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; + + rtadv_prefix_reset(zif, &rp, rprefix); } /* Add IPv6 prefixes learned from the kernel to the RA prefix list */ @@ -1235,7 +1241,7 @@ void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p) rp.prefix = *((struct prefix_ipv6 *)p); apply_mask_ipv6(&rp.prefix); rp.AdvPrefixCreate = PREFIX_SRC_AUTO; - rtadv_prefix_reset(zif, &rp); + rtadv_prefix_reset(zif, &rp, NULL); } static void rtadv_start_interface_events(struct zebra_vrf *zvrf, @@ -1261,8 +1267,8 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf, rtadv_event(zvrf, RTADV_START, 0); } -static void ipv6_nd_suppress_ra_set(struct interface *ifp, - enum ipv6_nd_suppress_ra_status status) +void ipv6_nd_suppress_ra_set(struct interface *ifp, + enum ipv6_nd_suppress_ra_status status) { struct zebra_if *zif; struct zebra_vrf *zvrf; @@ -1310,6 +1316,36 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, } } +void ipv6_nd_interval_set(struct interface *ifp, uint32_t interval) +{ + struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf = rtadv_interface_get_zvrf(ifp); + struct adv_if *adv_if; + + if (zif->rtadv.MaxRtrAdvInterval % 1000) { + adv_if = adv_msec_if_del(zvrf, ifp->name); + if (adv_if != NULL) + adv_if_free(adv_if); + } + + if (interval % 1000) + (void)adv_msec_if_add(zvrf, ifp->name); + + zif->rtadv.MaxRtrAdvInterval = interval; + zif->rtadv.MinRtrAdvInterval = 0.33 * interval; + + if (interval != RTADV_MAX_RTR_ADV_INTERVAL) { + SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); + zif->rtadv.AdvIntervalTimer = 0; + } else { + if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + zif->rtadv.MaxRtrAdvInterval = 10000; + + UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + } +} + /* * Handle client (BGP) message to enable or disable IPv6 RA on an interface. * Note that while the client could request RA on an interface on which the @@ -1427,7 +1463,7 @@ void rtadv_stop_ra_all(void) frr_each_safe (rtadv_prefixes, zif->rtadv.prefixes, rprefix) - rtadv_prefix_reset(zif, rprefix); + rtadv_prefix_reset(zif, rprefix, rprefix); rtadv_stop_ra(ifp); } @@ -1512,777 +1548,6 @@ DEFPY(show_ipv6_nd_ra_if, show_ipv6_nd_ra_if_cmd, return CMD_SUCCESS; } -DEFUN (ipv6_nd_ra_fast_retrans, - ipv6_nd_ra_fast_retrans_cmd, - "ipv6 nd ra-fast-retrans", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Fast retransmit of RA packets\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.UseFastRexmit = true; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_fast_retrans, - no_ipv6_nd_ra_fast_retrans_cmd, - "no ipv6 nd ra-fast-retrans", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Fast retransmit of RA packets\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.UseFastRexmit = false; - - return CMD_SUCCESS; -} - -DEFPY (ipv6_nd_ra_hop_limit, - ipv6_nd_ra_hop_limit_cmd, - "ipv6 nd ra-hop-limit (0-255)$hopcount", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Hop Limit\n" - "Advertisement Hop Limit in hops (default:64)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvCurHopLimit = hopcount; - - return CMD_SUCCESS; -} - -DEFPY (no_ipv6_nd_ra_hop_limit, - no_ipv6_nd_ra_hop_limit_cmd, - "no ipv6 nd ra-hop-limit [(0-255)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Hop Limit\n" - "Advertisement Hop Limit in hops\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; - - return CMD_SUCCESS; -} - -DEFPY (ipv6_nd_ra_retrans_interval, - ipv6_nd_ra_retrans_interval_cmd, - "ipv6 nd ra-retrans-interval (0-4294967295)$interval", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Retransmit Interval\n" - "Advertisement Retransmit Interval in msec\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on loopback interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvRetransTimer = interval; - - return CMD_SUCCESS; -} - -DEFPY (no_ipv6_nd_ra_retrans_interval, - no_ipv6_nd_ra_retrans_interval_cmd, - "no ipv6 nd ra-retrans-interval [(0-4294967295)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Retransmit Interval\n" - "Advertisement Retransmit Interval in msec\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot remove IPv6 Router Advertisements on loopback interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvRetransTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_suppress_ra, - ipv6_nd_suppress_ra_cmd, - "ipv6 nd suppress-ra", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Suppress Router Advertisement\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) - ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS); - - UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_suppress_ra, - no_ipv6_nd_suppress_ra_cmd, - "no ipv6 nd suppress-ra", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Suppress Router Advertisement\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_interval_msec, - ipv6_nd_ra_interval_msec_cmd, - "ipv6 nd ra-interval msec (70-1800000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in milliseconds\n" - "Router Advertisement interval in milliseconds\n") -{ - int idx_number = 4; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned interval; - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - interval = strtoul(argv[idx_number]->arg, NULL, 10); - if ((zif->rtadv.AdvDefaultLifetime != -1 - && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) { - vty_out(vty, - "This ra-interval would conflict with configured ra-lifetime!\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - if (interval % 1000) - (void)adv_msec_if_add(zvrf, ifp->name); - - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - zif->rtadv.MaxRtrAdvInterval = interval; - zif->rtadv.MinRtrAdvInterval = 0.33 * interval; - zif->rtadv.AdvIntervalTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_interval, - ipv6_nd_ra_interval_cmd, - "ipv6 nd ra-interval (1-1800)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in seconds\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned interval; - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - interval = strtoul(argv[idx_number]->arg, NULL, 10); - if ((zif->rtadv.AdvDefaultLifetime != -1 - && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) { - vty_out(vty, - "This ra-interval would conflict with configured ra-lifetime!\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - /* convert to milliseconds */ - interval = interval * 1000; - - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - zif->rtadv.MaxRtrAdvInterval = interval; - zif->rtadv.MinRtrAdvInterval = 0.33 * interval; - zif->rtadv.AdvIntervalTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_interval, - no_ipv6_nd_ra_interval_cmd, - "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in seconds\n" - "Specify millisecond router advertisement interval\n" - "Router Advertisement interval in milliseconds\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf = NULL; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - - if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) - zif->rtadv.MaxRtrAdvInterval = 10000; - else - zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; - - zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; - zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_lifetime, - ipv6_nd_ra_lifetime_cmd, - "ipv6 nd ra-lifetime (0-9000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router lifetime\n" - "Router lifetime in seconds (0 stands for a non-default gw)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - int lifetime; - - lifetime = strtoul(argv[idx_number]->arg, NULL, 10); - - /* The value to be placed in the Router Lifetime field - * of Router Advertisements sent from the interface, - * in seconds. MUST be either zero or between - * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */ - if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) { - vty_out(vty, - "This ra-lifetime would conflict with configured ra-interval\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvDefaultLifetime = lifetime; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_lifetime, - no_ipv6_nd_ra_lifetime_cmd, - "no ipv6 nd ra-lifetime [(0-9000)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router lifetime\n" - "Router lifetime in seconds (0 stands for a non-default gw)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvDefaultLifetime = -1; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_reachable_time, - ipv6_nd_reachable_time_cmd, - "ipv6 nd reachable-time (1-3600000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Reachable time\n" - "Reachable time in milliseconds\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_reachable_time, - no_ipv6_nd_reachable_time_cmd, - "no ipv6 nd reachable-time [(1-3600000)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Reachable time\n" - "Reachable time in milliseconds\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvReachableTime = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_preference, - ipv6_nd_homeagent_preference_cmd, - "ipv6 nd home-agent-preference (0-65535)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent preference\n" - "preference value (default is 0, least preferred)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.HomeAgentPreference = - strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_preference, - no_ipv6_nd_homeagent_preference_cmd, - "no ipv6 nd home-agent-preference [(0-65535)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent preference\n" - "preference value (default is 0, least preferred)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.HomeAgentPreference = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_lifetime, - ipv6_nd_homeagent_lifetime_cmd, - "ipv6 nd home-agent-lifetime (0-65520)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent lifetime\n" - "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_lifetime, - no_ipv6_nd_homeagent_lifetime_cmd, - "no ipv6 nd home-agent-lifetime [(0-65520)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent lifetime\n" - "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.HomeAgentLifetime = -1; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_managed_config_flag, - ipv6_nd_managed_config_flag_cmd, - "ipv6 nd managed-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Managed address configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvManagedFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_managed_config_flag, - no_ipv6_nd_managed_config_flag_cmd, - "no ipv6 nd managed-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Managed address configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvManagedFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_config_flag, - ipv6_nd_homeagent_config_flag_cmd, - "ipv6 nd home-agent-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvHomeAgentFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_config_flag, - no_ipv6_nd_homeagent_config_flag_cmd, - "no ipv6 nd home-agent-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvHomeAgentFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_adv_interval_config_option, - ipv6_nd_adv_interval_config_option_cmd, - "ipv6 nd adv-interval-option", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Interval Option\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvIntervalOption = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_adv_interval_config_option, - no_ipv6_nd_adv_interval_config_option_cmd, - "no ipv6 nd adv-interval-option", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Interval Option\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvIntervalOption = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_other_config_flag, - ipv6_nd_other_config_flag_cmd, - "ipv6 nd other-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Other statefull configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvOtherConfigFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_other_config_flag, - no_ipv6_nd_other_config_flag_cmd, - "no ipv6 nd other-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Other statefull configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvOtherConfigFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_prefix, - ipv6_nd_prefix_cmd, - "ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Prefix information\n" - "IPv6 prefix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n" - "Preferred lifetime in seconds\n" - "Infinite preferred lifetime\n" - "Set Router Address flag\n" - "Do not use prefix for onlink determination\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for onlink determination\n") -{ - /* prelude */ - char *prefix = argv[3]->arg; - int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN - || strmatch(argv[4]->text, "infinite")); - int routeropts = lifetimes ? argc > 6 : argc > 4; - - int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0; - - char *lifetime = NULL, *preflifetime = NULL; - int routeraddr = 0, offlink = 0, noautoconf = 0; - if (lifetimes) { - lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg - : argv[5]->text; - } - if (routeropts) { - routeraddr = - strmatch(argv[idx_routeropts]->text, "router-address"); - if (!routeraddr) { - offlink = (argc > idx_routeropts + 1 - || strmatch(argv[idx_routeropts]->text, - "off-link")); - noautoconf = (argc > idx_routeropts + 1 - || strmatch(argv[idx_routeropts]->text, - "no-autoconfig")); - } - } - - /* business */ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zebra_if = ifp->info; - int ret; - struct rtadv_prefix rp; - - ret = str2prefix_ipv6(prefix, &rp.prefix); - if (!ret) { - vty_out(vty, "Malformed IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */ - rp.AdvOnLinkFlag = !offlink; - rp.AdvAutonomousFlag = !noautoconf; - rp.AdvRouterAddressFlag = routeraddr; - rp.AdvValidLifetime = RTADV_VALID_LIFETIME; - rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; - rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; - - if (lifetimes) { - rp.AdvValidLifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - rp.AdvPreferredLifetime = - strmatch(preflifetime, "infinite") - ? UINT32_MAX - : strtoll(preflifetime, NULL, 10); - if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) { - vty_out(vty, "Invalid preferred lifetime\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - rtadv_prefix_set(zebra_if, &rp); - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_prefix, - no_ipv6_nd_prefix_cmd, - "no ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Prefix information\n" - "IPv6 prefix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n" - "Preferred lifetime in seconds\n" - "Infinite preferred lifetime\n" - "Set Router Address flag\n" - "Do not use prefix for onlink determination\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for onlink determination\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zebra_if = ifp->info; - int ret; - struct rtadv_prefix rp; - char *prefix = argv[4]->arg; - - ret = str2prefix_ipv6(prefix, &rp.prefix); - if (!ret) { - vty_out(vty, "Malformed IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */ - rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; - - ret = rtadv_prefix_reset(zebra_if, &rp); - if (!ret) { - vty_out(vty, "Non-existant IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_router_preference, - ipv6_nd_router_preference_cmd, - "ipv6 nd router-preference <high|medium|low>", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Default router preference\n" - "High default router preference\n" - "Medium default router preference (default)\n" - "Low default router preference\n") -{ - int idx_high_medium_low = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - int i = 0; - - while (0 != rtadv_pref_strs[i]) { - if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i], - 1) - == 0) { - zif->rtadv.DefaultPreference = i; - return CMD_SUCCESS; - } - i++; - } - - return CMD_ERR_NO_MATCH; -} - -DEFUN (no_ipv6_nd_router_preference, - no_ipv6_nd_router_preference_cmd, - "no ipv6 nd router-preference [<high|medium|low>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Default router preference\n" - "High default router preference\n" - "Medium default router preference (default)\n" - "Low default router preference\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.DefaultPreference = - RTADV_PREF_MEDIUM; /* Default per RFC4191. */ - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_mtu, - ipv6_nd_mtu_cmd, - "ipv6 nd mtu (1-65535)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertised MTU\n" - "MTU in bytes\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_mtu, - no_ipv6_nd_mtu_cmd, - "no ipv6 nd mtu [(1-65535)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertised MTU\n" - "MTU in bytes\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvLinkMTU = 0; - return CMD_SUCCESS; -} - static struct rtadv_rdnss *rtadv_rdnss_new(void) { return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss)); @@ -2293,55 +1558,22 @@ static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss) XFREE(MTYPE_RTADV_RDNSS, rdnss); } -static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list, - struct rtadv_rdnss *rdnss) +struct rtadv_rdnss *rtadv_rdnss_set(struct zebra_if *zif, + struct rtadv_rdnss *rdnss) { - struct listnode *node; struct rtadv_rdnss *p; - for (ALL_LIST_ELEMENTS_RO(list, node, p)) - if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr)) - return p; - return NULL; -} - -static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list, - struct rtadv_rdnss *rdnss) -{ - struct rtadv_rdnss *p; - - p = rtadv_rdnss_lookup(list, rdnss); - if (p) - return p; - p = rtadv_rdnss_new(); memcpy(p, rdnss, sizeof(struct rtadv_rdnss)); - listnode_add(list, p); + listnode_add(zif->rtadv.AdvRDNSSList, p); return p; } -static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +void rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *p) { - struct rtadv_rdnss *p; - - p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss); - p->lifetime = rdnss->lifetime; - p->lifetime_set = rdnss->lifetime_set; -} - -static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss) -{ - struct rtadv_rdnss *p; - - p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss); - if (p) { - listnode_delete(zif->rtadv.AdvRDNSSList, p); - rtadv_rdnss_free(p); - return 1; - } - - return 0; + listnode_delete(zif->rtadv.AdvRDNSSList, p); + rtadv_rdnss_free(p); } static struct rtadv_dnssl *rtadv_dnssl_new(void) @@ -2354,54 +1586,22 @@ static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl) XFREE(MTYPE_RTADV_DNSSL, dnssl); } -static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list, - struct rtadv_dnssl *dnssl) +struct rtadv_dnssl *rtadv_dnssl_set(struct zebra_if *zif, + struct rtadv_dnssl *dnssl) { - struct listnode *node; struct rtadv_dnssl *p; - for (ALL_LIST_ELEMENTS_RO(list, node, p)) - if (!strcasecmp(p->name, dnssl->name)) - return p; - return NULL; -} - -static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list, - struct rtadv_dnssl *dnssl) -{ - struct rtadv_dnssl *p; - - p = rtadv_dnssl_lookup(list, dnssl); - if (p) - return p; - p = rtadv_dnssl_new(); memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); - listnode_add(list, p); + listnode_add(zif->rtadv.AdvDNSSLList, p); return p; } -static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl) -{ - struct rtadv_dnssl *p; - - p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl); - memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); -} - -static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +void rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *p) { - struct rtadv_dnssl *p; - - p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl); - if (p) { - listnode_delete(zif->rtadv.AdvDNSSLList, p); - rtadv_dnssl_free(p); - return 1; - } - - return 0; + listnode_delete(zif->rtadv.AdvDNSSLList, p); + rtadv_dnssl_free(p); } /* @@ -2412,7 +1612,7 @@ static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) * Returns the number of octets written to out or -1 if in does not constitute * a valid domain name. */ -static int rtadv_dnssl_encode(uint8_t *out, const char *in) +int rtadv_dnssl_encode(uint8_t *out, const char *in) { const char *label_start, *label_end; size_t outp; @@ -2443,148 +1643,6 @@ static int rtadv_dnssl_encode(uint8_t *out, const char *in) return outp; } -DEFUN(ipv6_nd_rdnss, - ipv6_nd_rdnss_cmd, - "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Recursive DNS server information\n" - "IPv6 address\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_rdnss rdnss = {}; - - if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) { - vty_out(vty, "Malformed IPv6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (argc > 4) { - char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - rdnss.lifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - rdnss.lifetime_set = 1; - } - - rtadv_rdnss_set(zif, &rdnss); - - return CMD_SUCCESS; -} - -DEFUN(no_ipv6_nd_rdnss, - no_ipv6_nd_rdnss_cmd, - "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Recursive DNS server information\n" - "IPv6 address\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_rdnss rdnss = {}; - - if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) { - vty_out(vty, "Malformed IPv6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (rtadv_rdnss_reset(zif, &rdnss) != 1) { - vty_out(vty, "Non-existant RDNSS address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN(ipv6_nd_dnssl, - ipv6_nd_dnssl_cmd, - "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "DNS search list information\n" - "Domain name suffix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_dnssl dnssl = {}; - size_t len; - int ret; - - len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name)); - if (len == 0 || len >= sizeof(dnssl.name)) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (dnssl.name[len - 1] == '.') { - /* - * Allow, but don't require, a trailing dot signifying the root - * zone. Canonicalize by cutting it off if present. - */ - dnssl.name[len - 1] = '\0'; - len--; - } - if (argc > 4) { - char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - dnssl.lifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - dnssl.lifetime_set = 1; - } - - ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); - if (ret < 0) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - dnssl.encoded_len = ret; - rtadv_dnssl_set(zif, &dnssl); - - return CMD_SUCCESS; -} - -DEFUN(no_ipv6_nd_dnssl, - no_ipv6_nd_dnssl_cmd, - "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "DNS search list information\n" - "Domain name suffix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_dnssl dnssl = {}; - size_t len; - - len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name)); - if (len == 0 || len >= sizeof(dnssl.name)) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (dnssl.name[len - 1] == '.') { - dnssl.name[len - 1] = '\0'; - len--; - } - if (rtadv_dnssl_reset(zif, &dnssl) != 1) { - vty_out(vty, "Non-existant DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - - /* Dump interface ND information to vty. */ static int nd_dump_vty(struct vty *vty, struct interface *ifp) { @@ -2655,136 +1713,6 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp) return 0; } - -/* Write configuration about router advertisement. */ -static int rtadv_config_write(struct vty *vty, struct interface *ifp) -{ - struct zebra_if *zif; - struct listnode *node; - struct rtadv_prefix *rprefix; - struct rtadv_rdnss *rdnss; - struct rtadv_dnssl *dnssl; - int interval; - - zif = ifp->info; - - if (!if_is_loopback(ifp)) { - if (zif->rtadv.AdvSendAdvertisements - && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED)) - vty_out(vty, " no ipv6 nd suppress-ra\n"); - } - - interval = zif->rtadv.MaxRtrAdvInterval; - if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) { - if (interval % 1000) - vty_out(vty, " ipv6 nd ra-interval msec %d\n", - interval); - else if (interval != RTADV_MAX_RTR_ADV_INTERVAL) - vty_out(vty, " ipv6 nd ra-interval %d\n", - interval / 1000); - } - - if (zif->rtadv.AdvIntervalOption) - vty_out(vty, " ipv6 nd adv-interval-option\n"); - - if (!zif->rtadv.UseFastRexmit) - vty_out(vty, " no ipv6 nd ra-fast-retrans\n"); - - if (zif->rtadv.AdvRetransTimer != 0) - vty_out(vty, " ipv6 nd ra-retrans-interval %u\n", - zif->rtadv.AdvRetransTimer); - - if (zif->rtadv.AdvCurHopLimit != RTADV_DEFAULT_HOPLIMIT) - vty_out(vty, " ipv6 nd ra-hop-limit %d\n", - zif->rtadv.AdvCurHopLimit); - - if (zif->rtadv.AdvDefaultLifetime != -1) - vty_out(vty, " ipv6 nd ra-lifetime %d\n", - zif->rtadv.AdvDefaultLifetime); - - if (zif->rtadv.HomeAgentPreference) - vty_out(vty, " ipv6 nd home-agent-preference %u\n", - zif->rtadv.HomeAgentPreference); - - if (zif->rtadv.HomeAgentLifetime != -1) - vty_out(vty, " ipv6 nd home-agent-lifetime %u\n", - zif->rtadv.HomeAgentLifetime); - - if (zif->rtadv.AdvHomeAgentFlag) - vty_out(vty, " ipv6 nd home-agent-config-flag\n"); - - if (zif->rtadv.AdvReachableTime) - vty_out(vty, " ipv6 nd reachable-time %d\n", - zif->rtadv.AdvReachableTime); - - if (zif->rtadv.AdvManagedFlag) - vty_out(vty, " ipv6 nd managed-config-flag\n"); - - if (zif->rtadv.AdvOtherConfigFlag) - vty_out(vty, " ipv6 nd other-config-flag\n"); - - if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM) - vty_out(vty, " ipv6 nd router-preference %s\n", - rtadv_pref_strs[zif->rtadv.DefaultPreference]); - - if (zif->rtadv.AdvLinkMTU) - vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU); - - frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) { - if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL) - || (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) { - vty_out(vty, " ipv6 nd prefix %pFX", &rprefix->prefix); - if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) - || (rprefix->AdvPreferredLifetime - != RTADV_PREFERRED_LIFETIME)) { - if (rprefix->AdvValidLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", - rprefix->AdvValidLifetime); - if (rprefix->AdvPreferredLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", - rprefix->AdvPreferredLifetime); - } - if (!rprefix->AdvOnLinkFlag) - vty_out(vty, " off-link"); - if (!rprefix->AdvAutonomousFlag) - vty_out(vty, " no-autoconfig"); - if (rprefix->AdvRouterAddressFlag) - vty_out(vty, " router-address"); - vty_out(vty, "\n"); - } - } - - for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { - char buf[INET6_ADDRSTRLEN]; - - vty_out(vty, " ipv6 nd rdnss %s", - inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf))); - if (rdnss->lifetime_set) { - if (rdnss->lifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", rdnss->lifetime); - } - vty_out(vty, "\n"); - } - for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { - vty_out(vty, " ipv6 nd dnssl %s", dnssl->name); - if (dnssl->lifetime_set) { - if (dnssl->lifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", dnssl->lifetime); - } - vty_out(vty, "\n"); - } - return 0; -} - - static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) { struct rtadv *rtadv; @@ -2930,49 +1858,8 @@ void rtadv_cmd_init(void) interfaces_configured_for_ra_from_bgp = 0; hook_register(zebra_if_extra_info, nd_dump_vty); - hook_register(zebra_if_config_wr, rtadv_config_write); install_element(VIEW_NODE, &show_ipv6_nd_ra_if_cmd); - - install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_retrans_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_hop_limit_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd); - install_element(INTERFACE_NODE, - &ipv6_nd_adv_interval_config_option_cmd); - install_element(INTERFACE_NODE, - &no_ipv6_nd_adv_interval_config_option_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd); } static int if_join_all_router(int sock, struct interface *ifp) @@ -3069,3 +1956,13 @@ uint32_t rtadv_get_interfaces_configured_from_bgp(void) { return interfaces_configured_for_ra_from_bgp; } + +void rtadv_init(void) +{ + if (CMSG_SPACE(sizeof(struct in6_pktinfo)) > RTADV_ADATA_SIZE) { + zlog_debug("%s: RTADV_ADATA_SIZE choosen will not work on this platform, please use a larger size", + __func__); + + exit(-1); + } +} diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 1ec376a106..0983ea578f 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -385,6 +385,30 @@ extern void rtadv_if_fini(struct zebra_if *zif); extern void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p); extern void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p); +/* returns created prefix */ +struct rtadv_prefix *rtadv_add_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rp); +/* rprefix must be the one returned by rtadv_add_prefix_manual */ +void rtadv_delete_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rprefix); + +/* returns created address */ +struct rtadv_rdnss *rtadv_rdnss_set(struct zebra_if *zif, + struct rtadv_rdnss *rdnss); +/* p must be the one returned by rtadv_rdnss_set */ +void rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *p); + +/* returns created domain */ +struct rtadv_dnssl *rtadv_dnssl_set(struct zebra_if *zif, + struct rtadv_dnssl *dnssl); +/* p must be the one returned by rtadv_dnssl_set */ +void rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *p); +int rtadv_dnssl_encode(uint8_t *out, const char *in); + +void ipv6_nd_suppress_ra_set(struct interface *ifp, + enum ipv6_nd_suppress_ra_status status); +void ipv6_nd_interval_set(struct interface *ifp, uint32_t interval); + #else /* !HAVE_RTADV */ struct rtadv { /* empty structs aren't valid ISO C */ @@ -435,6 +459,7 @@ extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); extern uint32_t rtadv_get_interfaces_configured_from_bgp(void); extern bool rtadv_compiled_in(void); +extern void rtadv_init(void); #ifdef __cplusplus } diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index ef1e21b4f7..8e2d13faff 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -6,6 +6,8 @@ #include <zebra.h> +#include <net/route.h> + #if !defined(GNU_LINUX) #include "memory.h" diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index c7832992ea..05282793d7 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -9,6 +9,9 @@ #ifdef HAVE_NETLINK +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + #include "if.h" #include "prefix.h" #include "vrf.h" @@ -116,9 +119,9 @@ static ssize_t netlink_rule_msg_encode( return 0; } - /* dsfield, if specified */ - if (filter_bm & PBR_FILTER_DSFIELD) - req->frh.tos = dsfield; + /* dsfield, if specified; mask off the ECN bits */ + if (filter_bm & PBR_FILTER_DSCP) + req->frh.tos = dsfield & PBR_DSFIELD_DSCP; /* protocol to match on */ if (filter_bm & PBR_FILTER_IP_PROTOCOL) @@ -174,6 +177,17 @@ static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx, dplane_ctx_rule_get_old_ipproto(ctx), buf, buflen); } +/* + * Identify valid rule actions for netlink - other actions can't be installed + */ +static bool nl_rule_valid_action(uint32_t action) +{ + if (action == PBR_ACTION_TABLE) + return true; + else + return false; +} + /* Public functions */ enum netlink_msg_status @@ -181,6 +195,7 @@ netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) { enum dplane_op_e op; enum netlink_msg_status ret; + struct pbr_rule rule = {}; op = dplane_ctx_get_op(ctx); if (!(op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE @@ -192,6 +207,18 @@ netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) return FRR_NETLINK_ERROR; } + /* TODO -- special handling for rules that include actions that + * netlink cannot install. Some of the rule attributes are not + * available in netlink: only try to install valid actions. + */ + dplane_ctx_rule_get(ctx, &rule, NULL); + if (!nl_rule_valid_action(rule.action.flags)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: skip invalid action %#x", __func__, + rule.action.flags); + return 0; + } + ret = netlink_batch_add_msg(bth, ctx, netlink_rule_msg_encoder, false); /** @@ -400,6 +427,7 @@ int netlink_rules_read(struct zebra_ns *zns) ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, &dp_info, 0, true); + return ret; } diff --git a/zebra/subdir.am b/zebra/subdir.am index 1060e38785..f767447366 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -19,6 +19,12 @@ if LINUX module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la endif +#if FPM_LISTENER +sbin_PROGRAMS += zebra/fpm_listener +zebra_fpm_listener_SOURCES = zebra/fpm_listener.c +zebra_fpm_listener_LDADD = lib/libfrr.la +#endf + # Dataplane sample plugin if DEV_BUILD module_LTLIBRARIES += zebra/dplane_sample_plugin.la @@ -28,7 +34,7 @@ man8 += $(MANBUILD)/frr-zebra.8 ## endif ZEBRA endif -zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) $(UST_LIBS) +zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) $(LIBYANG_LIBS) $(UST_LIBS) if HAVE_PROTOBUF3 zebra_zebra_LDADD += mlag/libmlag_pb.la $(PROTOBUF_C_LIBS) zebra/zebra_mlag.$(OBJEXT): mlag/mlag.pb-c.h @@ -52,6 +58,7 @@ zebra_zebra_SOURCES = \ zebra/redistribute.c \ zebra/router-id.c \ zebra/rt_netlink.c \ + zebra/ge_netlink.c \ zebra/rt_socket.c \ zebra/rtadv.c \ zebra/rtread_netlink.c \ @@ -115,15 +122,17 @@ zebra_zebra_SOURCES = \ clippy_scan += \ zebra/debug.c \ + zebra/dplane_fpm_nl.c \ zebra/interface.c \ zebra/rtadv.c \ - zebra/zebra_evpn_mh.c \ zebra/zebra_mlag_vty.c \ zebra/zebra_routemap.c \ zebra/zebra_vty.c \ zebra/zebra_srv6_vty.c \ zebra/zebra_vrf.c \ zebra/dpdk/zebra_dplane_dpdk_vty.c \ + zebra/label_manager.c \ + zebra/zebra_cli.c \ # end noinst_HEADERS += \ @@ -143,6 +152,7 @@ noinst_HEADERS += \ zebra/router-id.h \ zebra/rt.h \ zebra/rt_netlink.h \ + zebra/ge_netlink.h \ zebra/rtadv.h \ zebra/rule_netlink.h \ zebra/table_manager.h \ diff --git a/zebra/table_manager.c b/zebra/table_manager.c index 77ec42e64b..8417a22114 100644 --- a/zebra/table_manager.c +++ b/zebra/table_manager.c @@ -24,21 +24,6 @@ #include "zebra/table_manager.h" #include "zebra/zebra_errors.h" -/* routing table identifiers - * - */ -#if !defined(GNU_LINUX) -/* BSD systems - */ -#else -/* Linux Systems - */ -#define RT_TABLE_ID_LOCAL 255 -#define RT_TABLE_ID_MAIN 254 -#define RT_TABLE_ID_DEFAULT 253 -#define RT_TABLE_ID_COMPAT 252 -#define RT_TABLE_ID_UNSPEC 0 -#endif /* !def(GNU_LINUX) */ #define RT_TABLE_ID_UNRESERVED_MIN 1 #define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff @@ -63,8 +48,7 @@ void table_manager_enable(struct zebra_vrf *zvrf) && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (def) - zvrf->tbl_mgr = def->tbl_mgr; + zvrf->tbl_mgr = def->tbl_mgr; return; } zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager)); @@ -280,52 +264,11 @@ void table_manager_disable(struct zebra_vrf *zvrf) zvrf->tbl_mgr = NULL; } -int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf, - const char *start_table_str, const char *end_table_str) +void table_manager_range(bool add, struct zebra_vrf *zvrf, uint32_t start, + uint32_t end) { - uint32_t start; - uint32_t end; - - if (add) { - if (!start_table_str || !end_table_str) { - vty_out(vty, "%% Labels not specified\n"); - return CMD_WARNING_CONFIG_FAILED; - } - start = atoi(start_table_str); - end = atoi(end_table_str); - if (end < start) { - vty_out(vty, "%% End table is less than Start table\n"); - return CMD_WARNING_CONFIG_FAILED; - } - -#if !defined(GNU_LINUX) -/* BSD systems - */ -#else - /* Linux Systems - */ - if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL) - || (end >= RT_TABLE_ID_COMPAT - && end <= RT_TABLE_ID_LOCAL)) { - vty_out(vty, "%% Values forbidden in range [%u;%u]\n", - RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); - return CMD_WARNING_CONFIG_FAILED; - } - if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) { - vty_out(vty, - "%% Range overlaps range [%u;%u] forbidden\n", - RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); - return CMD_WARNING_CONFIG_FAILED; - } -#endif - if (zvrf->tbl_mgr - && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start) - || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) { - vty_out(vty, - "%% New range will be taken into account at restart\n"); - } + if (add) table_range_add(zvrf, start, end); - } else + else table_range_add(zvrf, 0, 0); - return CMD_SUCCESS; } diff --git a/zebra/table_manager.h b/zebra/table_manager.h index f8e99a357d..21691994cb 100644 --- a/zebra/table_manager.h +++ b/zebra/table_manager.h @@ -18,6 +18,22 @@ extern "C" { #endif +/* routing table identifiers + * + */ +#if !defined(GNU_LINUX) +/* BSD systems + */ +#else +/* Linux Systems + */ +#define RT_TABLE_ID_LOCAL 255 +#define RT_TABLE_ID_MAIN 254 +#define RT_TABLE_ID_DEFAULT 253 +#define RT_TABLE_ID_COMPAT 252 +#define RT_TABLE_ID_UNSPEC 0 +#endif /* !def(GNU_LINUX) */ + /* * Table chunk struct * Client daemon which the chunk belongs to can be identified by either @@ -56,8 +72,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start, uint32_t end, struct zebra_vrf *zvrf); int release_daemon_table_chunks(struct zserv *client); void table_manager_disable(struct zebra_vrf *zvrf); -int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf, - const char *min, const char *max); +void table_manager_range(bool add, struct zebra_vrf *zvrf, uint32_t start, + uint32_t end); #ifdef __cplusplus } diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index 679dc80a58..19667e66ac 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -9,6 +9,7 @@ #ifdef HAVE_NETLINK +#include <linux/rtnetlink.h> #include <linux/pkt_cls.h> #include <linux/pkt_sched.h> #include <netinet/if_ether.h> @@ -160,7 +161,7 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -236,7 +237,7 @@ static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -486,7 +487,7 @@ static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -703,6 +704,8 @@ int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { struct tcmsg *tcm; struct zebra_tc_qdisc qdisc = {}; + enum tc_qdisc_kind kind = TC_QDISC_UNSPEC; + const char *kind_str = "Unknown"; int len; struct rtattr *tb[TCA_MAX + 1]; @@ -722,9 +725,11 @@ int netlink_qdisc_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) tcm = NLMSG_DATA(h); netlink_parse_rtattr(tb, TCA_MAX, TCA_RTA(tcm), len); - const char *kind_str = (const char *)RTA_DATA(tb[TCA_KIND]); + if (RTA_DATA(tb[TCA_KIND])) { + kind_str = (const char *)RTA_DATA(tb[TCA_KIND]); - enum tc_qdisc_kind kind = tc_qdisc_str2kind(kind_str); + kind = tc_qdisc_str2kind(kind_str); + } qdisc.qdisc.ifindex = tcm->tcm_ifindex; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4c6c336d41..76cabd1bf0 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -5,6 +5,8 @@ * Copyright (C) 1997-1999 Kunihiro Ishiguro * Copyright (C) 2015-2018 Cumulus Networks, Inc. * et al. + * Copyright (c) 2021 The MITRE Corporation. + * Copyright (c) 2023 LabN Consulting, L.L.C. */ #include <zebra.h> @@ -22,6 +24,7 @@ #include "lib/vrf.h" #include "lib/libfrr.h" #include "lib/lib_errors.h" +#include "lib/frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/rib.h" @@ -61,7 +64,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp) /* Interface information. */ struct zebra_if *zif = ifp->info; - stream_put(s, ifp->name, INTERFACE_NAMSIZ); + stream_put(s, ifp->name, IFNAMSIZ); stream_putl(s, ifp->ifindex); stream_putc(s, ifp->status); stream_putq(s, ifp->flags); @@ -69,6 +72,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp) stream_putc(s, ifp->ptm_status); stream_putl(s, ifp->metric); stream_putl(s, ifp->speed); + stream_putl(s, ifp->txqlen); stream_putl(s, ifp->mtu); stream_putl(s, ifp->mtu6); stream_putl(s, ifp->bandwidth); @@ -411,7 +415,7 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) struct nbr_connected *nc; /* Send interface addresses. */ - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) continue; @@ -432,27 +436,6 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) return 0; } -/* Notify client about interface moving from one VRF to another. - * Whether client is interested in old and new VRF is checked by caller. - */ -int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, - vrf_id_t vrf_id) -{ - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf->vrf_id); - - /* Fill in the name of the interface and its new VRF (id) */ - stream_put(s, ifp->name, INTERFACE_NAMSIZ); - stream_putl(s, vrf_id); - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - client->if_vrfchg_cnt++; - return zserv_send_message(client, s); -} - /* Add new nbr connected IPv6 address */ void nbr_connected_add_ipv6(struct interface *ifp, struct in6_addr *address) { @@ -528,7 +511,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) int zsend_redistribute_route(int cmd, struct zserv *client, const struct route_node *rn, - const struct route_entry *re) + const struct route_entry *re, bool is_table_direct) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -544,7 +527,11 @@ int zsend_redistribute_route(int cmd, struct zserv *client, api.vrf_id = re->vrf_id; api.type = re->type; api.safi = SAFI_UNICAST; - api.instance = re->instance; + if (is_table_direct) { + api.instance = re->table; + api.type = ZEBRA_ROUTE_TABLE_DIRECT; + } else + api.instance = re->instance; api.flags = re->flags; afi = family2afi(p->family); @@ -611,7 +598,10 @@ int zsend_redistribute_route(int cmd, struct zserv *client, /* Attributes. */ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = re->distance; + if (is_table_direct) + api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT; + else + api.distance = re->distance; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = re->metric; if (re->tag) { @@ -801,11 +791,17 @@ int zsend_route_notify_owner(const struct route_node *rn, int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, enum zapi_route_notify_owner note) { - return (route_notify_internal( - rib_find_rn_from_ctx(ctx), dplane_ctx_get_type(ctx), - dplane_ctx_get_instance(ctx), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), note, dplane_ctx_get_afi(ctx), - dplane_ctx_get_safi(ctx))); + int result; + struct route_node *rn = rib_find_rn_from_ctx(ctx); + + result = route_notify_internal( + rn, dplane_ctx_get_type(ctx), dplane_ctx_get_instance(ctx), + dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx), note, + dplane_ctx_get_afi(ctx), dplane_ctx_get_safi(ctx)); + + route_unlock_node(rn); + + return result; } static void zread_route_notify_request(ZAPI_HANDLER_ARGS) @@ -839,12 +835,14 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, + dplane_ctx_rule_get_vrfid(ctx)); + stream_put(s, ¬e, sizeof(note)); stream_putl(s, dplane_ctx_rule_get_seq(ctx)); stream_putl(s, dplane_ctx_rule_get_priority(ctx)); stream_putl(s, dplane_ctx_rule_get_unique(ctx)); - stream_put(s, dplane_ctx_rule_get_ifname(ctx), INTERFACE_NAMSIZ); + stream_put(s, dplane_ctx_rule_get_ifname(ctx), IFNAMSIZ); stream_putw_at(s, 0, stream_get_endp(s)); @@ -970,9 +968,9 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } -void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, - struct ipaddr *ipaddr, int ndm_state, - union sockunion *link_layer_ipv4) +void zsend_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4, int ip_len) { struct stream *s; struct listnode *node, *nnode; @@ -989,13 +987,13 @@ void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, family2addrsize(sockunion_family(&ip))); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], + if (!vrf_bitmap_check(&client->neighinfo[afi], ifp->vrf->vrf_id)) continue; s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_neigh_ip_encode(s, cmd, &ip, link_layer_ipv4, ifp, - ndm_state); + ndm_state, ip_len); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -1010,7 +1008,7 @@ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, struct stream *s; /* Check this client need interface information. */ - if (!vrf_bitmap_check(client->ridinfo[afi], vrf_id)) + if (!vrf_bitmap_check(&client->ridinfo[afi], vrf_id)) return 0; s = stream_new(ZEBRA_MAX_PACKET_SIZ); @@ -1038,7 +1036,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); - stream_write(s, pw->ifname, INTERFACE_NAMSIZ); + stream_write(s, pw->ifname, IFNAMSIZ); stream_putl(s, pw->ifindex); stream_putl(s, pw->status); @@ -1331,8 +1329,6 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS) s = msg; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return; /* * The minimum amount of data that can be sent for one fec @@ -1394,8 +1390,6 @@ static void zread_fec_unregister(ZAPI_HANDLER_ARGS) s = msg; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return; /* * The minimum amount of data that can be sent for one @@ -1554,7 +1548,6 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh, uint16_t backup_nexthop_num) { struct nexthop *nexthop = NULL; - struct ipaddr vtep_ip; struct interface *ifp; int i; char nhbuf[INET6_ADDRSTRLEN] = ""; @@ -1590,13 +1583,8 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh, * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { - memset(&vtep_ip, 0, sizeof(vtep_ip)); - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), - sizeof(struct in_addr)); - zebra_rib_queue_evpn_route_add( - api_nh->vrf_id, &api_nh->rmac, &vtep_ip, p); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN); + nexthop->rmac = api_nh->rmac; } break; case NEXTHOP_TYPE_IPV6: @@ -1624,13 +1612,8 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh, * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { - memset(&vtep_ip, 0, sizeof(vtep_ip)); - vtep_ip.ipa_type = IPADDR_V6; - memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), - sizeof(struct in6_addr)); - zebra_rib_queue_evpn_route_add( - api_nh->vrf_id, &api_nh->rmac, &vtep_ip, p); SET_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN); + nexthop->rmac = api_nh->rmac; } break; case NEXTHOP_TYPE_BLACKHOLE: @@ -1704,10 +1687,14 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, struct nexthop_group **png, struct nhg_backup_info **pbnhg) { + struct zapi_nexthop *znh; struct nexthop_group *ng = NULL; struct nhg_backup_info *bnhg = NULL; uint16_t i; struct nexthop *last_nh = NULL; + bool same_weight = true; + uint64_t max_weight = 0; + uint64_t tmp; assert(!(png && pbnhg)); @@ -1722,6 +1709,41 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, bnhg = zebra_nhg_backup_alloc(); } + for (i = 0; i < nexthop_num; i++) { + znh = &nhops[i]; + + if (max_weight < znh->weight) { + if (i != 0 || znh->weight != 1) + same_weight = false; + + max_weight = znh->weight; + } + } + + /* + * Let's convert the weights to a scaled value + * between 1 and zrouter.nexthop_weight_scale_value + * This is a simple application of a ratio: + * scaled_weight/zrouter.nexthop_weight_scale_value = + * weight/max_weight + * This translates to: + * scaled_weight = weight * zrouter.nexthop_weight_scale_value + * ------------------------------------------- + * max_weight + * + * This same formula is applied to both the nexthops + * and the backup nexthops + */ + if (!same_weight) { + for (i = 0; i < nexthop_num; i++) { + znh = &nhops[i]; + + tmp = (uint64_t)znh->weight * + zrouter.nexthop_weight_scale_value; + znh->weight = MAX(1, ((uint32_t)(tmp / max_weight))); + } + } + /* * TBD should _all_ of the nexthop add operations use * api_nh->vrf_id instead of re->vrf_id ? I only changed @@ -1800,7 +1822,8 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: adding seg6", __func__); - nexthop_add_srv6_seg6(nexthop, &api_nh->seg6_segs); + nexthop_add_srv6_seg6(nexthop, &api_nh->seg6_segs[0], + api_nh->seg_num); } if (IS_ZEBRA_DEBUG_RECV) { @@ -1936,20 +1959,21 @@ static void zread_nhg_del(ZAPI_HANDLER_ARGS) return; } - /* - * Delete the received nhg id - */ - nhe = zebra_nhg_proto_del(api_nhg.id, api_nhg.proto); + /* Create a temporary nhe */ + nhe = zebra_nhg_alloc(); + nhe->id = api_nhg.id; + nhe->type = api_nhg.proto; + nhe->zapi_instance = client->instance; + nhe->zapi_session = client->session_id; - if (nhe) { - zebra_nhg_decrement_ref(nhe); - zsend_nhg_notify(api_nhg.proto, client->instance, - client->session_id, api_nhg.id, - ZAPI_NHG_REMOVED); - } else - zsend_nhg_notify(api_nhg.proto, client->instance, - client->session_id, api_nhg.id, - ZAPI_NHG_REMOVE_FAIL); + /* Sanity check - Empty nexthop and group */ + nhe->nhg.nexthop = NULL; + + /* Enqueue to workqueue for processing */ + rib_queue_nhe_del(nhe); + + /* Stats */ + client->nhg_del_cnt++; } static void zread_nhg_add(ZAPI_HANDLER_ARGS) @@ -1958,7 +1982,7 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) struct zapi_nhg api_nhg = {}; struct nexthop_group *nhg = NULL; struct nhg_backup_info *bnhg = NULL; - struct nhg_hash_entry *nhe; + struct nhg_hash_entry *nhe, *nhe_tmp; s = msg; if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) { @@ -2016,6 +2040,12 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&nhg); zebra_nhg_backup_free(&bnhg); + /* Stats */ + nhe_tmp = zebra_nhg_lookup_id(api_nhg.id); + if (nhe_tmp) + client->nhg_upd8_cnt++; + else + client->nhg_add_cnt++; } static void zread_route_add(ZAPI_HANDLER_ARGS) @@ -2275,7 +2305,7 @@ static void zread_router_id_add(ZAPI_HANDLER_ARGS) } /* Router-id information is needed. */ - vrf_bitmap_set(client->ridinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_set(&client->ridinfo[afi], zvrf_id(zvrf)); router_id_get(afi, &p, zvrf); @@ -2311,7 +2341,7 @@ static void zread_router_id_delete(ZAPI_HANDLER_ARGS) goto stream_failure; } - vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->ridinfo[afi], zvrf_id(zvrf)); stream_failure: return; @@ -2326,7 +2356,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putc(s, mpls_enabled); stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); - + stream_putc(s, zrouter.v6_with_v4_nexthop); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -2353,23 +2383,19 @@ static void zread_hello(ZAPI_HANDLER_ARGS) /* type of protocol (lib/zebra.h) */ uint8_t proto; unsigned short instance; - uint8_t notify; uint8_t synchronous; uint32_t session_id; STREAM_GETC(msg, proto); STREAM_GETW(msg, instance); STREAM_GETL(msg, session_id); - STREAM_GETC(msg, notify); STREAM_GETC(msg, synchronous); - if (notify) - client->notify_owner = true; if (synchronous) client->synchronous = true; /* accept only dynamic routing protocols */ - if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_CONNECT)) { + if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_LOCAL)) { zlog_notice( "client %d says hello and bids fair to announce only %s routes vrf=%u", client->sock, zebra_route_string(proto), @@ -2401,10 +2427,11 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf)); - vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); - vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf)); - vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->redist[afi][i], + zvrf_id(zvrf)); + vrf_bitmap_unset(&client->redist_default[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->ridinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf)); } } @@ -2984,7 +3011,7 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) static void zread_pseudowire(ZAPI_HANDLER_ARGS) { struct stream *s; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int type; int af; @@ -3000,8 +3027,8 @@ static void zread_pseudowire(ZAPI_HANDLER_ARGS) s = msg; /* Get data. */ - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - ifname[INTERFACE_NAMSIZ - 1] = '\0'; + STREAM_GET(ifname, s, IFNAMSIZ); + ifname[IFNAMSIZ - 1] = '\0'; STREAM_GETL(s, ifindex); STREAM_GETL(s, type); STREAM_GETL(s, af); @@ -3097,6 +3124,28 @@ stream_failure: } +static void zread_interface_set_arp(ZAPI_HANDLER_ARGS) +{ + struct stream *s = msg; + struct interface *ifp; + bool arp_enable; + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + int ifindex; + + STREAM_GETL(s, ifindex); + STREAM_GETC(s, arp_enable); + ifp = if_lookup_by_index(ifindex, vrf_id); + + if (!ifp) + return; + + if_arp(ifp, arp_enable); + +stream_failure: + return; +} + + static void zread_vrf_label(ZAPI_HANDLER_ARGS) { struct interface *ifp; @@ -3179,7 +3228,6 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) struct zebra_pbr_rule zpr; struct stream *s; uint32_t total, i; - char ifname[INTERFACE_NAMSIZ + 1] = {}; s = msg; STREAM_GETL(s, total); @@ -3189,59 +3237,38 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) zpr.sock = client->sock; zpr.rule.vrf_id = hdr->vrf_id; - STREAM_GETL(s, zpr.rule.seq); - STREAM_GETL(s, zpr.rule.priority); - STREAM_GETL(s, zpr.rule.unique); - STREAM_GETC(s, zpr.rule.filter.ip_proto); - STREAM_GETC(s, zpr.rule.filter.src_ip.family); - STREAM_GETC(s, zpr.rule.filter.src_ip.prefixlen); - STREAM_GET(&zpr.rule.filter.src_ip.u.prefix, s, - prefix_blen(&zpr.rule.filter.src_ip)); - STREAM_GETW(s, zpr.rule.filter.src_port); - STREAM_GETC(s, zpr.rule.filter.dst_ip.family); - STREAM_GETC(s, zpr.rule.filter.dst_ip.prefixlen); - STREAM_GET(&zpr.rule.filter.dst_ip.u.prefix, s, - prefix_blen(&zpr.rule.filter.dst_ip)); - STREAM_GETW(s, zpr.rule.filter.dst_port); - STREAM_GETC(s, zpr.rule.filter.dsfield); - STREAM_GETL(s, zpr.rule.filter.fwmark); - - STREAM_GETL(s, zpr.rule.action.queue_id); - STREAM_GETW(s, zpr.rule.action.vlan_id); - STREAM_GETW(s, zpr.rule.action.vlan_flags); - STREAM_GETW(s, zpr.rule.action.pcp); - - STREAM_GETL(s, zpr.rule.action.table); - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - - strlcpy(zpr.ifname, ifname, sizeof(zpr.ifname)); - strlcpy(zpr.rule.ifname, ifname, sizeof(zpr.rule.ifname)); - - if (!is_default_prefix(&zpr.rule.filter.src_ip)) - zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP; - - if (!is_default_prefix(&zpr.rule.filter.dst_ip)) - zpr.rule.filter.filter_bm |= PBR_FILTER_DST_IP; - - if (zpr.rule.filter.src_port) - zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_PORT; - - if (zpr.rule.filter.dst_port) - zpr.rule.filter.filter_bm |= PBR_FILTER_DST_PORT; - - if (zpr.rule.filter.dsfield) - zpr.rule.filter.filter_bm |= PBR_FILTER_DSFIELD; - - if (zpr.rule.filter.ip_proto) - zpr.rule.filter.filter_bm |= PBR_FILTER_IP_PROTOCOL; - - if (zpr.rule.filter.fwmark) - zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK; + if (!zapi_pbr_rule_decode(s, &zpr.rule)) + goto stream_failure; + + strlcpy(zpr.ifname, zpr.rule.ifname, sizeof(zpr.ifname)); + + if ((zpr.rule.family != AF_INET) && + (zpr.rule.family != AF_INET6)) { + zlog_warn("Unsupported PBR source IP family: %s (%hhu)", + family2str(zpr.rule.family), zpr.rule.family); + return; + } + + /* + * Fixup filter src/dst IP addresses if they are unset + * because the netlink code currently obtains address family + * from them. Address family is used to specify which + * kernel database to use when adding/deleting rule. + * + * TBD: propagate zpr.rule.family into dataplane and + * netlink code so they can stop using filter src/dst addrs. + */ + if (!CHECK_FLAG(zpr.rule.filter.filter_bm, PBR_FILTER_SRC_IP)) + zpr.rule.filter.src_ip.family = zpr.rule.family; + if (!CHECK_FLAG(zpr.rule.filter.filter_bm, PBR_FILTER_DST_IP)) + zpr.rule.filter.dst_ip.family = zpr.rule.family; + + /* TBD delete below block when netlink code gets family from zpr.rule.family */ if (!(zpr.rule.filter.src_ip.family == AF_INET || zpr.rule.filter.src_ip.family == AF_INET6)) { zlog_warn( - "Unsupported PBR source IP family: %s (%hhu)", + "Unsupported PBR source IP family: %s (%u)", family2str(zpr.rule.filter.src_ip.family), zpr.rule.filter.src_ip.family); return; @@ -3249,11 +3276,12 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) if (!(zpr.rule.filter.dst_ip.family == AF_INET || zpr.rule.filter.dst_ip.family == AF_INET6)) { zlog_warn( - "Unsupported PBR destination IP family: %s (%hhu)", + "Unsupported PBR destination IP family: %s (%u)", family2str(zpr.rule.filter.dst_ip.family), zpr.rule.filter.dst_ip.family); return; } + /* TBD delete above block when netlink code gets family from zpr.rule.family */ zpr.vrf_id = zvrf->vrf->vrf_id; @@ -3508,7 +3536,7 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS) if (zpi.src_port_max != 0) zpi.filter_bm |= PBR_FILTER_SRC_PORT_RANGE; if (zpi.proto != 0) - zpi.filter_bm |= PBR_FILTER_PROTO; + zpi.filter_bm |= PBR_FILTER_IP_PROTOCOL; if (!(zpi.dst.family == AF_INET || zpi.dst.family == AF_INET6)) { @@ -3557,7 +3585,7 @@ static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS) afi); goto stream_failure; } - vrf_bitmap_set(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_set(&client->neighinfo[afi], zvrf_id(zvrf)); stream_failure: return; } @@ -3573,7 +3601,7 @@ static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS) afi); goto stream_failure; } - vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf)); stream_failure: return; } @@ -3899,6 +3927,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_REMOTE_MACIP_DEL] = zebra_vxlan_remote_macip_del, [ZEBRA_DUPLICATE_ADDR_DETECTION] = zebra_vxlan_dup_addr_detection, [ZEBRA_INTERFACE_SET_MASTER] = zread_interface_set_master, + [ZEBRA_INTERFACE_SET_ARP] = zread_interface_set_arp, [ZEBRA_PW_ADD] = zread_pseudowire, [ZEBRA_PW_DELETE] = zread_pseudowire, [ZEBRA_PW_SET] = zread_pseudowire, @@ -3930,8 +3959,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh, [ZEBRA_NEIGH_IP_ADD] = zebra_neigh_ip_add, [ZEBRA_NEIGH_IP_DEL] = zebra_neigh_ip_del, - [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register, - [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister, + [ZEBRA_NEIGH_REGISTER] = zebra_neigh_register, + [ZEBRA_NEIGH_UNREGISTER] = zebra_neigh_unregister, [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp, [ZEBRA_GRE_GET] = zebra_gre_get, [ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set, @@ -3976,8 +4005,7 @@ void zserv_handle_commands(struct zserv *client, struct stream_fifo *fifo) hdr.length -= ZEBRA_HEADER_SIZE; /* Before checking for a handler function, check for - * special messages that are handled in another module; - * we'll treat these as opaque. + * special messages that are handled the 'opaque zapi' module. */ if (zebra_opaque_handles_msgid(hdr.command)) { /* Reset message buffer */ diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index ce8e154465..43f734d26e 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -53,12 +53,11 @@ extern int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp); extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct route_node *rn, - const struct route_entry *re); + const struct route_entry *re, + bool is_table_direct); extern int zsend_router_id_update(struct zserv *zclient, afi_t afi, struct prefix *p, vrf_id_t vrf_id); -extern int zsend_interface_vrf_update(struct zserv *zclient, - struct interface *ifp, vrf_id_t vrf_id); extern int zsend_interface_link_params(struct zserv *zclient, struct interface *ifp); extern int zsend_pw_update(struct zserv *client, struct zebra_pw *pw); @@ -92,9 +91,9 @@ extern int zsend_label_manager_connect_response(struct zserv *client, extern int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint, char *name, int status); -extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, - struct ipaddr *ipaddr, int ndm_state, - union sockunion *link_layer_ipv4); +extern void zsend_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4, int ip_len); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); diff --git a/zebra/zebra_affinitymap.c b/zebra/zebra_affinitymap.c index ae0f9a8a35..79bc78a7dc 100644 --- a/zebra/zebra_affinitymap.c +++ b/zebra/zebra_affinitymap.c @@ -26,102 +26,26 @@ #include "zebra/redistribute.h" #include "zebra/zebra_affinitymap.h" -static bool zebra_affinity_map_check_use(const char *affmap_name) -{ - char xpath[XPATH_MAXLEN]; - struct interface *ifp; - struct vrf *vrf; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (yang_dnode_exists(running_config->dnode, xpath)) - return true; - } - } - return false; -} - -static bool zebra_affinity_map_check_update(const char *affmap_name, - uint16_t new_pos) -{ - char xpath[XPATH_MAXLEN]; - struct interface *ifp; - struct vrf *vrf; - - /* check whether the affinity-map new bit position is upper than 31 - * but is used on an interface on which affinity-mode is standard. - * Return false if the change is not possible. - */ - if (new_pos < 32) - return true; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - if (yang_dnode_get_enum( - running_config->dnode, - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", - ifp->name) == AFFINITY_MODE_STANDARD) - return false; - } - } - return true; -} - static void zebra_affinity_map_update(const char *affmap_name, uint16_t old_pos, uint16_t new_pos) { struct if_link_params *iflp; - enum affinity_mode aff_mode; - char xpath[XPATH_MAXLEN]; struct interface *ifp; struct vrf *vrf; RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - aff_mode = yang_dnode_get_enum( - running_config->dnode, - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", - ifp->name); iflp = if_link_params_get(ifp); - if (aff_mode == AFFINITY_MODE_EXTENDED || - aff_mode == AFFINITY_MODE_BOTH) { + if (!iflp) + continue; + if (IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + admin_group_get(&iflp->ext_admin_grp, old_pos)) { admin_group_unset(&iflp->ext_admin_grp, old_pos); admin_group_set(&iflp->ext_admin_grp, new_pos); } - if (aff_mode == AFFINITY_MODE_STANDARD || - aff_mode == AFFINITY_MODE_BOTH) { + if (IS_PARAM_SET(iflp, LP_ADM_GRP) && + (iflp->admin_grp & (1 << old_pos))) { iflp->admin_grp &= ~(1 << old_pos); if (new_pos < 32) iflp->admin_grp |= 1 << new_pos; @@ -138,7 +62,5 @@ void zebra_affinity_map_init(void) { affinity_map_init(); - affinity_map_set_check_use_hook(zebra_affinity_map_check_use); - affinity_map_set_check_update_hook(zebra_affinity_map_check_update); affinity_map_set_update_hook(zebra_affinity_map_update); } diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c new file mode 100644 index 0000000000..00e0a49cb8 --- /dev/null +++ b/zebra/zebra_cli.c @@ -0,0 +1,2984 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "command.h" +#include "defaults.h" +#include "northbound_cli.h" +#include "vrf.h" + +#include "zebra_cli.h" +#include "zebra/zebra_cli_clippy.c" + +#define EVPN_MH_VTY_STR "Multihoming\n" + +FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT, + { .val_bool = true, .match_profile = "traditional", }, + { .val_bool = false }, +); + +#if HAVE_BFDD == 0 +DEFPY_YANG (zebra_ptm_enable, + zebra_ptm_enable_cmd, + "[no] ptm-enable", + NO_STR + "Enable neighbor check with specified topology\n") +{ + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/ptm-enable", NB_OP_MODIFY, + no ? "false" : "true"); + return nb_cli_apply_changes(vty, NULL); +} + +static void zebra_ptm_enable_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool enable = yang_dnode_get_bool(dnode, NULL); + + if (enable) + vty_out(vty, "ptm-enable\n"); + else if (show_defaults) + vty_out(vty, "no ptm-enable\n"); +} +#endif + +DEFPY_YANG (zebra_route_map_timer, + zebra_route_map_timer_cmd, + "[no] zebra route-map delay-timer ![(0-600)$delay]", + NO_STR + ZEBRA_STR + "Set route-map parameters\n" + "Time to wait before route-map updates are processed\n" + "0 means route-map changes are run immediately instead of delaying\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/route-map-delay", + NB_OP_MODIFY, delay_str); + else + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/route-map-delay", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void zebra_route_map_delay_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + uint32_t delay = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, "zebra route-map delay-timer %u\n", delay); +} + +DEFPY_YANG (multicast_new, + multicast_new_cmd, + "[no] multicast <enable$on|disable$off>", + NO_STR + "Control multicast flag on interface\n" + "Set multicast flag on interface\n" + "Unset multicast flag on interface\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_CREATE, on ? "true" : "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_multicast_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool multicast = yang_dnode_get_bool(dnode, NULL); + + if (multicast) + vty_out(vty, " multicast enable\n"); + else + vty_out(vty, " multicast disable\n"); +} + +/* Deprecated multicast commands */ + +DEFPY_YANG_HIDDEN (multicast, + multicast_cmd, + "[no] multicast", + NO_STR + "Set multicast flag to interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_CREATE, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (mpls, + mpls_cmd, + "[no] mpls <enable$on|disable$off>", + NO_STR + MPLS_STR + "Set mpls to be on for the interface\n" + "Set mpls to be off for the interface\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", + NB_OP_CREATE, on ? "true" : "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_mpls_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool mpls = yang_dnode_get_bool(dnode, NULL); + + if (mpls) + vty_out(vty, " mpls enable\n"); + else + vty_out(vty, " mpls disable\n"); +} + +DEFPY_YANG (linkdetect, + linkdetect_cmd, + "[no] link-detect", + NO_STR + "Enable link detection on interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-detect", + NB_OP_CREATE, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_detect_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool link_detect = yang_dnode_get_bool(dnode, NULL); + + if (!link_detect) + vty_out(vty, " no link-detect\n"); + else if (show_defaults) + vty_out(vty, " link-detect\n"); +} + +DEFPY_YANG (shutdown_if, + shutdown_if_cmd, + "[no] shutdown", + NO_STR + "Shutdown the selected interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/enabled", NB_OP_CREATE, + no ? "true" : "false"); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_enabled_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool enabled = yang_dnode_get_bool(dnode, NULL); + + if (!enabled) + vty_out(vty, " shutdown\n"); + else if (show_defaults) + vty_out(vty, " no shutdown\n"); +} + +DEFPY_YANG (bandwidth_if, + bandwidth_if_cmd, + "[no] bandwidth ![(1-1000000)]$bw", + NO_STR + "Set bandwidth informational parameter\n" + "Bandwidth in megabits\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/bandwidth", + NB_OP_CREATE, bw_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/bandwidth", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_bandwidth_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + uint32_t bandwidth = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " bandwidth %u\n", bandwidth); +} + +DEFUN_YANG_NOSH (link_params, + link_params_cmd, + "link-params", + LINK_PARAMS_STR) +{ + int ret; + + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-params", + NB_OP_CREATE, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) { + char *xpath; + + xpath = asprintfrr(MTYPE_TMP, "%s/frr-zebra:zebra/link-params", + VTY_CURR_XPATH); + VTY_PUSH_XPATH(LINK_PARAMS_NODE, xpath); + XFREE(MTYPE_TMP, xpath); + } + + return ret; +} + +DEFUN_NOSH (exit_link_params, + exit_link_params_cmd, + "exit-link-params", + "Exit from Link Params configuration mode\n") +{ + cmd_exit(vty); + return CMD_SUCCESS; +} + +static void lib_interface_zebra_link_params_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " link-params\n"); +} + +static void +lib_interface_zebra_link_params_cli_write_end(struct vty *vty, + const struct lyd_node *dnode) +{ + vty_out(vty, " exit-link-params\n"); +} + +DEFUN_YANG (no_link_params, + no_link_params_cmd, + "no link-params", + NO_STR + LINK_PARAMS_STR) +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-params", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* [no] enable is deprecated, link-params is enabled when entering the node. */ + +DEFUN_YANG_HIDDEN (link_params_enable, + link_params_enable_cmd, + "enable", + "Activate link parameters on this interface\n") +{ + vty_out(vty, "This command is deprecated. Link parameters are activated when \"link-params\" node is entered.\n"); + + return CMD_SUCCESS; +} + +DEFUN_YANG_NOSH (no_link_params_enable, + no_link_params_enable_cmd, + "no enable", + NO_STR + "Disable link parameters on this interface\n") +{ + int ret; + + vty_out(vty, "This command is deprecated. To disable link parameters use \"no link-params\" in the interface node.\n"); + + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + cmd_exit(vty); + + return ret; +} + +DEFPY_YANG (link_params_metric, + link_params_metric_cmd, + "[no] metric ![(0-4294967295)]$metric", + NO_STR + "Link metric for MPLS-TE purpose\n" + "Metric value in decimal\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); + else + nb_cli_enqueue_change(vty, "./metric", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_metric_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t metric = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " metric %u\n", metric); +} + +DEFPY_YANG (link_params_maxbw, + link_params_maxbw_cmd, + "max-bw BANDWIDTH", + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./max-bandwidth", NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_max_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float max_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, NULL); + + vty_out(vty, " max-bw %g\n", max_bandwidth); +} + +DEFPY_YANG (link_params_max_rsv_bw, + link_params_max_rsv_bw_cmd, + "max-rsv-bw BANDWIDTH", + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./max-reservable-bandwidth", NB_OP_MODIFY, + value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_max_reservable_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float max_reservable_bandwidth = + yang_dnode_get_bandwidth_ieee_float32(dnode, NULL); + + vty_out(vty, " max-rsv-bw %g\n", max_reservable_bandwidth); +} + +DEFPY_YANG (link_params_unrsv_bw, + link_params_unrsv_bw_cmd, + "unrsv-bw (0-7)$priority BANDWIDTH", + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + char xpath[XPATH_MAXLEN]; + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(xpath, sizeof(xpath), + "./unreserved-bandwidths/unreserved-bandwidth[priority='%s']/unreserved-bandwidth", + priority_str); + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint8_t priority = yang_dnode_get_uint8(dnode, "priority"); + float unreserved_bandwidth = + yang_dnode_get_bandwidth_ieee_float32(dnode, + "unreserved-bandwidth"); + + vty_out(vty, " unrsv-bw %u %g\n", priority, unreserved_bandwidth); +} + +DEFPY_YANG (link_params_admin_grp, + link_params_admin_grp_cmd, + "[no] admin-grp ![BITPATTERN]", + NO_STR + "Administrative group membership\n" + "32-bit Hexadecimal value (e.g. 0xa1)\n") +{ + uint32_t value; + char value_str[YANG_VALUE_MAXLEN]; + + if (!no) { + assert(bitpattern); + + if (bitpattern[0] != '0' || bitpattern[1] != 'x' || + strlen(bitpattern) > 10) { + vty_out(vty, "Invalid bitpattern value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sscanf(bitpattern, "%x", &value) != 1) { + vty_out(vty, "Invalid bitpattern value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value_str, sizeof(value_str), "%u", value); + + nb_cli_enqueue_change(vty, "./legacy-admin-group", NB_OP_MODIFY, + value_str); + } else { + nb_cli_enqueue_change(vty, "./legacy-admin-group", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_legacy_admin_group_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " admin-grp %#x\n", yang_dnode_get_uint32(dnode, NULL)); +} + +/* RFC5392 & RFC5316: INTER-AS */ +DEFPY_YANG (link_params_inter_as, + link_params_inter_as_cmd, + "[no] neighbor ![A.B.C.D$ip as (1-4294967295)$as]", + NO_STR + "Configure remote ASBR information (Neighbor IP address and AS number)\n" + "Remote IP address in dot decimal A.B.C.D\n" + "Remote AS number\n" + "AS number in the range <1-4294967295>\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./neighbor/remote-as", NB_OP_MODIFY, + as_str); + nb_cli_enqueue_change(vty, "./neighbor/ipv4-remote-id", + NB_OP_MODIFY, ip_str); + } else { + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_neighbor_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t remote_as = yang_dnode_get_uint32(dnode, "remote-as"); + const char *ipv4_remote_id = yang_dnode_get_string(dnode, + "ipv4-remote-id"); + + vty_out(vty, " neighbor %s as %u\n", ipv4_remote_id, remote_as); +} + +/* RFC7471 & RFC8570 */ +DEFPY_YANG (link_params_delay, + link_params_delay_cmd, + "[no] delay ![(0-16777215)$delay [min (0-16777215)$min max (0-16777215)$max]]", + NO_STR + "Unidirectional Average Link Delay\n" + "Average delay in micro-second as decimal (0...16777215)\n" + "Minimum delay\n" + "Minimum delay in micro-second as decimal (0...16777215)\n" + "Maximum delay\n" + "Maximum delay in micro-second as decimal (0...16777215)\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, "./delay", NB_OP_MODIFY, delay_str); + if (min_str && max_str) { + nb_cli_enqueue_change(vty, "./min-max-delay", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./min-max-delay/delay-min", + NB_OP_MODIFY, min_str); + nb_cli_enqueue_change(vty, "./min-max-delay/delay-max", + NB_OP_MODIFY, max_str); + } else { + nb_cli_enqueue_change(vty, "./min-max-delay", + NB_OP_DESTROY, NULL); + } + } else { + nb_cli_enqueue_change(vty, "./delay", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./min-max-delay", NB_OP_DESTROY, + NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_delay_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t delay = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " delay %u", delay); + + if (yang_dnode_exists(dnode, "../min-max-delay")) { + uint32_t delay_min = + yang_dnode_get_uint32(dnode, + "../min-max-delay/delay-min"); + uint32_t delay_max = + yang_dnode_get_uint32(dnode, + "../min-max-delay/delay-max"); + + vty_out(vty, " min %u max %u", delay_min, delay_max); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (link_params_delay_var, + link_params_delay_var_cmd, + "[no] delay-variation ![(0-16777215)$delay_var]", + NO_STR + "Unidirectional Link Delay Variation\n" + "delay variation in micro-second as decimal (0...16777215)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./delay-variation", NB_OP_MODIFY, + delay_var_str); + else + nb_cli_enqueue_change(vty, "./delay-variation", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_delay_variation_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t delay_variation = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " delay-variation %u\n", delay_variation); +} + +DEFPY_YANG( + link_params_pkt_loss, link_params_pkt_loss_cmd, + "[no] packet-loss ![PERCENTAGE]", + NO_STR + "Unidirectional Link Packet Loss\n" + "percentage of total traffic by 0.000003% step and less than 50.331642%\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./packet-loss", NB_OP_MODIFY, + percentage); + else + nb_cli_enqueue_change(vty, "./packet-loss", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_packet_loss_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + double packet_loss = yang_dnode_get_dec64(dnode, NULL); + + vty_out(vty, " packet-loss %lf\n", packet_loss); +} + +DEFPY_YANG (link_params_res_bw, + link_params_res_bw_cmd, + "[no] res-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Residual Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./residual-bandwidth", NB_OP_MODIFY, + value); + } else { + nb_cli_enqueue_change(vty, "./residual-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_residual_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float residual_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " res-bw %g\n", residual_bandwidth); +} + +DEFPY_YANG (link_params_ava_bw, + link_params_ava_bw_cmd, + "[no] ava-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Available Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./available-bandwidth", + NB_OP_MODIFY, value); + } else { + nb_cli_enqueue_change(vty, "./available-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_available_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float available_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " ava-bw %g\n", available_bandwidth); +} + +DEFPY_YANG (link_params_use_bw, + link_params_use_bw_cmd, + "[no] use-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Utilised Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./utilized-bandwidth", NB_OP_MODIFY, + value); + } else { + nb_cli_enqueue_change(vty, "./utilized-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_utilized_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float utilized_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " use-bw %g\n", utilized_bandwidth); +} + +DEFPY_YANG (link_params_affinity, + link_params_affinity_cmd, + "[no] affinity NAME...", + NO_STR + "Interface affinities\n" + "Affinity names\n") +{ + char xpath[XPATH_MAXLEN]; + int i; + + for (i = no ? 2 : 1; i < argc; i++) { + snprintf(xpath, XPATH_MAXLEN, "./affinities/affinity[.='%s']", + argv[i]->arg); + nb_cli_enqueue_change(vty, xpath, + no ? NB_OP_DESTROY : NB_OP_CREATE, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static int ag_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct vty *vty = arg; + + vty_out(vty, " %s", yang_dnode_get_string(dnode, NULL)); + return YANG_ITER_CONTINUE; +} + +static void lib_interface_zebra_link_params_affinities_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " affinity"); + yang_dnode_iterate(ag_iter_cb, vty, dnode, "affinity"); + vty_out(vty, "\n"); +} + +DEFPY_YANG (link_params_affinity_mode, + link_params_affinity_mode_cmd, + "[no] affinity-mode ![<standard|extended|both>$mode]", + NO_STR + "Interface affinity mode\n" + "Standard Admin-Group only RFC3630,5305,5329\n" + "Extended Admin-Group only RFC7308 (default)\n" + "Standard and extended Admin-Group format\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./affinity-mode", NB_OP_MODIFY, + mode); + else + nb_cli_enqueue_change(vty, "./affinity-mode", NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_affinity_mode_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + enum affinity_mode affinity_mode = yang_dnode_get_enum(dnode, NULL); + + if (affinity_mode == AFFINITY_MODE_STANDARD) + vty_out(vty, " affinity-mode standard\n"); + else if (affinity_mode == AFFINITY_MODE_BOTH) + vty_out(vty, " affinity-mode both\n"); + else if (affinity_mode == AFFINITY_MODE_EXTENDED && show_defaults) + vty_out(vty, " affinity-mode extended\n"); +} + +#ifdef HAVE_NETLINK +DEFPY_YANG (ip_address, + ip_address_cmd, + "[no] ip address A.B.C.D/M [label LINE$label]", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +#else +DEFPY_YANG (ip_address, + ip_address_cmd, + "[no] ip address A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n") +#endif +{ + char ip[INET_ADDRSTRLEN + 3]; + char *mask; + + if (no) { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); +#ifdef HAVE_NETLINK + if (label) + nb_cli_enqueue_change(vty, "./label", NB_OP_MODIFY, + label); + else + nb_cli_enqueue_change(vty, "./label", NB_OP_DESTROY, + NULL); +#endif + } + + strlcpy(ip, address_str, sizeof(ip)); + + mask = strchr(ip, '/'); + assert(mask); + *mask = 0; + mask++; + + return nb_cli_apply_changes(vty, + "./frr-zebra:zebra/ipv4-addrs[ip='%s'][prefix-length='%s']", + ip, mask); +} + +static void lib_interface_zebra_ipv4_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + uint8_t prefix_length = yang_dnode_get_uint8(dnode, "prefix-length"); + + vty_out(vty, " ip address %s/%u", ip, prefix_length); + + if (yang_dnode_exists(dnode, "label")) { + const char *label = yang_dnode_get_string(dnode, "label"); + + vty_out(vty, " label %s", label); + } + + vty_out(vty, "\n"); +} + +#ifdef HAVE_NETLINK +DEFPY_YANG (ip_address_peer, + ip_address_peer_cmd, + "[no] ip address A.B.C.D peer A.B.C.D/M [label LINE$label]", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +#else +DEFPY_YANG (ip_address_peer, + ip_address_peer_cmd, + "[no] ip address A.B.C.D peer A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n") +#endif +{ + char peer_ip[INET_ADDRSTRLEN + 3]; + char *peer_mask; + + if (no) { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); +#ifdef HAVE_NETLINK + if (label) + nb_cli_enqueue_change(vty, "./label", NB_OP_MODIFY, + label); + else + nb_cli_enqueue_change(vty, "./label", NB_OP_DESTROY, + NULL); +#endif + } + + strlcpy(peer_ip, peer_str, sizeof(peer_ip)); + + peer_mask = strchr(peer_ip, '/'); + assert(peer_mask); + *peer_mask = 0; + peer_mask++; + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv4-p2p-addrs[ip='%s'][peer-ip='%s'][peer-prefix-length='%s']", + address_str, peer_ip, peer_mask); +} + +static void lib_interface_zebra_ipv4_p2p_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + const char *peer_ip = yang_dnode_get_string(dnode, "peer-ip"); + uint8_t peer_prefix_length = yang_dnode_get_uint8(dnode, + "peer-prefix-length"); + + vty_out(vty, " ip address %s peer %s/%u", ip, peer_ip, + peer_prefix_length); + + if (yang_dnode_exists(dnode, "label")) { + const char *label = yang_dnode_get_string(dnode, "label"); + + vty_out(vty, " label %s", label); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_address, + ipv6_address_cmd, + "[no] ipv6 address X:X::X:X/M", + NO_STR + "Interface IPv6 config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + char ip[INET6_ADDRSTRLEN + 4]; + char *mask; + + if (no) + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + + strlcpy(ip, address_str, sizeof(ip)); + + mask = strchr(ip, '/'); + assert(mask); + *mask = 0; + mask++; + + return nb_cli_apply_changes(vty, + "./frr-zebra:zebra/ipv6-addrs[ip='%s'][prefix-length='%s']", + ip, mask); +} + +static void lib_interface_zebra_ipv6_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + uint8_t prefix_length = yang_dnode_get_uint8(dnode, "prefix-length"); + + vty_out(vty, " ipv6 address %s/%u\n", ip, prefix_length); +} + +/* CLI for setting an ES in bypass mode */ +DEFPY_YANG_HIDDEN (zebra_evpn_es_bypass, + zebra_evpn_es_bypass_cmd, + "[no] evpn mh bypass", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Set bypass mode\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/bypass", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/bypass", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_bypass_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool bypass = yang_dnode_get_bool(dnode, NULL); + + if (bypass) + vty_out(vty, " evpn mh bypass\n"); + else if (show_defaults) + vty_out(vty, " no evpn mh bypass\n"); +} + +/* CLI for configuring DF preference part for an ES */ +DEFPY_YANG (zebra_evpn_es_pref, + zebra_evpn_es_pref_cmd, + "[no$no] evpn mh es-df-pref ![(1-65535)$df_pref]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Preference value used for DF election\n" + "Preference\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/df-preference", + NB_OP_MODIFY, df_pref_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/df-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_df_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t df_pref = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " evpn mh es-df-pref %u\n", df_pref); +} + +/* CLI for setting up sysmac part of ESI on an access port */ +DEFPY_YANG (zebra_evpn_es_sys_mac, + zebra_evpn_es_sys_mac_cmd, + "[no$no] evpn mh es-sys-mac ![X:X:X:X:X:X$mac]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Ethernet segment system MAC\n" + MAC_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/system-mac", + NB_OP_MODIFY, mac_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/system-mac", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_type_3_system_mac_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + char buf[ETHER_ADDR_STRLEN]; + struct ethaddr mac; + + yang_dnode_get_mac(&mac, dnode, NULL); + + vty_out(vty, " evpn mh es-sys-mac %s\n", + prefix_mac2str(&mac, buf, sizeof(buf))); +} + +/* CLI for setting up local-ID part of ESI on an access port */ +DEFPY_YANG (zebra_evpn_es_id, + zebra_evpn_es_id_cmd, + "[no$no] evpn mh es-id ![(1-16777215)$es_lid | NAME$esi_str]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Ethernet segment identifier\n" + "local discriminator\n" + "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n") +{ + if (no) { + /* We don't know which one is configured, so detroy both types. */ + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-0/esi", + NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + NB_OP_DESTROY, NULL); + } else { + if (esi_str) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-0/esi", + NB_OP_MODIFY, esi_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + NB_OP_MODIFY, es_lid_str); + } + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_type_0_esi_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *esi_str = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " evpn mh es-id %s\n", esi_str); +} + +static void lib_interface_zebra_evpn_mh_type_3_local_discriminator_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t es_lid = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " evpn mh es-id %u\n", es_lid); +} + +/* CLI for tagging an interface as an uplink */ +DEFPY_YANG (zebra_evpn_mh_uplink, + zebra_evpn_mh_uplink_cmd, + "[no] evpn mh uplink", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Uplink to the VxLAN core\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/uplink", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/uplink", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_uplink_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool uplink = yang_dnode_get_bool(dnode, NULL); + + if (uplink) + vty_out(vty, " evpn mh uplink\n"); + else if (show_defaults) + vty_out(vty, " no evpn mh uplink\n"); +} + +#if defined(HAVE_RTADV) +DEFPY_YANG (ipv6_nd_ra_fast_retrans, + ipv6_nd_ra_fast_retrans_cmd, + "[no] ipv6 nd ra-fast-retrans", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Fast retransmit of RA packets\n") +{ + if (no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool fast_retransmit = yang_dnode_get_bool(dnode, NULL); + + if (!fast_retransmit) + vty_out(vty, " no ipv6 nd ra-fast-retrans\n"); + else if (show_defaults) + vty_out(vty, " ipv6 nd ra-fast-retrans\n"); +} + +DEFPY_YANG (ipv6_nd_ra_hop_limit, + ipv6_nd_ra_hop_limit_cmd, + "[no] ipv6 nd ra-hop-limit ![(0-255)$hopcount]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Hop Limit\n" + "Advertisement Hop Limit in hops (default:64)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + NB_OP_MODIFY, hopcount_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint8_t hop_limit = yang_dnode_get_uint8(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-hop-limit %u\n", hop_limit); +} + +DEFPY_YANG (ipv6_nd_ra_retrans_interval, + ipv6_nd_ra_retrans_interval_cmd, + "[no] ipv6 nd ra-retrans-interval ![(0-4294967295)$interval]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Retransmit Interval\n" + "Advertisement Retransmit Interval in msec\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + NB_OP_MODIFY, interval_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_retrans_timer_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t retrans_timer = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-retrans-interval %u\n", retrans_timer); +} + +DEFPY_YANG (ipv6_nd_suppress_ra, + ipv6_nd_suppress_ra_cmd, + "[no] ipv6 nd suppress-ra", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + if (no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_send_advertisements_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool send_advertisements = yang_dnode_get_bool(dnode, NULL); + + if (send_advertisements) + vty_out(vty, " no ipv6 nd suppress-ra\n"); + else if (show_defaults) + vty_out(vty, " ipv6 nd suppress-ra\n"); +} + +DEFPY_YANG (ipv6_nd_ra_interval, + ipv6_nd_ra_interval_cmd, + "[no] ipv6 nd ra-interval ![<(1-1800)$sec|msec (70-1800000)$msec>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in seconds\n" + "Router Advertisement interval in milliseconds\n" + "Router Advertisement interval in milliseconds\n") +{ + char value[YANG_VALUE_MAXLEN]; + + if (!no) { + if (sec) + snprintf(value, sizeof(value), "%lu", sec * 1000); + else + snprintf(value, sizeof(value), "%lu", msec); + + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + NB_OP_MODIFY, value); + } else { + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t max_rtr_adv_interval = yang_dnode_get_uint32(dnode, NULL); + + if (max_rtr_adv_interval % 1000) + vty_out(vty, " ipv6 nd ra-interval msec %u\n", + max_rtr_adv_interval); + else + vty_out(vty, " ipv6 nd ra-interval %u\n", + max_rtr_adv_interval / 1000); +} + +DEFPY_YANG (ipv6_nd_ra_lifetime, + ipv6_nd_ra_lifetime_cmd, + "[no] ipv6 nd ra-lifetime ![(0-9000)$lifetime]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds (0 stands for a non-default gw)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + NB_OP_MODIFY, lifetime_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_default_lifetime_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t default_lifetime = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-lifetime %u\n", default_lifetime); +} + +DEFPY_YANG (ipv6_nd_reachable_time, + ipv6_nd_reachable_time_cmd, + "[no] ipv6 nd reachable-time ![(1-3600000)$msec]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + NB_OP_MODIFY, msec_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_reachable_time_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t reachable_time = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd reachable-time %u\n", reachable_time); +} + +DEFPY_YANG (ipv6_nd_homeagent_preference, + ipv6_nd_homeagent_preference_cmd, + "[no] ipv6 nd home-agent-preference ![(0-65535)$pref]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent preference\n" + "preference value (default is 0, least preferred)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + NB_OP_MODIFY, pref_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t home_agent_preference = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd home-agent-preference %u\n", + home_agent_preference); +} + +DEFPY_YANG (ipv6_nd_homeagent_lifetime, + ipv6_nd_homeagent_lifetime_cmd, + "[no] ipv6 nd home-agent-lifetime ![(1-65520)$lifetime]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent lifetime\n" + "Home Agent lifetime in seconds\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + NB_OP_MODIFY, lifetime_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t home_agent_lifetime = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd home-agent-lifetime %u\n", home_agent_lifetime); +} + +DEFPY_YANG (ipv6_nd_managed_config_flag, + ipv6_nd_managed_config_flag_cmd, + "[no] ipv6 nd managed-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ipv6_router_advertisements_managed_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool managed_flag = yang_dnode_get_bool(dnode, NULL); + + if (managed_flag) + vty_out(vty, " ipv6 nd managed-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd managed-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_homeagent_config_flag, + ipv6_nd_homeagent_config_flag_cmd, + "[no] ipv6 nd home-agent-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool home_agent_flag = yang_dnode_get_bool(dnode, NULL); + + if (home_agent_flag) + vty_out(vty, " ipv6 nd home-agent-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd home-agent-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_adv_interval_config_option, + ipv6_nd_adv_interval_config_option_cmd, + "[no] ipv6 nd adv-interval-option", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Interval Option\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool advertisement_interval_option = yang_dnode_get_bool(dnode, NULL); + + if (advertisement_interval_option) + vty_out(vty, " ipv6 nd adv-interval-option\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd adv-interval-option\n"); +} + +DEFPY_YANG (ipv6_nd_other_config_flag, + ipv6_nd_other_config_flag_cmd, + "[no] ipv6 nd other-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_other_config_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool other_config_flag = yang_dnode_get_bool(dnode, NULL); + + if (other_config_flag) + vty_out(vty, " ipv6 nd other-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd other-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_prefix, + ipv6_nd_prefix_cmd, + "[no] ipv6 nd prefix X:X::X:X/M$prefix [<(0-4294967295)|infinite>$valid <(0-4294967295)|infinite>$preferred] [{router-address$routeraddr|off-link$offlink|no-autoconfig$noautoconf}]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n" + "Preferred lifetime in seconds\n" + "Infinite preferred lifetime\n" + "Set Router Address flag\n" + "Do not use prefix for onlink determination\n" + "Do not use prefix for autoconfiguration\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (valid) { + if (strmatch(valid, "infinite")) + valid = "4294967295"; + nb_cli_enqueue_change(vty, "./valid-lifetime", + NB_OP_MODIFY, valid); + } else { + nb_cli_enqueue_change(vty, "./valid-lifetime", + NB_OP_DESTROY, NULL); + } + if (preferred) { + if (strmatch(preferred, "infinite")) + preferred = "4294967295"; + nb_cli_enqueue_change(vty, "./preferred-lifetime", + NB_OP_MODIFY, preferred); + } else { + nb_cli_enqueue_change(vty, "./preferred-lifetime", + NB_OP_DESTROY, NULL); + } + if (routeraddr) + nb_cli_enqueue_change(vty, "./router-address-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./router-address-flag", + NB_OP_DESTROY, NULL); + if (offlink) + nb_cli_enqueue_change(vty, "./on-link-flag", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./on-link-flag", + NB_OP_DESTROY, NULL); + if (noautoconf) + nb_cli_enqueue_change(vty, "./autonomous-flag", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./autonomous-flag", + NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix[prefix-spec='%s']", + prefix_str); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, "prefix-spec"); + struct lyd_node *valid = yang_dnode_get(dnode, "valid-lifetime"); + struct lyd_node *preferred = yang_dnode_get(dnode, "preferred-lifetime"); + bool router_address_flag = yang_dnode_get_bool(dnode, + "router-address-flag"); + bool on_link_flag = yang_dnode_get_bool(dnode, "on-link-flag"); + bool autonomous_flag = yang_dnode_get_bool(dnode, "autonomous-flag"); + + vty_out(vty, " ipv6 nd prefix %s", prefix); + + if (!yang_dnode_is_default(valid, NULL) || + !yang_dnode_is_default(preferred, NULL) || show_defaults) { + uint32_t valid_lifetime = yang_dnode_get_uint32(valid, NULL); + uint32_t preferred_lifetime = yang_dnode_get_uint32(preferred, + NULL); + + if (valid_lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", valid_lifetime); + if (preferred_lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", preferred_lifetime); + } + + if (!on_link_flag) + vty_out(vty, " off-link"); + + if (!autonomous_flag) + vty_out(vty, " no-autoconfig"); + + if (router_address_flag) + vty_out(vty, " router-address"); + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_nd_router_preference, + ipv6_nd_router_preference_cmd, + "[no] ipv6 nd router-preference ![<high|medium|low>$pref]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Default router preference\n" + "High default router preference\n" + "Medium default router preference (default)\n" + "Low default router preference\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + NB_OP_MODIFY, pref); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_default_router_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *default_router_preference = yang_dnode_get_string(dnode, + NULL); + + vty_out(vty, " ipv6 nd router-preference %s\n", + default_router_preference); +} + +DEFPY_YANG (ipv6_nd_mtu, + ipv6_nd_mtu_cmd, + "[no] ipv6 nd mtu ![(1-65535)]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertised MTU\n" + "MTU in bytes\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + NB_OP_MODIFY, mtu_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ipv6_router_advertisements_link_mtu_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t link_mtu = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd mtu %u\n", link_mtu); +} + +DEFPY_YANG (ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "[no] ipv6 nd rdnss X:X::X:X$addr [<(0-4294967295)|infinite>]$lifetime", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (lifetime) { + if (strmatch(lifetime, "infinite")) + lifetime = "4294967295"; + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_MODIFY, + lifetime); + } else { + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_DESTROY, + NULL); + } + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address[address='%s']", + addr_str); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *address = yang_dnode_get_string(dnode, "address"); + + vty_out(vty, " ipv6 nd rdnss %s", address); + + if (yang_dnode_exists(dnode, "lifetime")) { + uint32_t lifetime = yang_dnode_get_uint32(dnode, "lifetime"); + + if (lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", lifetime); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_nd_dnssl, + ipv6_nd_dnssl_cmd, + "[no] ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]$lifetime", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + char domain[254]; + size_t len; + + len = strlcpy(domain, suffix, sizeof(domain)); + if (len == 0 || len >= sizeof(domain)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (domain[len - 1] == '.') { + /* + * Allow, but don't require, a trailing dot signifying the root + * zone. Canonicalize by cutting it off if present. + */ + domain[len - 1] = '\0'; + len--; + } + + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (lifetime) { + if (strmatch(lifetime, "infinite")) + lifetime = "4294967295"; + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_MODIFY, + lifetime); + } else { + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_DESTROY, + NULL); + } + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain[domain='%s']", + domain); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *domain = yang_dnode_get_string(dnode, "domain"); + + vty_out(vty, " ipv6 nd dnssl %s", domain); + + if (yang_dnode_exists(dnode, "lifetime")) { + uint32_t lifetime = yang_dnode_get_uint32(dnode, "lifetime"); + + if (lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", lifetime); + } + + vty_out(vty, "\n"); +} +#endif /* HAVE_RTADV */ + +#if HAVE_BFDD == 0 +DEFPY_YANG (zebra_ptm_enable_if, + zebra_ptm_enable_if_cmd, + "[no] ptm-enable", + NO_STR + "Enable neighbor check with specified topology\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ptm-enable", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ptm-enable", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ptm_enable_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool enable = yang_dnode_get_bool(dnode, NULL); + + if (!enable) + vty_out(vty, " no ptm-enable\n"); + else if (show_defaults) + vty_out(vty, " ptm-enable\n"); +} +#endif /* HAVE_BFDD == 0 */ + +/* + * VRF commands + */ + +static void zebra_vrf_indent_cli_write(struct vty *vty, + const struct lyd_node *dnode) +{ + const struct lyd_node *vrf = yang_dnode_get_parent(dnode, "vrf"); + + if (vrf && strcmp(yang_dnode_get_string(vrf, "name"), VRF_DEFAULT_NAME)) + vty_out(vty, " "); +} + +DEFPY_YANG (ip_router_id, + ip_router_id_cmd, + "[no] ip router-id A.B.C.D$id vrf NAME", + NO_STR + IP_STR + "Manually set the router-id\n" + "IP address to use for router-id\n" + VRF_CMD_HELP_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_MODIFY, + id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", vrf); +} + +ALIAS_YANG (ip_router_id, + router_id_cmd, + "[no] router-id A.B.C.D$id vrf NAME", + NO_STR + "Manually set the router-id\n" + "IP address to use for router-id\n" + VRF_CMD_HELP_STR); + +DEFPY_YANG (ipv6_router_id, + ipv6_router_id_cmd, + "[no] ipv6 router-id X:X::X:X$id vrf NAME", + NO_STR + IPV6_STR + "Manually set the router-id\n" + "IPv6 address to use for router-id\n" + VRF_CMD_HELP_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_MODIFY, id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", vrf); +} + +DEFPY_YANG (ip_router_id_in_vrf, + ip_router_id_in_vrf_cmd, + "[no] ip router-id ![A.B.C.D$id]", + NO_STR + IP_STR + "Manually set the router-id\n" + "IP address to use for router-id\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_MODIFY, + id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_DESTROY, + NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +ALIAS_YANG (ip_router_id_in_vrf, + router_id_in_vrf_cmd, + "[no] router-id ![A.B.C.D$id]", + NO_STR + "Manually set the router-id\n" + "IP address to use for router-id\n"); + +DEFPY_YANG (ipv6_router_id_in_vrf, + ipv6_router_id_in_vrf_cmd, + "[no] ipv6 router-id ![X:X::X:X$id]", + NO_STR + IP6_STR + "Manually set the IPv6 router-id\n" + "IPV6 address to use for router-id\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_MODIFY, id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_DESTROY, NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_router_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *id = yang_dnode_get_string(dnode, NULL); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ip router-id %s\n", id); +} + +static void lib_vrf_zebra_ipv6_router_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *id = yang_dnode_get_string(dnode, NULL); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ipv6 router-id %s\n", id); +} + +DEFPY_YANG (ip_protocol, + ip_protocol_cmd, + "[no] ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP_STR + "Filter routing info exchanged between zebra and protocol\n" + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route-map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), proto); +} + +DEFPY_YANG (ipv6_protocol, + ipv6_protocol_cmd, + "[no] ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP6_STR + "Filter IPv6 routing info exchanged between zebra and protocol\n" + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route-map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), proto); +} + +static void lib_vrf_zebra_filter_protocol_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(dnode, "protocol"); + const char *rmap = yang_dnode_get_string(dnode, "route-map"); + afi_t afi; + safi_t safi; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (safi != SAFI_UNICAST) + return; + + zebra_vrf_indent_cli_write(vty, dnode); + + if (afi == AFI_IP) + vty_out(vty, "ip protocol %s route-map %s\n", proto, rmap); + else + vty_out(vty, "ipv6 protocol %s route-map %s\n", proto, rmap); +} + +DEFPY_YANG (ip_protocol_nht_rmap, + ip_protocol_nht_rmap_cmd, + "[no] ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP_STR + "Filter Next Hop tracking route resolution\n" + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), proto); +} + +DEFPY_YANG (ipv6_protocol_nht_rmap, + ipv6_protocol_nht_rmap_cmd, + "[no] ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), proto); +} + +static void lib_vrf_zebra_filter_nht_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(dnode, "protocol"); + const char *rmap = yang_dnode_get_string(dnode, "route-map"); + afi_t afi; + safi_t safi; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (safi != SAFI_UNICAST) + return; + + zebra_vrf_indent_cli_write(vty, dnode); + + if (afi == AFI_IP) + vty_out(vty, "ip nht %s route-map %s\n", proto, rmap); + else + vty_out(vty, "ipv6 nht %s route-map %s\n", proto, rmap); +} + +DEFPY_YANG (ip_nht_default_route, + ip_nht_default_route_cmd, + "[no] ip nht resolve-via-default", + NO_STR + IP_STR + "Filter Next Hop tracking route resolution\n" + "Resolve via default route\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/resolve-via-default", + NB_OP_MODIFY, no ? "false" : "true"); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_resolve_via_default_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool resolve_via_default = yang_dnode_get_bool(dnode, NULL); + + if (resolve_via_default != SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT || + show_defaults) { + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "%sip nht resolve-via-default\n", + resolve_via_default ? "" : "no "); + } +} + +DEFPY_YANG (ipv6_nht_default_route, + ipv6_nht_default_route_cmd, + "[no] ipv6 nht resolve-via-default", + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + "Resolve via default route\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-resolve-via-default", + NB_OP_MODIFY, no ? "false" : "true"); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_ipv6_resolve_via_default_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool resolve_via_default = yang_dnode_get_bool(dnode, NULL); + + if (resolve_via_default != SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT || + show_defaults) { + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "%sipv6 nht resolve-via-default\n", + resolve_via_default ? "" : "no "); + } +} + +DEFPY_YANG (vrf_netns, + vrf_netns_cmd, + "[no] netns ![NAME$netns_name]", + NO_STR + "Attach VRF to a Namespace\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + vty_out(vty, "%% This command doesn't do anything.\n"); + vty_out(vty, + "%% VRF is linked to a netns automatically based on its name.\n"); + return CMD_WARNING; +} + +DEFPY_YANG (ip_table_range, ip_table_range_cmd, + "[no] ip table range ![(1-4294967295)$start (1-4294967295)$end]", + NO_STR IP_STR + "table configuration\n" + "Configure table range\n" + "Start Routing Table\n" + "End Routing Table\n") +{ + if (!no) { + const struct lyd_node *start_node; + const struct lyd_node *end_node; + + if (vty->node == CONFIG_NODE) { + start_node = + yang_dnode_getf(vty->candidate_config->dnode, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/netns/table-range/start", + VRF_DEFAULT_NAME); + end_node = + yang_dnode_getf(vty->candidate_config->dnode, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/netns/table-range/end", + VRF_DEFAULT_NAME); + } else { + start_node = + yang_dnode_getf(vty->candidate_config->dnode, + "%s/frr-zebra:zebra/netns/table-range/start", + VTY_CURR_XPATH); + end_node = + yang_dnode_getf(vty->candidate_config->dnode, + "%s/frr-zebra:zebra/netns/table-range/end", + VTY_CURR_XPATH); + } + + if (start_node && end_node) { + if (yang_dnode_get_uint32(start_node, NULL) != + (uint32_t)start || + yang_dnode_get_uint32(end_node, NULL) != + (uint32_t)end) { + vty_out(vty, + "%% New range will be taken into account at restart.\n"); + vty_out(vty, + "%% Don't forget to save your configuration.\n"); + } + } + + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/netns/table-range", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/netns/table-range/start", + NB_OP_MODIFY, start_str); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/netns/table-range/end", + NB_OP_MODIFY, end_str); + } else { + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/netns/table-range", + NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_netns_table_range_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t start = yang_dnode_get_uint32(dnode, "start"); + uint32_t end = yang_dnode_get_uint32(dnode, "end"); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ip table range %u %u\n", start, end); +} + +DEFPY_YANG (vni_mapping, + vni_mapping_cmd, + "[no] vni ![" CMD_VNI_RANGE "[prefix-routes-only$filter]]", + NO_STR + "VNI corresponding to tenant VRF\n" + "VNI-ID\n" + "prefix-routes-only\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY, + vni_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY, + NULL); + + if (filter) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_DESTROY, NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_l3vni_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vni_t vni = yang_dnode_get_uint32(dnode, NULL); + bool prefix_only = yang_dnode_get_bool(dnode, "../prefix-only"); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "vni %u", vni); + + if (prefix_only) + vty_out(vty, " prefix-routes-only"); + + vty_out(vty, "\n"); +} + +DEFPY_YANG( + match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, + "match ip address prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, + "no match ip address prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, + "match ipv6 address prefix-len (0-128)$length", + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, + "no match ipv6 address prefix-len [(0-128)]", + NO_STR + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, + "match ip next-hop prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefixlen of given nexthop\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, + "no match ip next-hop prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefix length of nexthop\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_source_protocol, match_source_protocol_cmd, + "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_source_protocol, no_match_source_protocol_cmd, + "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", + NO_STR + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_source_instance, match_source_instance_cmd, + "match source-instance (0-255)$instance", + MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:source-instance", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_source_instance, no_match_source_instance_cmd, + "no match source-instance [(0-255)]", + NO_STR MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* set functions */ + +DEFPY_YANG( + set_src, set_src_cmd, + "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>", + SET_STR + "src address for route\n" + "IPv4 src address\n" + "IPv6 src address\n") +{ + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (addrv4_str) { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv4_str); + } else { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv6_str); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_set_src, no_set_src_cmd, + "no set src [<A.B.C.D|X:X::X:X>]", + NO_STR + SET_STR + "Source address for route\n" + "IPv4 address\n" + "IPv6 address\n") +{ + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +const char *features[] = { +#if HAVE_BFDD == 0 + "ptm-bfd", +#endif +#if defined(HAVE_RTADV) + "ipv6-router-advertisements", +#endif + NULL +}; + +/* clang-format off */ +const struct frr_yang_module_info frr_zebra_cli_info = { + .name = "frr-zebra", + .ignore_cfg_cbs = true, + .features = features, + .nodes = { +#if HAVE_BFDD == 0 + { + .xpath = "/frr-zebra:zebra/ptm-enable", + .cbs.cli_show = zebra_ptm_enable_cli_write, + }, +#endif + { + .xpath = "/frr-zebra:zebra/route-map-delay", + .cbs.cli_show = zebra_route_map_delay_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs", + .cbs.cli_show = lib_interface_zebra_ipv4_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs", + .cbs.cli_show = lib_interface_zebra_ipv4_p2p_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs", + .cbs.cli_show = lib_interface_zebra_ipv6_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/multicast", + .cbs.cli_show = lib_interface_zebra_multicast_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect", + .cbs.cli_show = lib_interface_zebra_link_detect_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/enabled", + .cbs.cli_show = lib_interface_zebra_enabled_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .cbs.cli_show = lib_interface_zebra_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/mpls", + .cbs.cli_show = lib_interface_zebra_mpls_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params", + .cbs.cli_show = lib_interface_zebra_link_params_cli_write, + .cbs.cli_show_end = lib_interface_zebra_link_params_cli_write_end, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/metric", + .cbs.cli_show = lib_interface_zebra_link_params_metric_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_max_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_max_reservable_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_residual_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_available_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_utilized_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group", + .cbs.cli_show = lib_interface_zebra_link_params_legacy_admin_group_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", + .cbs.cli_show = lib_interface_zebra_link_params_affinities_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode", + .cbs.cli_show = lib_interface_zebra_link_params_affinity_mode_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor", + .cbs.cli_show = lib_interface_zebra_link_params_neighbor_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay", + .cbs.cli_show = lib_interface_zebra_link_params_delay_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation", + .cbs.cli_show = lib_interface_zebra_link_params_delay_variation_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss", + .cbs.cli_show = lib_interface_zebra_link_params_packet_loss_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_0_esi_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_3_system_mac_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_3_local_discriminator_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference", + .cbs.cli_show = lib_interface_zebra_evpn_mh_df_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass", + .cbs.cli_show = lib_interface_zebra_evpn_mh_bypass_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink", + .cbs.cli_show = lib_interface_zebra_evpn_mh_uplink_cli_write, + }, +#if defined(HAVE_RTADV) + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_send_advertisements_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_managed_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_other_config_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_link_mtu_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_reachable_time_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_retrans_timer_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_default_router_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_cli_write, + }, +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ptm-enable", + .cbs.cli_show = lib_interface_zebra_ptm_enable_cli_write, + }, +#endif + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/router-id", + .cbs.cli_show = lib_vrf_zebra_router_id_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id", + .cbs.cli_show = lib_vrf_zebra_ipv6_router_id_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol", + .cbs.cli_show = lib_vrf_zebra_filter_protocol_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht", + .cbs.cli_show = lib_vrf_zebra_filter_nht_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default", + .cbs.cli_show = lib_vrf_zebra_resolve_via_default_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default", + .cbs.cli_show = lib_vrf_zebra_ipv6_resolve_via_default_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range", + .cbs.cli_show = lib_vrf_zebra_netns_table_range_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id", + .cbs.cli_show = lib_vrf_zebra_l3vni_id_cli_write, + }, + { + .xpath = NULL, + }, + } +}; + +struct cmd_node link_params_node = { + .name = "link-params", + .node = LINK_PARAMS_NODE, + .parent_node = INTERFACE_NODE, + .prompt = "%s(config-link-params)# ", +}; + +void zebra_cli_init(void) +{ + install_node(&link_params_node); + + install_element(INTERFACE_NODE, &multicast_new_cmd); + install_element(INTERFACE_NODE, &multicast_cmd); + install_element(INTERFACE_NODE, &mpls_cmd); + install_element(INTERFACE_NODE, &linkdetect_cmd); + install_element(INTERFACE_NODE, &shutdown_if_cmd); + install_element(INTERFACE_NODE, &bandwidth_if_cmd); + install_element(INTERFACE_NODE, &ip_address_cmd); + install_element(INTERFACE_NODE, &ip_address_peer_cmd); + install_element(INTERFACE_NODE, &ipv6_address_cmd); + install_element(INTERFACE_NODE, &link_params_cmd); + install_element(INTERFACE_NODE, &no_link_params_cmd); + install_default(LINK_PARAMS_NODE); + install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); + install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); + install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); + install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); + install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_mode_cmd); + install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); + + install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd); + +#if defined(HAVE_RTADV) + install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); +#endif +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd); +#endif + + install_element(CONFIG_NODE, &ip_router_id_cmd); + install_element(CONFIG_NODE, &router_id_cmd); + install_element(CONFIG_NODE, &ipv6_router_id_cmd); + install_element(CONFIG_NODE, &ip_router_id_in_vrf_cmd); + install_element(CONFIG_NODE, &router_id_in_vrf_cmd); + install_element(CONFIG_NODE, &ipv6_router_id_in_vrf_cmd); + install_element(VRF_NODE, &ip_router_id_in_vrf_cmd); + install_element(VRF_NODE, &router_id_in_vrf_cmd); + install_element(VRF_NODE, &ipv6_router_id_in_vrf_cmd); + + install_element(CONFIG_NODE, &ip_protocol_cmd); + install_element(VRF_NODE, &ip_protocol_cmd); + install_element(CONFIG_NODE, &ipv6_protocol_cmd); + install_element(VRF_NODE, &ipv6_protocol_cmd); + install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd); + install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd); + install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); + install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd); + install_element(CONFIG_NODE, &zebra_route_map_timer_cmd); + + install_element(CONFIG_NODE, &ip_nht_default_route_cmd); + install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); + install_element(VRF_NODE, &ip_nht_default_route_cmd); + install_element(VRF_NODE, &ipv6_nht_default_route_cmd); + + install_element(CONFIG_NODE, &vni_mapping_cmd); + install_element(VRF_NODE, &vni_mapping_cmd); + + if (vrf_is_backend_netns()) + install_element(VRF_NODE, &vrf_netns_cmd); + + install_element(CONFIG_NODE, &ip_table_range_cmd); + install_element(VRF_NODE, &ip_table_range_cmd); +#if HAVE_BFDD == 0 + install_element(CONFIG_NODE, &zebra_ptm_enable_cmd); +#endif + install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); + install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd); + install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); + install_element(RMAP_NODE, &match_source_protocol_cmd); + install_element(RMAP_NODE, &no_match_source_protocol_cmd); + install_element(RMAP_NODE, &match_source_instance_cmd); + install_element(RMAP_NODE, &no_match_source_instance_cmd); + + install_element(RMAP_NODE, &set_src_cmd); + install_element(RMAP_NODE, &no_set_src_cmd); +} diff --git a/zebra/zebra_cli.h b/zebra/zebra_cli.h new file mode 100644 index 0000000000..01931a47ab --- /dev/null +++ b/zebra/zebra_cli.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef _ZEBRA_CLI_H +#define _ZEBRA_CLI_H 1 + +extern const struct frr_yang_module_info frr_zebra_cli_info; + +void zebra_cli_init(void); + +#endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index f6c1fdd78e..06b34da209 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -2,6 +2,8 @@ /* * Zebra dataplane layer. * Copyright (c) 2018 Volta Networks, Inc. + * Portions: + * Copyright (c) 2021 The MITRE Corporation. */ #ifdef HAVE_CONFIG_H @@ -37,6 +39,13 @@ DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes"); # define AOK 0 #endif +/* + * Dataplane API version. This must be updated when any incompatible changes + * are made. The minor version (at least) should be updated when new APIs + * are introduced. + */ +static uint32_t zdplane_version = MAKE_FRRVERSION(2, 0, 0); + /* Control for collection of extra interface info with route updates; a plugin * can enable the extra info via a dplane api. */ @@ -180,10 +189,47 @@ struct dplane_br_port_info { */ struct dplane_intf_info { + enum zebra_iftype zif_type; + ifindex_t bond_ifindex; + ifindex_t link_ifindex; + int32_t mtu; + vrf_id_t vrf_id; + enum zebra_slave_iftype zif_slave_type; + ifindex_t master_ifindex; + ifindex_t bridge_ifindex; + ns_id_t link_nsid; + enum zebra_slave_iftype zslave_type; + uint8_t bypass; + enum zebra_link_type zltype; + bool startup; + uint8_t family; + struct zebra_vxlan_vni_array *vniarray; + bool no_bvinfo_avail; + bool no_afspec_avail; + struct zebra_dplane_bridge_vlan_info bvinfo; + struct zebra_dplane_bridge_vlan_info_array *bvarray; + + char desc[128]; + + int32_t hw_addr_len; + uint8_t hw_addr[INTERFACE_HWADDR_MAX]; + + uint32_t table_id; + + struct zebra_l2info_bridge binfo; + struct zebra_l2info_vlan vinfo; + struct zebra_l2info_vxlan vxinfo; + struct zebra_l2info_gre grinfo; + + uint32_t rc_bitfield; + + uint32_t txqlen; + uint32_t metric; uint32_t flags; bool protodown; + bool protodown_set; bool pd_reason_val; #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */ @@ -191,6 +237,7 @@ struct dplane_intf_info { #define DPLANE_INTF_BROADCAST (1 << 2) #define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED #define DPLANE_INTF_HAS_LABEL (1 << 4) +#define DPLANE_INTF_NOPREFIXROUTE (1 << 5) /* Interface address/prefix */ struct prefix prefix; @@ -245,28 +292,8 @@ struct dplane_neigh_table { * Policy based routing rule info for the dataplane */ struct dplane_ctx_rule { - uint32_t priority; - - /* The route table pointed by this rule */ - uint32_t table; - - /* Filter criteria */ - uint32_t filter_bm; - uint32_t fwmark; - uint8_t dsfield; - struct prefix src_ip; - struct prefix dst_ip; - uint8_t ip_proto; - uint16_t src_port; - uint16_t dst_port; - - uint8_t action_pcp; - uint16_t action_vlan_id; - uint16_t action_vlan_flags; + struct pbr_rule prule; - uint32_t action_queue_id; - - char ifname[INTERFACE_NAMSIZ + 1]; struct ethaddr smac; struct ethaddr dmac; int out_ifindex; @@ -337,6 +364,13 @@ struct dplane_tc_filter_info { }; /* + * SRv6 encapsulation params context for the dataplane + */ +struct dplane_srv6_encap_ctx { + struct in6_addr srcaddr; +}; + +/* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the * dataplane layer (and pthread). @@ -372,7 +406,7 @@ struct zebra_dplane_ctx { vrf_id_t zd_vrf_id; uint32_t zd_table_id; - char zd_ifname[INTERFACE_NAMSIZ]; + char zd_ifname[IFNAMSIZ]; ifindex_t zd_ifindex; /* Support info for different kinds of updates */ @@ -397,6 +431,8 @@ struct zebra_dplane_ctx { struct dplane_neigh_table neightable; struct dplane_gre_ctx gre; struct dplane_netconf_info netconf; + enum zebra_dplane_startup_notifications spot; + struct dplane_srv6_encap_ctx srv6_encap; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -578,6 +614,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_tcs_in; _Atomic uint32_t dg_tcs_errors; + _Atomic uint32_t dg_srv6_encap_srcaddr_set_in; + _Atomic uint32_t dg_srv6_encap_srcaddr_set_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -632,6 +671,12 @@ neigh_update_internal(enum dplane_op_e op, const struct interface *ifp, * Public APIs */ +/* Access the dplane API version */ +uint32_t zebra_dplane_get_version(void) +{ + return zdplane_version; +} + /* Obtain thread_master for dataplane thread */ struct event_loop *dplane_get_thread_master(void) { @@ -808,8 +853,14 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: case DPLANE_OP_IPSET_ADD: case DPLANE_OP_IPSET_DELETE: + break; case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: + if (ctx->u.intf.vniarray) + XFREE(MTYPE_TMP, ctx->u.intf.vniarray); + if (ctx->u.intf.bvarray) + XFREE(MTYPE_TMP, ctx->u.intf.bvarray); + break; case DPLANE_OP_INTF_DELETE: case DPLANE_OP_TC_QDISC_INSTALL: case DPLANE_OP_TC_QDISC_UNINSTALL: @@ -833,6 +884,8 @@ 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_STARTUP_STAGE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: break; } } @@ -1156,6 +1209,13 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_TC_FILTER_UPDATE: ret = "TC__FILTER_UPDATE"; break; + case DPLANE_OP_STARTUP_STAGE: + ret = "STARTUP_STAGE"; + break; + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + ret = "SRV6_ENCAP_SRCADDR_SET"; + break; } return ret; @@ -1297,6 +1357,450 @@ const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx) return ctx->zd_ifname; } +void dplane_ctx_set_ifp_bridge_vlan_info_array( + struct zebra_dplane_ctx *ctx, + struct zebra_dplane_bridge_vlan_info_array *bvarray) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.bvarray = bvarray; +} + +const struct zebra_dplane_bridge_vlan_info_array * +dplane_ctx_get_ifp_bridge_vlan_info_array(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.bvarray; +} + +void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, + struct zebra_vxlan_vni_array *vniarray) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.vniarray = vniarray; +} + +const struct zebra_vxlan_vni_array * +dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.vniarray; +} + +void dplane_ctx_set_ifp_no_afspec(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.no_afspec_avail = true; +} + +bool dplane_ctx_get_ifp_no_afspec(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.no_afspec_avail; +} + +void dplane_ctx_set_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.no_bvinfo_avail = true; +} + +bool dplane_ctx_get_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.no_bvinfo_avail; +} + +void dplane_ctx_set_ifp_bridge_vlan_info( + struct zebra_dplane_ctx *ctx, + struct zebra_dplane_bridge_vlan_info *bvinfo) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.bvinfo = *bvinfo; +} + +const struct zebra_dplane_bridge_vlan_info * +dplane_ctx_get_ifp_bridge_vlan_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.intf.bvinfo; +} + +void dplane_ctx_set_ifp_family(struct zebra_dplane_ctx *ctx, uint8_t family) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.family = family; +} + +uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.family; +} + +void dplane_ctx_set_ifp_zltype(struct zebra_dplane_ctx *ctx, + enum zebra_link_type zltype) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.zltype = zltype; +} + +enum zebra_link_type +dplane_ctx_get_ifp_zltype(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.zltype; +} + +void dplane_ctx_set_ifp_link_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t link_ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.link_ifindex = link_ifindex; +} + +ifindex_t dplane_ctx_get_ifp_link_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.link_ifindex; +} + +void dplane_ctx_set_ifp_desc(struct zebra_dplane_ctx *ctx, const char *desc) +{ + DPLANE_CTX_VALID(ctx); + + strlcpy(ctx->u.intf.desc, desc, sizeof(ctx->u.intf.desc)); +} + +char *dplane_ctx_get_ifp_desc(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.desc; +} + +void dplane_ctx_set_ifp_flags(struct zebra_dplane_ctx *ctx, uint64_t flags) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags = flags; +} + +uint64_t dplane_ctx_get_ifp_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.flags; +} + +void dplane_ctx_set_ifp_bypass(struct zebra_dplane_ctx *ctx, uint8_t bypass) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.bypass = bypass; +} + +uint8_t dplane_ctx_get_ifp_bypass(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.bypass; +} + +void dplane_ctx_set_ifp_bridge_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t bridge_ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.bridge_ifindex = bridge_ifindex; +} + +ifindex_t dplane_ctx_get_ifp_bridge_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.bridge_ifindex; +} + +void dplane_ctx_set_ifp_zif_slave_type(struct zebra_dplane_ctx *ctx, + enum zebra_slave_iftype zslave_type) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.zslave_type = zslave_type; +} + +enum zebra_slave_iftype +dplane_ctx_get_ifp_zif_slave_type(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.zslave_type; +} + +void dplane_ctx_set_ifp_master_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t master_ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.master_ifindex = master_ifindex; +} + +ifindex_t dplane_ctx_get_ifp_master_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.master_ifindex; +} + +void dplane_ctx_set_ifp_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.mtu = mtu; +} + +uint32_t dplane_ctx_get_ifp_mtu(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.mtu; +} + +void dplane_ctx_set_ifp_vrf_id(struct zebra_dplane_ctx *ctx, vrf_id_t vrf_id) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.vrf_id = vrf_id; +} + +vrf_id_t dplane_ctx_get_ifp_vrf_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.vrf_id; +} + +void dplane_ctx_set_ifp_link_nsid(struct zebra_dplane_ctx *ctx, + ns_id_t link_nsid) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.link_nsid = link_nsid; +} + +ns_id_t dplane_ctx_get_ifp_link_nsid(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.link_nsid; +} + +void dplane_ctx_set_ifp_startup(struct zebra_dplane_ctx *ctx, bool startup) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.startup = startup; +} + +bool dplane_ctx_get_ifp_startup(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.startup; +} + +void dplane_ctx_set_ifp_protodown_set(struct zebra_dplane_ctx *ctx, bool set) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.protodown_set = set; +} + +bool dplane_ctx_get_ifp_protodown_set(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.protodown_set; +} + +void dplane_ctx_set_ifp_protodown(struct zebra_dplane_ctx *ctx, bool protodown) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.protodown = protodown; +} + +bool dplane_ctx_get_ifp_protodown(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.protodown; +} + +ifindex_t dplane_ctx_get_ifp_bond_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.bond_ifindex; +} + +void dplane_ctx_set_ifp_rc_bitfield(struct zebra_dplane_ctx *ctx, + uint32_t rc_bitfield) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.rc_bitfield = rc_bitfield; +} + +uint32_t dplane_ctx_get_ifp_rc_bitfield(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.rc_bitfield; +} + +void dplane_ctx_set_ifp_gre_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_gre *grinfo) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.grinfo = *grinfo; +} + +const struct zebra_l2info_gre * +dplane_ctx_get_ifp_gre_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.intf.grinfo; +} + +void dplane_ctx_set_ifp_vxlan_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_vxlan *vxinfo) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.vxinfo = *vxinfo; +} + +const struct zebra_l2info_vxlan * +dplane_ctx_get_ifp_vxlan_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.intf.vxinfo; +} + +void dplane_ctx_set_ifp_vlan_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_vlan *vinfo) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.vinfo = *vinfo; +} + +const struct zebra_l2info_vlan * +dplane_ctx_get_ifp_vlan_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.intf.vinfo; +} + +void dplane_ctx_set_ifp_bridge_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_bridge *binfo) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.binfo = *binfo; +} + +const struct zebra_l2info_bridge * +dplane_ctx_get_ifp_bridge_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.intf.binfo; +} + +void dplane_ctx_set_ifp_table_id(struct zebra_dplane_ctx *ctx, + uint32_t table_id) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.table_id = table_id; +} + +uint32_t dplane_ctx_get_ifp_table_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.table_id; +} + +void dplane_ctx_set_ifp_hw_addr(struct zebra_dplane_ctx *ctx, + int32_t hw_addr_len, uint8_t *hw_addr) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.hw_addr_len = hw_addr_len; + memcpy(ctx->u.intf.hw_addr, hw_addr, hw_addr_len); +} + +int32_t dplane_ctx_get_ifp_hw_addr_len(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.hw_addr_len; +} + +const uint8_t *dplane_ctx_get_ifp_hw_addr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.hw_addr; +} + +void dplane_ctx_set_ifp_bond_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t bond_ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.bond_ifindex = bond_ifindex; +} + +enum zebra_iftype +dplane_ctx_get_ifp_zif_type(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.zif_type; +} + +void dplane_ctx_set_ifp_zif_type(struct zebra_dplane_ctx *ctx, + enum zebra_iftype zif_type) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.zif_type = zif_type; +} + void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname) { DPLANE_CTX_VALID(ctx); @@ -2068,6 +2572,13 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED); } +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return (ctx->u.intf.flags & DPLANE_INTF_NOPREFIXROUTE); +} + bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2096,6 +2607,13 @@ void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx) ctx->u.intf.flags |= DPLANE_INTF_SECONDARY; } +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_NOPREFIXROUTE; +} + void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2111,6 +2629,16 @@ const struct prefix *dplane_ctx_get_intf_addr( return &(ctx->u.intf.prefix); } + +/* Accessors for SRv6 encapsulation source address information */ +const struct in6_addr * +dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.srv6_encap.srcaddr); +} + void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, const struct prefix *p) { @@ -2185,6 +2713,20 @@ void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) } } +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.txqlen = txqlen; +} + +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.intf.txqlen; +} + /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx) { @@ -2307,6 +2849,25 @@ dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx) return &ctx->u.gre.info; } +/*********************************************************************** + * PBR RULE ACCESSORS - start + **********************************************************************/ + +/* + * This accessor fills one or two lib/pbr structs from the PBR context. + * New dataplane modules should use this interface where possible instead + * of adding more accessors that return fields from 'struct pbr_rule'. + */ +void dplane_ctx_rule_get(const struct zebra_dplane_ctx *ctx, + struct pbr_rule *pNew, struct pbr_rule *pOld) +{ + DPLANE_CTX_VALID(ctx); + if (pNew) + *pNew = ctx->u.rule.new.prule; + if (pOld) + *pOld = ctx->u.rule.old.prule; +} + /* Accessors for PBR rule information */ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx) { @@ -2319,7 +2880,7 @@ const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.ifname; + return ctx->u.rule.new.prule.ifname; } int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx) @@ -2340,112 +2901,112 @@ uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.priority; + return ctx->u.rule.new.prule.priority; } uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.priority; + return ctx->u.rule.old.prule.priority; } uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.table; + return ctx->u.rule.new.prule.action.table; } uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.table; + return ctx->u.rule.old.prule.action.table; } uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.filter_bm; + return ctx->u.rule.new.prule.filter.filter_bm; } uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.filter_bm; + return ctx->u.rule.old.prule.filter.filter_bm; } uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.fwmark; + return ctx->u.rule.new.prule.filter.fwmark; } uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.fwmark; + return ctx->u.rule.old.prule.filter.fwmark; } uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.ip_proto; + return ctx->u.rule.new.prule.filter.ip_proto; } uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.ip_proto; + return ctx->u.rule.old.prule.filter.ip_proto; } uint16_t dplane_ctx_rule_get_src_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.src_port; + return ctx->u.rule.new.prule.filter.src_port; } uint16_t dplane_ctx_rule_get_old_src_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.src_port; + return ctx->u.rule.old.prule.filter.src_port; } uint16_t dplane_ctx_rule_get_dst_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.dst_port; + return ctx->u.rule.new.prule.filter.dst_port; } uint16_t dplane_ctx_rule_get_old_dst_port(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.dst_port; + return ctx->u.rule.old.prule.filter.dst_port; } uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.new.dsfield; + return ctx->u.rule.new.prule.filter.dsfield; } uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return ctx->u.rule.old.dsfield; + return ctx->u.rule.old.prule.filter.dsfield; } const struct prefix * @@ -2453,7 +3014,7 @@ dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.new.src_ip); + return &(ctx->u.rule.new.prule.filter.src_ip); } const struct prefix * @@ -2461,7 +3022,7 @@ dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.old.src_ip); + return &(ctx->u.rule.old.prule.filter.src_ip); } const struct prefix * @@ -2469,7 +3030,7 @@ dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.new.dst_ip); + return &(ctx->u.rule.new.prule.filter.dst_ip); } const struct prefix * @@ -2477,9 +3038,65 @@ dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.rule.old.dst_ip); + return &(ctx->u.rule.old.prule.filter.dst_ip); +} + +const struct ethaddr * +dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rule.new.smac); +} + +const struct ethaddr * +dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rule.new.dmac); +} + +int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.out_ifindex; } +intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.old.dp_flow_ptr; +} + +intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.dp_flow_ptr; +} + +void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, + intptr_t dp_flow_ptr) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; +} + +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.prule.vrf_id; +} + +/*********************************************************************** + * PBR RULE ACCESSORS - end + **********************************************************************/ + uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2548,55 +3165,6 @@ void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry)); } -const struct ethaddr * -dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return &(ctx->u.rule.new.smac); -} - -const struct ethaddr * -dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return &(ctx->u.rule.new.dmac); -} - -int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.new.out_ifindex; -} - -intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.old.dp_flow_ptr; -} - -intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx) -{ - DPLANE_CTX_VALID(ctx); - - return ctx->u.rule.new.dp_flow_ptr; -} - -void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, - intptr_t dp_flow_ptr) -{ - DPLANE_CTX_VALID(ctx); - - ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; -} - -/* - * End of dplane context accessors - */ - /* Optional extra info about interfaces in nexthops - a plugin must enable * this extra info. */ @@ -2798,7 +3366,7 @@ int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx, { int ret = EINVAL; - if (!ctx || !re) + if (!ctx) return ret; dplane_intf_extra_list_init(&ctx->u.rinfo.intf_extra_list); @@ -2806,6 +3374,13 @@ int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + /* This function may be called to create/init a dplane context, not + * necessarily to copy a route object. Let's return if there is no route + * object to copy. + */ + if (!re) + return AOK; + ctx->u.rinfo.zd_type = re->type; ctx->u.rinfo.zd_old_type = re->type; @@ -2837,6 +3412,8 @@ int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx, /* * Initialize a context block for a route update from zebra data structs. + * If the `rn` or `re` parameters are NULL, this function only initializes the + * dplane context without copying a route object into it. */ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct route_node *rn, struct route_entry *re) @@ -2853,10 +3430,18 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, const struct interface *ifp; struct dplane_intf_extra *if_extra; - if (!ctx || !rn || !re) + if (!ctx) return ret; /* + * Initialize the dplane context and return, if there is no route + * object to copy + */ + if (!re || !rn) + return dplane_ctx_route_init_basic(ctx, op, NULL, NULL, NULL, + AFI_UNSPEC, SAFI_UNSPEC); + + /* * Let's grab the data from the route_node * so that we can call a helper function */ @@ -3414,24 +3999,8 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule, { struct zebra_neigh_ent *n; - dplane_rule->priority = rule->rule.priority; - dplane_rule->table = rule->rule.action.table; - - dplane_rule->filter_bm = rule->rule.filter.filter_bm; - dplane_rule->fwmark = rule->rule.filter.fwmark; - dplane_rule->dsfield = rule->rule.filter.dsfield; - dplane_rule->ip_proto = rule->rule.filter.ip_proto; - dplane_rule->src_port = rule->rule.filter.src_port; - dplane_rule->dst_port = rule->rule.filter.dst_port; - prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip); - prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip); + dplane_rule->prule = rule->rule; - dplane_rule->action_pcp = rule->rule.action.pcp; - dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags; - dplane_rule->action_vlan_id = rule->rule.action.vlan_id; - dplane_rule->action_queue_id = rule->rule.action.queue_id; - - strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ); dplane_rule->dp_flow_ptr = rule->action.dp_flow_ptr; n = rule->action.neigh; if (n && (n->flags & ZEBRA_NEIGH_ENT_ACTIVE)) { @@ -3533,6 +4102,7 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, ctx->zd_vrf_id = iptable->vrf_id; memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); + ctx->u.iptable.interface_name_list = NULL; if (iptable->nb_interface > 0) { ctx->u.iptable.interface_name_list = list_new(); ctx->u.iptable.interface_name_list->del = @@ -3785,18 +4355,12 @@ tc_qdisc_update_internal(enum dplane_op_e op, /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (!ctx) { - ret = ENOMEM; - goto done; - } - /* Init context with info from zebra data structs */ ret = dplane_ctx_tc_qdisc_init(ctx, op, qdisc); if (ret == AOK) ret = dplane_update_enqueue(ctx); -done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1, memory_order_relaxed); @@ -3805,8 +4369,7 @@ done: } else { atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; @@ -3822,18 +4385,12 @@ tc_class_update_internal(enum dplane_op_e op, struct zebra_tc_class *class) /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (!ctx) { - ret = ENOMEM; - goto done; - } - /* Init context with info from zebra data structs */ ret = dplane_ctx_tc_class_init(ctx, op, class); if (ret == AOK) ret = dplane_update_enqueue(ctx); -done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1, memory_order_relaxed); @@ -3842,8 +4399,7 @@ done: } else { atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; @@ -3859,18 +4415,12 @@ tc_filter_update_internal(enum dplane_op_e op, struct zebra_tc_filter *filter) /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (!ctx) { - ret = ENOMEM; - goto done; - } - /* Init context with info from zebra data structs */ ret = dplane_ctx_tc_filter_init(ctx, op, filter); if (ret == AOK) ret = dplane_update_enqueue(ctx); -done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1, memory_order_relaxed); @@ -3879,8 +4429,7 @@ done: } else { atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; @@ -3943,16 +4492,11 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (!ctx) { - ret = ENOMEM; - goto done; - } ret = dplane_ctx_nexthop_init(ctx, op, nhe); if (ret == AOK) ret = dplane_update_enqueue(ctx); -done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1, memory_order_relaxed); @@ -4083,8 +4627,6 @@ dplane_route_notif_update(struct route_node *rn, goto done; new_ctx = dplane_ctx_alloc(); - if (new_ctx == NULL) - goto done; /* Init context with info from zebra data structs */ dplane_ctx_route_init(new_ctx, op, rn, re); @@ -4216,10 +4758,6 @@ dplane_lsp_notif_update(struct zebra_lsp *lsp, enum dplane_op_e op, /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (ctx == NULL) { - ret = ENOMEM; - goto done; - } /* Copy info from zebra LSP */ ret = dplane_ctx_lsp_init(ctx, op, lsp); @@ -4259,8 +4797,7 @@ done: else { atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; } @@ -4589,16 +5126,11 @@ dplane_intf_update_internal(const struct interface *ifp, enum dplane_op_e op) /* Obtain context block */ ctx = dplane_ctx_alloc(); - if (!ctx) { - ret = ENOMEM; - goto done; - } ret = dplane_ctx_intf_init(ctx, op, ifp); if (ret == AOK) ret = dplane_update_enqueue(ctx); -done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_intfs_in, 1, memory_order_relaxed); @@ -4640,18 +5172,6 @@ enum zebra_dplane_result dplane_intf_update(const struct interface *ifp) } /* - * Enqueue a interface delete for the dataplane. - */ -enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp) -{ - enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; - - if (ifp) - ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_DELETE); - return ret; -} - -/* * Enqueue vxlan/evpn mac add (or update). */ enum zebra_dplane_result @@ -5337,8 +5857,10 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, ctx = dplane_ctx_alloc(); - if (!ifp) - return result; + if (!ifp) { + ret = EINVAL; + goto done; + } if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { zlog_debug("init dplane ctx %s: if %s link %s%s", @@ -5350,8 +5872,11 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; zns = zebra_ns_lookup(ifp->vrf->vrf_id); - if (!zns) - return result; + if (!zns) { + ret = EINVAL; + goto done; + } + dplane_ctx_ns_init(ctx, zns, false); dplane_ctx_set_ifname(ctx, ifp->name); @@ -5370,6 +5895,7 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, /* Enqueue context for processing */ ret = dplane_update_enqueue(ctx); +done: /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1, memory_order_relaxed); @@ -5387,6 +5913,59 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, } /* + * Common helper api for SRv6 encapsulation source address set + */ +enum zebra_dplane_result +dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx = NULL; + enum dplane_op_e op = DPLANE_OP_SRV6_ENCAP_SRCADDR_SET; + int ret; + struct zebra_ns *zns; + + if (!addr) + return result; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: addr %pI6", dplane_op2str(op), + addr); + } + + zns = zebra_ns_lookup(ns_id); + if (!zns) + return result; + + ctx = dplane_ctx_alloc(); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zns, false); + + /* Init the SRv6 encap source address specific data area */ + memcpy(&ctx->u.srv6_encap.srcaddr, addr, + sizeof(ctx->u.srv6_encap.srcaddr)); + + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_srv6_encap_srcaddr_set_in, 1, + memory_order_relaxed); + + /* Enqueue context for processing */ + ret = dplane_update_enqueue(ctx); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info + .dg_srv6_encap_srcaddr_set_errors, + 1, memory_order_relaxed); + dplane_ctx_free(&ctx); + } + return result; +} + +/* * Handler for 'show dplane' */ int dplane_show_helper(struct vty *vty, bool detailed) @@ -5578,7 +6157,7 @@ int dplane_provider_register(const char *name, struct zebra_dplane_provider **prov_p) { int ret = 0; - struct zebra_dplane_provider *p = NULL, *last; + struct zebra_dplane_provider *p = NULL, *last, *prev = NULL; /* Validate */ if (fp == NULL) { @@ -5621,10 +6200,11 @@ int dplane_provider_register(const char *name, frr_each (dplane_prov_list, &zdplane_info.dg_providers, last) { if (last->dp_priority > p->dp_priority) break; + prev = last; } if (last) - dplane_prov_list_add_after(&zdplane_info.dg_providers, last, p); + dplane_prov_list_add_after(&zdplane_info.dg_providers, prev, p); else dplane_prov_list_add_tail(&zdplane_info.dg_providers, p); @@ -5764,12 +6344,27 @@ void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov, memory_order_relaxed); } +static struct zebra_dplane_ctx * +dplane_provider_dequeue_out_ctx(struct zebra_dplane_provider *prov) +{ + struct zebra_dplane_ctx *ctx; + + ctx = dplane_ctx_list_pop(&(prov->dp_ctx_out_list)); + if (!ctx) + return NULL; + + atomic_fetch_sub_explicit(&(prov->dp_out_queued), 1, + memory_order_relaxed); + + return ctx; +} + /* * Accessor for provider object */ bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov) { - return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED); + return CHECK_FLAG(prov->dp_flags, DPLANE_PROV_FLAG_THREADED); } #ifdef HAVE_NETLINK @@ -6093,6 +6688,13 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_ADD: case DPLANE_OP_TC_FILTER_DELETE: case DPLANE_OP_TC_FILTER_UPDATE: + case DPLANE_OP_STARTUP_STAGE: + break; + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + zlog_debug("Dplane SRv6 encap source address set op %s, addr %pI6", + dplane_op2str(dplane_ctx_get_op(ctx)), + &ctx->u.srv6_encap.srcaddr); break; } } @@ -6264,7 +6866,15 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_NETCONFIG: break; + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info + .dg_srv6_encap_srcaddr_set_errors, + 1, memory_order_relaxed); + break; + case DPLANE_OP_NONE: + case DPLANE_OP_STARTUP_STAGE: if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) atomic_fetch_add_explicit(&zdplane_info.dg_other_errors, 1, memory_order_relaxed); @@ -6371,6 +6981,31 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) return 0; } +static int kernel_dplane_shutdown_func(struct zebra_dplane_provider *prov, + bool early) +{ + struct zebra_dplane_ctx *ctx; + + if (early) + return 1; + + ctx = dplane_provider_dequeue_in_ctx(prov); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_provider_dequeue_in_ctx(prov); + } + + ctx = dplane_provider_dequeue_out_ctx(prov); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_provider_dequeue_out_ctx(prov); + } + + return 1; +} + #ifdef DPLANE_TEST_PROVIDER /* @@ -6443,12 +7078,10 @@ static void dplane_provider_init(void) { int ret; - ret = dplane_provider_register("Kernel", - DPLANE_PRIO_KERNEL, + ret = dplane_provider_register("Kernel", DPLANE_PRIO_KERNEL, DPLANE_PROV_FLAGS_DEFAULT, NULL, kernel_dplane_process_func, - NULL, - NULL, NULL); + kernel_dplane_shutdown_func, NULL, NULL); if (ret != AOK) zlog_err("Unable to register kernel dplane provider: %d", @@ -6791,7 +7424,7 @@ static void dplane_thread_loop(struct event *event) dplane_provider_lock(prov); while (counter < limit) { - ctx = dplane_ctx_list_pop(&(prov->dp_ctx_out_list)); + ctx = dplane_provider_dequeue_out_ctx(prov); if (ctx) { dplane_ctx_list_add_tail(&work_list, ctx); counter++; @@ -6849,6 +7482,7 @@ static void dplane_thread_loop(struct event *event) void zebra_dplane_shutdown(void) { struct zebra_dplane_provider *dp; + struct zebra_dplane_ctx *ctx; if (IS_ZEBRA_DEBUG_DPLANE) zlog_debug("Zebra dataplane shutdown called"); @@ -6876,8 +7510,25 @@ void zebra_dplane_shutdown(void) } /* TODO -- Clean-up provider objects */ + dp = dplane_prov_list_first(&zdplane_info.dg_providers); + while (dp) { + dplane_prov_list_del(&zdplane_info.dg_providers, dp); + XFREE(MTYPE_DP_PROV, dp); + + dp = dplane_prov_list_first(&zdplane_info.dg_providers); + } /* TODO -- Clean queue(s), free memory */ + DPLANE_LOCK(); + { + ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); + } + } + DPLANE_UNLOCK(); } /* @@ -6955,6 +7606,25 @@ void zebra_dplane_start(void) frr_pthread_run(zdplane_info.dg_pthread, NULL); } +enum zebra_dplane_startup_notifications +dplane_ctx_get_startup_spot(struct zebra_dplane_ctx *ctx) +{ + return ctx->u.spot; +} + +void zebra_dplane_startup_stage(struct zebra_ns *zns, + enum zebra_dplane_startup_notifications spot) +{ + struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); + + ctx->zd_op = DPLANE_OP_STARTUP_STAGE; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_QUEUED; + + ctx->u.spot = spot; + dplane_ctx_set_ns_id(ctx, zns->ns_id); + + dplane_provider_enqueue_to_zebra(ctx); +} /* * Initialize the dataplane module at startup; called by zebra rib_init() */ diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 6716c0ffb6..060b1c8b9e 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -11,17 +11,26 @@ #include "lib/prefix.h" #include "lib/nexthop.h" #include "lib/nexthop_group.h" +#include "lib/pbr.h" #include "lib/vlan.h" #include "zebra/zebra_ns.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_nhg.h" +#include "zebra/ge_netlink.h" #ifdef __cplusplus extern "C" { #endif +/* Retrieve the dataplane API version number; see libfrr.h to decode major, + * minor, sub version values. + * Plugins should pay attention to the major version number, at least, to + * be able to detect API changes that may not be backward-compatible. + */ +uint32_t zebra_dplane_get_version(void); + /* Key netlink info from zebra ns */ struct zebra_dplane_info { ns_id_t ns_id; @@ -87,6 +96,11 @@ enum zebra_dplane_result { ZEBRA_DPLANE_REQUEST_FAILURE, }; +enum zebra_dplane_startup_notifications { + ZEBRA_DPLANE_INTERFACES_READ, + ZEBRA_DPLANE_TUNNELS_READ, + ZEBRA_DPLANE_ADDRESSES_READ, +}; /* * API between the zebra dataplane system and the main zebra processing * context. @@ -188,7 +202,13 @@ enum dplane_op_e { DPLANE_OP_TC_CLASS_UPDATE, DPLANE_OP_TC_FILTER_ADD, DPLANE_OP_TC_FILTER_DELETE, - DPLANE_OP_TC_FILTER_UPDATE + DPLANE_OP_TC_FILTER_UPDATE, + + /* Startup Control */ + DPLANE_OP_STARTUP_STAGE, + + /* Source address for SRv6 encapsulation */ + DPLANE_OP_SRV6_ENCAP_SRCADDR_SET, }; /* @@ -323,6 +343,122 @@ const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname); ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex); +void dplane_ctx_set_ifp_bond_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex); +ifindex_t dplane_ctx_get_ifp_bond_ifindex(const struct zebra_dplane_ctx *ctx); +enum zebra_iftype +dplane_ctx_get_ifp_zif_type(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_zif_type(struct zebra_dplane_ctx *ctx, + enum zebra_iftype zif_type); +void dplane_ctx_set_ifp_table_id(struct zebra_dplane_ctx *ctx, + uint32_t table_id); +uint32_t dplane_ctx_get_ifp_table_id(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_hw_addr(struct zebra_dplane_ctx *ctx, + int32_t hw_addr_len, uint8_t *hw_addr); +int32_t dplane_ctx_get_ifp_hw_addr_len(const struct zebra_dplane_ctx *ctx); +const uint8_t *dplane_ctx_get_ifp_hw_addr(const struct zebra_dplane_ctx *ctx); +struct zebra_l2info_bridge; +void dplane_ctx_set_ifp_bridge_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_bridge *binfo); +const struct zebra_l2info_bridge * +dplane_ctx_get_ifp_bridge_info(const struct zebra_dplane_ctx *ctx); +struct zebra_l2info_vlan; +void dplane_ctx_set_ifp_vlan_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_vlan *vinfo); +const struct zebra_l2info_vlan * +dplane_ctx_get_ifp_vlan_info(const struct zebra_dplane_ctx *ctx); +struct zebra_l2info_vxlan; +void dplane_ctx_set_ifp_vxlan_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_vxlan *vxinfo); +const struct zebra_l2info_vxlan * +dplane_ctx_get_ifp_vxlan_info(const struct zebra_dplane_ctx *ctx); +struct zebra_l2info_gre; +void dplane_ctx_set_ifp_gre_info(struct zebra_dplane_ctx *ctx, + struct zebra_l2info_gre *greinfo); +const struct zebra_l2info_gre * +dplane_ctx_get_ifp_gre_info(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_zltype(struct zebra_dplane_ctx *ctx, + enum zebra_link_type zlt); +enum zebra_link_type +dplane_ctx_get_ifp_zltype(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_link_nsid(struct zebra_dplane_ctx *ctx, ns_id_t ns_id); +ns_id_t dplane_ctx_get_ifp_link_nsid(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_desc(struct zebra_dplane_ctx *ctx, const char *desc); +char *dplane_ctx_get_ifp_desc(struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu); +uint32_t dplane_ctx_get_ifp_mtu(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_vrf_id(struct zebra_dplane_ctx *ctx, vrf_id_t vrf_id); +vrf_id_t dplane_ctx_get_ifp_vrf_id(const struct zebra_dplane_ctx *ctx); +enum zebra_slave_iftype; +void dplane_ctx_set_ifp_zif_slave_type(struct zebra_dplane_ctx *ctx, + enum zebra_slave_iftype zslave_type); +enum zebra_slave_iftype +dplane_ctx_get_ifp_zif_slave_type(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_master_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t master_ifindex); +ifindex_t dplane_ctx_get_ifp_master_ifindex(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_bridge_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t bridge_ifindex); +ifindex_t dplane_ctx_get_ifp_bridge_ifindex(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_bypass(struct zebra_dplane_ctx *ctx, uint8_t bypass); +uint8_t dplane_ctx_get_ifp_bypass(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_flags(struct zebra_dplane_ctx *ctx, uint64_t flags); +uint64_t dplane_ctx_get_ifp_flags(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_protodown(struct zebra_dplane_ctx *ctx, bool protodown); +bool dplane_ctx_get_ifp_protodown(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_startup(struct zebra_dplane_ctx *ctx, bool startup); +bool dplane_ctx_get_ifp_startup(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_protodown_set(struct zebra_dplane_ctx *ctx, bool set); +bool dplane_ctx_get_ifp_protodown_set(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_rc_bitfield(struct zebra_dplane_ctx *ctx, + uint32_t rc_bitfield); +uint32_t dplane_ctx_get_ifp_rc_bitfield(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_link_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t link_ifindex); +ifindex_t dplane_ctx_get_ifp_link_ifindex(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_family(struct zebra_dplane_ctx *ctx, uint8_t family); +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); + +/* + * These defines mirror the values for bridge values in linux + * at this point since we only have a linux implementation + * we don't need to do any type of translation. Let's just + * pass these through and use them + */ +#define DPLANE_BRIDGE_VLAN_INFO_PVID \ + (1 << 1) /* VLAN is PVID, ingress untagged */ +#define DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN \ + (1 << 3) /* VLAN is start of vlan range */ +#define DPLANE_BRIDGE_VLAN_INFO_RANGE_END \ + (1 << 4) /* VLAN is end of vlan range */ +const struct zebra_vxlan_vni_array * +dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx); +struct zebra_dplane_bridge_vlan_info { + uint16_t flags; + uint16_t vid; +}; +void dplane_ctx_set_ifp_no_afspec(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_get_ifp_no_afspec(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_get_ifp_no_bridge_vlan_info(struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifp_bridge_vlan_info( + struct zebra_dplane_ctx *ctx, + struct zebra_dplane_bridge_vlan_info *bvinfo); +const struct zebra_dplane_bridge_vlan_info * +dplane_ctx_get_ifp_bridge_vlan_info(const struct zebra_dplane_ctx *ctx); + +struct zebra_dplane_bridge_vlan_info_array { + int count; + struct zebra_dplane_bridge_vlan_info array[0]; +}; +void dplane_ctx_set_ifp_bridge_vlan_info_array( + struct zebra_dplane_ctx *ctx, + struct zebra_dplane_bridge_vlan_info_array *bvarray); +const struct zebra_dplane_bridge_vlan_info_array * +dplane_ctx_get_ifp_bridge_vlan_info_array(const struct zebra_dplane_ctx *ctx); /* Retrieve last/current provider id */ uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx); @@ -533,10 +669,14 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx); const struct prefix *dplane_ctx_get_intf_addr( const struct zebra_dplane_ctx *ctx); +const struct in6_addr * +dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, const struct prefix *p); bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx); @@ -547,6 +687,8 @@ void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx, bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label); +void dplane_ctx_set_intf_txqlen(struct zebra_dplane_ctx *ctx, uint32_t txqlen); +uint32_t dplane_ctx_get_intf_txqlen(const struct zebra_dplane_ctx *ctx); /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx); @@ -573,6 +715,8 @@ uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx); /* Accessors for policy based routing rule information */ +void dplane_ctx_rule_get(const struct zebra_dplane_ctx *ctx, + struct pbr_rule *pNew, struct pbr_rule *pOld); int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx); @@ -611,6 +755,8 @@ intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx); void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, intptr_t dp_flow_ptr); +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx); + /* Accessors for policy based routing iptable information */ struct zebra_pbr_iptable; void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, @@ -747,7 +893,6 @@ 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_delete(const struct interface *ifp); /* * Enqueue tc link changes for the dataplane. @@ -860,6 +1005,13 @@ enum zebra_dplane_result dplane_gre_set(struct interface *ifp, struct interface *ifp_link, unsigned int mtu, const struct zebra_l2info_gre *gre_info); +/* + * Enqueue an SRv6 encap source address set + */ +enum zebra_dplane_result +dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id); + + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; @@ -1067,6 +1219,9 @@ void zebra_dplane_pre_finish(void); void zebra_dplane_finish(void); void zebra_dplane_shutdown(void); +void zebra_dplane_startup_stage(struct zebra_ns *zns, + enum zebra_dplane_startup_notifications spot); + /* * decision point for sending a routing update through the old * straight to zebra master pthread or through the dplane to @@ -1077,6 +1232,9 @@ void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct nexthop_group *ng, int startup, struct zebra_dplane_ctx *ctx); +enum zebra_dplane_startup_notifications +dplane_ctx_get_startup_spot(struct zebra_dplane_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index ce5e639928..ebb5a42298 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -109,21 +109,14 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) } else { json_object_int_add(json, "vni", zevpn->vni); json_object_string_add(json, "type", "L2"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON output") -#endif - json_object_string_add(json, "vrf", - vrf_id_to_name(zevpn->vrf_id)); - json_object_string_add(json, "tenantVrf", - vrf_id_to_name(zevpn->vrf_id)); + json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id)); } if (!zevpn->vxlan_if) { // unexpected if (json == NULL) vty_out(vty, " VxLAN interface: unknown\n"); else - json_object_string_add(json, "vxlanInterface", - "unknown"); + json_object_string_add(json, "vxlanInterface", "unknown"); return; } num_macs = num_valid_macs(zevpn); @@ -135,35 +128,21 @@ CPP_NOTICE("Drop `vrf` from JSON output") (zevpn->svi_if ? zevpn->svi_if->name : "")); vty_out(vty, " SVI ifIndex: %u\n", (zevpn->svi_if ? zevpn->svi_if->ifindex : 0)); - vty_out(vty, " Local VTEP IP: %pI4\n", - &zevpn->local_vtep_ip); - vty_out(vty, " Mcast group: %pI4\n", - &zevpn->mcast_grp); + vty_out(vty, " Local VTEP IP: %pI4\n", &zevpn->local_vtep_ip); + vty_out(vty, " Mcast group: %pI4\n", &zevpn->mcast_grp); } else { - json_object_string_add(json, "vxlanInterface", - zevpn->vxlan_if->name); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `ifindex` from JSON output") -#endif - json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex); - json_object_int_add(json, "vxlanIfindex", - zevpn->vxlan_if->ifindex); + json_object_string_add(json, "vxlanInterface", zevpn->vxlan_if->name); + json_object_int_add(json, "vxlanIfindex", zevpn->vxlan_if->ifindex); if (zevpn->svi_if) { - json_object_string_add(json, "sviInterface", - zevpn->svi_if->name); - json_object_int_add(json, "sviIfindex", - zevpn->svi_if->ifindex); + json_object_string_add(json, "sviInterface", zevpn->svi_if->name); + json_object_int_add(json, "sviIfindex", zevpn->svi_if->ifindex); } - json_object_string_addf(json, "vtepIp", "%pI4", - &zevpn->local_vtep_ip); - json_object_string_addf(json, "mcastGroup", "%pI4", - &zevpn->mcast_grp); + json_object_string_addf(json, "vtepIp", "%pI4", &zevpn->local_vtep_ip); + json_object_string_addf(json, "mcastGroup", "%pI4", &zevpn->mcast_grp); json_object_string_add(json, "advertiseGatewayMacip", - zevpn->advertise_gw_macip ? "Yes" - : "No"); + zevpn->advertise_gw_macip ? "Yes" : "No"); json_object_string_add(json, "advertiseSviMacip", - zevpn->advertise_svi_macip ? "Yes" - : "No"); + zevpn->advertise_svi_macip ? "Yes" : "No"); json_object_int_add(json, "numMacs", num_macs); json_object_int_add(json, "numArpNd", num_neigh); } @@ -179,28 +158,21 @@ CPP_NOTICE("Drop `ifindex` from JSON output") json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { const char *flood_str = lookup_msg( - zvtep_flood_str, zvtep->flood_control, - VXLAN_FLOOD_STR_DEFAULT); + zvtep_flood_str, zvtep->flood_control, VXLAN_FLOOD_STR_DEFAULT); if (json == NULL) { - vty_out(vty, " %pI4 flood: %s\n", - &zvtep->vtep_ip, - flood_str); + vty_out(vty, " %pI4 flood: %s\n", &zvtep->vtep_ip, flood_str); } else { json_vtep = json_object_new_object(); - json_object_string_addf(json_vtep, "ip", "%pI4", - &zvtep->vtep_ip); - json_object_string_add(json_vtep, "flood", - flood_str); - json_object_array_add(json_vtep_list, - json_vtep); + json_object_string_addf(json_vtep, "ip", "%pI4", &zvtep->vtep_ip); + json_object_string_add(json_vtep, "flood", flood_str); + json_object_array_add(json_vtep_list, json_vtep); } num_vteps++; } if (json) { json_object_int_add(json, "numRemoteVteps", num_vteps); - json_object_object_add(json, "remoteVteps", - json_vtep_list); + json_object_object_add(json, "remoteVteps", json_vtep_list); } } if (json == NULL) { @@ -261,8 +233,7 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_object_int_add(json_evpn, "vni", zevpn->vni); json_object_string_add(json_evpn, "type", "L2"); json_object_string_add(json_evpn, "vxlanIf", - zevpn->vxlan_if ? zevpn->vxlan_if->name - : "unknown"); + zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown"); json_object_int_add(json_evpn, "numMacs", num_macs); json_object_int_add(json_evpn, "numArpNd", num_neigh); json_object_int_add(json_evpn, "numRemoteVteps", num_vteps); @@ -272,13 +243,10 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { json_ip_str = json_object_new_string( - inet_ntop(AF_INET, &zvtep->vtep_ip, buf, - sizeof(buf))); - json_object_array_add(json_vtep_list, - json_ip_str); + inet_ntop(AF_INET, &zvtep->vtep_ip, buf, sizeof(buf))); + json_object_array_add(json_vtep_list, json_ip_str); } - json_object_object_add(json_evpn, "remoteVteps", - json_vtep_list); + json_object_object_add(json_evpn, "remoteVteps", json_vtep_list); } json_object_object_add(json, vni_str, json_evpn); } @@ -310,13 +278,12 @@ void zebra_evpn_print_hash_detail(struct hash_bucket *bucket, void *data) int zebra_evpn_del_macip_for_intf(struct interface *ifp, struct zebra_evpn *zevpn) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each_safe (if_connected, ifp->connected, c) { struct ipaddr ip; memset(&ip, 0, sizeof(struct ipaddr)); @@ -344,13 +311,12 @@ int zebra_evpn_del_macip_for_intf(struct interface *ifp, int zebra_evpn_add_macip_for_intf(struct interface *ifp, struct zebra_evpn *zevpn) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each_safe (if_connected, ifp->connected, c) { struct ipaddr ip; if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) @@ -385,7 +351,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, vrf_id); stream_put(s, p, sizeof(struct prefix)); @@ -409,13 +375,12 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, int zebra_evpn_advertise_subnet(struct zebra_evpn *zevpn, struct interface *ifp, int advertise) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix p; memcpy(&p, c->address, sizeof(struct prefix)); @@ -493,8 +458,7 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn, /* Remove neighbor from BGP. */ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, - n->flags, ZEBRA_NEIGH_ACTIVE, - false /*force*/); + n->flags, ZEBRA_NEIGH_ACTIVE, false /*force*/); /* Delete this neighbor entry. */ zebra_evpn_neigh_del(zevpn, n); @@ -524,8 +488,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket, */ if (zevpn->advertise_gw_macip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", - zevpn->vni); + zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", zevpn->vni); return; } @@ -697,8 +660,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, if (zif->brslave_info.br_if != br_if) continue; - vni_id = - zebra_vxlan_if_access_vlan_vni_find(zif, br_if); + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; break; @@ -735,9 +697,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp, in_param.zif = zif; p_zevpn = &zevpn; - ns_walk_func(zebra_evpn_map_vlan_ns, - (void *)&in_param, - (void **)p_zevpn); + ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn); return zevpn; } @@ -857,9 +817,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp, return zevpn; } -static int zvni_map_to_macvlan_ns(struct ns *ns, - void *_in_param, - void **_p_ifp) +static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) { struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = @@ -921,9 +879,7 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, p_ifp = &tmp_if; /* Identify corresponding VLAN interface. */ - ns_walk_func(zvni_map_to_macvlan_ns, - (void *)&in_param, - (void **)p_ifp); + ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp); return tmp_if; } @@ -1128,8 +1084,7 @@ struct zebra_evpn *zebra_evpn_add(vni_t vni) /* Create hash table for MAC */ zevpn->mac_table = zebra_mac_db_create(buffer); - snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", - vni); + snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", vni); /* Create hash table for neighbors */ zevpn->neigh_table = zebra_neigh_db_create(buffer); @@ -1185,7 +1140,7 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) svi_index = zevpn->svi_if ? zevpn->svi_if->ifindex : 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id()); stream_putl(s, zevpn->vni); @@ -1208,8 +1163,8 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) client->vniadd_cnt++; rc = zserv_send_message(client, s); - if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) { - zevpn->flags |= ZEVPN_READY_FOR_BGP; + if (!CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + SET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* once the EVPN is sent the ES-EVIs can also be replayed * to BGP */ @@ -1231,13 +1186,13 @@ int zebra_evpn_send_del_to_client(struct zebra_evpn *zevpn) if (!client) return 0; - if (zevpn->flags & ZEVPN_READY_FOR_BGP) { - zevpn->flags &= ~ZEVPN_READY_FOR_BGP; + if (CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + UNSET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* the ES-EVIs must be removed from BGP before the EVPN is */ zebra_evpn_update_all_es(zevpn); } - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id()); @@ -1353,8 +1308,7 @@ int zebra_evpn_vtep_install(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep) if (is_vxlan_flooding_head_end() && (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) { if (ZEBRA_DPLANE_REQUEST_FAILURE == - dplane_vtep_add(zevpn->vxlan_if, - &zvtep->vtep_ip, zevpn->vni)) + dplane_vtep_add(zevpn->vxlan_if, &zvtep->vtep_ip, zevpn->vni)) return -1; } @@ -1445,9 +1399,7 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, zevpn->vni, macaddr, ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); return; @@ -1462,16 +1414,13 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } if (!mac) return; n = zebra_evpn_neigh_lookup(zevpn, ipaddr); - if (n - && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, - true)) + if (n && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, true)) return; zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, @@ -1517,22 +1466,19 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, * SYNC - if ES is local * REMOTE - if ES is not local */ - if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) { + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH)) { struct zebra_evpn_es *es; es = zebra_evpn_es_find(esi); - if (es && (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)) { + if (es && CHECK_FLAG(es->flags, ZEBRA_EVPNES_READY_FOR_BGP)) { zebra_evpn_process_sync_macip_add(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) { char esi_str[ESI_STR_LEN]; esi_to_str(esi, esi_str, sizeof(esi_str)); - zlog_debug( - "Ignore sync-macip add; ES %s is not ready", - esi_str); + zlog_debug("Ignore sync-macip add; ES %s is not ready", esi_str); } } @@ -1546,8 +1492,7 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, if (vtep_ip.s_addr) { zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); if (!zvtep) { - zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, - VXLAN_FLOOD_DISABLED); + zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, VXLAN_FLOOD_DISABLED); if (!zvtep) { flog_err( EC_ZEBRA_VTEP_ADD_FAILED, @@ -1624,9 +1569,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, vnip = zebra_vxlan_if_vni_find(zif, vni); if (!vnip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "VNI %u not in interface upon remote MACIP DEL", - vni); + zlog_debug("VNI %u not in interface upon remote MACIP DEL", vni); return; } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 6d5cd66143..bfc060db61 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -103,9 +103,7 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)", - zmac->zevpn->vni, - &zmac->macaddr, - ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); zif = ifp->info; list_delete_node(zif->mac_list, &zmac->ifp_listnode); @@ -122,7 +120,7 @@ void zebra_evpn_mac_ifp_del(struct interface *ifp) if (zif->mac_list) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("MAC list deleted for ifp %s (%u)", - zif->ifp->name, zif->ifp->ifindex); + zif->ifp->name, zif->ifp->ifindex); for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) { zebra_evpn_mac_ifp_unlink(zmac); @@ -161,9 +159,7 @@ static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)", - zmac->zevpn->vni, - &zmac->macaddr, - ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); zmac->ifp = ifp; listnode_init(&zmac->ifp_listnode, zmac); @@ -205,7 +201,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac, return -1; sticky = !!CHECK_FLAG(mac->flags, - (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); /* If nexthop group for the FDB entry is inactive (not programmed in * the dataplane) the MAC entry cannot be installed @@ -249,7 +245,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, enum zebra_dplane_result res; /* If the MAC was not installed there is no need to uninstall it */ - if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) + if (!force && mac->es && !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE)) return -1; if (!zevpn->vxlan_if) { @@ -282,8 +278,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, ifp = zevpn->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, - vtep_ip); + res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -341,8 +336,7 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac, *vid = mac->fwd_info.local.vid; zns = zebra_ns_lookup(mac->fwd_info.local.ns_id); - *p_ifp = if_lookup_by_index_per_ns(zns, - mac->fwd_info.local.ifindex); + *p_ifp = if_lookup_by_index_per_ns(zns, mac->fwd_info.local.ifindex); } } @@ -355,26 +349,19 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf, return buf; } - snprintfrr( - buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", + snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) - ? "PEER Active " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "PEER Active " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) - ? "LOC Inactive " - : ""); + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "LOC Inactive " : ""); return buf; } @@ -407,8 +394,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) zlog_debug( "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, listcount(mac->neigh_list)); } @@ -418,8 +404,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) ZEBRA_NEIGH_SET_INACTIVE(nbr); else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) - zebra_evpn_rem_neigh_install( - zevpn, nbr, false /*was_static*/); + zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); } UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); @@ -438,13 +423,11 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { /* Inform to BGP */ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, - mac->flags, mac->loc_seq, - mac->es)) + mac->flags, mac->loc_seq, mac->es)) return; /* Process all neighbors associated with this MAC. */ - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, - 0 /*es_change*/); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0 /*es_change*/); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -479,8 +462,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, zvrf->dad_freeze_time); } /* For duplicate MAC do not update @@ -516,8 +498,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count); } @@ -545,10 +526,10 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (mac->dad_count >= zvrf->dad_max_moves) { flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, - "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", - mac->zevpn->vni, &mac->macaddr, - is_local ? "local update, last" : - "remote update, from", &vtep_ip); + "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", + mac->zevpn->vni, &mac->macaddr, + is_local ? "local update, last" : "remote update, from", + &vtep_ip); SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); @@ -583,15 +564,13 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), zvrf->dad_freeze_time); } event_add_timer(zrouter.master, - zebra_evpn_dad_mac_auto_recovery_exp, - mac, zvrf->dad_freeze_time, - &mac->dad_mac_auto_recovery_timer); + zebra_evpn_dad_mac_auto_recovery_exp, mac, + zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer); } /* In case of local update, do not inform to client (BGPd), @@ -638,22 +617,18 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); json_object_string_add(json_mac, "type", "local"); if (ifp) { - json_object_string_add(json_mac, "intf", - ifp->name); - json_object_int_add(json_mac, "ifindex", - ifp->ifindex); + json_object_string_add(json_mac, "intf", ifp->name); + json_object_int_add(json_mac, "ifindex", ifp->ifindex); } if (vid) json_object_int_add(json_mac, "vlan", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", - mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); else json_object_string_addf( - json_mac, "remoteVtep", "%pI4", - &mac->fwd_info.r_vtep_ip); + json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) json_object_string_add(json_mac, "type", "auto"); @@ -664,12 +639,10 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) json_object_boolean_true_add(json_mac, "sviMac"); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) - json_object_boolean_true_add(json_mac, - "defaultGateway"); + json_object_boolean_true_add(json_mac, "defaultGateway"); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) - json_object_boolean_true_add(json_mac, - "remoteGatewayMac"); + json_object_boolean_true_add(json_mac, "remoteGatewayMac"); json_object_string_add(json_mac, "uptime", up_str); json_object_int_add(json_mac, "localSequence", mac->loc_seq); @@ -690,46 +663,31 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) json_object_boolean_true_add(json_mac, "peerActive"); if (mac->hold_timer) - json_object_string_add( - json_mac, "peerActiveHold", - event_timer_to_hhmmss(thread_buf, - sizeof(thread_buf), - mac->hold_timer)); + json_object_string_add(json_mac, "peerActiveHold", + event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); if (mac->es) - json_object_string_add(json_mac, "esi", - mac->es->esi_str); + json_object_string_add(json_mac, "esi", mac->es->esi_str); /* print all the associated neigh */ if (!listcount(mac->neigh_list)) json_object_string_add(json_mac, "neighbors", "none"); else { json_object *json_active_nbrs = json_object_new_array(); - json_object *json_inactive_nbrs = - json_object_new_array(); + json_object *json_inactive_nbrs = json_object_new_array(); json_object *json_nbrs = json_object_new_object(); for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { if (IS_ZEBRA_NEIGH_ACTIVE(n)) - json_object_array_add( - json_active_nbrs, - json_object_new_string( - ipaddr2str( - &n->ip, buf2, - sizeof(buf2)))); + json_object_array_add(json_active_nbrs, + json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); else json_object_array_add( json_inactive_nbrs, - json_object_new_string( - ipaddr2str( - &n->ip, buf2, - sizeof(buf2)))); + json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); } - json_object_object_add(json_nbrs, "active", - json_active_nbrs); - json_object_object_add(json_nbrs, "inactive", - json_inactive_nbrs); - json_object_object_add(json_mac, "neighbors", - json_nbrs); + json_object_object_add(json_nbrs, "active", json_active_nbrs); + json_object_object_add(json_nbrs, "inactive", json_inactive_nbrs); + json_object_object_add(json_mac, "neighbors", json_nbrs); } json_object_object_add(json, buf1, json_mac); @@ -746,18 +704,15 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " ESI: %s\n", mac->es->esi_str); if (ifp) - vty_out(vty, " Intf: %s(%u)", ifp->name, - ifp->ifindex); + vty_out(vty, " Intf: %s(%u)", ifp->name, ifp->ifindex); else vty_out(vty, " Intf: -"); vty_out(vty, " VLAN: %u", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { if (mac->es) - vty_out(vty, " Remote ES: %s", - mac->es->esi_str); + vty_out(vty, " Remote ES: %s", mac->es->esi_str); else - vty_out(vty, " Remote VTEP: %pI4", - &mac->fwd_info.r_vtep_ip); + vty_out(vty, " Remote VTEP: %pI4", &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { vty_out(vty, " Auto Mac "); } @@ -784,24 +739,18 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " peer-active"); if (mac->hold_timer) vty_out(vty, " (ht: %s)", - event_timer_to_hhmmss(thread_buf, - sizeof(thread_buf), - mac->hold_timer)); + event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); vty_out(vty, "\n"); - vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, - mac->rem_seq); + vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, mac->rem_seq); vty_out(vty, " Uptime: %s\n", up_str); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { vty_out(vty, " Duplicate, detected at %s", - time_to_string(mac->dad_dup_detect_time, - timebuf)); + time_to_string(mac->dad_dup_detect_time, timebuf)); } else if (mac->dad_count) { - monotime_since(&mac->detect_start_time, - &detect_start_time); + monotime_since(&mac->detect_start_time, &detect_start_time); if (detect_start_time.tv_sec <= zvrf->dad_time) { - time_to_string(mac->detect_start_time.tv_sec, - timebuf); + time_to_string(mac->detect_start_time.tv_sec, timebuf); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", timebuf, mac->dad_count); @@ -816,9 +765,7 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { vty_out(vty, " %s %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2)), - (IS_ZEBRA_NEIGH_ACTIVE(n) - ? "Active" - : "Inactive")); + (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" : "Inactive")); } } @@ -831,9 +778,9 @@ static char *zebra_evpn_print_mac_flags(struct zebra_mac *mac, char *flags_buf, { snprintf(flags_buf, flags_buf_sz, "%s%s%s%s", mac->sync_neigh_cnt ? "N" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "", - (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : ""); + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : ""); return flags_buf; } @@ -870,14 +817,12 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); if (json_mac_hdr == NULL) { vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local", - zebra_evpn_print_mac_flags(mac, flags_buf, - sizeof(flags_buf)), + zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), ifp ? ifp->name : "-"); } else { json_object_string_add(json_mac, "type", "local"); if (ifp) - json_object_string_add(json_mac, "intf", - ifp->name); + json_object_string_add(json_mac, "intf", ifp->name); } if (vid) { if (json_mac_hdr == NULL) @@ -891,18 +836,13 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq); vty_out(vty, "\n"); } else { - json_object_int_add(json_mac, "localSequence", - mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", - mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", - mac->dad_count); + json_object_int_add(json_mac, "localSequence", mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, - "isDuplicate"); + json_object_boolean_true_add(json_mac, "isDuplicate"); else - json_object_boolean_false_add(json_mac, - "isDuplicate"); + json_object_boolean_false_add(json_mac, "isDuplicate"); json_object_object_add(json_mac_hdr, buf1, json_mac); } @@ -910,19 +850,16 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) - && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, - &wctx->r_vtep_ip)) + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) + && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return; if (json_mac_hdr == NULL) { - if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) && (wctx->count == 0)) { vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni); vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n", - "MAC", "Type", "Flags", - "Intf/Remote ES/VTEP", "VLAN", - "Seq #'s"); + "MAC", "Type", "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s"); } if (mac->es == NULL) inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip, @@ -930,32 +867,24 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1, "remote", - zebra_evpn_print_mac_flags(mac, flags_buf, - sizeof(flags_buf)), + zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), mac->es ? mac->es->esi_str : addr_buf, "", mac->loc_seq, mac->rem_seq); } else { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", - mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); else json_object_string_addf( - json_mac, "remoteVtep", "%pI4", - &mac->fwd_info.r_vtep_ip); + json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); json_object_object_add(json_mac_hdr, buf1, json_mac); - json_object_int_add(json_mac, "localSequence", - mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", - mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", - mac->dad_count); + json_object_int_add(json_mac, "localSequence", mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, - "isDuplicate"); + json_object_boolean_true_add(json_mac, "isDuplicate"); else - json_object_boolean_false_add(json_mac, - "isDuplicate"); + json_object_boolean_false_add(json_mac, "isDuplicate"); } wctx->count++; @@ -1004,7 +933,7 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, zebra_vrf_get_evpn_id()); stream_putl(s, vni); @@ -1040,9 +969,9 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, zlog_debug( "Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", - zclient_evpn_dump_macip_flags(flags, flag_buf, - sizeof(flag_buf)), - state, macaddr, ip, seq, vni, es ? es->esi_str : "-", + zclient_evpn_dump_macip_flags(flags, flag_buf, sizeof(flag_buf)), + state, macaddr, ip, seq, vni, + es ? es->esi_str : "-", zebra_route_string(client->proto)); } @@ -1076,8 +1005,7 @@ static bool mac_cmp(const void *p1, const void *p2) if (pmac1 == NULL || pmac2 == NULL) return false; - return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) - == 0); + return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) == 0); } /* @@ -1117,10 +1045,8 @@ struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return mac; } @@ -1135,10 +1061,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* force de-ref any ES entry linked to the MAC */ @@ -1165,9 +1089,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " - "count %u, mark MAC as AUTO", - &mac->macaddr, mac->flags, zevpn->vni, - listcount(mac->neigh_list)); + "count %u, mark MAC as AUTO", &mac->macaddr, mac->flags, + zevpn->vni, listcount(mac->neigh_list)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); return 0; @@ -1204,25 +1127,25 @@ struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn, static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, struct zebra_mac *mac) { - if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) + if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return true; - else if ((wctx->flags & DEL_REMOTE_MAC) - && (mac->flags & ZEBRA_MAC_REMOTE)) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) return true; - else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) - && (mac->flags & ZEBRA_MAC_REMOTE) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return true; - else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO) + else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) && !listcount(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: Del MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + "%s: Del MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } wctx->uninstall = 0; @@ -1241,21 +1164,17 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct zebra_mac *mac = bucket->data; if (zebra_evpn_check_mac_del_from_db(wctx, mac)) { - if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { + if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni, - &mac->macaddr, - mac->flags, false); + &mac->macaddr, mac->flags, false); } if (wctx->uninstall) { if (zebra_evpn_mac_is_static(mac)) - zebra_evpn_sync_mac_dp_install( - mac, false /* set_inactive */, - true /* force_clear_static */, - __func__); + zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, + true /* force_clear_static */, __func__); if (mac->flags & ZEBRA_MAC_REMOTE) - zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, - false /*force*/); + zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false /*force*/); } zebra_evpn_mac_del(wctx->zevpn, mac); @@ -1330,8 +1249,7 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags, - seq, ZEBRA_NEIGH_ACTIVE, es, - ZEBRA_MACIP_ADD); + seq, ZEBRA_NEIGH_ACTIVE, es, ZEBRA_MACIP_ADD); } /* @@ -1357,9 +1275,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, state = ZEBRA_NEIGH_INACTIVE; } - return zebra_evpn_macip_send_msg_to_client( - vni, macaddr, NULL, 0 /* flags */, 0 /* seq */, state, NULL, - ZEBRA_MACIP_DEL); + return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, + 0 /* flags */, 0 /* seq */, state, NULL, ZEBRA_MACIP_DEL); } /* @@ -1412,8 +1329,7 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port", caller, zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } return -1; @@ -1429,8 +1345,7 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br", caller, zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } return -1; @@ -1455,19 +1370,16 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, set_static ? "install" : "uninstall", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } if (set_static) /* XXX - old_static needs to be computed more * accurately */ - zebra_evpn_rem_mac_install(zevpn, mac, - true /* old_static */); + zebra_evpn_rem_mac_install(zevpn, mac, true /* old_static */); else - zebra_evpn_rem_mac_uninstall(zevpn, mac, - false /* force */); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false /* force */); return 0; } @@ -1478,14 +1390,13 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_static ? "static " : "", set_inactive ? "inactive " : ""); } dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky, - set_static, set_inactive); + set_static, set_inactive); return 0; } @@ -1495,12 +1406,11 @@ void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac, { if (new_bgp_ready) zebra_evpn_mac_send_add_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, - mac->loc_seq, mac->es); + &mac->macaddr, mac->flags, + mac->loc_seq, mac->es); else if (old_bgp_ready) zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, - true /* force */); + &mac->macaddr, mac->flags, true /* force */); } /* MAC hold timer is used to age out peer-active flag. @@ -1537,8 +1447,7 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) "sync-mac vni %u mac %pEA es %s %shold expired", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* re-program the local mac in the dataplane if the mac is no @@ -1546,13 +1455,11 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) */ if (old_static != new_static) zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); /* inform bgp if needed */ if (old_bgp_ready != new_bgp_ready) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); } static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) @@ -1567,8 +1474,7 @@ static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) "sync-mac vni %u mac %pEA es %s %shold started", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } event_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac, zmh_info->mac_hold_time, &mac->hold_timer); @@ -1586,8 +1492,7 @@ void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac) "sync-mac vni %u mac %pEA es %s %shold stopped", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } EVENT_OFF(mac->hold_timer); @@ -1605,8 +1510,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) "sync-mac del vni %u mac %pEA es %s seq %d f %s", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } old_static = zebra_evpn_mac_is_static(mac); @@ -1618,8 +1522,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) if (old_static != new_static) /* program the local mac in the kernel */ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); } static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, @@ -1647,8 +1550,7 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, zlog_debug( "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x", sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, tmp_seq, - mac->flags); + n_type, &mac->macaddr, tmp_seq, mac->flags); return true; } @@ -1660,10 +1562,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s", - sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + (sync ? "sync" : "rem"), + zevpn->vni, n_type, &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return true; @@ -1672,10 +1573,8 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s", - sync ? "sync" : "rem", zevpn->vni, n_type, - &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + (sync ? "sync" : "rem"), zevpn->vni, n_type, &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return false; @@ -1749,9 +1648,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, "Ignore sync-macip vni %u mac %pEA%s%s%s%s", zevpn->vni, macaddr, ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); return NULL; @@ -1766,16 +1663,16 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, new_flags = 0; SET_FLAG(new_flags, ZEBRA_MAC_LOCAL); /* retain old local activity flag */ - if (old_flags & ZEBRA_MAC_LOCAL) - new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE); + if (CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL)) + SET_FLAG (new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL_INACTIVE)); else - new_flags |= ZEBRA_MAC_LOCAL_INACTIVE; + SET_FLAG(new_flags, ZEBRA_MAC_LOCAL_INACTIVE); if (ipa_len) { /* if mac-ip route do NOT update the peer flags * i.e. retain only flags as is */ - new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS); + SET_FLAG(new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_ALL_PEER_FLAGS)); } else { /* if mac-only route update peer flags */ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) { @@ -1785,10 +1682,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * holdtimer on it. the peer-active flag is * cleared on holdtimer expiry. */ - if (CHECK_FLAG(old_flags, - ZEBRA_MAC_ES_PEER_ACTIVE)) { - SET_FLAG(new_flags, - ZEBRA_MAC_ES_PEER_ACTIVE); + if (CHECK_FLAG(old_flags, ZEBRA_MAC_ES_PEER_ACTIVE)) { + SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE); zebra_evpn_mac_start_hold_timer(mac); } } else { @@ -1811,10 +1706,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, zlog_debug( "sync-mac vni %u mac %pEA old_f %snew_f %s", zevpn->vni, macaddr, - zebra_evpn_zebra_mac_flag_dump( - &omac, omac_buf, sizeof(omac_buf)), - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(&omac, omac_buf, sizeof(omac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* update es */ @@ -1854,24 +1747,24 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s", - created ? "created" : "updated", zevpn->vni, macaddr, - mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), - inform_bgp ? "inform_bgp" : "", - inform_dataplane ? " inform_dp" : ""); + created ? "created" : "updated", + zevpn->vni, macaddr, + mac->es ? mac->es->esi_str : "-", + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), + inform_bgp ? "inform_bgp" : "", + inform_dataplane ? " inform_dp" : ""); } if (inform_bgp) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); /* neighs using the mac may need to be re-sent to * bgp with updated info */ if (seq_change || es_change || !old_local) zebra_evpn_process_neigh_on_local_mac_change( - zevpn, mac, seq_change, es_change); + zevpn, mac, seq_change, es_change); if (inform_dataplane && !ipa_len) { /* program the local mac in the kernel. when the ES @@ -1879,9 +1772,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * the activity as we are yet to establish activity * locally */ - zebra_evpn_sync_mac_dp_install( - mac, mac_inactive /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, mac_inactive /* set_inactive */, + false /* force_clear_static */, __func__); } return mac; @@ -1891,8 +1783,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * is detected */ static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac, - struct interface *ifp, - vlanid_t vid) + struct interface *ifp, vlanid_t vid) { struct zebra_if *zif = ifp->info; bool es_change; @@ -1934,8 +1825,8 @@ static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket, if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni, - &zmac->macaddr, zmac->flags, - zmac->loc_seq, zmac->es); + &zmac->macaddr, zmac->flags, + zmac->loc_seq, zmac->es); } /* Iterator to Notify Local MACs of a EVPN */ @@ -1949,8 +1840,7 @@ void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn) memset(&wctx, 0, sizeof(wctx)); wctx.zevpn = zevpn; - hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, - &wctx); + hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, &wctx); } void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) @@ -1992,8 +1882,7 @@ void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt) } /* Print Duplicate MAC in detail */ -void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, - void *ctxt) +void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct zebra_mac *mac; @@ -2043,11 +1932,13 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * If so, that needs to be updated first. Note that client could * install MAC and MACIP separately or just install the latter. */ - if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) - || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) - || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) - || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq) + if (!mac + || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) + || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) + || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) + || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) + || memcmp(old_esi, esi, sizeof(esi_t)) + || seq != mac->rem_seq) update_mac = 1; if (update_mac) { @@ -2063,8 +1954,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * the sequence number and ignore this update * if appropriate. */ - if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, - false)) + if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, false)) return -1; old_es_present = !!mac->es; @@ -2091,8 +1981,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * MAC is already marked duplicate set dad, then * is_dup_detect will be set to not install the entry. */ - if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - && mac->dad_count) + if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && mac->dad_count) || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) do_dad = true; @@ -2108,14 +1997,12 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } zebra_evpn_mac_clear_sync_info(mac); - zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, - mac->flags, - false /* force */); + zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, + false /* force */); } /* Set "auto" and "remote" forwarding info. */ @@ -2135,8 +2022,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, - &is_dup_detect, false); + zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, &is_dup_detect, false); if (!is_dup_detect) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -2180,8 +2066,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug( "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", - sticky ? "sticky " : "", macaddr, - ifp->name, ifp->ifindex, vid, zevpn->vni, + sticky ? "sticky " : "", + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? " local-inactive" : ""); mac = zebra_evpn_mac_add(zevpn, macaddr); @@ -2196,11 +2082,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zlog_debug( "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", - sticky ? "sticky " : "", macaddr, - ifp->name, ifp->ifindex, vid, zevpn->vni, + sticky ? "sticky " : "", + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? "local-inactive " : "", - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { @@ -2209,42 +2094,34 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, bool old_static; zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid); - old_bgp_ready = - zebra_evpn_mac_is_ready_for_bgp(mac->flags); - old_local_inactive = - !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); + old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + old_local_inactive = !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); old_static = zebra_evpn_mac_is_static(mac); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) mac_sticky = true; - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); /* * Update any changes and if changes are relevant to * BGP, note it. */ - if (mac_sticky == sticky && old_ifp == ifp - && old_vid == vid - && old_local_inactive == local_inactive - && dp_static == old_static && !es_change) { + if (mac_sticky == sticky && old_ifp == ifp && old_vid == vid + && old_local_inactive == local_inactive + && dp_static == old_static && !es_change) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " "entry exists and has not changed ", sticky ? "sticky " : "", - macaddr, ifp->name, - ifp->ifindex, vid, zevpn->vni, - local_inactive - ? " local_inactive" - : ""); + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, + local_inactive ? " local_inactive" : ""); return 0; } if (mac_sticky != sticky) { if (sticky) SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); else - UNSET_FLAG(mac->flags, - ZEBRA_MAC_STICKY); + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); inform_client = true; } @@ -2262,11 +2139,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* force drop the peer/sync info as it is * simply no longer relevant */ - if (CHECK_FLAG(mac->flags, - ZEBRA_MAC_ALL_PEER_FLAGS)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS)) { zebra_evpn_mac_clear_sync_info(mac); - new_static = - zebra_evpn_mac_is_static(mac); + new_static = zebra_evpn_mac_is_static(mac); /* if we clear peer-flags we * also need to notify the dataplane * to drop the static flag @@ -2289,16 +2164,13 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, flog_warn( EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", - macaddr, - &mac->fwd_info.r_vtep_ip, - zevpn->vni); + macaddr, &mac->fwd_info.r_vtep_ip, zevpn->vni); return 0; } /* If an actual move, compute MAC's seq number */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - mac->loc_seq = - MAX(mac->rem_seq + 1, mac->loc_seq); + mac->loc_seq = MAX(mac->rem_seq + 1, mac->loc_seq); vtep_ip = mac->fwd_info.r_vtep_ip; /* Trigger DAD for remote MAC */ do_dad = true; @@ -2307,8 +2179,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); if (sticky) SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); else @@ -2321,8 +2192,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, upd_neigh = true; zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, vtep_ip, do_dad, &is_dup_detect, - true); + zvrf, mac, vtep_ip, do_dad, &is_dup_detect, true); if (is_dup_detect) { inform_client = false; upd_neigh = false; @@ -2357,8 +2227,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, "local mac vni %u mac %pEA es %s seq %d f %s%s", zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), local_inactive ? "local-inactive" : ""); } @@ -2374,18 +2243,15 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* Inform dataplane if required. */ if (inform_dataplane) zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); /* Inform BGP if required. */ if (inform_client) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); /* Process all neighbors associated with this MAC, if required. */ if (upd_neigh) - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, - es_change); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, es_change); return 0; } @@ -2415,23 +2281,20 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, "re-add sync-mac vni %u mac %pEA es %s seq %d f %s", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* inform-bgp about change in local-activity if any */ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) { SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); - new_bgp_ready = - zebra_evpn_mac_is_ready_for_bgp(mac->flags); + new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); zebra_evpn_mac_send_add_del_to_client( - mac, old_bgp_ready, new_bgp_ready); + mac, old_bgp_ready, new_bgp_ready); } /* re-install the inactive entry in the kernel */ zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); return 0; } @@ -2519,8 +2382,7 @@ void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn) old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI); - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - false); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false); zebra_evpn_deref_ip2mac(mac->zevpn, mac); } } @@ -2548,13 +2410,11 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("SVI %s mac add", zif->ifp->name); - old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) - ? true - : false; + old_bgp_ready = + (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) ? true : false; zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false); new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); } diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index bf488ca316..0d9d912f83 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -52,10 +52,9 @@ static void zebra_evpn_es_get_one_base_evpn(void); static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, struct zebra_evpn *zevpn, bool add); static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp); -static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi); +static void zebra_evpn_local_es_update(struct zebra_if *zif); static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es, const char *caller); -static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set); static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es, bool resync_dplane); static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es); @@ -535,19 +534,26 @@ static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2) } /* Lookup VLAN based broadcast domain */ -struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid, - struct interface *br_if) +struct zebra_evpn_access_bd * +zebra_evpn_acc_vl_find_index(vlanid_t vid, ifindex_t bridge_ifindex) { struct zebra_evpn_access_bd *acc_bd; struct zebra_evpn_access_bd tmp; tmp.vid = vid; - tmp.bridge_ifindex = br_if->ifindex; + tmp.bridge_ifindex = bridge_ifindex; acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp); return acc_bd; } +/* Lookup VLAN based broadcast domain */ +struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid, + struct interface *br_if) +{ + return zebra_evpn_acc_vl_find_index(vid, br_if->ifindex); +} + /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF * mapping is added. */ @@ -842,9 +848,9 @@ void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if, void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn, bool set) { - struct interface *br_if; struct zebra_vxlan_vni *vni; struct zebra_evpn_access_bd *acc_bd; + ifindex_t br_ifindex; if (!zif) return; @@ -854,11 +860,12 @@ void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn, if (!vni) return; - br_if = zif->brslave_info.br_if; - if (!br_if) + /* Use the index as the pointer can be stale (deleted) */ + br_ifindex = zif->brslave_info.bridge_ifindex; + if (!zif->brslave_info.br_if || br_ifindex == IFINDEX_INTERNAL) return; - acc_bd = zebra_evpn_acc_vl_find(vni->access_vlan, br_if); + acc_bd = zebra_evpn_acc_vl_find_index(vni->access_vlan, br_ifindex); if (!acc_bd) return; @@ -1131,7 +1138,7 @@ void zebra_evpn_if_init(struct zebra_if *zif) /* if an es_id and sysmac are already present against the interface * activate it */ - zebra_evpn_local_es_update(zif, &zif->es_info.esi); + zebra_evpn_local_es_update(zif); } /* handle deletion of an access port by removing it from all associated @@ -1928,7 +1935,7 @@ static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id()); stream_put(s, &es->esi, sizeof(esi_t)); @@ -1964,7 +1971,7 @@ static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id()); @@ -2242,8 +2249,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, /* attach es to interface */ zif->es_info.es = es; - es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref - : EVPN_MH_DF_PREF_DEFAULT; + es->df_pref = zif->es_info.df_pref; /* attach interface to es */ es->zif = zif; @@ -2394,73 +2400,63 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp) } } +void zebra_build_type3_esi(uint32_t lid, struct ethaddr *mac, esi_t *esi) +{ + int offset = 0; + int field_bytes = 0; + + /* build 10-byte type-3-ESI - + * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes) + */ + field_bytes = 1; + esi->val[offset] = ESI_TYPE_MAC; + offset += field_bytes; + + field_bytes = ETH_ALEN; + memcpy(&esi->val[offset], (uint8_t *)mac, field_bytes); + offset += field_bytes; + + esi->val[offset++] = (uint8_t)(lid >> 16); + esi->val[offset++] = (uint8_t)(lid >> 8); + esi->val[offset++] = (uint8_t)lid; +} + /* A new local es is created when a local-es-id and sysmac is configured * against an interface. */ -static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi) +static void zebra_evpn_local_es_update(struct zebra_if *zif) { struct zebra_evpn_es *old_es = zif->es_info.es; struct zebra_evpn_es *es; + esi_t _esi, *esi; + + if (!zebra_evpn_is_if_es_capable(zif)) + return; + + if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) { + esi = &zif->es_info.esi; + } else if (zif->es_info.lid && !is_zero_mac(&zif->es_info.sysmac)) { + zebra_build_type3_esi(zif->es_info.lid, &zif->es_info.sysmac, + &_esi); + esi = &_esi; + } else { + esi = zero_esi; + } if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi))) /* dup - nothing to be done */ - return 0; + return; /* release the old_es against the zif */ if (old_es) zebra_evpn_local_es_del(&old_es); es = zebra_evpn_es_find(esi); - if (es) { - /* if it exists against another interface flag an error */ - if (es->zif && es->zif != zif) - return -1; - } else { - /* create new es */ + if (!es) es = zebra_evpn_es_new(esi); - } - memcpy(&zif->es_info.esi, esi, sizeof(*esi)); if (es) zebra_evpn_es_local_info_set(es, zif); - - return 0; -} - -static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid, - struct ethaddr *sysmac) -{ - struct zebra_evpn_es *old_es = zif->es_info.es; - esi_t esi; - int offset = 0; - int field_bytes = 0; - - /* Complete config of the ES-ID bootstraps the ES */ - if (!lid || is_zero_mac(sysmac)) { - /* clear old esi */ - memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi)); - /* if in ES is attached to zif delete it */ - if (old_es) - zebra_evpn_local_es_del(&old_es); - return 0; - } - - /* build 10-byte type-3-ESI - - * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes) - */ - field_bytes = 1; - esi.val[offset] = ESI_TYPE_MAC; - offset += field_bytes; - - field_bytes = ETH_ALEN; - memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes); - offset += field_bytes; - - esi.val[offset++] = (uint8_t)(lid >> 16); - esi.val[offset++] = (uint8_t)(lid >> 8); - esi.val[offset++] = (uint8_t)lid; - - return zebra_evpn_local_es_update(zif, &esi); } int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip) @@ -2643,7 +2639,7 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL, @@ -2665,44 +2661,33 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, } /* sysmac part of a local ESI has changed */ -static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif, - struct ethaddr *sysmac) +void zebra_evpn_es_sys_mac_update(struct zebra_if *zif, struct ethaddr *sysmac) { - int rv; - - rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac); - if (!rv) + if (sysmac) memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr)); + else + memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr)); - return rv; + zebra_evpn_local_es_update(zif); } /* local-ID part of ESI has changed */ -static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid) +void zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid) { - int rv; + zif->es_info.lid = lid; - rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac); - if (!rv) - zif->es_info.lid = lid; - - return rv; + zebra_evpn_local_es_update(zif); } /* type-0 esi has changed */ -static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi) +void zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi) { - int rv; - - rv = zebra_evpn_local_es_update(zif, esi); - - /* clear the old es_lid, es_sysmac - type-0 is being set so old - * type-3 params need to be flushed - */ - memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr)); - zif->es_info.lid = 0; + if (esi) + memcpy(&zif->es_info.esi, esi, sizeof(*esi)); + else + memset(&zif->es_info.esi, 0, sizeof(*esi)); - return rv; + zebra_evpn_local_es_update(zif); } void zebra_evpn_es_cleanup(void) @@ -2718,10 +2703,9 @@ void zebra_evpn_es_cleanup(void) } } -static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) +void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) { struct zebra_evpn_es *es; - uint16_t tmp_pref; if (zif->es_info.df_pref == df_pref) return; @@ -2732,13 +2716,10 @@ static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) if (!es) return; - tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref - : EVPN_MH_DF_PREF_DEFAULT; - - if (es->df_pref == tmp_pref) + if (es->df_pref == zif->es_info.df_pref) return; - es->df_pref = tmp_pref; + es->df_pref = zif->es_info.df_pref; /* run df election */ zebra_evpn_es_run_df_election(es, __func__); /* notify bgp */ @@ -2825,7 +2806,7 @@ void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, zebra_evpn_es_br_port_dplane_update(es, __func__); } -static void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass) +void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass) { bool old_bypass = !!(zif->es_info.flags & ZIF_CFG_ES_FLAG_BYPASS); @@ -3157,6 +3138,9 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, json_array_string_add(json_flags, "local"); if (es->flags & ZEBRA_EVPNES_REMOTE) json_array_string_add(json_flags, "remote"); + if (es->flags & ZEBRA_EVPNES_LOCAL && + !(es->flags & ZEBRA_EVPNES_NON_DF)) + json_array_string_add(json_flags, "df"); if (es->flags & ZEBRA_EVPNES_NON_DF) json_array_string_add(json_flags, "nonDF"); if (es->flags & ZEBRA_EVPNES_BYPASS) @@ -3315,208 +3299,9 @@ void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) vty_json(vty, json); } -int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) -{ - struct zebra_if *zif = ifp->info; - char buf[ETHER_ADDR_STRLEN]; - bool type_3_esi = false; - char esi_buf[ESI_STR_LEN]; - - if (zif->es_info.lid) { - vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid); - type_3_esi = true; - } - - if (!is_zero_mac(&zif->es_info.sysmac)) { - vty_out(vty, " evpn mh es-sys-mac %s\n", - prefix_mac2str(&zif->es_info.sysmac, - buf, sizeof(buf))); - type_3_esi = true; - } - - if (!type_3_esi - && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) - vty_out(vty, " evpn mh es-id %s\n", - esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf))); - - if (zif->es_info.df_pref) - vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref); - - if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) - vty_out(vty, " evpn mh uplink\n"); - - return 0; -} - -#include "zebra/zebra_evpn_mh_clippy.c" -/* CLI for setting an ES in bypass mode */ -DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd, - "[no] evpn mh bypass", - NO_STR "EVPN\n" EVPN_MH_VTY_STR "set bypass mode\n") +void zebra_evpn_mh_if_init(struct zebra_if *zif) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - - if (no) { - zebra_evpn_es_bypass_cfg_update(zif, false); - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% DF bypass cannot be associated with this interface type\n"); - return CMD_WARNING; - } - zebra_evpn_es_bypass_cfg_update(zif, true); - } - return CMD_SUCCESS; -} - -/* CLI for configuring DF preference part for an ES */ -DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd, - "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]", - NO_STR "EVPN\n" EVPN_MH_VTY_STR - "preference value used for DF election\n" - "pref\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - - if (no) { - zebra_evpn_es_df_pref_update(zif, 0); - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% DF preference cannot be associated with this interface type\n"); - return CMD_WARNING; - } - zebra_evpn_es_df_pref_update(zif, df_pref); - } - return CMD_SUCCESS; -} - -/* CLI for setting up sysmac part of ESI on an access port */ -DEFPY(zebra_evpn_es_sys_mac, - zebra_evpn_es_sys_mac_cmd, - "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]", - NO_STR - "EVPN\n" - EVPN_MH_VTY_STR - "Ethernet segment system MAC\n" - MAC_STR -) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - int ret = 0; - - zif = ifp->info; - - if (no) { - static struct ethaddr zero_mac; - - ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac); - if (ret == -1) { - vty_out(vty, "%% Failed to clear ES sysmac\n"); - return CMD_WARNING; - } - } else { - - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% ESI cannot be associated with this interface type\n"); - return CMD_WARNING; - } - - if (!mac || is_zero_mac(&mac->eth_addr)) { - vty_out(vty, "%% ES sysmac value is invalid\n"); - return CMD_WARNING; - } - - ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr); - if (ret == -1) { - vty_out(vty, - "%% ESI already exists on a different interface\n"); - return CMD_WARNING; - } - } - return CMD_SUCCESS; -} - -/* CLI for setting up local-ID part of ESI on an access port */ -DEFPY(zebra_evpn_es_id, - zebra_evpn_es_id_cmd, - "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]", - NO_STR - "EVPN\n" - EVPN_MH_VTY_STR - "Ethernet segment identifier\n" - "local discriminator\n" - "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n" -) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - int ret = 0; - esi_t esi; - - zif = ifp->info; - - if (no) { - if (zif->es_info.lid) - ret = zebra_evpn_es_lid_update(zif, 0); - else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) - ret = zebra_evpn_es_type0_esi_update(zif, zero_esi); - - if (ret == -1) { - vty_out(vty, - "%% Failed to clear ES local id or ESI name\n"); - return CMD_WARNING; - } - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% ESI cannot be associated with this interface type\n"); - return CMD_WARNING; - } - - if (esi_str) { - if (!str_to_esi(esi_str, &esi)) { - vty_out(vty, "%% Malformed ESI name\n"); - return CMD_WARNING; - } - ret = zebra_evpn_es_type0_esi_update(zif, &esi); - } else { - if (!es_lid) { - vty_out(vty, - "%% Specify ES local id or ESI name\n"); - return CMD_WARNING; - } - ret = zebra_evpn_es_lid_update(zif, es_lid); - } - - if (ret == -1) { - vty_out(vty, - "%% ESI already exists on a different interface\n"); - return CMD_WARNING; - } - } - return CMD_SUCCESS; -} - -/* CLI for tagging an interface as an uplink */ -DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink", - NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true); - - return CMD_SUCCESS; + zif->es_info.df_pref = EVPN_MH_DF_PREF_DEFAULT; } void zebra_evpn_mh_json(json_object *json) @@ -3853,7 +3638,7 @@ static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif, } } -static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set) +void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set) { bool old_protodown = zebra_evpn_mh_is_all_uplinks_down(); bool new_protodown; @@ -4076,15 +3861,6 @@ int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off) return 0; } -void zebra_evpn_interface_init(void) -{ - install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd); -} - void zebra_evpn_mh_init(void) { zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info)); diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 6dda30a57f..34ef79f155 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -17,8 +17,7 @@ #include "zebra_vxlan.h" #include "zebra_vxlan_private.h" #include "zebra_nhg.h" - -#define EVPN_MH_VTY_STR "Multihoming\n" +#include "zebra_nb.h" /* Ethernet Segment entry - * - Local and remote ESs are maintained in a global RB tree, @@ -155,7 +154,7 @@ struct zebra_evpn_es_vtep { /* Parameters for DF election */ uint8_t df_alg; - uint32_t df_pref; + uint16_t df_pref; /* XXX - maintain a backpointer to struct zebra_vtep */ }; @@ -336,14 +335,14 @@ extern bool zebra_evpn_es_mac_ref_entry(struct zebra_mac *mac, struct zebra_evpn_es *es); extern bool zebra_evpn_es_mac_ref(struct zebra_mac *mac, const esi_t *esi); extern struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi); -extern void zebra_evpn_interface_init(void); -extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp); extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj); extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj); extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json, struct zebra_if *zif); extern struct zebra_evpn_access_bd * zebra_evpn_acc_vl_find(vlanid_t vid, struct interface *br_if); +struct zebra_evpn_access_bd * +zebra_evpn_acc_vl_find_index(vlanid_t vid, ifindex_t bridge_ifindex); extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid, struct interface *br_if); extern void zebra_evpn_es_cleanup(void); @@ -380,4 +379,16 @@ extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS); extern struct zebra_evpn_es_evi * zebra_evpn_es_evi_find(struct zebra_evpn_es *es, struct zebra_evpn *zevpn); +void zebra_build_type3_esi(uint32_t lid, struct ethaddr *mac, esi_t *esi); + +void zebra_evpn_es_sys_mac_update(struct zebra_if *zif, struct ethaddr *sysmac); +void zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid); +void zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi); + +void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref); +void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass); +void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set); + +void zebra_evpn_mh_if_init(struct zebra_if *zif); + #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 74141e4f34..81705d4e85 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -6,6 +6,10 @@ #include <zebra.h> +#ifdef GNU_LINUX +#include <linux/neighbour.h> +#endif + #include "hash.h" #include "interface.h" #include "jhash.h" @@ -1038,11 +1042,10 @@ static inline void zebra_evpn_local_neigh_update_log( * from MAC. */ static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, - struct zebra_mac *old_zmac, + bool is_old_mac_dup, struct zebra_mac *new_zmac, struct zebra_neigh *nbr) { - bool is_old_mac_dup = false; bool is_new_mac_dup = false; if (!zebra_evpn_do_dup_addr_detect(zvrf)) @@ -1050,9 +1053,6 @@ static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, /* Check old or new MAC is detected as duplicate * mark this neigh as duplicate */ - if (old_zmac) - is_old_mac_dup = - CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE); if (new_zmac) is_new_mac_dup = CHECK_FLAG(new_zmac->flags, ZEBRA_MAC_DUPLICATE); @@ -1262,6 +1262,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, bool new_static = false; bool old_bgp_ready = false; bool new_bgp_ready; + bool is_old_mac_dup = false; /* Check if the MAC exists. */ zmac = zebra_evpn_mac_lookup(zevpn, macaddr); @@ -1408,6 +1409,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, old_bgp_ready = false; } if (old_zmac) { + is_old_mac_dup = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE); old_mac_seq = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_REMOTE) ? old_zmac->rem_seq @@ -1437,6 +1439,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, != 0) { old_zmac = n->mac; if (old_zmac) { + is_old_mac_dup = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE); old_mac_seq = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_REMOTE) @@ -1499,7 +1502,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, /* Check old and/or new MAC detected as duplicate mark * the neigh as duplicate */ - if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) { + if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, is_old_mac_dup, zmac, n)) { flog_warn( EC_ZEBRA_DUP_IP_INHERIT_DETECTED, "VNI %u: MAC %pEA IP %pIA detected as duplicate during local update, inherit duplicate from MAC", @@ -2034,6 +2037,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn, bool do_dad = false; bool is_dup_detect = false; bool is_router; + bool is_old_mac_dup = false; assert(mac); is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); @@ -2086,6 +2090,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn, old_mac = zebra_evpn_mac_lookup(zevpn, &n->emac); if (old_mac) { + is_old_mac_dup = CHECK_FLAG(old_mac->flags, ZEBRA_MAC_DUPLICATE); listnode_delete(old_mac->neigh_list, n); n->mac = NULL; zebra_evpn_deref_ip2mac(zevpn, old_mac); @@ -2128,7 +2133,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn, /* Check old or new MAC detected as duplicate, * inherit duplicate flag to this neigh. */ - if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_mac, mac, n)) { + if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, is_old_mac_dup, mac, n)) { flog_warn( EC_ZEBRA_DUP_IP_INHERIT_DETECTED, "VNI %u: MAC %pEA IP %pIA detected as duplicate during remote update, inherit duplicate from MAC", diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index e379a5868c..92dc591d40 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -8,6 +8,10 @@ #include <zebra.h> +#ifdef GNU_LINUX +#include <linux/rtnetlink.h> +#endif + #include "log.h" #include "libfrr.h" #include "stream.h" @@ -497,6 +501,11 @@ static inline void zfpm_connect_off(void) EVENT_OFF(zfpm_g->t_connect); } +static inline void zfpm_conn_down_off(void) +{ + EVENT_OFF(zfpm_g->t_conn_down); +} + /* * zfpm_conn_up_thread_cb * @@ -635,8 +644,6 @@ static void zfpm_conn_down_thread_cb(struct event *thread) while ((mac = TAILQ_FIRST(&zfpm_g->mac_q)) != NULL) zfpm_mac_info_del(mac); - zfpm_g->t_conn_down = NULL; - iter = &zfpm_g->t_conn_down_state.iter; while ((rnode = zfpm_rnodes_iter_next(iter))) { @@ -667,7 +674,6 @@ static void zfpm_conn_down_thread_cb(struct event *thread) zfpm_g->stats.t_conn_down_yields++; zfpm_rnodes_iter_pause(iter); - zfpm_g->t_conn_down = NULL; event_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, &zfpm_g->t_conn_down); return; @@ -712,7 +718,7 @@ static void zfpm_connection_down(const char *detail) */ assert(!zfpm_g->t_conn_down); zfpm_rnodes_iter_init(&zfpm_g->t_conn_down_state.iter); - zfpm_g->t_conn_down = NULL; + zfpm_conn_down_off(); event_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, &zfpm_g->t_conn_down); zfpm_g->stats.t_conn_down_starts++; @@ -2042,10 +2048,13 @@ static int zfpm_fini(void) zfpm_write_off(); zfpm_read_off(); zfpm_connect_off(); + zfpm_conn_down_off(); zfpm_stop_stats_timer(); hook_unregister(rib_update, zfpm_trigger_update); + hook_unregister(zebra_rmac_update, zfpm_trigger_rmac_update); + return 0; } diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index 94308a961b..ce5eb6fe15 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -22,6 +22,10 @@ */ #include <zebra.h> + +#ifdef GNU_LINUX +#include <linux/rtnetlink.h> +#endif #include "log.h" #include "vrf.h" diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 5adca14d71..95207ce75c 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -11,6 +11,9 @@ #ifdef HAVE_NETLINK +#include <linux/rtnetlink.h> +#include <linux/neighbour.h> + #include "log.h" #include "rib.h" #include "vty.h" @@ -252,20 +255,15 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, rib_dest_t *dest, struct route_entry *re) { struct nexthop *nexthop; - struct rib_table_info *table_info = - rib_table_info(rib_dest_table(dest)); - struct zebra_vrf *zvrf = table_info->zvrf; memset(ri, 0, sizeof(*ri)); ri->prefix = rib_dest_prefix(dest); ri->af = rib_dest_af(dest); - if (zvrf && zvrf->zns) - ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid; + ri->nlmsg_pid = pid; ri->nlmsg_type = cmd; - ri->rtm_table = table_info->table_id; ri->rtm_protocol = RTPROT_UNSPEC; /* @@ -280,6 +278,8 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, return 0; } + ri->rtm_table = re->table; + ri->rtm_protocol = netlink_proto_from_route_type(re->type); ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; @@ -290,6 +290,8 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { switch (nexthop->bh_type) { @@ -590,19 +592,19 @@ int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, RTM_DELNEIGH : RTM_NEWNEIGH; req->hdr.nlmsg_flags = NLM_F_REQUEST; if (req->hdr.nlmsg_type == RTM_NEWNEIGH) - req->hdr.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + SET_FLAG(req->hdr.nlmsg_flags, (NLM_F_CREATE | NLM_F_REPLACE)); /* Construct ndmsg */ req->ndm.ndm_family = AF_BRIDGE; req->ndm.ndm_ifindex = mac->vxlan_if; req->ndm.ndm_state = NUD_REACHABLE; - req->ndm.ndm_flags |= NTF_SELF | NTF_MASTER; + SET_FLAG(req->ndm.ndm_flags, (NTF_SELF | NTF_MASTER)); if (CHECK_FLAG(mac->zebra_flags, (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW))) - req->ndm.ndm_state |= NUD_NOARP; + SET_FLAG(req->ndm.ndm_state, NUD_NOARP); else - req->ndm.ndm_flags |= NTF_EXT_LEARNED; + SET_FLAG(req->ndm.ndm_flags, NTF_EXT_LEARNED); /* Add attributes */ nl_attr_put(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index cf2056b7ac..cee66cc055 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -80,13 +80,12 @@ void zebra_gr_stale_client_cleanup(struct list *client_list) /* Cancel the stale timer */ if (info->t_stale_removal != NULL) { EVENT_OFF(info->t_stale_removal); - info->t_stale_removal = NULL; info->do_delete = true; /* Process the stale routes */ event_execute( zrouter.master, zebra_gr_route_stale_delete_timer_expiry, - info, 0); + info, 0, NULL); } } } @@ -299,6 +298,16 @@ struct zebra_gr_afi_clean { * Functions to deal with capabilities */ +void zebra_gr_client_final_shutdown(struct zserv *client) +{ + struct client_gr_info *info; + + while (!TAILQ_EMPTY(&client->gr_info_queue)) { + info = TAILQ_FIRST(&client->gr_info_queue); + zebra_gr_client_info_delete(client, info); + } +} + /* * Function to decode and call appropriate functions * to handle client capabilities. @@ -328,7 +337,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) return; /* GR only for dynamic clients */ - if (client->proto <= ZEBRA_ROUTE_CONNECT) { + if (client->proto <= ZEBRA_ROUTE_LOCAL) { LOG_GR("%s: GR capabilities for client %s not supported", __func__, zebra_route_string(client->proto)); return; diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 2eea772f9f..0f591810b9 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -111,13 +111,13 @@ static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) { struct listnode *node; struct zebra_if *bond_mbr; - bool old_bypass = !!(bond_zif->flags & ZIF_FLAG_LACP_BYPASS); + bool old_bypass = !!CHECK_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); bool new_bypass = false; if (bond_zif->bond_info.mbr_zifs) { for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, bond_mbr)) { - if (bond_mbr->flags & ZIF_FLAG_LACP_BYPASS) { + if (CHECK_FLAG(bond_mbr->flags, ZIF_FLAG_LACP_BYPASS)) { new_bypass = true; break; } @@ -132,9 +132,9 @@ static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) bond_zif->ifp->name, new_bypass ? "on" : "off"); if (new_bypass) - bond_zif->flags |= ZIF_FLAG_LACP_BYPASS; + SET_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); else - bond_zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + UNSET_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); if (bond_zif->es_info.es) zebra_evpn_es_bypass_update(bond_zif->es_info.es, bond_zif->ifp, @@ -174,8 +174,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) } } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond mbr %s link to bond skipped", - zif->ifp->name); + zlog_debug("bond mbr %s link to bond skipped", zif->ifp->name); } } @@ -186,8 +185,7 @@ void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif) if (!bond_slave->bond_if) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond mbr %s unlink from bond skipped", - zif->ifp->name); + zlog_debug("bond mbr %s unlink from bond skipped", zif->ifp->name); return; } @@ -218,8 +216,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) if (add) { if (!bond->mbr_zifs) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond %s mbr list create", - ifp->name); + zlog_debug("bond %s mbr list create", ifp->name); bond->mbr_zifs = list_new(); } } else { @@ -244,8 +241,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) * map slaves (if any) to the bridge. */ void zebra_l2_bridge_add_update(struct interface *ifp, - struct zebra_l2info_bridge *bridge_info, - int add) + const struct zebra_l2info_bridge *bridge_info) { struct zebra_if *zif; struct zebra_l2_bridge_if *br; @@ -284,7 +280,7 @@ void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) * VLAN Id and this cannot change. */ void zebra_l2_vlanif_update(struct interface *ifp, - struct zebra_l2info_vlan *vlan_info) + const struct zebra_l2info_vlan *vlan_info) { struct zebra_if *zif; @@ -301,7 +297,7 @@ void zebra_l2_vlanif_update(struct interface *ifp, * clients about GRE information. */ void zebra_l2_greif_add_update(struct interface *ifp, - struct zebra_l2info_gre *gre_info, int add) + const struct zebra_l2info_gre *gre_info, int add) { struct zebra_if *zif; struct in_addr old_vtep_ip; @@ -328,7 +324,8 @@ void zebra_l2_greif_add_update(struct interface *ifp, * IP and VLAN mapping, but the latter is handled separately. */ void zebra_l2_vxlanif_add_update(struct interface *ifp, - struct zebra_l2info_vxlan *vxlan_info, int add) + const struct zebra_l2info_vxlan *vxlan_info, + int add) { struct zebra_if *zif; uint16_t chgflags = 0; @@ -347,7 +344,7 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp, ctx.old_vtep_ip = zif->l2info.vxl.vtep_ip; if (!IPV4_ADDR_SAME(&ctx.old_vtep_ip, &vxlan_info->vtep_ip)) { - chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE; + SET_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE); zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip; } @@ -355,7 +352,7 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp, ctx.old_vni = vxlan_info->vni_info.vni; if (!IPV4_ADDR_SAME(&zif->l2info.vxl.vni_info.vni.mcast_grp, &vxlan_info->vni_info.vni.mcast_grp)) { - chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE; + SET_FLAG(chgflags, ZEBRA_VXLIF_MCAST_GRP_CHANGE); zif->l2info.vxl.vni_info.vni.mcast_grp = vxlan_info->vni_info.vni.mcast_grp; } @@ -383,7 +380,8 @@ void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, assert(zif); /* This would be called only in non svd case */ - assert(IS_ZEBRA_VXLAN_IF_VNI(zif)); + if (!IS_ZEBRA_VXLAN_IF_VNI(zif)) + return; old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan; ; @@ -440,11 +438,11 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, if (zif->zif_type == ZEBRA_IF_VXLAN && chgflags != ZEBRA_BRIDGE_NO_ACTION) { - if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_BRIDGE_MASTER_MAC_CHANGE)) { ctx.chgflags = ZEBRA_VXLIF_MASTER_MAC_CHANGE; zebra_vxlan_if_update(ifp, &ctx); } - if (chgflags & ZEBRA_BRIDGE_MASTER_UP) { + if (CHECK_FLAG(chgflags, ZEBRA_BRIDGE_MASTER_UP)) { ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE; zebra_vxlan_if_update(ifp, &ctx); } @@ -493,16 +491,16 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, zif = ifp->info; assert(zif); - old_bypass = !!(zif->flags & ZIF_FLAG_LACP_BYPASS); + old_bypass = !!CHECK_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); if (old_bypass != new_bypass) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) zlog_debug("bond-mbr %s lacp bypass changed to %s", zif->ifp->name, new_bypass ? "on" : "off"); if (new_bypass) - zif->flags |= ZIF_FLAG_LACP_BYPASS; + SET_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); else - zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + UNSET_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); bond_mbr = &zif->bondslave_info; if (bond_mbr->bond_if) { diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 3be002656a..588917f4c0 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -80,6 +80,12 @@ struct zebra_vxlan_vni { vni_t vni; /* VNI */ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */ struct in_addr mcast_grp; + uint16_t flags; +}; + +struct zebra_vxlan_vni_array { + uint16_t count; + struct zebra_vxlan_vni vnis[0]; }; enum { @@ -159,18 +165,19 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave, struct zebra_ns *zns); extern void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); -extern void zebra_l2_bridge_add_update(struct interface *ifp, - struct zebra_l2info_bridge *bridge_info, - int add); +extern void +zebra_l2_bridge_add_update(struct interface *ifp, + const struct zebra_l2info_bridge *bridge_info); extern void zebra_l2_bridge_del(struct interface *ifp); extern void zebra_l2_vlanif_update(struct interface *ifp, - struct zebra_l2info_vlan *vlan_info); + const struct zebra_l2info_vlan *vlan_info); extern void zebra_l2_greif_add_update(struct interface *ifp, - struct zebra_l2info_gre *vxlan_info, + const struct zebra_l2info_gre *vxlan_info, int add); -extern void zebra_l2_vxlanif_add_update(struct interface *ifp, - struct zebra_l2info_vxlan *vxlan_info, - int add); +extern void +zebra_l2_vxlanif_add_update(struct interface *ifp, + const struct zebra_l2info_vxlan *vxlan_info, + int add); extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, vlanid_t access_vlan); extern void zebra_l2_greif_del(struct interface *ifp); diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 6713dbc967..8fd373cb19 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -338,8 +338,6 @@ static void zebra_mlag_post_data_from_main_thread(struct event *thread) } } - stream_free(s); - return; stream_failure: stream_free(s); if (zebra_s) @@ -629,6 +627,8 @@ void zebra_mlag_init(void) void zebra_mlag_terminate(void) { + stream_fifo_free(zrouter.mlag_info.mlag_fifo); + zrouter.mlag_info.mlag_fifo = NULL; } @@ -985,8 +985,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* No Batching */ stream_putw(s, MLAG_MSG_NO_BATCH); /* Actual Data */ - zebra_fill_protobuf_msg(s, msg->peerlink, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, msg->peerlink, IFNAMSIZ); stream_putl(s, msg->my_role); stream_putl(s, msg->peer_state); zebra_mlag_status_update__free_unpacked(msg, NULL); @@ -1034,9 +1033,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) zebra_fill_protobuf_msg(s, msg->intf_name, - INTERFACE_NAMSIZ); + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); zebra_mlag_mroute_add__free_unpacked(msg, NULL); } break; case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: { @@ -1061,9 +1060,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) zebra_fill_protobuf_msg(s, msg->intf_name, - INTERFACE_NAMSIZ); + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); zebra_mlag_mroute_del__free_unpacked(msg, NULL); } break; case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: { @@ -1085,8 +1084,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* Actual Data */ for (i = 0; i < Bulk_msg->n_mroute_add; i++) { - if (STREAM_SIZE(s) - < VRF_NAMSIZ + 22 + INTERFACE_NAMSIZ) { + if (STREAM_SIZE(s) < VRF_NAMSIZ + 22 + IFNAMSIZ) { zlog_warn( "We have received more messages than we can parse at this point in time: %zu", Bulk_msg->n_mroute_add); @@ -1105,11 +1103,11 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putc(s, msg->am_i_dual_active); stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) - zebra_fill_protobuf_msg( - s, msg->intf_name, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, + msg->intf_name, + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); } stream_putw_at(s, length_spot, i + 1); @@ -1136,8 +1134,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* Actual Data */ for (i = 0; i < Bulk_msg->n_mroute_del; i++) { - if (STREAM_SIZE(s) - < VRF_NAMSIZ + 16 + INTERFACE_NAMSIZ) { + if (STREAM_SIZE(s) < VRF_NAMSIZ + 16 + IFNAMSIZ) { zlog_warn( "We have received more messages than we can parse at this time"); break; @@ -1152,11 +1149,11 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->owner_id); stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) - zebra_fill_protobuf_msg( - s, msg->intf_name, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, + msg->intf_name, + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); } stream_putw_at(s, length_spot, i + 1); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index f1a99d89ce..4cc85d461f 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -97,8 +97,8 @@ static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list, static struct zebra_nhlfe * nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, const union g_addr *gate, - ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels, - bool is_backup); + ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels, + const mpls_label_t *labels, bool is_backup); static int nhlfe_del(struct zebra_nhlfe *nhlfe); static void nhlfe_free(struct zebra_nhlfe *nhlfe); static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe, @@ -212,11 +212,11 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, changed++; } else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type, - &nexthop->gate, nexthop->ifindex, - nexthop->nh_label->num_labels, - nexthop->nh_label->label, - false /*backup*/); + nhlfe = nhlfe_add( + lsp, lsp_type, nexthop->type, &nexthop->gate, + nexthop->ifindex, nexthop->vrf_id, + nexthop->nh_label->num_labels, + nexthop->nh_label->label, false /*backup*/); if (!nhlfe) return -1; @@ -329,7 +329,7 @@ static void fec_evaluate(struct zebra_vrf *zvrf) /* Skip configured FECs and those without a label index. */ - if (fec->flags & FEC_FLAG_CONFIGURED + if (CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) || fec->label_index == MPLS_INVALID_LABEL_INDEX) continue; @@ -616,8 +616,9 @@ static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe, for (match_nh = match->nhe->nhg.nexthop; match_nh; match_nh = match_nh->next) { - if (match->type == ZEBRA_ROUTE_CONNECT - || nexthop->ifindex == match_nh->ifindex) { + if ((match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL) || + nexthop->ifindex == match_nh->ifindex) { nexthop->ifindex = match_nh->ifindex; return 1; } @@ -659,9 +660,10 @@ static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe, /* Locate a valid connected route. */ RNODE_FOREACH_RE (rn, match) { - if ((match->type == ZEBRA_ROUTE_CONNECT) - && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) - && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) + if (((match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL)) && + !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) && + CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) break; } @@ -1029,8 +1031,6 @@ static void lsp_processq_del(struct work_queue *wq, void *data) return; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - assert(zvrf); - lsp_table = zvrf->lsp_table; if (!lsp_table) // unexpected return; @@ -1184,6 +1184,7 @@ static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size) break; case NEXTHOP_TYPE_IFINDEX: snprintf(buf, size, "Ifindex: %u", nexthop->ifindex); + break; case NEXTHOP_TYPE_BLACKHOLE: break; } @@ -1236,6 +1237,7 @@ static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe, /* * Locate NHLFE that matches with passed info. + * TODO: handle vrf_id if vrf backend is netns based */ static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list, enum lsp_types_t lsp_type, @@ -1261,7 +1263,8 @@ static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list, static struct zebra_nhlfe * nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, const union g_addr *gate, - ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels) + ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels, + const mpls_label_t *labels) { struct zebra_nhlfe *nhlfe; struct nexthop *nexthop; @@ -1278,7 +1281,7 @@ nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, nexthop_add_labels(nexthop, lsp_type, num_labels, labels); - nexthop->vrf_id = VRF_DEFAULT; + nexthop->vrf_id = vrf_id; nexthop->type = gtype; switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -1313,29 +1316,20 @@ nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, * Add primary or backup NHLFE. Base entry must have been created and * duplicate check done. */ -static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp, - enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, - const union g_addr *gate, - ifindex_t ifindex, uint8_t num_labels, - const mpls_label_t *labels, bool is_backup) +static struct zebra_nhlfe * +nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, + enum nexthop_types_t gtype, const union g_addr *gate, + ifindex_t ifindex, vrf_id_t vrf_id, uint8_t num_labels, + const mpls_label_t *labels, bool is_backup) { struct zebra_nhlfe *nhlfe; if (!lsp) return NULL; - /* Must have labels */ - if (num_labels == 0 || labels == NULL) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug("%s: invalid nexthop: no labels", __func__); - - return NULL; - } - /* Allocate new object */ - nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels, - labels); + nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, vrf_id, + num_labels, labels); if (!nhlfe) return NULL; @@ -1510,16 +1504,18 @@ static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe) json_nhlfe = json_object_new_object(); json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type)); - json_object_int_add(json_nhlfe, "outLabel", - nexthop->nh_label->label[0]); - - json_label_stack = json_object_new_array(); - json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack); - for (i = 0; i < nexthop->nh_label->num_labels; i++) - json_object_array_add( - json_label_stack, - json_object_new_int(nexthop->nh_label->label[i])); - + if (nexthop->nh_label) { + json_object_int_add(json_nhlfe, "outLabel", + nexthop->nh_label->label[0]); + json_label_stack = json_object_new_array(); + json_object_object_add(json_nhlfe, "outLabelStack", + json_label_stack); + for (i = 0; i < nexthop->nh_label->num_labels; i++) + json_object_array_add( + json_label_stack, + json_object_new_int( + nexthop->nh_label->label[i])); + } json_object_int_add(json_nhlfe, "distance", nhlfe->distance); if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) @@ -1530,6 +1526,10 @@ static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe) case NEXTHOP_TYPE_IPV4_IFINDEX: json_object_string_addf(json_nhlfe, "nexthop", "%pI4", &nexthop->gate.ipv4); + if (nexthop->ifindex) + json_object_string_add(json_nhlfe, "interface", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -1772,14 +1772,9 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) label = dplane_ctx_get_in_label(ctx); - switch (op) { - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: + if (op == DPLANE_OP_LSP_INSTALL || op == DPLANE_OP_LSP_UPDATE) { /* Look for zebra LSP object */ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (zvrf == NULL) - break; - lsp_table = zvrf->lsp_table; tmp_ile.in_label = label; @@ -1788,7 +1783,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE) zlog_debug("LSP ctx %p: in-label %u not found", ctx, dplane_ctx_get_in_label(ctx)); - break; + return; } /* TODO -- Confirm that this result is still 'current' */ @@ -1799,7 +1794,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, "LSP Install Failure: in-label %u", lsp->ile.in_label); - break; + return; } /* Update zebra object */ @@ -1820,73 +1815,16 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) ? ZEBRA_SR_POLICY_LABEL_CREATED : ZEBRA_SR_POLICY_LABEL_UPDATED; zebra_sr_policy_label_update(label, update_mode); - break; - - case DPLANE_OP_LSP_DELETE: + } else if (op == DPLANE_OP_LSP_DELETE) { if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) { flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, "LSP Deletion Failure: in-label %u", dplane_ctx_get_in_label(ctx)); - break; + return; } zebra_sr_policy_label_update(label, ZEBRA_SR_POLICY_LABEL_REMOVED); - break; - - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - break; - - } /* Switch */ + } } /* @@ -2093,9 +2031,6 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) /* Look for zebra LSP object */ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (zvrf == NULL) - return; - lsp_table = zvrf->lsp_table; tmp_ile.in_label = dplane_ctx_get_in_label(ctx); @@ -2242,8 +2177,8 @@ zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type, const mpls_label_t *out_labels) { /* Just a public pass-through to the internal implementation */ - return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels, - out_labels, false /*backup*/); + return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, VRF_DEFAULT, + num_labels, out_labels, false /*backup*/); } /* @@ -2257,8 +2192,8 @@ struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe( uint8_t num_labels, const mpls_label_t *out_labels) { /* Just a public pass-through to the internal implementation */ - return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels, - out_labels, true); + return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, VRF_DEFAULT, + num_labels, out_labels, true); } /* @@ -2270,12 +2205,10 @@ struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp, { struct zebra_nhlfe *nhlfe; - if (nh->nh_label == NULL || nh->nh_label->num_labels == 0) - return NULL; - - nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex, - nh->nh_label->num_labels, nh->nh_label->label, - false /*backup*/); + nhlfe = nhlfe_add( + lsp, lsp_type, nh->type, &nh->gate, nh->ifindex, nh->vrf_id, + nh->nh_label ? nh->nh_label->num_labels : 0, + nh->nh_label ? nh->nh_label->label : NULL, false /*backup*/); return nhlfe; } @@ -2290,12 +2223,10 @@ struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp, { struct zebra_nhlfe *nhlfe; - if (nh->nh_label == NULL || nh->nh_label->num_labels == 0) - return NULL; - - nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, - nh->ifindex, nh->nh_label->num_labels, - nh->nh_label->label, true); + nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex, + nh->vrf_id, + nh->nh_label ? nh->nh_label->num_labels : 0, + nh->nh_label ? nh->nh_label->label : NULL, true); return nhlfe; } @@ -2360,7 +2291,7 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, new_client = true; } else { /* Check if the FEC has been statically defined in the config */ - is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED; + is_configured_fec = CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED); /* Client may register same FEC with different label index. */ new_client = (listnode_lookup(fec->client_list, client) == NULL); @@ -2451,8 +2382,8 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, /* If not a configured entry, delete the FEC if no other clients. Before * deleting, see if any LSP needs to be uninstalled. */ - if (!(fec->flags & FEC_FLAG_CONFIGURED) - && list_isempty(fec->client_list)) { + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) && + list_isempty(fec->client_list)) { mpls_label_t old_label = fec->label; fec->label = MPLS_INVALID_LABEL; /* reset */ fec_change_update_lsp(zvrf, fec, old_label); @@ -2489,7 +2420,7 @@ static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client) if (fec_client == client) { listnode_delete(fec->client_list, fec_client); - if (!(fec->flags & FEC_FLAG_CONFIGURED) + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) && list_isempty(fec->client_list)) fec_del(fec); break; @@ -2545,7 +2476,7 @@ static int zebra_mpls_cleanup_zclient_labels(struct zserv *client) * hash.. */ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, - mpls_label_t label) + struct prefix *p, mpls_label_t label) { struct route_node *rn; struct zebra_fec *fec; @@ -2560,8 +2491,11 @@ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, if (!rn->info) continue; fec = rn->info; - if (fec->label == label) + if (fec->label == label) { + if (p && prefix_same(p, &rn->p)) + return NULL; return fec; + } } } @@ -2571,9 +2505,10 @@ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, /* * Inform if specified label is currently bound to a FEC or not. */ -int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label) +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t label) { - return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0); + return (zebra_mpls_fec_for_label(zvrf, p, label) ? 1 : 0); } /* @@ -2607,7 +2542,7 @@ int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p, if (IS_ZEBRA_DEBUG_MPLS) zlog_debug("Add fec %pFX label %u", p, in_label); } else { - fec->flags |= FEC_FLAG_CONFIGURED; + SET_FLAG(fec->flags, FEC_FLAG_CONFIGURED); if (fec->label == in_label) /* Duplicate config */ return 0; @@ -2656,7 +2591,7 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p) } old_label = fec->label; - fec->flags &= ~FEC_FLAG_CONFIGURED; + UNSET_FLAG(fec->flags, FEC_FLAG_CONFIGURED); fec->label = MPLS_INVALID_LABEL; /* If no client exists, just delete the FEC. */ @@ -2699,7 +2634,7 @@ int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf) char lstr[BUFSIZ]; fec = rn->info; - if (!(fec->flags & FEC_FLAG_CONFIGURED)) + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED)) continue; write = 1; @@ -3113,7 +3048,7 @@ static struct zebra_nhlfe * lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, uint8_t num_out_labels, const mpls_label_t *out_labels, enum nexthop_types_t gtype, const union g_addr *gate, - ifindex_t ifindex, bool is_backup) + ifindex_t ifindex, vrf_id_t vrf_id, bool is_backup) { struct zebra_nhlfe *nhlfe; char buf[MPLS_LABEL_STRLEN]; @@ -3133,13 +3068,18 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, struct nexthop *nh = nhlfe->nexthop; assert(nh); - assert(nh->nh_label); /* Clear deleted flag (in case it was set) */ UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); - if (nh->nh_label->num_labels == num_out_labels - && !memcmp(nh->nh_label->label, out_labels, - sizeof(mpls_label_t) * num_out_labels)) + + if (!nh->nh_label || num_out_labels == 0) + /* No change */ + return nhlfe; + + if (nh->nh_label && + nh->nh_label->num_labels == num_out_labels && + !memcmp(nh->nh_label->label, out_labels, + sizeof(mpls_label_t) * num_out_labels)) /* No change */ return nhlfe; @@ -3160,7 +3100,7 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, } /* Update out label(s), trigger processing. */ - if (nh->nh_label->num_labels == num_out_labels) + if (nh->nh_label && nh->nh_label->num_labels == num_out_labels) memcpy(nh->nh_label->label, out_labels, sizeof(mpls_label_t) * num_out_labels); else { @@ -3170,7 +3110,7 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, } } else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, + nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, vrf_id, num_out_labels, out_labels, is_backup); if (!nhlfe) return NULL; @@ -3179,8 +3119,11 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, char buf2[MPLS_LABEL_STRLEN]; nhlfe2str(nhlfe, buf, sizeof(buf)); - mpls_label2str(num_out_labels, out_labels, buf2, - sizeof(buf2), 0, 0); + if (num_out_labels) + mpls_label2str(num_out_labels, out_labels, buf2, + sizeof(buf2), 0, 0); + else + snprintf(buf2, sizeof(buf2), "-"); zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s", lsp->ile.in_label, type, backup_str, buf, @@ -3199,6 +3142,8 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type, /* * Install an LSP and forwarding entry; used primarily * from vrf zapi message processing. + * TODO: handle vrf_id parameter when mpls API extends to interface or SRTE + * changes */ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, uint8_t num_out_labels, @@ -3220,7 +3165,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype, - gate, ifindex, false /*backup*/); + gate, ifindex, VRF_DEFAULT, false /*backup*/); if (nhlfe == NULL) return -1; @@ -3239,8 +3184,8 @@ static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type, { struct zebra_nhlfe *nhlfe; - nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, - znh->type, &znh->gate, znh->ifindex, + nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, znh->type, + &znh->gate, znh->ifindex, znh->vrf_id, false /*backup*/); if (nhlfe == NULL) return -1; @@ -3277,9 +3222,9 @@ static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type, { struct zebra_nhlfe *nhlfe; - nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, - znh->labels, znh->type, &znh->gate, - znh->ifindex, true /*backup*/); + nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels, znh->type, + &znh->gate, znh->ifindex, znh->vrf_id, + true /*backup*/); if (nhlfe == NULL) { if (IS_ZEBRA_DEBUG_MPLS) zlog_debug("%s: unable to add backup nhlfe, label: %u", @@ -3610,8 +3555,8 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label, } else { /* Add static LSP entry to this nexthop */ - nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate, - ifindex, 1, &out_label, false /*backup*/); + nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate, ifindex, + VRF_DEFAULT, 1, &out_label, false /*backup*/); if (!nhlfe) return -1; @@ -3820,7 +3765,8 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, break; } - if (nexthop->type != NEXTHOP_TYPE_IFINDEX) + if (nexthop->type != NEXTHOP_TYPE_IFINDEX && + nexthop->nh_label) out_label_str = mpls_label2str( nexthop->nh_label->num_labels, &nexthop->nh_label->label[0], @@ -4094,10 +4040,12 @@ void zebra_mpls_turned_on(void) if (!mpls_enabled) { mpls_processq_init(); mpls_enabled = true; - } - hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); - hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels); + hook_register(zserv_client_close, + zebra_mpls_cleanup_fecs_for_client); + hook_register(zserv_client_close, + zebra_mpls_cleanup_zclient_labels); + } } /* @@ -4116,3 +4064,9 @@ void zebra_mpls_init(void) zebra_mpls_turned_on(); } + +void zebra_mpls_terminate(void) +{ + hook_unregister(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); + hook_unregister(zserv_client_close, zebra_mpls_cleanup_zclient_labels); +} diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 7feace56b5..dd6f960146 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -203,12 +203,13 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, * hash.. */ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, - mpls_label_t label); + struct prefix *p, mpls_label_t label); /* * Inform if specified label is currently bound to a FEC or not. */ -int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label); +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t label); /* * Add static FEC to label binding. If there are clients registered for this @@ -400,9 +401,10 @@ void zebra_mpls_init_tables(struct zebra_vrf *zvrf); void zebra_mpls_turned_on(void); /* - * Global MPLS initialization. + * Global MPLS initialization/termination. */ void zebra_mpls_init(void); +void zebra_mpls_terminate(void); /* * MPLS VTY. diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index 4bc676f392..f0f2c4b7a3 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -4,9 +4,13 @@ */ #include <zebra.h> +#include <sys/stat.h> #ifdef HAVE_NETLINK +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + #include "zebra/debug.h" #include "zebra/rt.h" #include "zebra/rt_netlink.h" diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index ee6f7045f5..85a53dd4c5 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -4,6 +4,8 @@ */ #include <zebra.h> +#include <sys/ioctl.h> +#include <sys/uio.h> #ifdef OPEN_BSD @@ -62,8 +64,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, sa_label_in.smpls_family = AF_MPLS; sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_flags |= RTF_MPLS | RTF_MPATH; - hdr.rtm_addrs |= RTA_DST; + SET_FLAG(hdr.rtm_flags, (RTF_MPLS | RTF_MPATH)); + SET_FLAG(hdr.rtm_addrs, RTA_DST); hdr.rtm_msglen += sizeof(sa_label_in); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_in; @@ -75,8 +77,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, nexthop.sin_family = AF_INET; nexthop.sin_addr = nhlfe->nexthop->gate.ipv4; /* adjust header */ - hdr.rtm_flags |= RTF_GATEWAY; - hdr.rtm_addrs |= RTA_GATEWAY; + SET_FLAG(hdr.rtm_flags, RTF_GATEWAY); + SET_FLAG(hdr.rtm_addrs, RTA_GATEWAY); hdr.rtm_msglen += sizeof(nexthop); /* adjust iovec */ iov[iovcnt].iov_base = &nexthop; @@ -91,8 +93,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_addrs |= RTA_SRC; - hdr.rtm_flags |= RTF_MPLS; + SET_FLAG(hdr.rtm_addrs, RTA_SRC); + SET_FLAG(hdr.rtm_flags, RTF_MPLS); hdr.rtm_msglen += sizeof(sa_label_out); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_out; @@ -157,8 +159,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, sa_label_in.smpls_family = AF_MPLS; sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_flags |= RTF_MPLS | RTF_MPATH; - hdr.rtm_addrs |= RTA_DST; + SET_FLAG(hdr.rtm_flags, (RTF_MPLS | RTF_MPATH)); + SET_FLAG(hdr.rtm_addrs, RTA_DST); hdr.rtm_msglen += sizeof(sa_label_in); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_in; @@ -182,8 +184,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, } /* adjust header */ - hdr.rtm_flags |= RTF_GATEWAY; - hdr.rtm_addrs |= RTA_GATEWAY; + SET_FLAG(hdr.rtm_flags, RTF_GATEWAY); + SET_FLAG(hdr.rtm_addrs, RTA_GATEWAY); hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); /* adjust iovec */ iov[iovcnt].iov_base = &nexthop; @@ -198,8 +200,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_addrs |= RTA_SRC; - hdr.rtm_flags |= RTF_MPLS; + SET_FLAG(hdr.rtm_addrs, RTA_SRC); + SET_FLAG(hdr.rtm_flags, RTF_MPLS); hdr.rtm_msglen += sizeof(sa_label_out); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_out; @@ -229,70 +231,18 @@ static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) const struct nexthop *nexthop = NULL; unsigned int nexthop_num = 0; int action; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_LSP_DELETE: + op = dplane_ctx_get_op(ctx); + + if (op == DPLANE_OP_LSP_DELETE) action = RTM_DELETE; - break; - case DPLANE_OP_LSP_INSTALL: + else if (op == DPLANE_OP_LSP_INSTALL) action = RTM_ADD; - break; - case DPLANE_OP_LSP_UPDATE: + else if (op == DPLANE_OP_LSP_UPDATE) action = RTM_CHANGE; - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: + else return -1; - } head = dplane_ctx_get_nhlfe_list(ctx); frr_each(nhlfe_list_const, head, nhlfe) { @@ -374,8 +324,8 @@ static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD) - imr.imr_flags |= IMR_FLAG_CONTROLWORD; + if (CHECK_FLAG(dplane_ctx_get_pw_flags(ctx), F_PSEUDOWIRE_CWORD)) + SET_FLAG(imr.imr_flags, IMR_FLAG_CONTROLWORD); /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); @@ -442,68 +392,14 @@ static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx) enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_PW_INSTALL: + op = dplane_ctx_get_op(ctx); + + if (op == DPLANE_OP_PW_INSTALL) result = kmpw_install(ctx); - break; - case DPLANE_OP_PW_UNINSTALL: + else if (op == DPLANE_OP_PW_UNINSTALL) result = kmpw_uninstall(ctx); - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - break; - } return result; } diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index 6b8859e0ca..8248d4a555 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -22,6 +22,7 @@ #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" +#include "zebra/label_manager.h" static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, const char *inlabel_str, const char *gate_str, @@ -42,10 +43,6 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, } zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) { - vty_out(vty, "%% Default VRF does not exist\n"); - return CMD_WARNING_CONFIG_FAILED; - } if (!inlabel_str) { vty_out(vty, "%% No Label Information\n"); @@ -186,10 +183,6 @@ static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix, int ret; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) { - vty_out(vty, "%% Default VRF does not exist\n"); - return CMD_WARNING_CONFIG_FAILED; - } memset(&p, 0, sizeof(p)); ret = str2prefix(prefix, &p); @@ -217,7 +210,7 @@ static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix, vty_out(vty, "%% Invalid label\n"); return CMD_WARNING_CONFIG_FAILED; } - if (zebra_mpls_label_already_bound(zvrf, label)) { + if (zebra_mpls_label_already_bound(zvrf, &p, label)) { vty_out(vty, "%% Label already bound to a FEC\n"); return CMD_WARNING_CONFIG_FAILED; @@ -274,12 +267,12 @@ static int zebra_mpls_config(struct vty *vty) struct zebra_vrf *zvrf; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return 0; write += zebra_mpls_write_lsp_config(vty, zvrf); write += zebra_mpls_write_fec_config(vty, zvrf); write += zebra_mpls_write_label_block_config(vty, zvrf); + write += lm_write_label_block_config_call(vty, zvrf); + return write; } @@ -297,8 +290,6 @@ DEFUN (show_mpls_fec, int ret; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return 0; if (argc == 3) zebra_mpls_print_fec_table(vty, zvrf); @@ -373,10 +364,6 @@ static int zebra_mpls_global_block(struct vty *vty, int add_cmd, struct zebra_vrf *zvrf; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) { - vty_out(vty, "%% Default VRF does not exist\n"); - return CMD_WARNING_CONFIG_FAILED; - } if (add_cmd) { if (!start_label_str || !end_label_str) { diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index d94547cffc..eee9323082 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -10,9 +10,20 @@ #include "libfrr.h" #include "zebra_nb.h" +const char *features[] = { +#if HAVE_BFDD == 0 + "ptm-bfd", +#endif +#if defined(HAVE_RTADV) + "ipv6-router-advertisements", +#endif + NULL +}; + /* clang-format off */ const struct frr_yang_module_info frr_zebra_info = { .name = "frr-zebra", + .features = features, .nodes = { { .xpath = "/frr-zebra:zebra/mcast-rpf-lookup", @@ -79,6 +90,20 @@ const struct frr_yang_module_info frr_zebra_info = { .modify = zebra_dplane_queue_limit_modify, } }, +#if HAVE_BFDD == 0 + { + .xpath = "/frr-zebra:zebra/ptm-enable", + .cbs = { + .modify = zebra_ptm_enable_modify, + } + }, +#endif + { + .xpath = "/frr-zebra:zebra/route-map-delay", + .cbs = { + .modify = zebra_route_map_delay_modify, + } + }, { .xpath = "/frr-zebra:zebra/debugs/debug-events", .cbs = { @@ -290,24 +315,38 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs", .cbs = { - .create = lib_interface_zebra_ip_addrs_create, - .destroy = lib_interface_zebra_ip_addrs_destroy, + .create = lib_interface_zebra_ipv4_addrs_create, + .destroy = lib_interface_zebra_ipv4_addrs_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs/label", .cbs = { - .modify = lib_interface_zebra_ip_addrs_label_modify, - .destroy = lib_interface_zebra_ip_addrs_label_destroy, + .modify = lib_interface_zebra_ipv4_addrs_label_modify, + .destroy = lib_interface_zebra_ipv4_addrs_label_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs", .cbs = { - .modify = lib_interface_zebra_ip_addrs_ip4_peer_modify, - .destroy = lib_interface_zebra_ip_addrs_ip4_peer_destroy, + .create = lib_interface_zebra_ipv4_p2p_addrs_create, + .destroy = lib_interface_zebra_ipv4_p2p_addrs_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs/label", + .cbs = { + .modify = lib_interface_zebra_ipv4_p2p_addrs_label_modify, + .destroy = lib_interface_zebra_ipv4_p2p_addrs_label_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs", + .cbs = { + .create = lib_interface_zebra_ipv6_addrs_create, + .destroy = lib_interface_zebra_ipv6_addrs_destroy, } }, { @@ -321,14 +360,13 @@ const struct frr_yang_module_info frr_zebra_info = { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect", .cbs = { .modify = lib_interface_zebra_link_detect_modify, - .destroy = lib_interface_zebra_link_detect_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/shutdown", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/enabled", .cbs = { - .modify = lib_interface_zebra_shutdown_modify, - .destroy = lib_interface_zebra_shutdown_destroy, + .modify = lib_interface_zebra_enabled_modify, + .destroy = lib_interface_zebra_enabled_destroy, } }, { @@ -339,10 +377,73 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/mpls", .cbs = { - .modify = lib_interface_zebra_bandwidth_modify, - .destroy = lib_interface_zebra_bandwidth_destroy, + .modify = lib_interface_zebra_mpls_modify, + .destroy = lib_interface_zebra_mpls_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params", + .cbs = { + .create = lib_interface_zebra_link_params_create, + .destroy = lib_interface_zebra_link_params_destroy, + .apply_finish = lib_interface_zebra_link_params_apply_finish, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/metric", + .cbs = { + .modify = lib_interface_zebra_link_params_metric_modify, + .destroy = lib_interface_zebra_link_params_metric_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_max_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_max_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_max_reservable_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_max_reservable_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth", + .cbs = { + .create = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create, + .destroy = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth/unreserved-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_residual_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_residual_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_available_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_available_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_utilized_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_utilized_bandwidth_destroy, } }, { @@ -350,13 +451,13 @@ const struct frr_yang_module_info frr_zebra_info = { .cbs = { .modify = lib_interface_zebra_legacy_admin_group_modify, .destroy = lib_interface_zebra_legacy_admin_group_destroy, - .cli_show = cli_show_legacy_admin_group, }, }, { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", .cbs = { - .cli_show = cli_show_affinity, + .create = lib_interface_zebra_affinities_create, + .destroy = lib_interface_zebra_affinities_destroy, }, }, { @@ -370,10 +471,290 @@ const struct frr_yang_module_info frr_zebra_info = { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode", .cbs = { .modify = lib_interface_zebra_affinity_mode_modify, - .cli_show = cli_show_affinity_mode, }, }, { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor", + .cbs = { + .create = lib_interface_zebra_link_params_neighbor_create, + .destroy = lib_interface_zebra_link_params_neighbor_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/remote-as", + .cbs = { + .modify = lib_interface_zebra_link_params_neighbor_remote_as_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/ipv4-remote-id", + .cbs = { + .modify = lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay", + .cbs = { + .modify = lib_interface_zebra_link_params_delay_modify, + .destroy = lib_interface_zebra_link_params_delay_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay", + .cbs = { + .create = lib_interface_zebra_link_params_min_max_delay_create, + .destroy = lib_interface_zebra_link_params_min_max_delay_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-min", + .cbs = { + .modify = lib_interface_zebra_link_params_min_max_delay_delay_min_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-max", + .cbs = { + .modify = lib_interface_zebra_link_params_min_max_delay_delay_max_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation", + .cbs = { + .modify = lib_interface_zebra_link_params_delay_variation_modify, + .destroy = lib_interface_zebra_link_params_delay_variation_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss", + .cbs = { + .modify = lib_interface_zebra_link_params_packet_loss_modify, + .destroy = lib_interface_zebra_link_params_packet_loss_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_0_create, + .destroy = lib_interface_zebra_evpn_mh_type_0_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_0_esi_modify, + .destroy = lib_interface_zebra_evpn_mh_type_0_esi_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_3_create, + .destroy = lib_interface_zebra_evpn_mh_type_3_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_3_system_mac_modify, + .destroy = lib_interface_zebra_evpn_mh_type_3_system_mac_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify, + .destroy = lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_df_preference_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_bypass_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_uplink_modify, + } + }, +#if defined(HAVE_RTADV) + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain/lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/valid-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/on-link-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/preferred-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/autonomous-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/router-address-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address/lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy, + } + }, +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ptm-enable", + .cbs = { + .modify = lib_interface_zebra_ptm_enable_modify, + } + }, +#endif + { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/up-count", .cbs = { .get_elem = lib_interface_zebra_state_up_count_get_elem, @@ -422,11 +803,93 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/bond", + .cbs = { + .get_elem = lib_interface_zebra_state_bond_get_elem, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/router-id", + .cbs = { + .modify = lib_vrf_zebra_router_id_modify, + .destroy = lib_vrf_zebra_router_id_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id", + .cbs = { + .modify = lib_vrf_zebra_ipv6_router_id_modify, + .destroy = lib_vrf_zebra_ipv6_router_id_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol", + .cbs = { + .create = lib_vrf_zebra_filter_protocol_create, + .destroy = lib_vrf_zebra_filter_protocol_destroy, + .apply_finish = lib_vrf_zebra_filter_protocol_apply_finish, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol/route-map", + .cbs = { + .modify = lib_vrf_zebra_filter_protocol_route_map_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht", + .cbs = { + .create = lib_vrf_zebra_filter_nht_create, + .destroy = lib_vrf_zebra_filter_nht_destroy, + .apply_finish = lib_vrf_zebra_filter_nht_apply_finish, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht/route-map", + .cbs = { + .modify = lib_vrf_zebra_filter_nht_route_map_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default", + .cbs = { + .modify = lib_vrf_zebra_resolve_via_default_modify, + .destroy = lib_vrf_zebra_resolve_via_default_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default", + .cbs = { + .modify = lib_vrf_zebra_ipv6_resolve_via_default_modify, + .destroy = lib_vrf_zebra_ipv6_resolve_via_default_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range", + .cbs = { + .create = lib_vrf_zebra_netns_table_range_create, + .destroy = lib_vrf_zebra_netns_table_range_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/start", + .cbs = { + .modify = lib_vrf_zebra_netns_table_range_start_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/end", + .cbs = { + .modify = lib_vrf_zebra_netns_table_range_end_modify, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib", .cbs = { .get_next = lib_vrf_zebra_ribs_rib_get_next, .get_keys = lib_vrf_zebra_ribs_rib_get_keys, .lookup_entry = lib_vrf_zebra_ribs_rib_lookup_entry, + .lookup_next = lib_vrf_zebra_ribs_rib_lookup_next, } }, { @@ -447,6 +910,7 @@ const struct frr_yang_module_info frr_zebra_info = { .get_next = lib_vrf_zebra_ribs_rib_route_get_next, .get_keys = lib_vrf_zebra_ribs_rib_route_get_keys, .lookup_entry = lib_vrf_zebra_ribs_rib_route_lookup_entry, + .lookup_next = lib_vrf_zebra_ribs_rib_route_lookup_next, } }, { @@ -591,6 +1055,28 @@ const struct frr_yang_module_info frr_zebra_info = { .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem, } }, + + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry", + .cbs = { + .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next, + .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys, + .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/id", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/seg", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/mpls-label-stack/entry", .cbs = { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index fa576ec3f4..b40ed68229 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -44,6 +44,10 @@ int zebra_import_kernel_table_route_map_destroy( int zebra_allow_external_route_update_create(struct nb_cb_create_args *args); int zebra_allow_external_route_update_destroy(struct nb_cb_destroy_args *args); int zebra_dplane_queue_limit_modify(struct nb_cb_modify_args *args); +#if HAVE_BFDD == 0 +int zebra_ptm_enable_modify(struct nb_cb_modify_args *args); +#endif +int zebra_route_map_delay_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_events_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_events_destroy(struct nb_cb_destroy_args *args); int zebra_debugs_debug_zapi_send_modify(struct nb_cb_modify_args *args); @@ -80,29 +84,191 @@ int zebra_debugs_debug_dplane_detail_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_dplane_detail_destroy(struct nb_cb_destroy_args *args); int zebra_debugs_debug_mlag_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_mlag_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args); -int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_label_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_ip4_peer_modify( +int lib_interface_zebra_ipv4_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv4_addrs_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_addrs_label_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv4_addrs_label_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_label_modify( struct nb_cb_modify_args *args); -int lib_interface_zebra_ip_addrs_ip4_peer_destroy( +int lib_interface_zebra_ipv4_p2p_addrs_label_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_addrs_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_multicast_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_multicast_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_link_detect_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_enabled_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_enabled_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_legacy_admin_group_modify( +int lib_interface_zebra_mpls_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_mpls_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_create(struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_destroy(struct nb_cb_destroy_args *args); +void lib_interface_zebra_link_params_apply_finish( + struct nb_cb_apply_finish_args *args); +int lib_interface_zebra_link_params_metric_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_metric_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_max_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_max_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_max_reservable_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_max_reservable_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create( + struct nb_cb_create_args *args); +void lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify( + struct nb_cb_modify_args *args); +void lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +int lib_interface_zebra_link_params_residual_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_residual_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_available_bandwidth_modify( struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_available_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_utilized_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_utilized_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_legacy_admin_group_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_legacy_admin_group_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args); +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args); int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_neighbor_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_neighbor_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_neighbor_remote_as_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_min_max_delay_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_min_max_delay_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_min_max_delay_delay_min_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_min_max_delay_delay_max_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_variation_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_variation_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_packet_loss_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_packet_loss_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_0_esi_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_df_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_bypass_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_uplink_modify(struct nb_cb_modify_args *args); +#if defined(HAVE_RTADV) +int lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy( + struct nb_cb_destroy_args *args); +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 +int lib_interface_zebra_ptm_enable_modify(struct nb_cb_modify_args *args); +#endif struct yang_data * lib_interface_zebra_state_up_count_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * @@ -119,10 +285,36 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem( struct nb_cb_get_elem_args *args); struct yang_data *lib_interface_zebra_state_mcast_group_get_elem( struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args); +int lib_vrf_zebra_router_id_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_router_id_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_ipv6_router_id_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_ipv6_router_id_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_filter_protocol_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_filter_protocol_destroy(struct nb_cb_destroy_args *args); +void lib_vrf_zebra_filter_protocol_apply_finish( + struct nb_cb_apply_finish_args *args); +int lib_vrf_zebra_filter_protocol_route_map_modify( + struct nb_cb_modify_args *args); +int lib_vrf_zebra_filter_nht_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_filter_nht_destroy(struct nb_cb_destroy_args *args); +void lib_vrf_zebra_filter_nht_apply_finish(struct nb_cb_apply_finish_args *args); +int lib_vrf_zebra_filter_nht_route_map_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_resolve_via_default_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_resolve_via_default_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_ipv6_resolve_via_default_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_ipv6_resolve_via_default_destroy( + struct nb_cb_destroy_args *args); +int lib_vrf_zebra_netns_table_range_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_netns_table_range_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_netns_table_range_start_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args); const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args); const void * lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args); +const void * +lib_vrf_zebra_ribs_rib_lookup_next(struct nb_cb_lookup_entry_args *args); struct yang_data * lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * @@ -132,6 +324,8 @@ lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args); const void * lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args); +const void * +lib_vrf_zebra_ribs_rib_route_lookup_next(struct nb_cb_lookup_entry_args *args); struct yang_data * lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args); struct yang_data *lib_vrf_zebra_ribs_rib_route_protocol_get_elem( @@ -238,6 +432,20 @@ struct yang_data * lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem( struct nb_cb_get_elem_args *args); const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next( + struct nb_cb_get_next_args *args); +int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys( + struct nb_cb_get_keys_args *args); +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry( + struct nb_cb_lookup_entry_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem( + struct nb_cb_get_elem_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem( + struct nb_cb_get_elem_args *args); +const void * lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_mpls_label_stack_entry_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_mpls_label_stack_entry_get_keys( diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index 336669a49b..04eac63d3e 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -23,6 +23,12 @@ #include "zebra/debug.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_evpn_mh.h" +#include "zebra/zebra_ptm.h" +#include "zebra/router-id.h" +#include "zebra/zebra_routemap.h" +#include "zebra/zebra_rnh.h" +#include "zebra/table_manager.h" /* * XPath: /frr-zebra:zebra/mcast-rpf-lookup @@ -264,6 +270,43 @@ int zebra_dplane_queue_limit_modify(struct nb_cb_modify_args *args) return NB_OK; } +#if HAVE_BFDD == 0 +/* + * XPath: /frr-zebra:zebra/ptm-enable + */ +int zebra_ptm_enable_modify(struct nb_cb_modify_args *args) +{ + bool ptm; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ptm = yang_dnode_get_bool(args->dnode, NULL); + + if (ptm) + zebra_global_ptm_enable(); + else + zebra_global_ptm_disable(); + + return NB_OK; +} +#endif + +/* + * XPath: /frr-zebra:zebra/route-map-delay + */ +int zebra_route_map_delay_modify(struct nb_cb_modify_args *args) +{ + uint32_t delay = yang_dnode_get_uint32(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + zebra_route_map_set_delay_timer(delay); + + return NB_OK; +} + /* * XPath: /frr-zebra:zebra/debugs/debug-events */ @@ -823,28 +866,26 @@ int zebra_debugs_debug_mlag_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs */ -int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) +int lib_interface_zebra_ipv4_addrs_create(struct nb_cb_create_args *args) { struct interface *ifp; - struct prefix prefix; + struct prefix p; + const char *label = NULL; + + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); - // addr_family = yang_dnode_get_enum(dnode, "./address-family"); - yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); - apply_mask(&prefix); + if (yang_dnode_exists(args->dnode, "label")) + label = yang_dnode_get_string(args->dnode, "label"); switch (args->event) { case NB_EV_VALIDATE: - if (prefix.family == AF_INET - && ipv4_martian(&prefix.u.prefix4)) { + if (ipv4_martian(&p.u.prefix4)) { snprintfrr(args->errmsg, args->errmsg_len, - "invalid address %pFX", &prefix); - return NB_ERR_VALIDATION; - } else if (prefix.family == AF_INET6 - && ipv6_martian(&prefix.u.prefix6)) { - snprintfrr(args->errmsg, args->errmsg_len, - "invalid address %pFX", &prefix); + "invalid address %pFX", &p); return NB_ERR_VALIDATION; } break; @@ -853,65 +894,105 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - if (prefix.family == AF_INET) - if_ip_address_install(ifp, &prefix, NULL, NULL); - else if (prefix.family == AF_INET6) - if_ipv6_address_install(ifp, &prefix, NULL); + if_ip_address_install(ifp, &p, label, NULL); + /* set something for checking on label modify */ + nb_running_set_entry(args->dnode, (void *)0x1); break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv4_addrs_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; - struct prefix prefix; - struct connected *ifc; + struct prefix p; - yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); - apply_mask(&prefix); + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); switch (args->event) { case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, false); - if (!ifp) - return NB_OK; - - if (prefix.family == AF_INET) { - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, &prefix, NULL); - if (!ifc) { - snprintf(args->errmsg, args->errmsg_len, - "interface %s Can't find address\n", - ifp->name); - return NB_ERR_VALIDATION; - } - } else if (prefix.family == AF_INET6) { - /* Check current interface address. */ - ifc = connected_check(ifp, &prefix); - if (!ifc) { - snprintf(args->errmsg, args->errmsg_len, - "interface can't find address %s", - ifp->name); - return NB_ERR_VALIDATION; - } - } else - return NB_ERR_VALIDATION; + if_ip_address_uninstall(ifp, &p, NULL); + break; + } + + return NB_OK; +} - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs/label + */ +int lib_interface_zebra_ipv4_addrs_label_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + if (nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, + false)) { snprintf(args->errmsg, args->errmsg_len, - "interface %s not configured", ifp->name); + "Changing label is not allowed"); return NB_ERR_VALIDATION; } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_zebra_ipv4_addrs_label_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + snprintf(args->errmsg, args->errmsg_len, + "Removing label is not allowed"); + return NB_ERR_VALIDATION; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } - /* This is not real address or interface is not active. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); - connected_free(&ifc); + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs + */ +int lib_interface_zebra_ipv4_p2p_addrs_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct prefix p, pp; + const char *label = NULL; + + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = 32; + + pp.family = AF_INET; + yang_dnode_get_ipv4(&pp.u.prefix4, args->dnode, "peer-ip"); + pp.prefixlen = yang_dnode_get_uint8(args->dnode, "peer-prefix-length"); + + if (yang_dnode_exists(args->dnode, "label")) + label = yang_dnode_get_string(args->dnode, "label"); + + switch (args->event) { + case NB_EV_VALIDATE: + if (ipv4_martian(&p.u.prefix4)) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid address %pFX", &p); return NB_ERR_VALIDATION; } break; @@ -920,7 +1001,39 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - if_ip_address_uinstall(ifp, &prefix); + if_ip_address_install(ifp, &p, label, &pp); + + /* set something for checking on label modify */ + nb_running_set_entry(args->dnode, (void *)0x1); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_ipv4_p2p_addrs_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct prefix p, pp; + + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = 32; + + pp.family = AF_INET; + yang_dnode_get_ipv4(&pp.u.prefix4, args->dnode, "peer-ip"); + pp.prefixlen = yang_dnode_get_uint8(args->dnode, "peer-prefix-length"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nb_running_unset_entry(args->dnode); + + ifp = nb_running_get_entry(args->dnode, NULL, false); + if_ip_address_uninstall(ifp, &p, &pp); break; } @@ -928,30 +1041,39 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs/label */ -int lib_interface_zebra_ip_addrs_label_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_ipv4_p2p_addrs_label_modify(struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: + if (nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, + false)) { + snprintf(args->errmsg, args->errmsg_len, + "Changing label is not allowed"); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv4_p2p_addrs_label_destroy( + struct nb_cb_destroy_args *args) { switch (args->event) { case NB_EV_VALIDATE: + snprintf(args->errmsg, args->errmsg_len, + "Removing label is not allowed"); + return NB_ERR_VALIDATION; case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } @@ -959,31 +1081,54 @@ int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs */ -int lib_interface_zebra_ip_addrs_ip4_peer_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_ipv6_addrs_create(struct nb_cb_create_args *args) { + struct interface *ifp; + struct prefix p; + + p.family = AF_INET6; + yang_dnode_get_ipv6(&p.u.prefix6, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); + switch (args->event) { case NB_EV_VALIDATE: + if (ipv6_martian(&p.u.prefix6)) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid address %pFX", &p); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: - /* TODO: implement me. */ + ifp = nb_running_get_entry(args->dnode, NULL, true); + if_ipv6_address_install(ifp, &p); break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_ip4_peer_destroy( - struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv6_addrs_destroy(struct nb_cb_destroy_args *args) { + struct interface *ifp; + struct prefix p; + + p.family = AF_INET6; + yang_dnode_get_ipv6(&p.u.prefix6, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); + switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: - /* TODO: implement me. */ + ifp = nb_running_get_entry(args->dnode, NULL, false); + if_ipv6_address_uninstall(ifp, &p); break; } @@ -999,10 +1144,14 @@ int lib_interface_zebra_multicast_modify(struct nb_cb_modify_args *args) return NB_OK; struct interface *ifp; + bool multicast = yang_dnode_get_bool(args->dnode, NULL); ifp = nb_running_get_entry(args->dnode, NULL, true); - if_multicast_set(ifp); + if (multicast) + if_multicast_set(ifp); + else + if_multicast_unset(ifp); return NB_OK; } @@ -1013,10 +1162,12 @@ int lib_interface_zebra_multicast_destroy(struct nb_cb_destroy_args *args) return NB_OK; struct interface *ifp; + struct zebra_if *zif; ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; - if_multicast_unset(ifp); + zif->multicast = IF_ZEBRA_DATA_UNSPEC; return NB_OK; } @@ -1033,56 +1184,91 @@ int lib_interface_zebra_link_detect_modify(struct nb_cb_modify_args *args) bool link_detect; ifp = nb_running_get_entry(args->dnode, NULL, true); - link_detect = yang_dnode_get_bool(args->dnode, "./link-detect"); + link_detect = yang_dnode_get_bool(args->dnode, NULL); if_linkdetect(ifp, link_detect); return NB_OK; } -int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args) +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/enabled + */ +int lib_interface_zebra_enabled_modify(struct nb_cb_modify_args *args) { if (args->event != NB_EV_APPLY) return NB_OK; struct interface *ifp; - bool link_detect; + bool enabled; ifp = nb_running_get_entry(args->dnode, NULL, true); - link_detect = yang_dnode_get_bool(args->dnode, "./link-detect"); + enabled = yang_dnode_get_bool(args->dnode, NULL); - if_linkdetect(ifp, link_detect); + if (enabled) + if_no_shutdown(ifp); + else + if_shutdown(ifp); return NB_OK; } -/* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/shutdown - */ -int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_enabled_destroy(struct nb_cb_destroy_args *args) { if (args->event != NB_EV_APPLY) return NB_OK; struct interface *ifp; + struct zebra_if *zif; ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; - if_shutdown(ifp); + zif->shutdown = IF_ZEBRA_DATA_UNSPEC; return NB_OK; } -int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args) +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/mpls + */ +int lib_interface_zebra_mpls_modify(struct nb_cb_modify_args *args) { + struct interface *ifp; + bool mpls; + struct zebra_if *zif; + if (args->event != NB_EV_APPLY) return NB_OK; + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + mpls = yang_dnode_get_bool(args->dnode, NULL); + + if (mpls) + zif->mpls_config = IF_ZEBRA_DATA_ON; + else + zif->mpls_config = IF_ZEBRA_DATA_OFF; + + dplane_intf_mpls_modify_state(ifp, mpls); + + return NB_OK; +} + +int lib_interface_zebra_mpls_destroy(struct nb_cb_destroy_args *args) +{ struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->mpls_config = IF_ZEBRA_DATA_UNSPEC; - if_no_shutdown(ifp); + /* keep the state as it is */ return NB_OK; } @@ -1099,7 +1285,7 @@ int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args) uint32_t bandwidth; ifp = nb_running_get_entry(args->dnode, NULL, true); - bandwidth = yang_dnode_get_uint32(args->dnode, "./bandwidth"); + bandwidth = yang_dnode_get_uint32(args->dnode, NULL); ifp->bandwidth = bandwidth; @@ -1129,58 +1315,447 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params */ -int lib_interface_zebra_legacy_admin_group_modify( +int lib_interface_zebra_link_params_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + if_link_params_enable(ifp); + + /* + * The interface is updated in the apply_finish callback after all + * parameters are set in the corresponding callbacks. + */ + + return NB_OK; +} + +int lib_interface_zebra_link_params_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + if_link_params_free(ifp); + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); + + return NB_OK; +} + +void lib_interface_zebra_link_params_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct interface *ifp; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/metric + */ +int lib_interface_zebra_link_params_metric_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t metric; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + metric = yang_dnode_get_uint32(args->dnode, NULL); + + link_param_cmd_set_uint32(ifp, &iflp->te_metric, LP_TE_METRIC, metric); + + return NB_OK; +} + +int lib_interface_zebra_link_params_metric_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + link_param_cmd_unset(ifp, LP_TE_METRIC); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth + */ +int lib_interface_zebra_link_params_max_bandwidth_modify( struct nb_cb_modify_args *args) { struct interface *ifp; struct if_link_params *iflp; - uint32_t admin_group_value; + float max_bw, res_bw, ava_bw, use_bw; + + max_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (yang_dnode_exists(args->dnode, "../residual-bandwidth")) { + res_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../residual-bandwidth"); + if (max_bw < res_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than residual-bandwidth %f", + max_bw, res_bw); + return NB_ERR_VALIDATION; + } + } + if (yang_dnode_exists(args->dnode, "../available-bandwidth")) { + ava_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../available-bandwidth"); + if (max_bw < ava_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than available-bandwidth %f", + max_bw, ava_bw); + return NB_ERR_VALIDATION; + } + } + if (yang_dnode_exists(args->dnode, "../utilized-bandwidth")) { + use_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../utilized-bandwidth"); + if (max_bw < use_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than utilized-bandwidth %f", + max_bw, use_bw); + return NB_ERR_VALIDATION; + } + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->max_bw, LP_MAX_BW, max_bw); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_link_params_max_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing max-bandwidth is not allowed"); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth + */ +int lib_interface_zebra_link_params_max_reservable_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_rsv_bw; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + max_rsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); ifp = nb_running_get_entry(args->dnode, NULL, true); - admin_group_value = yang_dnode_get_uint32(args->dnode, "."); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, + max_rsv_bw); + + return NB_OK; +} + +int lib_interface_zebra_link_params_max_reservable_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing max-reservable-bandwidth is not allowed"); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth + */ +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint8_t priority; + float unrsv_bw; - if (!ifp) - return NB_ERR_RESOURCE; + if (args->event != NB_EV_APPLY) + return NB_OK; + + priority = yang_dnode_get_uint8(args->dnode, "priority"); + unrsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "unreserved-bandwidth"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, + unrsv_bw); + + return NB_OK; +} + +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing unreserved-bandwidth is not allowed"); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth/unreserved-bandwidth + */ +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint8_t priority; + float unrsv_bw; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + priority = yang_dnode_get_uint8(args->dnode, "../priority"); + unrsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); + ifp = nb_running_get_entry(args->dnode, NULL, true); iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, + unrsv_bw); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth + */ +int lib_interface_zebra_link_params_residual_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, res_bw; + + res_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < res_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than residual-bandwidth %f", + max_bw, res_bw); + return NB_ERR_VALIDATION; + } + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->res_bw, LP_RES_BW, res_bw); + break; + } - iflp->admin_grp = admin_group_value; - SET_PARAM(iflp, LP_ADM_GRP); + return NB_OK; +} - admin_group_clear(&iflp->ext_admin_grp); - UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); +int lib_interface_zebra_link_params_residual_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + link_param_cmd_unset(ifp, LP_RES_BW); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth + */ +int lib_interface_zebra_link_params_available_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, ava_bw; + + ava_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < ava_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than available-bandwidth %f", + max_bw, ava_bw); + return NB_ERR_VALIDATION; + } + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->ava_bw, LP_AVA_BW, ava_bw); break; } + return NB_OK; } -int lib_interface_zebra_legacy_admin_group_destroy( +int lib_interface_zebra_link_params_available_bandwidth_destroy( struct nb_cb_destroy_args *args) { struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + link_param_cmd_unset(ifp, LP_AVA_BW); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth + */ +int lib_interface_zebra_link_params_utilized_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; struct if_link_params *iflp; + float max_bw, use_bw; + + use_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < use_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than utilized-bandwidth %f", + max_bw, use_bw); + return NB_ERR_VALIDATION; + } + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->use_bw, LP_USE_BW, use_bw); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_link_params_utilized_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); + link_param_cmd_unset(ifp, LP_USE_BW); - if (!ifp) - return NB_ERR_RESOURCE; + return NB_OK; +} - iflp = if_link_params_get(ifp); +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group + */ +int lib_interface_zebra_legacy_admin_group_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t admin_group_value; + + admin_group_value = yang_dnode_get_uint32(args->dnode, "."); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->admin_grp = admin_group_value; + SET_PARAM(iflp, LP_ADM_GRP); + break; + } + return NB_OK; +} + +int lib_interface_zebra_legacy_admin_group_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; switch (args->event) { case NB_EV_VALIDATE: @@ -1188,14 +1763,11 @@ int lib_interface_zebra_legacy_admin_group_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); iflp->admin_grp = 0; UNSET_PARAM(iflp, LP_ADM_GRP); - - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); break; } return NB_OK; @@ -1203,6 +1775,35 @@ int lib_interface_zebra_legacy_admin_group_destroy( /* * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities + */ +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + + return NB_OK; +} + +/* + * XPath: * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity */ int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) @@ -1213,39 +1814,18 @@ int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) struct affinity_map *affmap; enum affinity_mode affinity_mode; - - ifp = nb_running_get_entry(args->dnode, NULL, true); affname = yang_dnode_get_string(args->dnode, "."); affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); - if (!ifp) - return NB_ERR_RESOURCE; - - affmap = affinity_map_get(affname); - iflp = if_link_params_get(ifp); - switch (args->event) { case NB_EV_VALIDATE: - if (!affmap) { - snprintf(args->errmsg, args->errmsg_len, - "affinity-map %s not found.", affname); - return NB_ERR_VALIDATION; - } - if (affinity_mode == AFFINITY_MODE_STANDARD && - affmap->bit_position > 31) { - snprintf( - args->errmsg, args->errmsg_len, - "affinity %s bit-position %d is not compatible with affinity-mode standard (bit-position > 31).", - affname, affmap->bit_position); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + affmap = affinity_map_get(affname); if (affmap->bit_position < 32 && (affinity_mode == AFFINITY_MODE_STANDARD || @@ -1259,9 +1839,6 @@ int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) affmap->bit_position); SET_PARAM(iflp, LP_EXTEND_ADM_GRP); } - - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); break; } return NB_OK; @@ -1275,30 +1852,19 @@ int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args) struct affinity_map *affmap; enum affinity_mode affinity_mode; - ifp = nb_running_get_entry(args->dnode, NULL, true); affname = yang_dnode_get_string(args->dnode, "."); affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); - if (!ifp) - return NB_ERR_RESOURCE; - - affmap = affinity_map_get(affname); - iflp = if_link_params_get(ifp); - switch (args->event) { case NB_EV_VALIDATE: - if (!affmap) { - snprintf(args->errmsg, args->errmsg_len, - "affinity-map %s not found.", affname); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - return NB_OK; + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + affmap = affinity_map_get(affname); + if (affmap->bit_position < 32 && (affinity_mode == AFFINITY_MODE_STANDARD || affinity_mode == AFFINITY_MODE_BOTH)) { @@ -1313,9 +1879,6 @@ int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args) if (admin_group_zero(&iflp->ext_admin_grp)) UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); } - - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); break; } return NB_OK; @@ -1331,31 +1894,17 @@ int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args) struct if_link_params *iflp; enum affinity_mode affinity_mode; - - ifp = nb_running_get_entry(args->dnode, NULL, true); affinity_mode = yang_dnode_get_enum(args->dnode, "."); - if (!ifp) - return NB_ERR_RESOURCE; - - iflp = if_link_params_get(ifp); - switch (args->event) { case NB_EV_VALIDATE: - if (affinity_mode == AFFINITY_MODE_STANDARD && - admin_group_nb_words(&iflp->ext_admin_grp) > 1) { - snprintf( - args->errmsg, args->errmsg_len, - "affinity-mode standard cannot be set when a bit-position > 31 is set."); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + if (affinity_mode == AFFINITY_MODE_STANDARD) { if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { @@ -1389,84 +1938,1880 @@ int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args) SET_PARAM(iflp, LP_ADM_GRP); } } + break; + } + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor + */ +int lib_interface_zebra_link_params_neighbor_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + struct in_addr ip; + uint32_t as; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + as = yang_dnode_get_uint32(args->dnode, "remote-as"); + yang_dnode_get_ipv4(&ip, args->dnode, "ipv4-remote-id"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = as; + iflp->rmt_ip = ip; + SET_PARAM(iflp, LP_RMT_AS); + + return NB_OK; +} + +int lib_interface_zebra_link_params_neighbor_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = 0; + iflp->rmt_ip.s_addr = 0; + UNSET_PARAM(iflp, LP_RMT_AS); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/remote-as + */ +int lib_interface_zebra_link_params_neighbor_remote_as_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t as; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + as = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = as; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/ipv4-remote-id + */ +int lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + struct in_addr ip; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv4(&ip, args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_ip = ip; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/delay + */ +int lib_interface_zebra_link_params_delay_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->av_delay, LP_DELAY, delay); + + return NB_OK; +} + +int lib_interface_zebra_link_params_delay_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->av_delay = 0; + link_param_cmd_unset(ifp, LP_DELAY); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay + */ +int lib_interface_zebra_link_params_min_max_delay_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_min, delay_max; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_min = yang_dnode_get_uint32(args->dnode, "delay-min"); + delay_max = yang_dnode_get_uint32(args->dnode, "delay-max"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = delay_min; + iflp->max_delay = delay_max; + SET_PARAM(iflp, LP_MM_DELAY); + + return NB_OK; +} + +int lib_interface_zebra_link_params_min_max_delay_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-min + */ +int lib_interface_zebra_link_params_min_max_delay_delay_min_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_min; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_min = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = delay_min; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-max + */ +int lib_interface_zebra_link_params_min_max_delay_delay_max_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_max; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_max = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->max_delay = delay_max; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation + */ +int lib_interface_zebra_link_params_delay_variation_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_var; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_var = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->delay_var, LP_DELAY_VAR, + delay_var); + + return NB_OK; +} + +int lib_interface_zebra_link_params_delay_variation_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + link_param_cmd_unset(ifp, LP_DELAY_VAR); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss + */ +int lib_interface_zebra_link_params_packet_loss_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + double packet_loss; + uint32_t value; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + packet_loss = yang_dnode_get_dec64(args->dnode, NULL); + value = (uint32_t)(packet_loss / LOSS_PRECISION); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->pkt_loss, LP_PKT_LOSS, value); + + return NB_OK; +} + +int lib_interface_zebra_link_params_packet_loss_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + link_param_cmd_unset(ifp, LP_PKT_LOSS); + + return NB_OK; +} + +static bool evpn_mh_dnode_to_esi(const struct lyd_node *dnode, esi_t *esi) +{ + if (yang_dnode_exists(dnode, "type-0/esi")) { + if (!str_to_esi(yang_dnode_get_string(dnode, "type-0/esi"), esi)) + assert(false); + } else if (yang_dnode_exists(dnode, "type-3/system-mac") && + yang_dnode_exists(dnode, "type-3/local-discriminator")) { + struct ethaddr mac; + uint32_t lid; + + yang_dnode_get_mac(&mac, dnode, "type-3/system-mac"); + lid = yang_dnode_get_uint32(dnode, "type-3/local-discriminator"); + + zebra_build_type3_esi(lid, &mac, esi); + } else { + return false; + } + + return true; +} + +struct esi_cmp_iter_arg { + struct lyd_node *dnode; + esi_t esi; + bool exists; +}; + +static int esi_cmp_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct esi_cmp_iter_arg *iter = arg; + esi_t esi; + + if (dnode == iter->dnode) + return YANG_ITER_CONTINUE; + + if (!evpn_mh_dnode_to_esi(dnode, &esi)) + return YANG_ITER_CONTINUE; + + if (!memcmp(&esi, &iter->esi, ESI_BYTES)) { + iter->exists = true; + return YANG_ITER_STOP; + } + + return YANG_ITER_CONTINUE; +} + +/* evpn-mh should be passed to this function */ +static bool esi_unique(struct lyd_node *dnode) +{ + struct esi_cmp_iter_arg iter; + + iter.dnode = dnode; + evpn_mh_dnode_to_esi(dnode, &iter.esi); + iter.exists = false; + + yang_dnode_iterate(esi_cmp_iter_cb, &iter, dnode, + "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh"); + + if (iter.exists) + return false; + + return true; +} - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0 + */ +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_type0_esi_update(ifp->info, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi + */ +int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + esi_t esi; + + switch (args->event) { + case NB_EV_VALIDATE: + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + if (!str_to_esi(yang_dnode_get_string(args->dnode, NULL), &esi)) + assert(false); + zebra_evpn_es_type0_esi_update(ifp->info, &esi); break; } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_0_esi_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_type0_esi_update(ifp->info, NULL); + return NB_OK; } /* - * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3 */ -int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args) { - struct vrf *vrf; - struct zebra_vrf *zvrf; - vni_t vni = 0; - struct zebra_l3vni *zl3vni = NULL; - char err[ERR_STR_SZ]; - bool pfx_only = false; - const struct lyd_node *pn_dnode; - const char *vrfname; + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, NULL); + zebra_evpn_es_lid_update(ifp->info, 0); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac + */ +int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct ethaddr mac; + + yang_dnode_get_mac(&mac, args->dnode, NULL); switch (args->event) { + case NB_EV_VALIDATE: + if (is_zero_mac(&mac)) { + snprintfrr(args->errmsg, args->errmsg_len, + "MAC cannot be all-zeroes"); + return NB_ERR_VALIDATION; + } + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, &mac); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator + */ +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint32_t lid; + + switch (args->event) { case NB_EV_VALIDATE: - vni = yang_dnode_get_uint32(args->dnode, NULL); - /* Get vrf info from parent node, reject configuration - * if zebra vrf already mapped to different vni id. - */ - pn_dnode = yang_dnode_get_parent(args->dnode, "vrf"); - vrfname = yang_dnode_get_string(pn_dnode, "./name"); - zvrf = zebra_vrf_lookup_by_name(vrfname); - if (!zvrf) { - snprintf(args->errmsg, args->errmsg_len, - "zebra vrf info not found for vrf:%s.", - vrfname); + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + lid = yang_dnode_get_uint32(args->dnode, NULL); + zebra_evpn_es_lid_update(ifp->info, lid); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_lid_update(ifp->info, 0); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference + */ +int lib_interface_zebra_evpn_mh_df_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint16_t df_pref; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + df_pref = yang_dnode_get_uint16(args->dnode, NULL); + zebra_evpn_es_df_pref_update(ifp->info, df_pref); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass + */ +int lib_interface_zebra_evpn_mh_bypass_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool bypass; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + bypass = yang_dnode_get_bool(args->dnode, NULL); + zebra_evpn_es_bypass_cfg_update(ifp->info, bypass); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink + */ +int lib_interface_zebra_evpn_mh_uplink_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool uplink; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + uplink = yang_dnode_get_bool(args->dnode, NULL); + zebra_evpn_mh_uplink_cfg_update(ifp->info, uplink); + + return NB_OK; +} + +#if defined(HAVE_RTADV) +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements + */ +int lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool send_adv; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + send_adv = yang_dnode_get_bool(args->dnode, NULL); + + if (send_adv) { + ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); + SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); + } else { + if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS); + UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval + */ +int lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint32_t interval; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + interval = yang_dnode_get_uint32(args->dnode, NULL); + + ipv6_nd_interval_set(ifp, interval); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool managed_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + managed_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvManagedFlag = managed_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool other_config_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + other_config_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvOtherConfigFlag = other_config_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool home_agent_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + home_agent_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvHomeAgentFlag = home_agent_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu + */ +int lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t mtu; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + mtu = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvLinkMTU = mtu; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time + */ +int lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + time = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvReachableTime = time; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer + */ +int lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t timer; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + timer = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvRetransTimer = timer; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit + */ +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint8_t limit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + limit = yang_dnode_get_uint8(args->dnode, NULL); + + zif->rtadv.AdvCurHopLimit = limit; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t lifetime; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + lifetime = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.AdvDefaultLifetime = lifetime; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.AdvDefaultLifetime = -1; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit + */ +int lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool fast_retransmit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + fast_retransmit = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.UseFastRexmit = fast_retransmit; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option + */ +int lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool option; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + option = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvIntervalOption = option; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t preference; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + preference = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.HomeAgentPreference = preference; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.HomeAgentPreference = 0; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t lifetime; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + lifetime = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.HomeAgentLifetime = lifetime; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.HomeAgentLifetime = -1; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference + */ +int lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + int preference; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + preference = yang_dnode_get_enum(args->dnode, NULL); + + zif->rtadv.DefaultPreference = preference; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_prefix rp, *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6p(&rp.prefix, args->dnode, "prefix-spec"); + rp.AdvOnLinkFlag = yang_dnode_get_bool(args->dnode, "on-link-flag"); + rp.AdvAutonomousFlag = yang_dnode_get_bool(args->dnode, + "autonomous-flag"); + rp.AdvRouterAddressFlag = yang_dnode_get_bool(args->dnode, + "router-address-flag"); + rp.AdvValidLifetime = yang_dnode_get_uint32(args->dnode, + "valid-lifetime"); + rp.AdvPreferredLifetime = yang_dnode_get_uint32(args->dnode, + "preferred-lifetime"); + + prefix = rtadv_add_prefix_manual(ifp->info, &rp); + nb_running_set_entry(args->dnode, prefix); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_delete_prefix_manual(ifp->info, prefix); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/valid-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvValidLifetime = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/on-link-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvOnLinkFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/preferred-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvPreferredLifetime = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/autonomous-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvAutonomousFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/router-address-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvRouterAddressFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address + */ +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_rdnss rdnss = {{{{0}}}}, *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6(&rdnss.addr, args->dnode, "address"); + if (yang_dnode_exists(args->dnode, "lifetime")) { + rdnss.lifetime = yang_dnode_get_uint32(args->dnode, "lifetime"); + rdnss.lifetime_set = 1; + } else { + rdnss.lifetime_set = 0; + } + + p = rtadv_rdnss_set(ifp->info, &rdnss); + nb_running_set_entry(args->dnode, p); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_rdnss_reset(ifp->info, p); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address/lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime = yang_dnode_get_uint32(args->dnode, NULL); + p->lifetime_set = 1; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime_set = 0; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain + */ +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_dnssl dnssl = {{0}}, *p; + int ret; + + strlcpy(dnssl.name, yang_dnode_get_string(args->dnode, "domain"), + sizeof(dnssl.name)); + ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); + + if (args->event == NB_EV_VALIDATE) { + if (ret < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "Malformed DNS search domain"); return NB_ERR_VALIDATION; } - if (zvrf->l3vni && zvrf->l3vni != vni) { - snprintf( - args->errmsg, args->errmsg_len, - "vni %u cannot be configured as vni %u is already configured under the vrf", - vni, zvrf->l3vni); + } + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + if (yang_dnode_exists(args->dnode, "lifetime")) { + dnssl.lifetime = yang_dnode_get_uint32(args->dnode, "lifetime"); + dnssl.lifetime_set = 1; + } else { + dnssl.lifetime_set = 0; + } + + p = rtadv_dnssl_set(ifp->info, &dnssl); + nb_running_set_entry(args->dnode, p); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_dnssl_reset(ifp->info, p); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain/lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime = yang_dnode_get_uint32(args->dnode, NULL); + p->lifetime_set = 1; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime_set = 0; + + return NB_OK; +} +#endif /* defined(HAVE_RTADV) */ + +#if HAVE_BFDD == 0 +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ptm-enable + */ +int lib_interface_zebra_ptm_enable_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool ptm; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + ptm = yang_dnode_get_bool(args->dnode, NULL); + if (ptm) + zebra_if_ptm_enable(ifp); + else + zebra_if_ptm_disable(ifp); + + return NB_OK; +} +#endif + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/router-id + */ +int lib_vrf_zebra_router_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv4p(&p, args->dnode, NULL); + + router_id_set(AFI_IP, &p, vrf->info); + + return NB_OK; +} + +int lib_vrf_zebra_router_id_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + memset(&p, 0, sizeof(p)); + p.family = AF_INET; + + router_id_set(AFI_IP, &p, vrf->info); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id + */ +int lib_vrf_zebra_ipv6_router_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6p(&p, args->dnode, NULL); + + router_id_set(AFI_IP6, &p, vrf->info); + + return NB_OK; +} + +int lib_vrf_zebra_ipv6_router_id_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + memset(&p, 0, sizeof(p)); + p.family = AF_INET6; + + router_id_set(AFI_IP6, &p, vrf->info); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol + */ +int lib_vrf_zebra_filter_protocol_create(struct nb_cb_create_args *args) +{ + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + int rtype; + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + if (args->event == NB_EV_VALIDATE) + if (rtype < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid protocol name \"%s\"", proto); return NB_ERR_VALIDATION; } - /* Check if this VNI is already present in the system */ - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - snprintf(args->errmsg, args->errmsg_len, - "VNI %u is already configured as L3-VNI", vni); + /* the creation finishes in the apply_finish callback */ + + return NB_OK; +} + +int lib_vrf_zebra_filter_protocol_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* deleting an existing entry, it can't be invalid */ + assert(rtype >= 0); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_protocol_rm_del(vrf->info, rmap, rtype, afi, safi); + + return NB_OK; +} + +void lib_vrf_zebra_filter_protocol_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* finishing apply for a validated entry, it can't be invalid */ + assert(rtype >= 0); + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_protocol_rm_add(vrf->info, rmap, rtype, afi, safi); +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol/route-map + */ +int lib_vrf_zebra_filter_protocol_route_map_modify(struct nb_cb_modify_args *args) +{ + /* the update is done in the apply_finish callback */ + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht + */ +int lib_vrf_zebra_filter_nht_create(struct nb_cb_create_args *args) +{ + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + if (args->event == NB_EV_VALIDATE) { + if (rtype < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid protocol name \"%s\"", proto); + return NB_ERR_VALIDATION; + } + if (safi != SAFI_UNICAST) { + snprintfrr(args->errmsg, args->errmsg_len, + "only SAFI unicast is supported"); return NB_ERR_VALIDATION; } + } + + /* the creation finishes in the apply_finish callback */ + + return NB_OK; +} + +int lib_vrf_zebra_filter_nht_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* deleting an existing entry, it can't be invalid */ + assert(rtype >= 0); + assert(safi == SAFI_UNICAST); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_nht_rm_del(vrf->info, rmap, rtype, afi); + + return NB_OK; +} + +void lib_vrf_zebra_filter_nht_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* finishing apply for an existing entry, it can't be invalid */ + assert(rtype >= 0); + assert(safi == SAFI_UNICAST); + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_nht_rm_add(vrf->info, rmap, rtype, afi); +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht/route-map + */ +int lib_vrf_zebra_filter_nht_route_map_modify(struct nb_cb_modify_args *args) +{ + /* the update is done in the apply_finish callback */ + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default + */ +int lib_vrf_zebra_resolve_via_default_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = yang_dnode_get_bool(args->dnode, NULL); + + if (zvrf->zebra_rnh_ip_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ip_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +int lib_vrf_zebra_resolve_via_default_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT; + + if (zvrf->zebra_rnh_ip_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ip_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default + */ +int lib_vrf_zebra_ipv6_resolve_via_default_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = yang_dnode_get_bool(args->dnode, NULL); + + if (zvrf->zebra_rnh_ipv6_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ipv6_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +int lib_vrf_zebra_ipv6_resolve_via_default_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT; + + if (zvrf->zebra_rnh_ipv6_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ipv6_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range + */ +static int table_range_validate(uint32_t start, uint32_t end, char *errmsg, + size_t errmsg_len) +{ +#if defined(GNU_LINUX) + if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL) || + (end >= RT_TABLE_ID_COMPAT && end <= RT_TABLE_ID_LOCAL)) { + snprintfrr(errmsg, errmsg_len, + "Values forbidden in range [%u;%u]", + RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); + return NB_ERR_VALIDATION; + } + if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) { + snprintfrr(errmsg, errmsg_len, + "Range overlaps range [%u;%u] forbidden", + RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); + return NB_ERR_VALIDATION; + } +#endif + return NB_OK; +} + +int lib_vrf_zebra_netns_table_range_create(struct nb_cb_create_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + const char *vrf_name; + + start = yang_dnode_get_uint32(args->dnode, "start"); + end = yang_dnode_get_uint32(args->dnode, "end"); + + if (args->event == NB_EV_VALIDATE) { + vrf_name = yang_dnode_get_string(args->dnode, "../../../name"); + if (!vrf_is_backend_netns() && + strcmp(vrf_name, VRF_DEFAULT_NAME)) { + snprintfrr(args->errmsg, args->errmsg_len, + "Configuration is not available in non-default VRFs when using VRF-lite backend."); + return NB_ERR_VALIDATION; + } + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + } + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +int lib_vrf_zebra_netns_table_range_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(false, vrf->info, 0, 0); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/start + */ +int lib_vrf_zebra_netns_table_range_start_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + + start = yang_dnode_get_uint32(args->dnode, NULL); + end = yang_dnode_get_uint32(args->dnode, "../end"); + + if (args->event == NB_EV_VALIDATE) + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/end + */ +int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + + start = yang_dnode_get_uint32(args->dnode, "../start"); + end = yang_dnode_get_uint32(args->dnode, NULL); + + if (args->event == NB_EV_VALIDATE) + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id + */ +int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + vni_t vni = 0; + bool pfx_only = false; + uint32_t count; + + vni = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_VALIDATE: + count = yang_dnode_count(args->dnode, + "/frr-vrf:lib/vrf/frr-zebra:zebra[l3vni-id='%u']", + vni); + if (count > 1) { + snprintfrr(args->errmsg, args->errmsg_len, + "vni %u is already mapped to another vrf", + vni); + return NB_ERR_VALIDATION; + } break; case NB_EV_APPLY: - vrf = nb_running_get_entry(args->dnode, NULL, true); - zvrf = zebra_vrf_lookup_by_name(vrf->name); - vni = yang_dnode_get_uint32(args->dnode, NULL); - /* Note: This covers lib_vrf_zebra_prefix_only_modify() config - * along with l3vni config - */ pfx_only = yang_dnode_get_bool(args->dnode, "../prefix-only"); - if (zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - pfx_only ? 1 : 0, 1) - != 0) { - if (IS_ZEBRA_DEBUG_VXLAN) - snprintf( - args->errmsg, args->errmsg_len, - "vrf vni %u mapping failed with error: %s", - vni, err); - return NB_ERR; - } - + zebra_vxlan_process_vrf_vni_cmd(vrf->info, vni, + pfx_only ? 1 : 0, 1); break; } @@ -1476,10 +3821,7 @@ int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) int lib_vrf_zebra_l3vni_id_destroy(struct nb_cb_destroy_args *args) { struct vrf *vrf; - struct zebra_vrf *zvrf; vni_t vni = 0; - char err[ERR_STR_SZ]; - uint8_t filter = 0; switch (args->event) { case NB_EV_PREPARE: @@ -1488,32 +3830,9 @@ int lib_vrf_zebra_l3vni_id_destroy(struct nb_cb_destroy_args *args) return NB_OK; case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); - zvrf = zebra_vrf_lookup_by_name(vrf->name); vni = yang_dnode_get_uint32(args->dnode, NULL); - if (!zl3vni_lookup(vni)) - return NB_OK; - - if (zvrf->l3vni != vni) { - snprintf(args->errmsg, args->errmsg_len, - "vrf %s has different vni %u mapped", - vrf->name, zvrf->l3vni); - return NB_ERR; - } - - if (is_l3vni_for_prefix_routes_only(zvrf->l3vni)) - filter = 1; - - if (zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - filter, 0) - != 0) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "vrf vni %u unmapping failed with error: %s", - vni, err); - return NB_ERR; - } - + zebra_vxlan_process_vrf_vni_cmd(vrf->info, vni, 0, 0); break; } diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index acf0b80aca..46492f023a 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -49,8 +49,46 @@ lib_interface_zebra_state_down_count_get_elem(struct nb_cb_get_elem_args *args) struct yang_data * lib_interface_zebra_state_zif_type_get_elem(struct nb_cb_get_elem_args *args) { - /* TODO: implement me. */ - return NULL; + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + const char *type = NULL; + + zebra_if = ifp->info; + + switch (zebra_if->zif_type) { + case ZEBRA_IF_OTHER: + type = "frr-zebra:zif-other"; + break; + case ZEBRA_IF_VXLAN: + type = "frr-zebra:zif-vxlan"; + break; + case ZEBRA_IF_VRF: + type = "frr-zebra:zif-vrf"; + break; + case ZEBRA_IF_BRIDGE: + type = "frr-zebra:zif-bridge"; + break; + case ZEBRA_IF_VLAN: + type = "frr-zebra:zif-vlan"; + break; + case ZEBRA_IF_MACVLAN: + type = "frr-zebra:zif-macvlan"; + break; + case ZEBRA_IF_VETH: + type = "frr-zebra:zif-veth"; + break; + case ZEBRA_IF_BOND: + type = "frr-zebra:zif-bond"; + break; + case ZEBRA_IF_GRE: + type = "frr-zebra:zif-gre"; + break; + } + + if (!type) + return NULL; + + return yang_data_new_string(args->xpath, type); } /* @@ -145,6 +183,28 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args) return yang_data_new_ipv4(args->xpath, &vni->mcast_grp); } +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/bond + */ +struct yang_data * +lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + struct interface *bond; + + if (!IS_ZEBRA_IF_BOND_SLAVE(ifp)) + return NULL; + + zebra_if = ifp->info; + bond = zebra_if->bondslave_info.bond_if; + + if (!bond) + return NULL; + + return yang_data_new_string(args->xpath, bond->name); +} + const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) { struct vrf *vrf = (struct vrf *)args->parent_list_entry; @@ -156,6 +216,8 @@ const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) safi_t safi; zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; if (args->list_entry == NULL) { afi = AFI_IP; @@ -167,7 +229,8 @@ const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) } else { zrt = RB_NEXT(zebra_router_table_head, zrt); /* vrf_id/ns_id do not match, only walk for the given VRF */ - while (zrt && zrt->ns_id != zvrf->zns->ns_id) + while (zrt && (zrt->tableid != zvrf->table_id || + zrt->ns_id != zvrf->zns->ns_id)) zrt = RB_NEXT(zebra_router_table_head, zrt); } @@ -198,6 +261,8 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args) uint32_t table_id = 0; zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; yang_afi_safi_identity2value(args->keys->key[0], &afi, &safi); table_id = yang_str2uint32(args->keys->key[1]); @@ -208,6 +273,28 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args) return zebra_router_find_zrt(zvrf, table_id, afi, safi); } +const void * +lib_vrf_zebra_ribs_rib_lookup_next(struct nb_cb_lookup_entry_args *args) +{ + struct vrf *vrf = (struct vrf *)args->parent_list_entry; + struct zebra_vrf *zvrf; + afi_t afi; + safi_t safi; + uint32_t table_id = 0; + + zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; + + yang_afi_safi_identity2value(args->keys->key[0], &afi, &safi); + table_id = yang_str2uint32(args->keys->key[1]); + /* table_id 0 assume vrf's table_id. */ + if (!table_id) + table_id = zvrf->table_id; + + return zebra_router_find_next_zrt(zvrf, table_id, afi, safi); +} + /* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name */ @@ -285,6 +372,25 @@ lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args) return rn; } +const void * +lib_vrf_zebra_ribs_rib_route_lookup_next(struct nb_cb_lookup_entry_args *args) +{ + const struct zebra_router_table *zrt = args->parent_list_entry; + struct prefix p; + struct route_node *rn; + + yang_str2prefix(args->keys->key[0], &p); + + rn = route_table_get_next(zrt->table, &p); + + if (!rn) + return NULL; + + route_unlock_node(rn); + + return rn; +} + /* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/prefix */ @@ -502,7 +608,7 @@ struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem( { struct route_entry *re = (struct route_entry *)args->list_entry; - return yang_data_new_date_and_time(args->xpath, re->uptime); + return yang_data_new_date_and_time(args->xpath, re->uptime, true); } /* @@ -842,6 +948,58 @@ lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_color_get_elem( /* * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry + */ +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_next( + struct nb_cb_get_next_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_get_keys( + struct nb_cb_get_keys_args *args) +{ + /* TODO: implement me. */ + return NB_OK; +} + +const void * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_lookup_entry( + struct nb_cb_lookup_entry_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/id + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_id_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/srv6-segs-stack/entry/seg + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_srv6_segs_stack_entry_seg_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + + +/* + * XPath: * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/nexthop/mpls-label-stack/entry */ const void * diff --git a/zebra/zebra_neigh.c b/zebra/zebra_neigh.c index 0c3fb97afd..941088afd6 100644 --- a/zebra/zebra_neigh.c +++ b/zebra/zebra_neigh.c @@ -152,6 +152,19 @@ void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip) zebra_neigh_free(n); } +/* kernel neigh delete all for a given interface */ +void zebra_neigh_del_all(struct interface *ifp) +{ + struct zebra_neigh_ent *n, *nn; + + if (IS_ZEBRA_DEBUG_NEIGH) + zlog_debug("zebra neigh delete all for interface %s/%d", + ifp->name, ifp->ifindex); + + RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, nn) + zebra_neigh_del(ifp, &n->ip); +} + /* kernel neigh add */ void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac) diff --git a/zebra/zebra_neigh.h b/zebra/zebra_neigh.h index b957b5efe5..adc5f94f76 100644 --- a/zebra/zebra_neigh.h +++ b/zebra/zebra_neigh.h @@ -43,6 +43,7 @@ struct zebra_neigh_info { extern void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac); extern void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip); +extern void zebra_neigh_del_all(struct interface *ifp); extern void zebra_neigh_show(struct vty *vty); extern void zebra_neigh_init(void); extern void zebra_neigh_terminate(void); diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 0531ab9591..1af3a3e857 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -5,6 +5,12 @@ */ #include <zebra.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifdef GNU_LINUX +#include <linux/if_link.h> +#endif #include "ns.h" #include "vrf.h" diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 4260d29c43..1bb1292e34 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -5,6 +5,7 @@ */ #include <zebra.h> +#include <fcntl.h> #ifdef HAVE_NETLINK #ifdef HAVE_NETNS diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 8616b14050..934b8ba0db 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -72,25 +72,13 @@ static uint32_t nhg_get_next_id(void) while (1) { id_counter++; - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID %u checking", __func__, id_counter); - if (id_counter == ZEBRA_NHG_PROTO_LOWER) { - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID counter wrapped", __func__); - id_counter = 0; continue; } - if (zebra_nhg_lookup_id(id_counter)) { - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID already exists", __func__); - - continue; - } - - break; + if (!zebra_nhg_lookup_id(id_counter)) + break; } return id_counter; @@ -321,8 +309,10 @@ static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; + nhe->ifp = ifp; - if_nhg_dependents_add(ifp, nhe); + nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe); } static void @@ -690,12 +680,6 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ struct nhg_hash_entry *newnhe, *backup_nhe; struct nexthop *nh = NULL; - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug( - "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s", - __func__, lookup->id, lookup, lookup->vrf_id, - lookup->type, nhg_depends, - (from_dplane ? " (from dplane)" : "")); if (lookup->id) (*nhe) = zebra_nhg_lookup_id(lookup->id); @@ -703,7 +687,10 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ (*nhe) = hash_lookup(zrouter.nhgs, lookup); if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe); + zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p%s => Found %p(%pNG)", + __func__, lookup->id, lookup, lookup->vrf_id, + lookup->type, nhg_depends, + (from_dplane ? " (from dplane)" : ""), *nhe, *nhe); /* If we found an existing object, we're done */ if (*nhe) @@ -1046,31 +1033,25 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, return ctx; } -static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe) -{ - struct nhg_connected *rb_node_dep; - - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - - frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) - zebra_nhg_set_valid(rb_node_dep->nhe); -} - -static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) +static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) { struct nhg_connected *rb_node_dep; - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + if (valid) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + else { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - /* If we're in shutdown, this interface event needs to clean - * up installed NHGs, so don't clear that flag directly. - */ - if (!zebra_router_in_shutdown()) - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + /* If we're in shutdown, this interface event needs to clean + * up installed NHGs, so don't clear that flag directly. + */ + if (!zebra_router_in_shutdown()) + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } /* Update validity of nexthops depending on it */ frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) - zebra_nhg_check_valid(rb_node_dep->nhe); + zebra_nhg_set_valid(rb_node_dep->nhe, valid); } void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) @@ -1082,15 +1063,11 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) { valid = true; - goto done; + break; } } -done: - if (valid) - zebra_nhg_set_valid(nhe); - else - zebra_nhg_set_invalid(nhe); + zebra_nhg_set_valid(nhe, valid); } static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe) @@ -1098,8 +1075,11 @@ static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe) /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); zebra_nhg_dependents_release(nhe); - if (nhe->ifp) - if_nhg_dependents_del(nhe->ifp, nhe); + if (nhe->ifp) { + struct zebra_if *zif = nhe->ifp->info; + + nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe); + } } static void zebra_nhg_release(struct nhg_hash_entry *nhe) @@ -1125,13 +1105,23 @@ static void zebra_nhg_handle_uninstall(struct nhg_hash_entry *nhe) zebra_nhg_free(nhe); } -static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe) +static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install) { /* Update validity of groups depending on it */ struct nhg_connected *rb_node_dep; - frr_each_safe(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) - zebra_nhg_set_valid(rb_node_dep->nhe); + frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { + zebra_nhg_set_valid(rb_node_dep->nhe, true); + /* install dependent NHG into kernel */ + if (install) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug( + "%s nh id %u (flags 0x%x) associated dependent NHG %pNG install", + __func__, nhe->id, nhe->flags, + rb_node_dep->nhe); + zebra_nhg_install_kernel(rb_node_dep->nhe); + } + } } /* @@ -1300,6 +1290,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) break; case NHG_CTX_OP_DEL: ret = nhg_ctx_process_del(ctx); + break; case NHG_CTX_OP_NONE: break; } @@ -1515,19 +1506,23 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; - if (!(rt_nhe && rt_nhe->nhg.nexthop)) { + if (!rt_nhe) { flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, - "No nexthop passed to %s", __func__); + "No nhg_hash_entry passed to %s", __func__); return NULL; } - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe); + if (!rt_nhe->nhg.nexthop) { + flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, + "No nexthop passed to %s", __func__); + return NULL; + } zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false); if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe); + zlog_debug("%s: rt_nhe %p(%pNG) => nhe %p(%pNG)", __func__, + rt_nhe, rt_nhe, nhe, nhe); return nhe; } @@ -1858,11 +1853,18 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, labels); if (nexthop->nh_srv6) { - nexthop_add_srv6_seg6local(resolved_hop, - nexthop->nh_srv6->seg6local_action, - &nexthop->nh_srv6->seg6local_ctx); - nexthop_add_srv6_seg6(resolved_hop, - &nexthop->nh_srv6->seg6_segs); + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + nexthop_add_srv6_seg6local(resolved_hop, + nexthop->nh_srv6 + ->seg6local_action, + &nexthop->nh_srv6 + ->seg6local_ctx); + if (nexthop->nh_srv6->seg6_segs) + nexthop_add_srv6_seg6(resolved_hop, + &nexthop->nh_srv6->seg6_segs->seg[0], + nexthop->nh_srv6->seg6_segs + ->num_segs); } resolved_hop->rparent = nexthop; @@ -2111,7 +2113,8 @@ zebra_nhg_connected_ifindex(struct route_node *rn, struct route_entry *match, * of those ifindexes match as well. */ RNODE_FOREACH_RE (rn, re) { - if (re->type != ZEBRA_ROUTE_CONNECT) + if (re->type != ZEBRA_ROUTE_CONNECT && + re->type != ZEBRA_ROUTE_LOCAL) continue; if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) @@ -2171,11 +2174,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, case NEXTHOP_TYPE_IFINDEX: ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - /* - * If the interface exists and its operative or its a kernel - * route and interface is up, its active. We trust kernel routes - * to be good. - */ + /* If the interface exists and its operative, it's active */ if (ifp && (if_is_operative(ifp))) return 1; else @@ -2234,20 +2233,6 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, return 1; } - if (top && - ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN && - nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) || - (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN && - memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) == - 0)) && - nexthop->vrf_id == vrf_id) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - " :%s: Attempting to install a max prefixlength route through itself", - __func__); - return 0; - } - /* Validation for ipv4 mapped ipv6 nexthop. */ if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) { afi = AFI_IP; @@ -2350,7 +2335,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, zlog_debug( " %s: Matched against ourself and prefix length is not max bit length", __func__); - return 0; + goto continue_up_tree; } /* Pick up selected route. */ @@ -2360,60 +2345,58 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, if (is_default_prefix(&rn->p) && !rnh_resolve_via_default(zvrf, p.family)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - " :%s: Resolved against default route", - __func__); + zlog_debug(" :%s: %pFX Resolved against default route", + __func__, &p); return 0; } dest = rib_dest_from_rnode(rn); - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, - ROUTE_ENTRY_REMOVED) - && dest->selected_fib->type != ZEBRA_ROUTE_TABLE) + if (dest && dest->selected_fib && + (!CHECK_FLAG(dest->selected_fib->status, + ROUTE_ENTRY_REMOVED) || + CHECK_FLAG(dest->selected_fib->status, + ROUTE_ENTRY_ROUTE_REPLACING)) && + dest->selected_fib->type != ZEBRA_ROUTE_TABLE) match = dest->selected_fib; /* If there is no selected route or matched route is EGP, go up * tree. */ - if (!match) { - do { - rn = rn->parent; - } while (rn && rn->info == NULL); - if (rn) - route_lock_node(rn); - - continue; - } - if ((match->type == ZEBRA_ROUTE_CONNECT) || - (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) { + /* If the candidate match's type is considered "connected", + * we consider it first. + */ + if (match && (RIB_CONNECTED_ROUTE(match) || + (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type)))) { match = zebra_nhg_connected_ifindex(rn, match, nexthop->ifindex); newhop = match->nhe->nhg.nexthop; - if (nexthop->type == NEXTHOP_TYPE_IPV4 || - nexthop->type == NEXTHOP_TYPE_IPV6) + if (nexthop->type == NEXTHOP_TYPE_IPV4) { + nexthop->ifindex = newhop->ifindex; + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + } else if (nexthop->type == NEXTHOP_TYPE_IPV6) { nexthop->ifindex = newhop->ifindex; - else if (nexthop->ifindex != newhop->ifindex) { + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + } else if (nexthop->ifindex != newhop->ifindex) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv", __func__, nexthop, newhop); - /* - * NEXTHOP_TYPE_*_IFINDEX but ifindex - * doesn't match what we found. - */ - return 0; + goto continue_up_tree; } + /* NHRP special case: need to indicate onlink */ + if (match->type == ZEBRA_ROUTE_NHRP) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "%s: CONNECT match %p (%pNG), newhop %pNHv", __func__, match, match->nhe, newhop); return 1; - } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) { + } else if (match && CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) { struct nexthop_group *nhg; struct nexthop *resolver; struct backup_nh_map_s map = {}; @@ -2449,6 +2432,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, "%s: match %p (%pNG) not installed or being Route Replaced", __func__, match, match->nhe); + if (CHECK_FLAG(match->status, + ROUTE_ENTRY_QUEUED)) + goto continue_up_tree; + goto done_with_match; } @@ -2517,25 +2504,37 @@ done_with_match: if (pmtu) *pmtu = match->mtu; - } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - " %s: Recursion failed to find", - __func__); - - return resolved; - } else { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - zlog_debug( - " %s: Route Type %s has not turned on recursion", - __func__, zebra_route_string(type)); - if (type == ZEBRA_ROUTE_BGP - && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP)) + } else { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); + " %s: Recursion failed to find while looking at %pRN", + __func__, rn); + goto continue_up_tree; } - return 0; + + return 1; + } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + zlog_debug( + " %s: Route Type %s has not turned on recursion %pRN failed to match", + __func__, zebra_route_string(type), rn); + if (type == ZEBRA_ROUTE_BGP + && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP)) + zlog_debug( + " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); } + + continue_up_tree: + /* + * If there is no selected route or matched route is EGP, go up + * tree. + */ + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node(rn); } + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug(" %s: Nexthop did not lookup in table", __func__); @@ -2576,6 +2575,8 @@ static unsigned nexthop_active_check(struct route_node *rn, if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop); + vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn))); + /* * If this is a kernel route, then if the interface is *up* then * by golly gee whiz it's a good route. @@ -2585,13 +2586,12 @@ static unsigned nexthop_active_check(struct route_node *rn, ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - if (ifp && (if_is_operative(ifp) || if_is_up(ifp))) { + if (ifp && ifp->vrf->vrf_id == vrf_id && if_is_up(ifp)) { SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); goto skip_check; } } - vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn))); switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, @@ -2686,8 +2686,7 @@ skip_check: } /* It'll get set if required inside */ - ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop, - zvrf, re->tag); + ret = zebra_route_map_check(family, re, p, nexthop, zvrf); if (ret == RMAP_DENYMATCH) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( @@ -3080,19 +3079,26 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) /* Resolve it first */ nhe = zebra_nhg_resolve(nhe); + if (zebra_nhg_set_valid_if_active(nhe)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: valid flag set for nh %pNG", __func__, + nhe); + } + /* Make sure all depends are installed/queued */ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_install_kernel(rb_node_dep->nhe); } - if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) && + (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) || + CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) && + !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { /* Change its type to us since we are installing it */ if (!ZEBRA_NHG_CREATED(nhe)) nhe->type = ZEBRA_ROUTE_NHG; - int ret = dplane_nexthop_add(nhe); + enum zebra_dplane_result ret = dplane_nexthop_add(nhe); switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: @@ -3105,8 +3111,9 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) nhe); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_handle_install(nhe); + flog_err(EC_ZEBRA_DP_INVALID_RC, + "DPlane returned an invalid result code for attempt of installation of %pNG into the kernel", + nhe); break; } } @@ -3153,8 +3160,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", ctx, dplane_op2str(op), id, dplane_res2str(status)); - switch (op) { - case DPLANE_OP_NH_DELETE: + if (op == DPLANE_OP_NH_DELETE) { if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) flog_err( EC_ZEBRA_DP_DELETE_FAIL, @@ -3162,32 +3168,32 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) id); /* We already free'd the data, nothing to do */ - break; - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: + } else if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) { nhe = zebra_nhg_lookup_id(id); if (!nhe) { if (IS_ZEBRA_DEBUG_NHG) - zlog_debug( - "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", - dplane_op2str(op), id); + zlog_debug("%s operation performed on Nexthop ID (%u) in the kernel, that we no longer have in our table", + dplane_op2str(op), id); - break; + return; } UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL); + switch (status) { + case ZEBRA_DPLANE_REQUEST_SUCCESS: SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_handle_install(nhe); + zebra_nhg_handle_install(nhe, true); /* If daemon nhg, send it an update */ if (PROTO_OWNED(nhe)) zsend_nhg_notify(nhe->type, nhe->zapi_instance, nhe->zapi_session, nhe->id, ZAPI_NHG_INSTALLED); - } else { + break; + case ZEBRA_DPLANE_REQUEST_FAILURE: + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); /* If daemon nhg, send it an update */ if (PROTO_OWNED(nhe)) zsend_nhg_notify(nhe->type, nhe->zapi_instance, @@ -3200,61 +3206,13 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) EC_ZEBRA_DP_INSTALL_FAIL, "Failed to install Nexthop (%pNG) into the kernel", nhe); + break; + case ZEBRA_DPLANE_REQUEST_QUEUED: + flog_err(EC_ZEBRA_DP_INVALID_RC, + "Dplane returned an invalid result code for a result from the dplane for %pNG into the kernel", + nhe); + break; } - break; - - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_NONE: - 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_TABLE_UPDATE: - 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_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - break; } } @@ -3397,6 +3355,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, struct nhg_connected *rb_node_dep = NULL; struct nexthop *newhop; bool replace = false; + int ret = 0; if (!nhg->nexthop) { if (IS_ZEBRA_DEBUG_NHG) @@ -3494,22 +3453,31 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED)) zebra_nhg_increment_ref(old); - rib_handle_nhg_replace(old, new); + ret = rib_handle_nhg_replace(old, new); + if (ret) + /* + * if ret > 0, some previous re->nhe has freed the + * address to which old_entry is pointing. Hence mark + * the old NHE as NULL + */ + old = NULL; + else { + /* We have to decrement its singletons + * because some might not exist in NEW. + */ + if (!zebra_nhg_depends_is_empty(old)) { + frr_each (nhg_connected_tree, &old->nhg_depends, + rb_node_dep) + zebra_nhg_decrement_ref( + rb_node_dep->nhe); + } - /* We have to decrement its singletons - * because some might not exist in NEW. - */ - if (!zebra_nhg_depends_is_empty(old)) { - frr_each (nhg_connected_tree, &old->nhg_depends, - rb_node_dep) - zebra_nhg_decrement_ref(rb_node_dep->nhe); + /* Dont call the dec API, we dont want to uninstall the ID */ + old->refcnt = 0; + EVENT_OFF(old->timer); + zebra_nhg_free(old); + old = NULL; } - - /* Dont call the dec API, we dont want to uninstall the ID */ - old->refcnt = 0; - EVENT_OFF(old->timer); - zebra_nhg_free(old); - old = NULL; } if (IS_ZEBRA_DEBUG_NHG_DETAIL) @@ -3614,7 +3582,18 @@ unsigned long zebra_nhg_score_proto(int type) * This should be the last ref if we remove client routes too, * and thus should remove and free them. */ - zebra_nhg_decrement_ref(nhe); + if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED)) + zebra_nhg_decrement_ref(nhe); + else { + + /* protocol sends explicit delete of nhg, the + * nhe->refcount is decremented in zread_nhg_del() + */ + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "%s: nhe %u (%p) refcount %u already decremented in zread_nhg_del", + __func__, nhe->id, nhe, nhe->refcnt); + } } count = iter.found->count; @@ -3651,3 +3630,70 @@ static ssize_t printfrr_nhghe(struct fbuf *buf, struct printfrr_eargs *ea, ret += bputs(buf, "]"); return ret; } + +/* + * On interface add the nexthop that resolves to this intf needs + * a re-install. There are following scenarios when the nexthop group update + * gets skipped: + * 1. When upper level protocol sends removal of NHG, there is + * timer running to keep NHG for 180 seconds, during this interval, same route + * with same set of nexthops installation is given , the same NHG is used + * but since NHG is not reinstalled on interface address add, it is not aware + * in Dplan/Kernel. + * 2. Due to a quick port flap due to interface add and delete + * to be processed in same queue one after another. Zebra believes that + * there is no change in nhg in this case. Hence this re-install will + * make sure the nexthop group gets updated to Dplan/Kernel. + */ +void zebra_interface_nhg_reinstall(struct interface *ifp) +{ + struct nhg_connected *rb_node_dep = NULL; + struct zebra_if *zif = ifp->info; + struct nexthop *nh; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug( + "%s: Installing interface %s associated NHGs into kernel", + __func__, ifp->name); + + frr_each (nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) { + nh = rb_node_dep->nhe->nhg.nexthop; + if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug( + "%s: Setting the valid flag for nhe %pNG, interface: %s", + __func__, rb_node_dep->nhe, ifp->name); + } + /* Check for singleton NHG associated to interface */ + if (nexthop_is_ifindex_type(nh) && + zebra_nhg_depends_is_empty(rb_node_dep->nhe)) { + struct nhg_connected *rb_node_dependent; + + if (IS_ZEBRA_DEBUG_NHG) + zlog_debug( + "%s install nhe %pNG nh type %u flags 0x%x", + __func__, rb_node_dep->nhe, nh->type, + rb_node_dep->nhe->flags); + zebra_nhg_install_kernel(rb_node_dep->nhe); + + /* Don't need to modify dependents if installed */ + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_INSTALLED)) + continue; + + /* mark dependent uninstalled; when interface associated + * singleton is installed, install dependent + */ + frr_each_safe (nhg_connected_tree, + &rb_node_dep->nhe->nhg_dependents, + rb_node_dependent) { + if (IS_ZEBRA_DEBUG_NHG) + zlog_debug("%s dependent nhe %pNG Setting Reinstall flag", + __func__, + rb_node_dependent->nhe); + SET_FLAG(rb_node_dependent->nhe->flags, + NEXTHOP_GROUP_REINSTALL); + } + } + } +} diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index b178007b4e..3bb697aa75 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -85,7 +85,7 @@ struct nhg_hash_entry { * nhg(1)->nhg_dependents is 3 in the tree * * nhg(2)->nhg_depends is empty - * nhg(3)->nhg_dependents is 3 in the tree + * nhg(2)->nhg_dependents is 3 in the tree */ struct nhg_connected_tree_head nhg_depends, nhg_dependents; @@ -143,7 +143,15 @@ struct nhg_hash_entry { /* * Track FPM installation status.. */ -#define NEXTHOP_GROUP_FPM (1 << 6) +#define NEXTHOP_GROUP_FPM (1 << 7) + +/* + * When an interface comes up install the + * singleton's and schedule the NHG's that + * are using this nhg to be reinstalled + * when installation is successful. + */ +#define NEXTHOP_GROUP_REINSTALL (1 << 8) }; /* Upper 4 bits of the NHG are reserved for indicating the NHG type */ @@ -358,6 +366,7 @@ extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, /* Dataplane install/uninstall */ extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); +extern void zebra_interface_nhg_reinstall(struct interface *ifp); /* Forward ref of dplane update context type */ struct zebra_dplane_ctx; diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 6bb5e971e6..803d8f0034 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -23,6 +23,7 @@ #include "rib.h" #include "table_manager.h" #include "zebra_errors.h" +#include "zebra_dplane.h" extern struct zebra_privs_t zserv_privs; @@ -41,11 +42,6 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) return (info == NULL) ? dzns : info; } -static struct zebra_ns *zebra_ns_alloc(void) -{ - return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); -} - static int zebra_ns_new(struct ns *ns) { struct zebra_ns *zns; @@ -56,7 +52,7 @@ static int zebra_ns_new(struct ns *ns) if (IS_ZEBRA_DEBUG_EVENT) zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id); - zns = zebra_ns_alloc(); + zns = XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); ns->info = zns; zns->ns = ns; zns->ns_id = ns->ns_id; @@ -101,6 +97,36 @@ int zebra_ns_disabled(struct ns *ns) return zebra_ns_disable_internal(zns, true); } +void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx) +{ + struct zebra_ns *zns = zebra_ns_lookup(dplane_ctx_get_ns_id(ctx)); + enum zebra_dplane_startup_notifications spot; + + if (!zns) { + zlog_err("%s: No Namespace associated with %u", __func__, + dplane_ctx_get_ns_id(ctx)); + return; + } + + spot = dplane_ctx_get_startup_spot(ctx); + + switch (spot) { + case ZEBRA_DPLANE_INTERFACES_READ: + interface_list_tunneldump(zns); + break; + case ZEBRA_DPLANE_TUNNELS_READ: + interface_list_second(zns); + break; + case ZEBRA_DPLANE_ADDRESSES_READ: + route_read(zns); + + vlan_read(zns); + kernel_read_pbr_rules(zns); + kernel_read_tc_qdisc(zns); + break; + } +} + /* Do global enable actions - open sockets, read kernel config etc. */ int zebra_ns_enable(ns_id_t ns_id, void **info) { @@ -111,11 +137,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) kernel_init(zns); zebra_dplane_ns_enable(zns, true); interface_list(zns); - route_read(zns); - - vlan_read(zns); - kernel_read_pbr_rules(zns); - kernel_read_tc_qdisc(zns); return 0; } @@ -168,6 +189,8 @@ int zebra_ns_final_shutdown(struct ns *ns, kernel_terminate(zns, true); + zebra_ns_delete(ns); + return NS_WALK_CONTINUE; } @@ -215,10 +238,3 @@ int zebra_ns_init(void) return 0; } - -int zebra_ns_config_write(struct vty *vty, struct ns *ns) -{ - if (ns && ns->name != NULL) - vty_out(vty, " netns %s\n", ns->name); - return 0; -} diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index e759d522fa..8d988c3f82 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -18,6 +18,8 @@ extern "C" { #endif #ifdef HAVE_NETLINK +#include <linux/netlink.h> + /* Socket interface to kernel */ struct nlsock { int sock; @@ -47,6 +49,8 @@ struct zebra_ns { struct nlsock netlink_dplane_out; struct nlsock netlink_dplane_in; struct event *t_netlink; + + struct nlsock ge_netlink_cmd; /* command channel for generic netlink */ #endif struct route_table *if_table; @@ -66,7 +70,8 @@ int zebra_ns_early_shutdown(struct ns *ns, int zebra_ns_final_shutdown(struct ns *ns, void *param_in __attribute__((unused)), void **param_out __attribute__((unused))); -int zebra_ns_config_write(struct vty *vty, struct ns *ns); + +void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); #ifdef __cplusplus } diff --git a/zebra/zebra_opaque.c b/zebra/zebra_opaque.c index 8ceb1f8dc5..90533955a4 100644 --- a/zebra/zebra_opaque.c +++ b/zebra/zebra_opaque.c @@ -26,10 +26,16 @@ struct opq_client_reg { int instance; uint32_t session_id; + int flags; + struct opq_client_reg *next; struct opq_client_reg *prev; }; +/* Registration is for receiving or for notifications */ +#define OPQ_CLIENT_FLAG_RECV 0x01 +#define OPQ_CLIENT_FLAG_NOTIFY 0x02 + /* Opaque message registration info */ struct opq_msg_reg { struct opq_regh_item item; @@ -99,14 +105,18 @@ static int handle_opq_registration(const struct zmsghdr *hdr, struct stream *msg); static int handle_opq_unregistration(const struct zmsghdr *hdr, struct stream *msg); +static int handle_opq_notif_req(const struct zmsghdr *hdr, struct stream *msg); +static int handle_opq_notif_unreg(const struct zapi_opaque_notif_info *info); static int dispatch_opq_messages(struct stream_fifo *msg_fifo); static struct opq_msg_reg *opq_reg_lookup(uint32_t type); static bool opq_client_match(const struct opq_client_reg *client, const struct zapi_opaque_reg_info *info); +static bool opq_client_notif_match(const struct opq_client_reg *client, + const struct zapi_opaque_notif_info *info); static struct opq_msg_reg *opq_reg_alloc(uint32_t type); static void opq_reg_free(struct opq_msg_reg **reg); -static struct opq_client_reg *opq_client_alloc( - const struct zapi_opaque_reg_info *info); +static struct opq_client_reg *opq_client_alloc(uint8_t proto, uint16_t instance, + uint32_t session_id); static void opq_client_free(struct opq_client_reg **client); static const char *opq_client2str(char *buf, size_t buflen, const struct opq_client_reg *client); @@ -213,6 +223,7 @@ bool zebra_opaque_handles_msgid(uint16_t id) case ZEBRA_OPAQUE_MESSAGE: case ZEBRA_OPAQUE_REGISTER: case ZEBRA_OPAQUE_UNREGISTER: + case ZEBRA_OPAQUE_NOTIFY: ret = true; break; default: @@ -243,7 +254,7 @@ uint32_t zebra_opaque_enqueue_batch(struct stream_fifo *batch) } } - /* Schedule module pthread to process the batch */ + /* Schedule module's pthread to process the batch */ if (counter > 0) { if (IS_ZEBRA_DEBUG_RECV && IS_ZEBRA_DEBUG_DETAIL) zlog_debug("%s: received %u messages", @@ -326,6 +337,38 @@ done: } /* + * Helper to acquire/lock a client session and send the message in 's'. + * Note that 's' is enqueued for an io pthread, so don't free it + * or touch it if this returns 'true'. + */ +static bool opq_send_message(uint8_t proto, uint16_t instance, + uint32_t session_id, struct stream *s) +{ + bool ret = false; + struct zserv *zclient; + + /* + * TODO -- this isn't ideal: we're going through an + * acquire/release cycle for each client for each + * message. Replace this with a batching version. + */ + zclient = zserv_acquire_client(proto, instance, session_id); + if (zclient) { + /* + * Sending a message actually means enqueuing + * it for a zapi io pthread to send - so we + * don't touch the message after this call. + */ + zserv_send_message(zclient, s); + + zserv_release_client(zclient); + ret = true; + } + + return ret; +} + +/* * Process (dispatch) or drop opaque messages. */ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) @@ -336,7 +379,6 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) struct opq_msg_reg *reg; int ret; struct opq_client_reg *client; - struct zserv *zclient; char buf[50]; while ((msg = stream_fifo_pop(msg_fifo)) != NULL) { @@ -350,6 +392,9 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) } else if (hdr.command == ZEBRA_OPAQUE_UNREGISTER) { handle_opq_unregistration(&hdr, msg); continue; + } else if (hdr.command == ZEBRA_OPAQUE_NOTIFY) { + handle_opq_notif_req(&hdr, msg); + continue; } /* We only process OPAQUE messages - drop anything else */ @@ -381,9 +426,9 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) if (CHECK_FLAG(info.flags, ZAPI_OPAQUE_FLAG_UNICAST)) { - if (client->proto != info.proto || - client->instance != info.instance || - client->session_id != info.session_id) + if (client->proto != info.dest_proto || + client->instance != info.dest_instance || + client->session_id != info.dest_session_id) continue; if (IS_ZEBRA_DEBUG_RECV && @@ -400,36 +445,25 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) dup = stream_dup(msg); } + if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_DETAIL) + zlog_debug("%s: sending %s to client %s", + __func__, (dup ? "dup" : "msg"), + opq_client2str(buf, sizeof(buf), + client)); + /* * TODO -- this isn't ideal: we're going through an * acquire/release cycle for each client for each * message. Replace this with a batching version. */ - zclient = zserv_acquire_client(client->proto, - client->instance, - client->session_id); - if (zclient) { - if (IS_ZEBRA_DEBUG_SEND && - IS_ZEBRA_DEBUG_DETAIL) - zlog_debug("%s: sending %s to client %s", - __func__, - (dup ? "dup" : "msg"), - opq_client2str(buf, - sizeof(buf), - client)); - - /* - * Sending a message actually means enqueuing - * it for a zapi io pthread to send - so we - * don't touch the message after this call. - */ - zserv_send_message(zclient, dup ? dup : msg); + if (opq_send_message(client->proto, client->instance, + client->session_id, + (dup ? dup : msg))) { + /* Message is gone - don't touch it */ if (dup) dup = NULL; else msg = NULL; - - zserv_release_client(zclient); } else { if (IS_ZEBRA_DEBUG_RECV && IS_ZEBRA_DEBUG_DETAIL) @@ -457,6 +491,66 @@ drop_it: return 0; } +/* Enqueue registration client object */ +static void opq_enqueue_client(struct opq_msg_reg *reg, + struct opq_client_reg *client) +{ + client->next = reg->clients; + if (reg->clients) + reg->clients->prev = client; + reg->clients = client; +} + +/* Dequeue registration client object */ +static void opq_dequeue_client(struct opq_msg_reg *reg, + struct opq_client_reg *client) +{ + if (client->prev) + client->prev->next = client->next; + if (client->next) + client->next->prev = client->prev; + if (reg->clients == client) + reg->clients = client->next; +} + +/* + * Send notification messages to any interested clients in 'reg', + * about 'server'; the sense is 'registered' (or not). + * The 'server' is not required for un-registrations. + */ +static void opq_send_notifications(const struct opq_msg_reg *reg, + const struct opq_client_reg *server, + bool registered) +{ + const struct opq_client_reg *client; + struct stream *msg = NULL; + + /* If there are any notification clients, send them a message */ + for (client = reg->clients; client; client = client->next) { + if (CHECK_FLAG(client->flags, OPQ_CLIENT_FLAG_NOTIFY)) { + msg = stream_new(ZEBRA_SMALL_PACKET_SIZE); + + if (registered) { + zclient_opaque_notif_encode(msg, reg->type, + registered, + server->proto, + server->instance, + server->session_id); + } else { + zclient_opaque_notif_encode(msg, reg->type, + registered, 0, 0, 0); + } + + /* Locate zebra client and enqueue message to it */ + if (!opq_send_message(client->proto, client->instance, + client->session_id, msg)) { + /* Error - need to free the message */ + stream_free(msg); + } + } + } +} + /* * Process a register/unregister message */ @@ -499,7 +593,9 @@ static int handle_opq_registration(const struct zmsghdr *hdr, goto done; } - client = opq_client_alloc(&info); + client = opq_client_alloc(info.proto, info.instance, + info.session_id); + SET_FLAG(client->flags, OPQ_CLIENT_FLAG_RECV); if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: client %s registers for %u", @@ -508,17 +604,20 @@ static int handle_opq_registration(const struct zmsghdr *hdr, info.type); /* Link client into registration */ - client->next = reg->clients; - if (reg->clients) - reg->clients->prev = client; - reg->clients = client; + opq_enqueue_client(reg, client); + + /* Send notifications to any clients who want them */ + opq_send_notifications(reg, client, true); + } else { /* * No existing registrations - create one, add the * client, and add registration to hash. */ reg = opq_reg_alloc(info.type); - client = opq_client_alloc(&info); + client = opq_client_alloc(info.proto, info.instance, + info.session_id); + SET_FLAG(client->flags, OPQ_CLIENT_FLAG_RECV); if (IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: client %s registers for new reg %u", @@ -545,8 +644,9 @@ static int handle_opq_unregistration(const struct zmsghdr *hdr, { int ret = 0; struct zapi_opaque_reg_info info; - struct opq_client_reg *client; + struct opq_client_reg *client, *tclient; struct opq_msg_reg key, *reg; + int scount; char buf[50]; memset(&info, 0, sizeof(info)); @@ -571,11 +671,16 @@ static int handle_opq_unregistration(const struct zmsghdr *hdr, goto done; } - /* Look for client */ - for (client = reg->clients; client != NULL; - client = client->next) { - if (opq_client_match(client, &info)) - break; + /* Look for client info, count servers and notif clients too */ + client = NULL; + scount = 0; + + for (tclient = reg->clients; tclient != NULL; tclient = tclient->next) { + if (opq_client_match(tclient, &info)) + client = tclient; + + if (CHECK_FLAG(tclient->flags, OPQ_CLIENT_FLAG_RECV)) + scount++; } if (client == NULL) { @@ -592,19 +697,18 @@ static int handle_opq_unregistration(const struct zmsghdr *hdr, __func__, opq_client2str(buf, sizeof(buf), client), info.type); - if (client->prev) - client->prev->next = client->next; - if (client->next) - client->next->prev = client->prev; - if (reg->clients == client) - reg->clients = client->next; - + opq_dequeue_client(reg, client); opq_client_free(&client); + scount--; /* Is registration empty now? */ if (reg->clients == NULL) { + opq_regh_del(&opq_reg_hash, reg); opq_reg_free(®); + } else if (scount == 0) { + /* Send notifications if no more servers for the message. */ + opq_send_notifications(reg, NULL, false); } done: @@ -613,13 +717,182 @@ done: return ret; } +/* + * Handle requests about opaque notifications. + */ +static int handle_opq_notif_req(const struct zmsghdr *hdr, struct stream *msg) +{ + int ret; + struct zapi_opaque_notif_info info = {}; + struct opq_client_reg *client; + struct opq_msg_reg key, *reg; + char buf[50]; + + ret = zclient_opaque_notif_decode(msg, &info); + if (ret < 0) + goto done; + + /* Handle deregistration */ + if (!info.reg) { + ret = handle_opq_notif_unreg(&info); + goto done; + } + + memset(&key, 0, sizeof(key)); + + key.type = info.msg_type; + + reg = opq_regh_find(&opq_reg_hash, &key); + if (reg) { + /* Look for dup client */ + for (client = reg->clients; client != NULL; + client = client->next) { + if (opq_client_notif_match(client, &info)) + break; + } + + if (client) { + /* Oops - duplicate ? */ + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: duplicate opq notif reg client %s", + __func__, opq_client2str(buf, + sizeof(buf), + client)); + goto done; + } + + client = opq_client_alloc(info.proto, info.instance, + info.session_id); + SET_FLAG(client->flags, OPQ_CLIENT_FLAG_NOTIFY); + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: client %s registers for notif %u", + __func__, + opq_client2str(buf, sizeof(buf), client), + info.msg_type); + + /* Link client into registration */ + opq_enqueue_client(reg, client); + + /* Send notification if any registered servers */ + /* Look for a server */ + for (client = reg->clients; client != NULL; + client = client->next) { + if (CHECK_FLAG(client->flags, OPQ_CLIENT_FLAG_RECV)) + break; + } + if (client) + opq_send_notifications(reg, client, true); + + } else if (info.reg) { + /* + * No existing registrations - create one, add the + * client, and add registration to hash. + */ + reg = opq_reg_alloc(info.msg_type); + client = opq_client_alloc(info.proto, info.instance, + info.session_id); + SET_FLAG(client->flags, OPQ_CLIENT_FLAG_NOTIFY); + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: client %s registers for new notif %u", + __func__, + opq_client2str(buf, sizeof(buf), client), + info.msg_type); + + reg->clients = client; + + opq_regh_add(&opq_reg_hash, reg); + } + +done: + stream_free(msg); + return ret; +} + +/* + * Unregister notification + */ +static int handle_opq_notif_unreg(const struct zapi_opaque_notif_info *info) +{ + int ret = 0; + struct opq_client_reg *client; + struct opq_msg_reg key, *reg; + char buf[50]; + + memset(&key, 0, sizeof(key)); + + key.type = info->msg_type; + + reg = opq_regh_find(&opq_reg_hash, &key); + if (reg == NULL) { + /* Weird: unregister for unknown message? */ + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: unknown client %s/%u/%u unregisters notif for unknown type %u", + __func__, zebra_route_string(info->proto), + info->instance, info->session_id, + info->msg_type); + goto done; + } + + /* Look for client */ + for (client = reg->clients; client != NULL; client = client->next) { + if (opq_client_notif_match(client, info)) + break; + } + + if (client == NULL) { + /* Oops - unregister for unknown client? */ + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: unknown client %s/%u/%u unregisters notif for %u", + __func__, zebra_route_string(info->proto), + info->instance, info->session_id, + info->msg_type); + goto done; + } + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: client %s unregisters notif for %u", __func__, + opq_client2str(buf, sizeof(buf), client), + info->msg_type); + + /* Dequeue client object */ + opq_dequeue_client(reg, client); + + opq_client_free(&client); + + /* Is registration empty now? */ + if (reg->clients == NULL) { + opq_regh_del(&opq_reg_hash, reg); + opq_reg_free(®); + } + +done: + + return ret; +} + /* Compare utility for registered clients */ static bool opq_client_match(const struct opq_client_reg *client, const struct zapi_opaque_reg_info *info) { - if (client->proto == info->proto && - client->instance == info->instance && - client->session_id == info->session_id) + /* look for matching client, skip notifications */ + if (client->proto == info->proto && client->instance == info->instance && + client->session_id == info->session_id && + CHECK_FLAG(client->flags, OPQ_CLIENT_FLAG_RECV)) + return true; + else + return false; +} + +/* Compare helper for clients registered for notifications */ +static bool opq_client_notif_match(const struct opq_client_reg *client, + const struct zapi_opaque_notif_info *info) +{ + /* look for matching client, only for notifications */ + if (client->proto == info->proto && client->instance == info->instance && + client->session_id == info->session_id && + CHECK_FLAG(client->flags, OPQ_CLIENT_FLAG_NOTIFY)) return true; else return false; @@ -655,16 +928,16 @@ static void opq_reg_free(struct opq_msg_reg **reg) XFREE(MTYPE_OPQ, (*reg)); } -static struct opq_client_reg *opq_client_alloc( - const struct zapi_opaque_reg_info *info) +static struct opq_client_reg *opq_client_alloc(uint8_t proto, uint16_t instance, + uint32_t session_id) { struct opq_client_reg *client; client = XCALLOC(MTYPE_OPQ, sizeof(struct opq_client_reg)); - client->proto = info->proto; - client->instance = info->instance; - client->session_id = info->session_id; + client->proto = proto; + client->instance = instance; + client->session_id = session_id; return client; } diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 56cac1342e..7f3635702f 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* Zebra Policy Based Routing (PBR) main handling. * Copyright (C) 2018 Cumulus Networks, Inc. + * Portions: + * Copyright (c) 2021 The MITRE Corporation. + * Copyright (c) 2023 LabN Consulting, L.L.C. */ #include <zebra.h> @@ -166,10 +169,16 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg) key = jhash(rule->ifname, strlen(rule->ifname), key); - return jhash_3words(rule->rule.filter.src_port, - rule->rule.filter.dst_port, - prefix_hash_key(&rule->rule.filter.dst_ip), - jhash_1word(rule->rule.unique, key)); + key = jhash_3words(rule->rule.filter.pcp, rule->rule.filter.vlan_id, + rule->rule.filter.vlan_flags, key); + + key = jhash_3words(rule->rule.filter.src_port, + rule->rule.filter.dst_port, + prefix_hash_key(&rule->rule.filter.dst_ip), key); + + key = jhash_2words(rule->rule.unique, rule->sock, key); + + return key; } bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) @@ -185,6 +194,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (r1->rule.priority != r2->rule.priority) return false; + if (r1->sock != r2->sock) + return false; + if (r1->rule.unique != r2->rule.unique) return false; @@ -220,8 +232,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) struct pbr_rule_unique_lookup { struct zebra_pbr_rule *rule; + int sock; uint32_t unique; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; vrf_id_t vrf_id; }; @@ -230,9 +243,9 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) struct pbr_rule_unique_lookup *pul = data; struct zebra_pbr_rule *rule = b->data; - if (pul->unique == rule->rule.unique - && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0 - && pul->vrf_id == rule->vrf_id) { + if (pul->sock == rule->sock && pul->unique == rule->rule.unique && + strmatch(pul->ifname, rule->rule.ifname) && + pul->vrf_id == rule->vrf_id) { pul->rule = rule; return HASHWALK_ABORT; } @@ -246,9 +259,10 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) struct pbr_rule_unique_lookup pul; pul.unique = zrule->rule.unique; - strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ); + strlcpy(pul.ifname, zrule->rule.ifname, IFNAMSIZ); pul.rule = NULL; pul.vrf_id = zrule->vrf_id; + pul.sock = zrule->sock; hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); return pul.rule; @@ -501,6 +515,7 @@ void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty) { struct pbr_rule *prule = &rule->rule; struct zebra_pbr_action *zaction = &rule->action; + struct pbr_action *pa = &prule->action; vty_out(vty, "Rules if %s\n", rule->ifname); vty_out(vty, " Seq %u pri %u\n", prule->seq, prule->priority); @@ -516,15 +531,55 @@ void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty) if (prule->filter.filter_bm & PBR_FILTER_DST_PORT) vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port); - if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) { + if (prule->filter.filter_bm & PBR_FILTER_DSCP) vty_out(vty, " DSCP Match: %u\n", (prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2); + if (prule->filter.filter_bm & PBR_FILTER_ECN) vty_out(vty, " ECN Match: %u\n", prule->filter.dsfield & PBR_DSFIELD_ECN); - } if (prule->filter.filter_bm & PBR_FILTER_FWMARK) vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark); + if (prule->filter.filter_bm & PBR_FILTER_PCP) + vty_out(vty, " PCP Match: %u\n", prule->filter.pcp); + if (prule->filter.filter_bm & PBR_FILTER_VLAN_ID) + vty_out(vty, " VLAN ID Match: %u\n", prule->filter.vlan_id); + if (prule->filter.filter_bm & PBR_FILTER_VLAN_FLAGS) { + vty_out(vty, " VLAN Flags Match:"); + if (CHECK_FLAG(prule->filter.vlan_flags, PBR_VLAN_FLAGS_TAGGED)) + vty_out(vty, " tagged"); + if (CHECK_FLAG(prule->filter.vlan_flags, + PBR_VLAN_FLAGS_UNTAGGED)) + vty_out(vty, " untagged"); + if (CHECK_FLAG(prule->filter.vlan_flags, + PBR_VLAN_FLAGS_UNTAGGED_0)) + vty_out(vty, " untagged-or-zero"); + vty_out(vty, "\n"); + } + + if (CHECK_FLAG(pa->flags, PBR_ACTION_ECN)) + vty_out(vty, " Action: Set ECN: %u\n", pa->ecn); + if (CHECK_FLAG(pa->flags, PBR_ACTION_DSCP)) + vty_out(vty, " Action: Set DSCP: %u\n", pa->dscp >> 2); + + if (CHECK_FLAG(pa->flags, PBR_ACTION_SRC_IP)) + vty_out(vty, " Action: Set SRC IP: %pSU\n", &pa->src_ip); + if (CHECK_FLAG(pa->flags, PBR_ACTION_DST_IP)) + vty_out(vty, " Action: Set DST IP: %pSU\n", &pa->dst_ip); + if (CHECK_FLAG(pa->flags, PBR_ACTION_SRC_PORT)) + vty_out(vty, " Action: Set SRC PORT: %u\n", pa->src_port); + if (CHECK_FLAG(pa->flags, PBR_ACTION_DST_PORT)) + vty_out(vty, " Action: Set DST PORT: %u\n", pa->dst_port); + + if (CHECK_FLAG(pa->flags, PBR_ACTION_QUEUE_ID)) + vty_out(vty, " Action: Set Queue ID: %u\n", pa->queue_id); + + if (CHECK_FLAG(pa->flags, PBR_ACTION_PCP)) + vty_out(vty, " Action: Set PCP: %u\n", pa->pcp); + if (CHECK_FLAG(pa->flags, PBR_ACTION_VLAN_ID)) + vty_out(vty, " Action: Set VLAN ID: %u\n", pa->vlan_id); + if (CHECK_FLAG(pa->flags, PBR_ACTION_VLAN_STRIP_INNER_ANY)) + vty_out(vty, " Action: Strip VLAN ID\n"); vty_out(vty, " Tableid: %u\n", prule->action.table); if (zaction->afi == AFI_IP) @@ -1118,7 +1173,7 @@ static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, uint16_t port_min, uint16_t port_max, uint8_t proto) { - if (!(filter_bm & PBR_FILTER_PROTO)) { + if (!(filter_bm & PBR_FILTER_IP_PROTOCOL)) { if (port_max) vty_out(vty, ":udp/tcp:%d-%d", port_min, port_max); diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 15ad4e35cf..1e4b5cd0f3 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -46,7 +46,7 @@ struct zebra_pbr_rule { struct pbr_rule rule; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; struct zebra_pbr_action action; @@ -61,8 +61,6 @@ struct zebra_pbr_rule { (r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT) #define IS_RULE_FILTERING_ON_DST_PORT(r) \ (r->rule.filter.filter_bm & PBR_FILTER_DST_PORT) -#define IS_RULE_FILTERING_ON_DSFIELD(r) \ - (r->rule.filter.filter_bm & PBR_FILTER_DSFIELD) #define IS_RULE_FILTERING_ON_FWMARK(r) \ (r->rule.filter.filter_bm & PBR_FILTER_FWMARK) diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index a1fee840df..d7d752f01e 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -16,6 +16,7 @@ #include "ptm_lib.h" #include "rib.h" #include "stream.h" +#include "lib/version.h" #include "vrf.h" #include "vty.h" #include "lib_errors.h" @@ -85,7 +86,6 @@ struct zebra_ptm_cb ptm_cb; static int zebra_ptm_socket_init(void); void zebra_ptm_sock_read(struct event *thread); -static void zebra_ptm_install_commands(void); static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt); void zebra_bfd_peer_replay_req(void); void zebra_ptm_send_status_req(void); @@ -114,7 +114,6 @@ void zebra_ptm_init(void) } ptm_cb.pid = getpid(); - zebra_ptm_install_commands(); snprintf(buf, sizeof(buf), "%s", FRR_PTM_NAME); ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb, @@ -239,10 +238,7 @@ void zebra_ptm_connect(struct event *t) } } -DEFUN (zebra_ptm_enable, - zebra_ptm_enable_cmd, - "ptm-enable", - "Enable neighbor check with specified topology\n") +void zebra_global_ptm_enable(void) { struct vrf *vrf; struct interface *ifp; @@ -265,27 +261,16 @@ DEFUN (zebra_ptm_enable, } zebra_ptm_connect(NULL); - - return CMD_SUCCESS; } -DEFUN (no_zebra_ptm_enable, - no_zebra_ptm_enable_cmd, - "no ptm-enable", - NO_STR - "Enable neighbor check with specified topology\n") +void zebra_global_ptm_disable(void) { ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; zebra_ptm_reset_status(1); - return CMD_SUCCESS; } -DEFUN (zebra_ptm_enable_if, - zebra_ptm_enable_if_cmd, - "ptm-enable", - "Enable neighbor check with specified topology\n") +void zebra_if_ptm_enable(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *if_data; int old_ptm_enable; int send_linkdown = 0; @@ -294,7 +279,7 @@ DEFUN (zebra_ptm_enable_if, if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; if (ifp->ifindex == IFINDEX_INTERNAL) { - return CMD_SUCCESS; + return; } old_ptm_enable = ifp->ptm_enable; @@ -311,19 +296,12 @@ DEFUN (zebra_ptm_enable_if, if_down(ifp); } } - - return CMD_SUCCESS; } -DEFUN (no_zebra_ptm_enable_if, - no_zebra_ptm_enable_if_cmd, - "no ptm-enable", - NO_STR - "Enable neighbor check with specified topology\n") +void zebra_if_ptm_disable(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); - int send_linkup = 0; struct zebra_if *if_data; + int send_linkup = 0; if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) { if (!if_is_operative(ifp)) @@ -340,17 +318,6 @@ DEFUN (no_zebra_ptm_enable_if, if_data = ifp->info; if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; - - return CMD_SUCCESS; -} - - -void zebra_ptm_write(struct vty *vty) -{ - if (ptm_cb.ptm_enable) - vty_out(vty, "ptm-enable\n"); - - return; } static int zebra_ptm_socket_init(void) @@ -393,14 +360,6 @@ static int zebra_ptm_socket_init(void) return sock; } -static void zebra_ptm_install_commands(void) -{ - install_element(CONFIG_NODE, &zebra_ptm_enable_cmd); - install_element(CONFIG_NODE, &no_zebra_ptm_enable_cmd); - install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd); - install_element(INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd); -} - /* BFD session goes down, send message to the protocols. */ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp, struct prefix *sp, int status, @@ -677,7 +636,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) uint8_t detect_mul; unsigned int min_rx_timer; unsigned int min_tx_timer; - char if_name[INTERFACE_NAMSIZ]; + char if_name[IFNAMSIZ]; uint8_t len; void *out_ctxt; char buf[INET6_ADDRSTRLEN]; @@ -840,7 +799,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) struct prefix src_p; struct prefix dst_p; uint8_t multi_hop; - char if_name[INTERFACE_NAMSIZ]; + char if_name[IFNAMSIZ]; uint8_t len; char buf[INET6_ADDRSTRLEN]; char tmp_buf[64]; @@ -1164,12 +1123,6 @@ void zebra_ptm_if_set_ptm_state(struct interface *ifp, ifp->ptm_enable = zebra_ifp->ptm_enable; } -void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp) -{ - if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF) - vty_out(vty, " no ptm-enable\n"); -} - #else /* HAVE_BFDD */ /* @@ -1184,7 +1137,7 @@ struct ptm_process { TAILQ_HEAD(ppqueue, ptm_process) ppqueue; DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS, - "PTM BFD process registration table."); + "PTM BFD process reg table"); /* * Prototypes. @@ -1532,16 +1485,6 @@ void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)), /* NOTHING */ } -void zebra_ptm_write(struct vty *vty __attribute__((__unused__))) -{ - /* NOTHING */ -} - -void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)), - struct zebra_if *zifp __attribute__((__unused__))) -{ - /* NOTHING */ -} void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)), struct zebra_if *zi __attribute__((__unused__))) { diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 1b2f7a02d4..20a53e2fea 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -53,14 +53,20 @@ struct zebra_ptm_cb { (protocol) == ZEBRA_ROUTE_OSPF6 || (protocol) == ZEBRA_ROUTE_ISIS || \ (protocol) == ZEBRA_ROUTE_PIM || \ (protocol) == ZEBRA_ROUTE_OPENFABRIC || \ - (protocol) == ZEBRA_ROUTE_STATIC) + (protocol) == ZEBRA_ROUTE_STATIC || (protocol) == ZEBRA_ROUTE_RIP) void zebra_ptm_init(void); void zebra_ptm_finish(void); void zebra_ptm_connect(struct event *t); -void zebra_ptm_write(struct vty *vty); int zebra_ptm_get_enable_state(void); +#if HAVE_BFDD == 0 +void zebra_global_ptm_enable(void); +void zebra_global_ptm_disable(void); +void zebra_if_ptm_enable(struct interface *ifp); +void zebra_if_ptm_disable(struct interface *ifp); +#endif + /* ZAPI message handlers */ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS); void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS); @@ -74,7 +80,6 @@ void zebra_ptm_show_status(struct vty *vty, json_object *json, void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); -void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp); #ifdef __cplusplus } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 12dcac1de5..deed3b6ad3 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -377,15 +377,18 @@ static int zebra_pw_client_close(struct zserv *client) return 0; } -void zebra_pw_init(struct zebra_vrf *zvrf) +static void zebra_pw_init(void) +{ + hook_register(zserv_client_close, zebra_pw_client_close); +} + +void zebra_pw_init_vrf(struct zebra_vrf *zvrf) { RB_INIT(zebra_pw_head, &zvrf->pseudowires); RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires); - - hook_register(zserv_client_close, zebra_pw_client_close); } -void zebra_pw_exit(struct zebra_vrf *zvrf) +void zebra_pw_exit_vrf(struct zebra_vrf *zvrf) { struct zebra_pw *pw; @@ -396,6 +399,11 @@ void zebra_pw_exit(struct zebra_vrf *zvrf) } } +void zebra_pw_terminate(void) +{ + hook_unregister(zserv_client_close, zebra_pw_client_close); +} + DEFUN_NOSH (pseudowire_if, pseudowire_if_cmd, "pseudowire IFNAME", @@ -408,8 +416,6 @@ DEFUN_NOSH (pseudowire_if, int idx = 0; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return CMD_WARNING; argv_find(argv, argc, "IFNAME", &idx); ifname = argv[idx]->arg; @@ -440,8 +446,6 @@ DEFUN (no_pseudowire_if, int idx = 0; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return CMD_WARNING; argv_find(argv, argc, "IFNAME", &idx); ifname = argv[idx]->arg; @@ -564,8 +568,6 @@ DEFUN (show_pseudowires, struct zebra_pw *pw; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return 0; vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor", "Labels", "Protocol", "Status"); @@ -603,8 +605,6 @@ static void vty_show_mpls_pseudowire_detail(struct vty *vty) struct nexthop_group *nhg; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return; RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) { char buf_nbr[INET6_ADDRSTRLEN]; @@ -759,8 +759,6 @@ static void vty_show_mpls_pseudowire_detail_json(struct vty *vty) struct zebra_pw *pw; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return; json = json_object_new_object(); json_pws = json_object_new_array(); @@ -795,8 +793,6 @@ static int zebra_pw_config(struct vty *vty) struct zebra_pw *pw; zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return 0; RB_FOREACH (pw, zebra_static_pw_head, &zvrf->static_pseudowires) { vty_out(vty, "pseudowire %s\n", pw->ifname); @@ -849,4 +845,6 @@ void zebra_pw_vty_init(void) install_element(VIEW_NODE, &show_pseudowires_cmd); install_element(VIEW_NODE, &show_pseudowires_detail_cmd); + + zebra_pw_init(); } diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index fd94d5e5ed..431d663f7c 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -24,7 +24,7 @@ extern "C" { struct zebra_pw { RB_ENTRY(zebra_pw) pw_entry, static_pw_entry; vrf_id_t vrf_id; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int type; int af; @@ -60,8 +60,9 @@ void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *); void zebra_pw_update(struct zebra_pw *); void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus); -void zebra_pw_init(struct zebra_vrf *); -void zebra_pw_exit(struct zebra_vrf *); +void zebra_pw_init_vrf(struct zebra_vrf *); +void zebra_pw_exit_vrf(struct zebra_vrf *); +void zebra_pw_terminate(void); void zebra_pw_vty_init(void); #ifdef __cplusplus diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index adcaf64044..5b95d8668a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -5,6 +5,10 @@ #include <zebra.h> +#ifdef GNU_LINUX +#include <linux/rtnetlink.h> +#endif + #include "command.h" #include "if.h" #include "linklist.h" @@ -25,6 +29,7 @@ #include "frr_pthread.h" #include "printfrr.h" #include "frrscript.h" +#include "frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/connected.h" @@ -103,6 +108,9 @@ static const struct { [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, ZEBRA_CONNECT_DISTANCE_DEFAULT, META_QUEUE_CONNECTED}, + [ZEBRA_ROUTE_LOCAL] = {ZEBRA_ROUTE_LOCAL, + ZEBRA_CONNECT_DISTANCE_DEFAULT, + META_QUEUE_CONNECTED}, [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, ZEBRA_STATIC_DISTANCE_DEFAULT, META_QUEUE_STATIC}, @@ -130,6 +138,7 @@ static const struct { [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, ZEBRA_MAX_DISTANCE_DEFAULT, META_QUEUE_OTHER}, [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, ZEBRA_TABLE_DISTANCE_DEFAULT, META_QUEUE_STATIC}, + [ZEBRA_ROUTE_TABLE_DIRECT] = {ZEBRA_ROUTE_TABLE_DIRECT, ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT, META_QUEUE_STATIC}, [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, ZEBRA_LDP_DISTANCE_DEFAULT, META_QUEUE_OTHER}, [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, ZEBRA_EBGP_DISTANCE_DEFAULT, @@ -177,6 +186,7 @@ struct wq_nhg_wrapper { struct nhg_ctx *ctx; struct nhg_hash_entry *nhe; } u; + bool deletion; }; #define WQ_NHG_WRAPPER_TYPE_CTX 0x01 @@ -330,7 +340,7 @@ static char *_dump_re_status(const struct route_entry *re, char *buf, : "", CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "", CHECK_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING) - ? "Replacing" + ? "Replacing " : "", CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed " : "", @@ -365,7 +375,7 @@ int is_zebra_valid_kernel_table(uint32_t table_id) int is_zebra_main_routing_table(uint32_t table_id) { - if (table_id == RT_TABLE_MAIN) + if (table_id == rt_table_main_id) return 1; return 0; } @@ -428,18 +438,29 @@ int route_entry_update_nhe(struct route_entry *re, done: /* Detach / deref previous nhg */ - if (old_nhg) + + if (old_nhg) { + /* + * Return true if we are deleting the previous NHE + * Note: we dont check the return value of the function anywhere + * except at rib_handle_nhg_replace(). + */ + if (old_nhg->refcnt == 1) + ret = 1; + zebra_nhg_decrement_ref(old_nhg); + } return ret; } -void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, - struct nhg_hash_entry *new_entry) +int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, + struct nhg_hash_entry *new_entry) { struct zebra_router_table *zrt; struct route_node *rn; struct route_entry *re, *next; + int ret = 0; if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p", @@ -451,10 +472,17 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry, rn = srcdest_route_next(rn)) { RNODE_FOREACH_RE_SAFE (rn, re, next) { if (re->nhe && re->nhe == old_entry) - route_entry_update_nhe(re, new_entry); + ret += route_entry_update_nhe(re, + new_entry); } } } + + /* + * if ret > 0, some previous re->nhe has freed the address to which + * old_entry is pointing. + */ + return ret; } struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, @@ -503,7 +531,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, if (rn) route_lock_node(rn); } else { - if (match->type != ZEBRA_ROUTE_CONNECT) { + if (match->type != ZEBRA_ROUTE_CONNECT && + match->type != ZEBRA_ROUTE_LOCAL) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) return NULL; @@ -605,7 +634,8 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) if (!match) return NULL; - if (match->type == ZEBRA_ROUTE_CONNECT) + if (match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL) return match; if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) @@ -1104,27 +1134,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } -/* Check if 'alternate' RIB entry is better than 'current'. */ -static struct route_entry *rib_choose_best(struct route_entry *current, - struct route_entry *alternate) +static struct route_entry *rib_choose_best_type(uint8_t route_type, + struct route_entry *current, + struct route_entry *alternate) { - if (current == NULL) - return alternate; - - /* filter route selection in following order: - * - connected beats other types - * - if both connected, loopback or vrf wins - * - lower distance beats higher - * - lower metric beats higher for equal distance - * - last, hence oldest, route wins tie break. - */ - - /* Connected routes. Check to see if either are a vrf - * or loopback interface. If not, pick the last connected - * route of the set of lowest metric connected routes. + /* + * We know that alternate and current are now non-NULL */ - if (alternate->type == ZEBRA_ROUTE_CONNECT) { - if (current->type != ZEBRA_ROUTE_CONNECT) + if (alternate->type == route_type) { + if (current->type != route_type) return alternate; /* both are connected. are either loop or vrf? */ @@ -1153,7 +1171,41 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return current; } - if (current->type == ZEBRA_ROUTE_CONNECT) + return NULL; +} + +/* Check if 'alternate' RIB entry is better than 'current'. */ +static struct route_entry *rib_choose_best(struct route_entry *current, + struct route_entry *alternate) +{ + struct route_entry *possible; + + if (current == NULL) + return alternate; + + /* filter route selection in following order: + * - Local beats Connected + * - connected beats other types + * - if both connected, loopback or vrf wins + * - lower distance beats higher + * - lower metric beats higher for equal distance + * - last, hence oldest, route wins tie break. + */ + + /* Connected or Local routes. Check to see if either are a vrf + * or loopback interface. If not, pick the last connected + * route of the set of lowest metric connected routes. + */ + possible = rib_choose_best_type(ZEBRA_ROUTE_LOCAL, current, alternate); + if (possible) + return possible; + + possible = rib_choose_best_type(ZEBRA_ROUTE_CONNECT, current, alternate); + if (possible) + return possible; + + if (current->type == ZEBRA_ROUTE_CONNECT || + current->type == ZEBRA_ROUTE_LOCAL) return current; /* higher distance loses */ @@ -1182,6 +1234,7 @@ static void rib_process(struct route_node *rn) rib_dest_t *dest; struct zebra_vrf *zvrf = NULL; struct vrf *vrf; + struct route_entry *proto_re_changed = NULL; vrf_id_t vrf_id = VRF_UNKNOWN; @@ -1251,6 +1304,7 @@ static void rib_process(struct route_node *rn) * skip it. */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { + proto_re_changed = re; if (!nexthop_active_update(rn, re)) { const struct prefix *p; struct rib_table_info *info; @@ -1336,6 +1390,8 @@ static void rib_process(struct route_node *rn) * new_selected --- RE entry that is newly SELECTED * old_fib --- RE entry currently in kernel FIB * new_fib --- RE entry that is newly to be in kernel FIB + * proto_re_changed -- RE that is the last changed entry in the + * list of RE's. * * new_selected will get SELECTED flag, and is going to be redistributed * the zclients. new_fib (which can be new_selected) will be installed @@ -1390,6 +1446,22 @@ static void rib_process(struct route_node *rn) } } + /* + * If zebra has a new_selected and a proto_re_changed + * entry that was not the old selected and the protocol + * is different, zebra should notify the upper level + * protocol that the sent down entry was not selected + */ + if (new_selected && proto_re_changed && + proto_re_changed != old_selected && + new_selected->type != proto_re_changed->type) { + struct rib_table_info *info = srcdest_rnode_table_info(rn); + + zsend_route_notify_owner(rn, proto_re_changed, + ZAPI_ROUTE_BETTER_ADMIN_WON, info->afi, + info->safi); + } + /* Update fib according to selection results */ if (new_fib && old_fib) rib_process_update_fib(zvrf, rn, old_fib, new_fib); @@ -1438,7 +1510,7 @@ static void zebra_rib_evaluate_mpls(struct route_node *rn) */ static bool rib_route_match_ctx(const struct route_entry *re, const struct zebra_dplane_ctx *ctx, - bool is_update) + bool is_update, bool async) { bool result = false; @@ -1454,13 +1526,12 @@ static bool rib_route_match_ctx(const struct route_entry *re, /* We use an extra test for statics, and another for * kernel routes. */ - if (re->type == ZEBRA_ROUTE_STATIC && + if (re->type == ZEBRA_ROUTE_STATIC && !async && (re->distance != dplane_ctx_get_old_distance(ctx) || re->tag != dplane_ctx_get_old_tag(ctx))) { result = false; } else if (re->type == ZEBRA_ROUTE_KERNEL && - re->metric != - dplane_ctx_get_old_metric(ctx)) { + re->metric != dplane_ctx_get_old_metric(ctx)) { result = false; } } @@ -1482,14 +1553,15 @@ static bool rib_route_match_ctx(const struct route_entry *re, /* We use an extra test for statics, and another for * kernel routes. */ - if (re->type == ZEBRA_ROUTE_STATIC && + if (re->type == ZEBRA_ROUTE_STATIC && !async && (re->distance != dplane_ctx_get_distance(ctx) || re->tag != dplane_ctx_get_tag(ctx))) { result = false; } else if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != dplane_ctx_get_metric(ctx)) { result = false; - } else if (re->type == ZEBRA_ROUTE_CONNECT) { + } else if (re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) { result = nexthop_group_equal_no_recurse( &re->nhe->nhg, dplane_ctx_get_ng(ctx)); } @@ -1547,7 +1619,7 @@ static bool rib_compare_routes(const struct route_entry *re1, * v6 link-locals, and we also support multiple addresses in the same * subnet on a single interface. */ - if (re1->type != ZEBRA_ROUTE_CONNECT) + if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL) return true; return false; @@ -1946,13 +2018,13 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) RNODE_FOREACH_RE(rn, rib) { if (re == NULL) { - if (rib_route_match_ctx(rib, ctx, false)) + if (rib_route_match_ctx(rib, ctx, false, false)) re = rib; } /* Check for old route match */ if (is_update && (old_re == NULL)) { - if (rib_route_match_ctx(rib, ctx, true /*is_update*/)) + if (rib_route_match_ctx(rib, ctx, true, false)) old_re = rib; } @@ -1997,9 +2069,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } - switch (op) { - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: + if (op == DPLANE_OP_ROUTE_INSTALL || op == DPLANE_OP_ROUTE_UPDATE) { if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { if (re) { UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); @@ -2090,8 +2160,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx), rn); } - break; - case DPLANE_OP_ROUTE_DELETE: + } else if (op == DPLANE_OP_ROUTE_DELETE) { rt_delete = true; if (re) SET_FLAG(re->status, ROUTE_ENTRY_FAILED); @@ -2130,60 +2199,6 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if ((re && RIB_SYSTEM_ROUTE(re)) || (old_re && RIB_SYSTEM_ROUTE(old_re))) zebra_rib_fixup_system(rn); - break; - - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - 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_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - break; } zebra_rib_evaluate_rn_nexthops(rn, seq, rt_delete); @@ -2271,7 +2286,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) * info. */ RNODE_FOREACH_RE(rn, re) { - if (rib_route_match_ctx(re, ctx, false /*!update*/)) + if (rib_route_match_ctx(re, ctx, false, true)) break; } @@ -2517,7 +2532,7 @@ static void process_subq_evpn(struct listnode *lnode) static void process_subq_nhg(struct listnode *lnode) { struct nhg_ctx *ctx; - struct nhg_hash_entry *nhe, *newnhe; + struct nhg_hash_entry *nhe, *newnhe, *oldnhe; struct wq_nhg_wrapper *w; uint8_t qindex = META_QUEUE_NHG; @@ -2549,15 +2564,33 @@ static void process_subq_nhg(struct listnode *lnode) subqueue2str(qindex)); /* Process incoming nhg update, probably from a proto daemon */ - newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, - nhe->zapi_instance, - nhe->zapi_session, &nhe->nhg, 0); + if (w->deletion) { + /* + * Delete the received nhg id + */ + oldnhe = zebra_nhg_proto_del(nhe->id, nhe->type); + if (oldnhe) { + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_REMOVED); + zebra_nhg_decrement_ref(oldnhe); + } else + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_REMOVE_FAIL); - /* Report error to daemon via ZAPI */ - if (newnhe == NULL) - zsend_nhg_notify(nhe->type, nhe->zapi_instance, - nhe->zapi_session, nhe->id, - ZAPI_NHG_FAIL_INSTALL); + } else { + newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, + nhe->zapi_instance, + nhe->zapi_session, + &nhe->nhg, 0); + + /* Report error to daemon via ZAPI */ + if (newnhe == NULL) + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_FAIL_INSTALL); + } /* Free temp nhe - we own that memory. */ zebra_nhg_free(nhe); @@ -2660,6 +2693,7 @@ static void early_route_memory_free(struct zebra_early_route *ere) if (ere->re_nhe) zebra_nhg_free(ere->re_nhe); + zapi_re_opaque_free(ere->re->opaque); XFREE(MTYPE_RE, ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -2706,6 +2740,8 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) return; } } else { + struct nexthop *tmp_nh; + /* Lookup nhe from route information */ nhe = zebra_nhg_rib_find_nhe(ere->re_nhe, ere->afi); if (!nhe) { @@ -2723,6 +2759,22 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) early_route_memory_free(ere); return; } + for (ALL_NEXTHOPS(nhe->nhg, tmp_nh)) { + if (CHECK_FLAG(tmp_nh->flags, NEXTHOP_FLAG_EVPN)) { + struct ipaddr vtep_ip = {}; + + if (ere->afi == AFI_IP) { + vtep_ip.ipa_type = IPADDR_V4; + vtep_ip.ipaddr_v4 = tmp_nh->gate.ipv4; + } else { + vtep_ip.ipa_type = IPADDR_V6; + vtep_ip.ipaddr_v6 = tmp_nh->gate.ipv6; + } + zebra_rib_queue_evpn_route_add( + re->vrf_id, &tmp_nh->rmac, &vtep_ip, + &ere->p); + } + } } /* @@ -2823,14 +2875,17 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); rib_addnode(rn, re, 1); + dest = rib_dest_from_rnode(rn); /* Free implicit route.*/ - if (same) + if (same) { + if (dest && same == dest->selected_fib) + SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING); rib_delnode(rn, same); + } /* See if we can remove some RE entries that are queued for * removal, but won't be considered in rib processing. */ - dest = rib_dest_from_rnode(rn); RNODE_FOREACH_RE_SAFE (rn, re, same) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { /* If the route was used earlier, must retain it. */ @@ -2907,8 +2962,8 @@ static void process_subq_early_route_delete(struct zebra_early_route *ere) struct nexthop *nh = NULL; - if (ere->re->nhe) - nh = ere->re->nhe->nhg.nexthop; + if (ere->re_nhe) + nh = ere->re_nhe->nhg.nexthop; /* Lookup same type route. */ RNODE_FOREACH_RE (rn, re) { @@ -2926,7 +2981,9 @@ static void process_subq_early_route_delete(struct zebra_early_route *ere) if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != ere->re->metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = nh) && + if ((re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) && + (rtnh = re->nhe->nhg.nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -3232,12 +3289,26 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) return -1; /* Invariant: at this point we always have rn->info set. */ - if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_QUEUED(qindex))) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) + /* A route node must only be in one sub-queue at a time. */ + if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags, MQ_BIT_MASK)) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + /* + * curr_qindex_bitmask is power of 2, because a route node must only be in one sub-queue at a time, + * so for getting current sub-queue index from bitmask we may use part of classic msb function + * (find most significant set bit). + */ + const uint32_t curr_qindex_bitmask = CHECK_FLAG(rib_dest_from_rnode(rn)->flags, MQ_BIT_MASK); + static const uint8_t pos[32] = { 0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, + 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + + curr_qindex = pos[(uint32_t)(curr_qindex_bitmask * 0x077CB531UL) >> 27]; + rnode_debug(rn, re->vrf_id, "rn %p is already queued in sub-queue %s", - (void *)rn, subqueue2str(qindex)); + (void *)rn, subqueue2str(curr_qindex)); + } + return -1; } @@ -3286,7 +3357,8 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) return 0; } -static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +static int rib_meta_queue_nhg_process(struct meta_queue *mq, void *data, + bool deletion) { struct nhg_hash_entry *nhe = NULL; uint8_t qindex = META_QUEUE_NHG; @@ -3301,6 +3373,7 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) w->type = WQ_NHG_WRAPPER_TYPE_NHG; w->u.nhe = nhe; + w->deletion = deletion; listnode_add(mq->subq[qindex], w); mq->size++; @@ -3312,6 +3385,16 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) return 0; } +static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +{ + return rib_meta_queue_nhg_process(mq, data, false); +} + +static int rib_meta_queue_nhg_del(struct meta_queue *mq, void *data) +{ + return rib_meta_queue_nhg_process(mq, data, true); +} + static int rib_meta_queue_evpn_add(struct meta_queue *mq, void *data) { listnode_add(mq->subq[META_QUEUE_EVPN], data); @@ -3420,6 +3503,17 @@ int rib_queue_nhe_add(struct nhg_hash_entry *nhe) } /* + * Enqueue incoming nhg from proto daemon for processing + */ +int rib_queue_nhe_del(struct nhg_hash_entry *nhe) +{ + if (nhe == NULL) + return -1; + + return mq_add_handler(nhe, rib_meta_queue_nhg_del); +} + +/* * Enqueue evpn route for processing */ int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, @@ -3978,6 +4072,10 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) if (IS_ZEBRA_DEBUG_RIB) rnode_debug(rn, re->vrf_id, "rn %p, re %p, removing", (void *)rn, (void *)re); + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + route_entry_dump(&rn->p, NULL, re); + SET_FLAG(re->status, ROUTE_ENTRY_REMOVED); afi = (rn->p.family == AF_INET) @@ -4023,7 +4121,6 @@ static void _route_entry_dump_nh(const struct route_entry *re, ifp ? ifp->name : "Unknown"); break; case NEXTHOP_TYPE_IPV4: - /* fallthrough */ case NEXTHOP_TYPE_IPV4_IFINDEX: inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN); break; @@ -4123,8 +4220,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zclient_dump_route_flags(re->flags, flags_buf, sizeof(flags_buf)), _dump_re_status(re, status_buf, sizeof(status_buf))); - zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, - nexthop_group_nexthop_num(&(re->nhe->nhg)), + zlog_debug("%s: tag == %u, nexthop_num == %u, nexthop_active_num == %u", + straddr, re->tag, nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); /* Dump nexthops */ @@ -4161,10 +4258,10 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) mq->size++; if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - "Route %pFX(%u) queued for processing into sub-queue %s", - &ere->p, ere->re->vrf_id, - subqueue2str(META_QUEUE_EARLY_ROUTE)); + zlog_debug("Route %pFX(%u) (%s) queued for processing into sub-queue %s", + &ere->p, ere->re->vrf_id, + ere->deletion ? "delete" : "add", + subqueue2str(META_QUEUE_EARLY_ROUTE)); return 0; } @@ -4207,6 +4304,12 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, return re; } + +void zebra_rib_route_entry_free(struct route_entry *re) +{ + XFREE(MTYPE_RE, re); +} + /* * Internal route-add implementation; there are a couple of different public * signatures. Callers in this path are responsible for the memory they @@ -4704,6 +4807,21 @@ static void rib_process_dplane_results(struct event *thread) struct dplane_ctx_list_head ctxlist; bool shut_p = false; +#ifdef HAVE_SCRIPTING + char *script_name = + frrscript_names_get_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL); + + int ret = 1; + struct frrscript *fs = NULL; + + if (script_name) { + fs = frrscript_new(script_name); + if (fs) + ret = frrscript_load(fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL, + NULL); + } +#endif /* HAVE_SCRIPTING */ + /* Dequeue a list of completed updates with one lock/unlock cycle */ do { @@ -4737,24 +4855,7 @@ static void rib_process_dplane_results(struct event *thread) continue; } -#ifdef HAVE_SCRIPTING - char *script_name = frrscript_names_get_script_name( - ZEBRA_ON_RIB_PROCESS_HOOK_CALL); - - int ret = 1; - struct frrscript *fs; - - if (script_name) { - fs = frrscript_new(script_name); - if (fs) - ret = frrscript_load( - fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL, - NULL); - } -#endif /* HAVE_SCRIPTING */ - while (ctx) { - #ifdef HAVE_SCRIPTING if (ret == 0) frrscript_call(fs, @@ -4859,8 +4960,12 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: break; + case DPLANE_OP_STARTUP_STAGE: + zebra_ns_startup_continue(ctx); + break; } /* Dispatch by op code */ @@ -4869,6 +4974,11 @@ static void rib_process_dplane_results(struct event *thread) } } while (1); + +#ifdef HAVE_SCRIPTING + if (fs) + frrscript_delete(fs); +#endif } /* @@ -4913,7 +5023,7 @@ static void check_route_info(void) } /* Routing information base initialize. */ -void rib_init(void) +void zebra_rib_init(void) { check_route_info(); @@ -4925,6 +5035,20 @@ void rib_init(void) zebra_dplane_init(rib_dplane_results); } +void zebra_rib_terminate(void) +{ + struct zebra_dplane_ctx *ctx; + + EVENT_OFF(t_dplane); + + ctx = dplane_ctx_dequeue(&rib_dplane_q); + while (ctx) { + dplane_ctx_fini(&ctx); + + ctx = dplane_ctx_dequeue(&rib_dplane_q); + } +} + /* * vrf_id_get_next * @@ -4978,7 +5102,7 @@ struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter) iter->vrf_id = VRF_DEFAULT; iter->afi_safi_ix = -1; - /* Fall through */ + fallthrough; case RIB_TABLES_ITER_S_ITERATING: iter->afi_safi_ix++; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 3bbcd38d1c..b387e9949b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -513,10 +513,14 @@ static bool rnh_check_re_nexthops(const struct route_entry *re, goto done; } - /* Some special checks if registration asked for them. */ + /* + * Some special checks if registration asked for them. + * LOCAL routes are by their definition not CONNECTED + * and as such should not be considered here + */ if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { - if ((re->type == ZEBRA_ROUTE_CONNECT) - || (re->type == ZEBRA_ROUTE_STATIC)) + if ((re->type == ZEBRA_ROUTE_CONNECT) || + (re->type == ZEBRA_ROUTE_STATIC)) ret = true; if (re->type == ZEBRA_ROUTE_NHRP) { @@ -1268,6 +1272,7 @@ void show_nexthop_json_helper(json_object *json_nexthop, json_object *json_backups = NULL; json_object *json_seg6local = NULL; json_object *json_seg6 = NULL; + json_object *json_segs = NULL; int i; json_object_int_add(json_nexthop, "flags", nexthop->flags); @@ -1425,11 +1430,31 @@ void show_nexthop_json_helper(json_object *json_nexthop, nexthop->nh_srv6->seg6local_action)); json_object_object_add(json_nexthop, "seg6local", json_seg6local); - - json_seg6 = json_object_new_object(); - json_object_string_addf(json_seg6, "segs", "%pI6", - &nexthop->nh_srv6->seg6_segs); - json_object_object_add(json_nexthop, "seg6", json_seg6); + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs == 1) { + json_seg6 = json_object_new_object(); + json_object_string_addf(json_seg6, "segs", "%pI6", + &nexthop->nh_srv6->seg6_segs + ->seg[0]); + json_object_object_add(json_nexthop, "seg6", json_seg6); + } else { + if (nexthop->nh_srv6->seg6_segs) { + json_segs = json_object_new_array(); + for (int seg_idx = 0; + seg_idx < + nexthop->nh_srv6->seg6_segs->num_segs; + seg_idx++) + json_object_array_add( + json_segs, + json_object_new_stringf( + "%pI6", + &nexthop->nh_srv6 + ->seg6_segs + ->seg[seg_idx])); + json_object_object_add(json_nexthop, "seg6", + json_segs); + } + } } } @@ -1440,7 +1465,9 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, const struct nexthop *nexthop) { char buf[MPLS_LABEL_STRLEN]; - int i; + char seg_buf[SRV6_SEG_STRLEN]; + struct seg6_segs segs; + uint8_t i; switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -1532,11 +1559,23 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, seg6local_context2str(buf, sizeof(buf), &nexthop->nh_srv6->seg6local_ctx, nexthop->nh_srv6->seg6local_action); - vty_out(vty, ", seg6local %s %s", - seg6local_action2str( - nexthop->nh_srv6->seg6local_action), - buf); - vty_out(vty, ", seg6 %pI6", &nexthop->nh_srv6->seg6_segs); + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + vty_out(vty, ", seg6local %s %s", + seg6local_action2str( + nexthop->nh_srv6->seg6local_action), + buf); + if (nexthop->nh_srv6->seg6_segs && + IPV6_ADDR_CMP(&nexthop->nh_srv6->seg6_segs->seg[0], + &in6addr_any)) { + segs.num_segs = nexthop->nh_srv6->seg6_segs->num_segs; + for (i = 0; i < segs.num_segs; i++) + memcpy(&segs.segs[i], + &nexthop->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); + snprintf_seg6_segs(seg_buf, SRV6_SEG_STRLEN, &segs); + vty_out(vty, ", seg6 %s", seg_buf); + } } if (nexthop->weight) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 142501b149..95da789108 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -14,7 +14,6 @@ #include "filter.h" #include "plist.h" #include "nexthop.h" -#include "northbound_cli.h" #include "lib/route_types.h" #include "vrf.h" #include "frrstr.h" @@ -24,6 +23,7 @@ #include "zebra/debug.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" +#include "zebra/zebra_vrf.h" #include "zebra/zebra_routemap_clippy.c" @@ -31,17 +31,11 @@ static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER; static struct event *zebra_t_rmap_update = NULL; char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; -struct nh_rmap_obj { +struct zebra_rmap_obj { struct nexthop *nexthop; - vrf_id_t vrf_id; - uint32_t source_protocol; - uint8_t instance; - int metric; - route_tag_t tag; + struct route_entry *re; }; -static void zebra_route_map_set_delay_timer(uint32_t value); - /* 'match tag TAG' * Match function return 1 if match is success else return 0 */ @@ -49,12 +43,12 @@ static enum route_map_cmd_result_t route_match_tag(void *rule, const struct prefix *prefix, void *object) { route_tag_t *tag; - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; tag = rule; - nh_data = object; + rm_data = object; - if (nh_data->tag == *tag) + if (rm_data->re->tag == *tag) return RMAP_MATCH; return RMAP_NOMATCH; @@ -74,19 +68,19 @@ static const struct route_map_rule_cmd route_match_tag_cmd = { static enum route_map_cmd_result_t route_match_interface(void *rule, const struct prefix *prefix, void *object) { - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; char *ifname = rule; ifindex_t ifindex; if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; - nh_data = object; - if (!nh_data || !nh_data->nexthop) + rm_data = object; + if (!rm_data || !rm_data->nexthop) return RMAP_NOMATCH; - ifindex = ifname2ifindex(ifname, nh_data->vrf_id); + ifindex = ifname2ifindex(ifname, rm_data->nexthop->vrf_id); if (ifindex == 0) return RMAP_NOMATCH; - if (nh_data->nexthop->ifindex == ifindex) + if (rm_data->nexthop->ifindex == ifindex) return RMAP_MATCH; return RMAP_NOMATCH; @@ -288,8 +282,8 @@ static const struct route_map_rule_cmd route_match_interface_cmd = { route_match_interface_free }; -static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, - int rtype, afi_t afi, safi_t safi) +int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, + afi_t afi, safi_t safi) { struct route_table *table; @@ -321,8 +315,8 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; } -static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, - int rtype, afi_t afi, safi_t safi) +int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, + afi_t afi, safi_t safi) { struct route_table *table; @@ -350,8 +344,7 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; } -static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, - int afi) +int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, int afi) { if (NHT_RM_NAME(zvrf, afi, rtype)) { @@ -367,13 +360,12 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) - zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); + zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST); return CMD_SUCCESS; } -static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, - int afi) +int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, int afi) { if (!NHT_RM_NAME(zvrf, afi, rtype)) @@ -388,358 +380,14 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, zvrf->vrf->vrf_id, rtype); NHT_RM_MAP(zvrf, afi, rtype) = NULL; - zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); + zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST); } XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); } return CMD_SUCCESS; } -DEFPY_YANG( - match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, - "match ip address prefix-len (0-32)$length", - MATCH_STR - IP_STR - "Match prefix length of IP address\n" - "Match prefix length of IP address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, - "no match ip address prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefix length of IP address\n" - "Match prefix length of IP address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, - "match ipv6 address prefix-len (0-128)$length", - MATCH_STR - IPV6_STR - "Match prefix length of IPv6 address\n" - "Match prefix length of IPv6 address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, - "no match ipv6 address prefix-len [(0-128)]", - NO_STR - MATCH_STR - IPV6_STR - "Match prefix length of IPv6 address\n" - "Match prefix length of IPv6 address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, - "match ip next-hop prefix-len (0-32)$length", - MATCH_STR - IP_STR - "Match prefixlen of nexthop IP address\n" - "Match prefixlen of given nexthop\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, - "no match ip next-hop prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefixlen of nexthop IP address\n" - "Match prefix length of nexthop\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_source_protocol, match_source_protocol_cmd, - "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", - MATCH_STR - "Match protocol via which the route was learnt\n" - FRR_REDIST_HELP_STR_ZEBRA) -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-protocol']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_source_protocol, no_match_source_protocol_cmd, - "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", - NO_STR - MATCH_STR - "Match protocol via which the route was learnt\n" - FRR_REDIST_HELP_STR_ZEBRA) -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-protocol']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_source_instance, match_source_instance_cmd, - "match source-instance (0-255)$instance", - MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-instance']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:source-instance", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_source_instance, no_match_source_instance_cmd, - "no match source-instance [(0-255)]", - NO_STR MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-instance']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -/* set functions */ - -DEFPY_YANG( - set_src, set_src_cmd, - "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>", - SET_STR - "src address for route\n" - "IPv4 src address\n" - "IPv6 src address\n") -{ - const char *xpath = - "./set-action[action='frr-zebra-route-map:src-address']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - if (addrv4_str) { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv4_str); - } else { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv6_str); - } - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_set_src, no_set_src_cmd, - "no set src [<A.B.C.D|X:X::X:X>]", - NO_STR - SET_STR - "Source address for route\n" - "IPv4 address\n" - "IPv6 address\n") -{ - const char *xpath = - "./set-action[action='frr-zebra-route-map:src-address']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN_YANG (zebra_route_map_timer, - zebra_route_map_timer_cmd, - "zebra route-map delay-timer (0-600)", - ZEBRA_STR - "Set route-map parameters\n" - "Time to wait before route-map updates are processed\n" - "0 means route-map changes are run immediately instead of delaying\n") -{ - int idx_number = 3; - uint32_t rmap_delay_timer; - - rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10); - zebra_route_map_set_delay_timer(rmap_delay_timer); - - return (CMD_SUCCESS); -} - -DEFUN_YANG (no_zebra_route_map_timer, - no_zebra_route_map_timer_cmd, - "no zebra route-map delay-timer [(0-600)]", - NO_STR - ZEBRA_STR - "Set route-map parameters\n" - "Reset delay-timer to default value, 30 secs\n" - "0 means route-map changes are run immediately instead of delaying\n") -{ - zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER); - - return (CMD_SUCCESS); -} - -DEFPY_YANG (ip_protocol, - ip_protocol_cmd, - "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP_STR - "Filter routing info exchanged between zebra and protocol\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - assert(rmap); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (no_ip_protocol, - no_ip_protocol_cmd, - "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP_STR - "Stop filtering routing info between zebra and protocol\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (show_ip_protocol, +DEFPY (show_ip_protocol, show_ip_protocol_cmd, "show ip protocol [vrf <NAME$vrf_name|all$vrf_all>]", SHOW_STR @@ -752,75 +400,7 @@ DEFPY_YANG (show_ip_protocol, return ret; } -DEFPY_YANG (ipv6_protocol, - ipv6_protocol_cmd, - "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP6_STR - "Filter IPv6 routing info exchanged between zebra and protocol\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(rmap); - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (no_ipv6_protocol, - no_ipv6_protocol_cmd, - "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP6_STR - "Stop filtering IPv6 routing info between zebra and protocol\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (show_ipv6_protocol, +DEFPY (show_ipv6_protocol, show_ipv6_protocol_cmd, "show ipv6 protocol [vrf <NAME$vrf_name|all$vrf_all>]", SHOW_STR @@ -833,76 +413,7 @@ DEFPY_YANG (show_ipv6_protocol, return ret; } -DEFPY_YANG (ip_protocol_nht_rmap, - ip_protocol_nht_rmap_cmd, - "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - - int ret, rtype; - - assert(proto); - assert(rmap); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP); - - return ret; -} - -DEFPY_YANG (no_ip_protocol_nht_rmap, - no_ip_protocol_nht_rmap_cmd, - "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map [ROUTE-MAP$rmap]", - NO_STR - IP_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP); - - return ret; -} - -DEFPY_YANG (show_ip_protocol_nht, +DEFPY (show_ip_protocol_nht, show_ip_protocol_nht_cmd, "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", SHOW_STR @@ -921,75 +432,7 @@ DEFPY_YANG (show_ip_protocol_nht, return ret; } -DEFPY_YANG (ipv6_protocol_nht_rmap, - ipv6_protocol_nht_rmap_cmd, - "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP6_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(rmap); - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP6); - - return ret; -} - -DEFPY_YANG (no_ipv6_protocol_nht_rmap, - no_ipv6_protocol_nht_rmap_cmd, - "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP6_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP6); - - return ret; -} - -DEFPY_YANG (show_ipv6_protocol_nht, +DEFPY (show_ipv6_protocol_nht, show_ipv6_protocol_nht_cmd, "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", SHOW_STR @@ -1017,21 +460,21 @@ static enum route_map_cmd_result_t route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object) { struct access_list *alist; - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; struct prefix_ipv4 p; - nh_data = object; - if (!nh_data) + rm_data = object; + if (!rm_data) return RMAP_NOMATCH; - switch (nh_data->nexthop->type) { + switch (rm_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; - p.prefix = nh_data->nexthop->gate.ipv4; + p.prefix = rm_data->nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; case NEXTHOP_TYPE_IPV6: @@ -1080,21 +523,21 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, void *object) { struct prefix_list *plist; - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; struct prefix_ipv4 p; - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data) return RMAP_NOMATCH; - switch (nh_data->nexthop->type) { + switch (rm_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; - p.prefix = nh_data->nexthop->gate.ipv4; + p.prefix = rm_data->nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; case NEXTHOP_TYPE_IPV6: @@ -1264,14 +707,14 @@ static enum route_map_cmd_result_t route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, void *object) { - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; if (prefix->family == AF_INET6) { - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data) return RMAP_NOMATCH; - if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + if (rm_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) return RMAP_MATCH; } @@ -1356,21 +799,21 @@ route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, void *object) { uint32_t *prefixlen = (uint32_t *)rule; - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; struct prefix_ipv4 p; - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data || !nh_data->nexthop) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data || !rm_data->nexthop) return RMAP_NOMATCH; - switch (nh_data->nexthop->type) { + switch (rm_data->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; - p.prefix = nh_data->nexthop->gate.ipv4; + p.prefix = rm_data->nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; case NEXTHOP_TYPE_IPV6: @@ -1395,14 +838,14 @@ static enum route_map_cmd_result_t route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, void *object) { - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; if (prefix->family == AF_INET) { - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data) return RMAP_NOMATCH; - if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + if (rm_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) return RMAP_MATCH; } @@ -1432,15 +875,14 @@ static const struct route_map_rule_cmd static enum route_map_cmd_result_t route_match_source_protocol(void *rule, const struct prefix *p, void *object) { - uint32_t *rib_type = (uint32_t *)rule; - struct nh_rmap_obj *nh_data; + int32_t *rib_type = (int32_t *)rule; + struct zebra_rmap_obj *rm_data; - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data) return RMAP_NOMATCH; - return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH - : RMAP_NOMATCH); + return ((rm_data->re->type == *rib_type) ? RMAP_MATCH : RMAP_NOMATCH); } static void *route_match_source_protocol_compile(const char *arg) @@ -1473,13 +915,13 @@ static enum route_map_cmd_result_t route_match_source_instance(void *rule, const struct prefix *p, void *object) { uint8_t *instance = (uint8_t *)rule; - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; - nh_data = (struct nh_rmap_obj *)object; - if (!nh_data) + rm_data = (struct zebra_rmap_obj *)object; + if (!rm_data) return RMAP_NOMATCH; - return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH; + return (rm_data->re->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH; } static void *route_match_source_instance_compile(const char *arg) @@ -1513,10 +955,10 @@ static const struct route_map_rule_cmd route_match_source_instance_cmd = { static enum route_map_cmd_result_t route_set_src(void *rule, const struct prefix *prefix, void *object) { - struct nh_rmap_obj *nh_data; + struct zebra_rmap_obj *rm_data; - nh_data = (struct nh_rmap_obj *)object; - nh_data->nexthop->rmap_src = *(union g_addr *)rule; + rm_data = (struct zebra_rmap_obj *)object; + rm_data->nexthop->rmap_src = *(union g_addr *)rule; return RMAP_OKAY; } @@ -1703,7 +1145,7 @@ static void zebra_nht_rm_update(const char *rmap) afi_ipv6 = 1; zebra_evaluate_rnh( - zvrf, AFI_IP, 1, NULL, + zvrf, AFI_IP6, 1, NULL, SAFI_UNICAST); } } @@ -1741,7 +1183,7 @@ static void zebra_route_map_update_timer(struct event *thread) */ } -static void zebra_route_map_set_delay_timer(uint32_t value) +void zebra_route_map_set_delay_timer(uint32_t value) { zebra_rmap_update_timer = value; if (!value && zebra_t_rmap_update) { @@ -1761,26 +1203,22 @@ void zebra_routemap_finish(void) route_map_finish(); } -route_map_result_t -zebra_route_map_check(afi_t family, int rib_type, uint8_t instance, - const struct prefix *p, struct nexthop *nexthop, - struct zebra_vrf *zvrf, route_tag_t tag) +route_map_result_t zebra_route_map_check(afi_t family, struct route_entry *re, + const struct prefix *p, + struct nexthop *nexthop, + struct zebra_vrf *zvrf) { struct route_map *rmap = NULL; char *rm_name; route_map_result_t ret = RMAP_PERMITMATCH; - struct nh_rmap_obj nh_obj; + struct zebra_rmap_obj rm_obj; - nh_obj.nexthop = nexthop; - nh_obj.vrf_id = nexthop->vrf_id; - nh_obj.source_protocol = rib_type; - nh_obj.instance = instance; - nh_obj.metric = 0; - nh_obj.tag = tag; + rm_obj.nexthop = nexthop; + rm_obj.re = re; - if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) { - rm_name = PROTO_RM_NAME(zvrf, family, rib_type); - rmap = PROTO_RM_MAP(zvrf, family, rib_type); + if (re->type >= 0 && re->type < ZEBRA_ROUTE_MAX) { + rm_name = PROTO_RM_NAME(zvrf, family, re->type); + rmap = PROTO_RM_MAP(zvrf, family, re->type); if (rm_name && !rmap) return RMAP_DENYMATCH; @@ -1793,7 +1231,7 @@ zebra_route_map_check(afi_t family, int rib_type, uint8_t instance, return RMAP_DENYMATCH; } if (rmap) { - ret = route_map_apply(rmap, p, &nh_obj); + ret = route_map_apply(rmap, p, &rm_obj); } return (ret); @@ -1816,28 +1254,23 @@ void zebra_del_import_table_route_map(afi_t afi, uint32_t table) XFREE(MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]); } -route_map_result_t -zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, - const struct prefix *p, - struct nexthop *nexthop, - vrf_id_t vrf_id, route_tag_t tag, - const char *rmap_name) +route_map_result_t zebra_import_table_route_map_check(int family, + struct route_entry *re, + const struct prefix *p, + struct nexthop *nexthop, + const char *rmap_name) { struct route_map *rmap = NULL; route_map_result_t ret = RMAP_DENYMATCH; - struct nh_rmap_obj nh_obj; + struct zebra_rmap_obj rm_obj; - nh_obj.nexthop = nexthop; - nh_obj.vrf_id = vrf_id; - nh_obj.source_protocol = re_type; - nh_obj.instance = instance; - nh_obj.metric = 0; - nh_obj.tag = tag; + rm_obj.nexthop = nexthop; + rm_obj.re = re; - if (re_type >= 0 && re_type < ZEBRA_ROUTE_MAX) + if (re->type >= 0 && re->type < ZEBRA_ROUTE_MAX) rmap = route_map_lookup_by_name(rmap_name); if (rmap) { - ret = route_map_apply(rmap, p, &nh_obj); + ret = route_map_apply(rmap, p, &rm_obj); } return (ret); @@ -1851,21 +1284,17 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, { struct route_map *rmap = NULL; route_map_result_t ret = RMAP_PERMITMATCH; - struct nh_rmap_obj nh_obj; + struct zebra_rmap_obj rm_obj; - nh_obj.nexthop = nexthop; - nh_obj.vrf_id = nexthop->vrf_id; - nh_obj.source_protocol = re->type; - nh_obj.instance = re->instance; - nh_obj.metric = re->metric; - nh_obj.tag = re->tag; + rm_obj.nexthop = nexthop; + rm_obj.re = re; if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX) rmap = NHT_RM_MAP(zvrf, afi, client_proto); if (!rmap && NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX)) rmap = NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX); if (rmap) - ret = route_map_apply(rmap, p, &nh_obj); + ret = route_map_apply(rmap, p, &rm_obj); return ret; } @@ -1921,88 +1350,14 @@ void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf) } } -/* ip protocol configuration write function */ -void zebra_routemap_config_write_protocol(struct vty *vty, - struct zebra_vrf *zvrf) -{ - int i; - char space[2]; - - memset(space, 0, sizeof(space)); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - snprintf(space, sizeof(space), "%s", " "); - - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (PROTO_RM_NAME(zvrf, AFI_IP, i)) - vty_out(vty, "%sip protocol %s route-map %s\n", space, - zebra_route_string(i), - PROTO_RM_NAME(zvrf, AFI_IP, i)); - - if (PROTO_RM_NAME(zvrf, AFI_IP6, i)) - vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, - zebra_route_string(i), - PROTO_RM_NAME(zvrf, AFI_IP6, i)); - - if (NHT_RM_NAME(zvrf, AFI_IP, i)) - vty_out(vty, "%sip nht %s route-map %s\n", space, - zebra_route_string(i), - NHT_RM_NAME(zvrf, AFI_IP, i)); - - if (NHT_RM_NAME(zvrf, AFI_IP6, i)) - vty_out(vty, "%sipv6 nht %s route-map %s\n", space, - zebra_route_string(i), - NHT_RM_NAME(zvrf, AFI_IP6, i)); - } - - if (PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sip protocol %s route-map %s\n", space, "any", - PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); - - if (PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, "any", - PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); - - if (NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sip nht %s route-map %s\n", space, "any", - NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); - - if (NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any", - NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); - - if (zvrf_id(zvrf) == VRF_DEFAULT - && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER) - vty_out(vty, "zebra route-map delay-timer %d\n", - zebra_rmap_update_timer); -} - void zebra_route_map_init(void) { - install_element(CONFIG_NODE, &ip_protocol_cmd); - install_element(CONFIG_NODE, &no_ip_protocol_cmd); - install_element(VRF_NODE, &ip_protocol_cmd); - install_element(VRF_NODE, &no_ip_protocol_cmd); install_element(VIEW_NODE, &show_ip_protocol_cmd); - install_element(CONFIG_NODE, &ipv6_protocol_cmd); - install_element(CONFIG_NODE, &no_ipv6_protocol_cmd); - install_element(VRF_NODE, &ipv6_protocol_cmd); - install_element(VRF_NODE, &no_ipv6_protocol_cmd); install_element(VIEW_NODE, &show_ipv6_protocol_cmd); - install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd); - install_element(CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &no_ip_protocol_nht_rmap_cmd); install_element(VIEW_NODE, &show_ip_protocol_nht_cmd); - install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); - install_element(CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &no_ipv6_protocol_nht_rmap_cmd); install_element(VIEW_NODE, &show_ipv6_protocol_nht_cmd); - install_element(CONFIG_NODE, &zebra_route_map_timer_cmd); - install_element(CONFIG_NODE, &no_zebra_route_map_timer_cmd); - route_map_init(); + route_map_init_new(true); route_map_add_hook(zebra_route_map_add); route_map_delete_hook(zebra_route_map_delete); @@ -2056,19 +1411,4 @@ void zebra_route_map_init(void) /* */ route_map_install_set(&route_set_src_cmd); - /* */ - install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); - install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd); - install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); - install_element(RMAP_NODE, &match_source_protocol_cmd); - install_element(RMAP_NODE, &no_match_source_protocol_cmd); - install_element(RMAP_NODE, &match_source_instance_cmd); - install_element(RMAP_NODE, &no_match_source_instance_cmd); - - /* */ - install_element(RMAP_NODE, &set_src_cmd); - install_element(RMAP_NODE, &no_set_src_cmd); } diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index f77735edc2..2039e80e3a 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -14,26 +14,34 @@ extern "C" { #endif extern void zebra_route_map_init(void); -extern void zebra_routemap_config_write_protocol(struct vty *vty, - struct zebra_vrf *vrf); extern char *zebra_get_import_table_route_map(afi_t afi, uint32_t table); extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name, uint32_t table); extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table); -extern route_map_result_t -zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance, - const struct prefix *p, - struct nexthop *nexthop, vrf_id_t vrf_id, - route_tag_t tag, const char *rmap_name); -extern route_map_result_t -zebra_route_map_check(afi_t family, int rib_type, uint8_t instance, - const struct prefix *p, struct nexthop *nexthop, - struct zebra_vrf *zvrf, route_tag_t tag); -extern route_map_result_t -zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, - struct zebra_vrf *zvrf, struct route_entry *, - struct nexthop *nexthop); +extern route_map_result_t zebra_import_table_route_map_check( + int family, struct route_entry *re, const struct prefix *p, + struct nexthop *nexthop, const char *rmap_name); +extern route_map_result_t zebra_route_map_check(afi_t family, + struct route_entry *re, + const struct prefix *p, + struct nexthop *nexthop, + struct zebra_vrf *zvrf); +extern route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, + const struct prefix *p, + struct zebra_vrf *zvrf, + struct route_entry *re, + struct nexthop *nexthop); + +extern void zebra_route_map_set_delay_timer(uint32_t value); +extern int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, + int rtype, afi_t afi, safi_t safi); +extern int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, + int rtype, afi_t afi, safi_t safi); +extern int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, + int afi); +extern int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, + int afi); extern void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf); diff --git a/zebra/zebra_routemap_nb_config.c b/zebra/zebra_routemap_nb_config.c index 5bcfb720e1..ad012da4c2 100644 --- a/zebra/zebra_routemap_nb_config.c +++ b/zebra/zebra_routemap_nb_config.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include <zebra.h> #include "lib/command.h" diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index a477287913..3fd4e6eb1f 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -70,6 +70,26 @@ struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf, return zrt; } +struct zebra_router_table *zebra_router_find_next_zrt(struct zebra_vrf *zvrf, + uint32_t tableid, + afi_t afi, safi_t safi) +{ + struct zebra_router_table finder; + struct zebra_router_table *zrt; + + memset(&finder, 0, sizeof(finder)); + finder.afi = afi; + finder.safi = safi; + finder.tableid = tableid; + finder.ns_id = zvrf->zns->ns_id; + zrt = RB_NFIND(zebra_router_table_head, &zrouter.tables, &finder); + if (zrt->afi == afi && zrt->safi == safi && zrt->tableid == tableid && + zrt->ns_id == finder.ns_id) + zrt = RB_NEXT(zebra_router_table_head, zrt); + + return zrt; +} + struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi) @@ -241,11 +261,15 @@ void zebra_router_terminate(void) zebra_pbr_ipset_entry_free); hash_clean_and_free(&zrouter.ipset_hash, zebra_pbr_ipset_free); hash_clean_and_free(&zrouter.iptable_hash, zebra_pbr_iptable_free); + hash_clean_and_free(&zrouter.filter_hash, (void (*)(void *)) zebra_tc_filter_free); + hash_clean_and_free(&zrouter.qdisc_hash, (void (*)(void *)) zebra_tc_qdisc_free); + hash_clean_and_free(&zrouter.class_hash, (void (*)(void *)) zebra_tc_class_free); #ifdef HAVE_SCRIPTING zebra_script_destroy(); #endif + zebra_vxlan_terminate(); /* OS-specific deinit */ kernel_router_terminate(); } @@ -255,10 +279,13 @@ bool zebra_router_notify_on_ack(void) return !zrouter.asic_offloaded || zrouter.notify_on_ack; } -void zebra_router_init(bool asic_offload, bool notify_on_ack) +void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop) { zrouter.sequence_num = 0; + zrouter.protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; + zrouter.allow_delete = false; zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; @@ -292,10 +319,6 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, "Zebra Router Nexthop Groups ID index"); - zrouter.rules_hash = - hash_create_size(8, zebra_pbr_rules_hash_key, - zebra_pbr_rules_hash_equal, "Rules Hash"); - zrouter.qdisc_hash = hash_create_size(8, zebra_tc_qdisc_hash_key, zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash"); @@ -308,7 +331,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.asic_offloaded = asic_offload; zrouter.notify_on_ack = notify_on_ack; - + zrouter.v6_with_v4_nexthop = v6_with_v4_nexthop; /* * If you start using asic_notification_nexthop_control * come talk to the FRR community about what you are doing @@ -320,6 +343,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) #endif zrouter.asic_notification_nexthop_control = false; + zrouter.nexthop_weight_scale_value = 255; + #ifdef HAVE_SCRIPTING zebra_script_init(); #endif diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index d81c7df589..3041707439 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -207,6 +207,9 @@ struct zebra_router { */ bool asic_offloaded; bool notify_on_ack; + bool v6_with_v4_nexthop; + + bool v6_rr_semantics; /* * If the asic is notifying us about successful nexthop @@ -228,6 +231,10 @@ struct zebra_router { /* Should we allow non FRR processes to delete our routes */ bool allow_delete; + + uint8_t protodown_r_bit; + + uint64_t nexthop_weight_scale_value; }; #define GRACEFUL_RESTART_TIME 60 @@ -235,13 +242,17 @@ struct zebra_router { extern struct zebra_router zrouter; extern uint32_t rcvbufsize; -extern void zebra_router_init(bool asic_offload, bool notify_on_ack); +extern void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop); extern void zebra_router_cleanup(void); extern void zebra_router_terminate(void); extern struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); +extern struct zebra_router_table * +zebra_router_find_next_zrt(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, + safi_t safi); extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); @@ -286,6 +297,32 @@ static inline bool zebra_router_in_shutdown(void) return atomic_load_explicit(&zrouter.in_shutdown, memory_order_relaxed); } +#define FRR_PROTODOWN_REASON_DEFAULT_BIT 7 +/* Protodown bit setter/getter + * + * Allow users to change the bit if it conflicts with another + * on their system. + */ +static inline void if_netlink_set_frr_protodown_r_bit(uint8_t bit) +{ + zrouter.protodown_r_bit = bit; +} + +static inline void if_netlink_unset_frr_protodown_r_bit(void) +{ + zrouter.protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; +} + +static inline bool if_netlink_frr_protodown_r_bit_is_set(void) +{ + return (zrouter.protodown_r_bit != FRR_PROTODOWN_REASON_DEFAULT_BIT); +} + +static inline uint8_t if_netlink_get_frr_protodown_r_bit(void) +{ + return zrouter.protodown_r_bit; +} + /* zebra_northbound.c */ extern const struct frr_yang_module_info frr_zebra_info; diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index 3f107cb48d..6c34d12c64 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -396,6 +396,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) lua_setfield(L, -2, "mtu"); } lua_setfield(L, -2, "gre"); + break; case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: @@ -414,7 +415,9 @@ 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_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: + case DPLANE_OP_STARTUP_STAGE: break; } /* Dispatch by op code */ } diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index e06733cb8c..1c6d58159e 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -223,6 +223,8 @@ static int proto_trans(int type) return 1; /* other */ case ZEBRA_ROUTE_CONNECT: return 2; /* local interface */ + case ZEBRA_ROUTE_LOCAL: + return 2; case ZEBRA_ROUTE_STATIC: return 3; /* static route */ case ZEBRA_ROUTE_RIP: @@ -353,7 +355,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], if (policy) /* Not supported (yet?) */ return; for (*np = route_top(table); *np; *np = route_next(*np)) { - if (!in_addr_cmp(&(*np)->p.u.prefix, + if (!in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { if (!in_addr_cmp((uint8_t *)&(*re)->nhe @@ -374,13 +376,14 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], for (np2 = route_top(table); np2; np2 = route_next(np2)) { /* Check destination first */ - if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) > 0) + if (in_addr_cmp((uint8_t *)&np2->p.u.prefix4, + (uint8_t *)&dest) > 0) RNODE_FOREACH_RE (np2, re2) { check_replace(np2, re2, np, re); } - if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) - == 0) { /* have to look at each re individually */ + if (in_addr_cmp((uint8_t *)&np2->p.u.prefix4, (uint8_t *)&dest) == + 0) { /* have to look at each re individually */ RNODE_FOREACH_RE (np2, re2) { int proto2, policy2; diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 94b93e5e8d..bb872ef91c 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -17,6 +17,7 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" +#include "zebra/ge_netlink.h" #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -216,9 +217,10 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) } } +struct zebra_srv6 srv6; + struct zebra_srv6 *zebra_srv6_get_default(void) { - static struct zebra_srv6 srv6; static bool first_execution = true; if (first_execution) { @@ -408,6 +410,40 @@ int release_daemon_srv6_locator_chunks(struct zserv *client) return count; } +void zebra_srv6_encap_src_addr_set(struct in6_addr *encap_src_addr) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + if (!encap_src_addr) + return; + + memcpy(&srv6->encap_src_addr, encap_src_addr, sizeof(struct in6_addr)); +} + +void zebra_srv6_encap_src_addr_unset(void) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); +} + +void zebra_srv6_terminate(void) +{ + struct srv6_locator *locator; + + if (!srv6.locators) + return; + + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); + + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } + + list_delete(&srv6.locators); +} + void zebra_srv6_init(void) { hook_register(zserv_client_close, zebra_srv6_cleanup); diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 51db83d6fb..21936c3323 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -19,6 +19,9 @@ /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; + + /* Source address for SRv6 encapsulation */ + struct in6_addr encap_src_addr; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -52,6 +55,7 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator); void zebra_notify_srv6_locator_delete(struct srv6_locator *locator); extern void zebra_srv6_init(void); +extern void zebra_srv6_terminate(void); extern struct zebra_srv6 *zebra_srv6_get_default(void); extern bool zebra_srv6_is_enable(void); @@ -67,4 +71,7 @@ extern void srv6_manager_release_locator_chunk_call(struct zserv *client, extern int srv6_manager_client_disconnect_cb(struct zserv *client); extern int release_daemon_srv6_locator_chunks(struct zserv *client); +extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); +extern void zebra_srv6_encap_src_addr_unset(void); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 3775d3dcdf..c5b8505992 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -61,6 +61,52 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# " }; +static struct cmd_node srv6_encap_node = { + .name = "srv6-encap", + .node = SRV6_ENCAP_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-encap)# " +}; + +DEFPY (show_srv6_manager, + show_srv6_manager_cmd, + "show segment-routing srv6 manager [json]", + SHOW_STR + "Segment Routing\n" + "Segment Routing SRv6\n" + "Verify SRv6 Manager\n" + JSON_STR) +{ + const bool uj = use_json(argc, argv); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + json_object *json = NULL; + json_object *json_parameters = NULL; + json_object *json_encapsulation = NULL; + json_object *json_source_address = NULL; + + if (uj) { + json = json_object_new_object(); + json_parameters = json_object_new_object(); + json_object_object_add(json, "parameters", json_parameters); + json_encapsulation = json_object_new_object(); + json_object_object_add(json_parameters, "encapsulation", + json_encapsulation); + json_source_address = json_object_new_object(); + json_object_object_add(json_encapsulation, "sourceAddress", + json_source_address); + json_object_string_addf(json_source_address, "configured", + "%pI6", &srv6->encap_src_addr); + vty_json(vty, json); + } else { + vty_out(vty, "Parameters:\n"); + vty_out(vty, " Encapsulation:\n"); + vty_out(vty, " Source Address:\n"); + vty_out(vty, " Configured: %pI6\n", &srv6->encap_src_addr); + } + + return CMD_SUCCESS; +} + DEFUN (show_srv6_locator, show_srv6_locator_cmd, "show segment-routing srv6 locator [json]", @@ -391,6 +437,38 @@ DEFPY (locator_behavior, return CMD_SUCCESS; } +DEFUN_NOSH (srv6_encap, + srv6_encap_cmd, + "encapsulation", + "Segment Routing SRv6 encapsulation\n") +{ + vty->node = SRV6_ENCAP_NODE; + return CMD_SUCCESS; +} + +DEFPY (srv6_src_addr, + srv6_src_addr_cmd, + "source-address X:X::X:X$encap_src_addr", + "Segment Routing SRv6 source address\n" + "Specify source address for SRv6 encapsulation\n") +{ + zebra_srv6_encap_src_addr_set(&encap_src_addr); + dplane_srv6_encap_srcaddr_set(&encap_src_addr, NS_DEFAULT); + return CMD_SUCCESS; +} + +DEFPY (no_srv6_src_addr, + no_srv6_src_addr_cmd, + "no source-address [X:X::X:X$encap_src_addr]", + NO_STR + "Segment Routing SRv6 source address\n" + "Specify source address for SRv6 encapsulation\n") +{ + zebra_srv6_encap_src_addr_unset(); + dplane_srv6_encap_srcaddr_set(&in6addr_any, NS_DEFAULT); + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -402,6 +480,11 @@ static int zebra_sr_config(struct vty *vty) if (zebra_srv6_is_enable()) { vty_out(vty, "segment-routing\n"); vty_out(vty, " srv6\n"); + if (!IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) { + vty_out(vty, " encapsulation\n"); + vty_out(vty, " source-address %pI6\n", + &srv6->encap_src_addr); + } vty_out(vty, " locators\n"); for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { inet_ntop(AF_INET6, &locator->prefix.prefix, @@ -444,24 +527,30 @@ void zebra_srv6_vty_init(void) install_node(&srv6_node); install_node(&srv6_locs_node); install_node(&srv6_loc_node); + install_node(&srv6_encap_node); install_default(SEGMENT_ROUTING_NODE); install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); + install_default(SRV6_ENCAP_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_encap_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); + install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); install_element(VIEW_NODE, &show_srv6_locator_detail_cmd); + install_element(VIEW_NODE, &show_srv6_manager_cmd); } diff --git a/zebra/zebra_tc.c b/zebra/zebra_tc.c index 3d7e03b63e..1b5a57ae53 100644 --- a/zebra/zebra_tc.c +++ b/zebra/zebra_tc.c @@ -132,13 +132,18 @@ static void *tc_qdisc_alloc_intern(void *arg) return new; } +void zebra_tc_qdisc_free(struct zebra_tc_qdisc *qdisc) +{ + XFREE(MTYPE_TC_QDISC, qdisc); +} + static struct zebra_tc_qdisc *tc_qdisc_free(struct zebra_tc_qdisc *hash_data, bool free_data) { hash_release(zrouter.qdisc_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_QDISC, hash_data); + zebra_tc_qdisc_free(hash_data); return NULL; } @@ -178,7 +183,7 @@ void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc) new = hash_get(zrouter.qdisc_hash, qdisc, tc_qdisc_alloc_intern); (void)dplane_tc_qdisc_install(new); - XFREE(MTYPE_TC_QDISC, old); + zebra_tc_qdisc_free(old); } } else { new = hash_get(zrouter.qdisc_hash, qdisc, @@ -243,13 +248,18 @@ static void *tc_class_alloc_intern(void *arg) return new; } +void zebra_tc_class_free(struct zebra_tc_class *class) +{ + XFREE(MTYPE_TC_CLASS, class); +} + static struct zebra_tc_class *tc_class_free(struct zebra_tc_class *hash_data, bool free_data) { hash_release(zrouter.class_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_CLASS, hash_data); + zebra_tc_class_free(hash_data); return NULL; } @@ -353,13 +363,18 @@ bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2) return true; } +void zebra_tc_filter_free(struct zebra_tc_filter *filter) +{ + XFREE(MTYPE_TC_FILTER, filter); +} + static struct zebra_tc_filter *tc_filter_free(struct zebra_tc_filter *hash_data, bool free_data) { hash_release(zrouter.filter_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_FILTER, hash_data); + zebra_tc_filter_free(hash_data); return NULL; } diff --git a/zebra/zebra_tc.h b/zebra/zebra_tc.h index 335430c93d..814b453ec5 100644 --- a/zebra/zebra_tc.h +++ b/zebra/zebra_tc.h @@ -42,16 +42,19 @@ uint32_t zebra_tc_qdisc_hash_key(const void *arg); bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2); void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc); void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc); +void zebra_tc_qdisc_free(struct zebra_tc_qdisc *qdisc); uint32_t zebra_tc_class_hash_key(const void *arg); bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2); void zebra_tc_class_add(struct zebra_tc_class *class); void zebra_tc_class_delete(struct zebra_tc_class *class); +void zebra_tc_class_free(struct zebra_tc_class *class); const char *tc_filter_kind2str(uint32_t type); enum tc_qdisc_kind tc_filter_str2kind(const char *type); void zebra_tc_filter_add(struct zebra_tc_filter *filter); void zebra_tc_filter_delete(struct zebra_tc_filter *filter); +void zebra_tc_filter_free(struct zebra_tc_filter *filter); void zebra_tc_filters_free(void *arg); uint32_t zebra_tc_filter_hash_key(const void *arg); diff --git a/zebra/zebra_trace.c b/zebra/zebra_trace.c index fef5ad20ac..7b0fb3279b 100644 --- a/zebra/zebra_trace.c +++ b/zebra/zebra_trace.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 3365cdcdba..e464e47b1f 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -195,7 +195,7 @@ static int zebra_vrf_disable(struct vrf *vrf) /* Cleanup Vxlan, MPLS and PW tables. */ zebra_vxlan_cleanup_tables(zvrf); zebra_mpls_cleanup_tables(zvrf); - zebra_pw_exit(zvrf); + zebra_pw_exit_vrf(zvrf); /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */ @@ -265,6 +265,12 @@ static int zebra_vrf_delete(struct vrf *vrf) otable_fini(&zvrf->other_tables); XFREE(MTYPE_ZEBRA_VRF, zvrf); + + if (vrf->ns_ctxt) { + ns_delete(vrf->ns_ctxt); + vrf->ns_ctxt = NULL; + } + vrf->info = NULL; return 0; @@ -370,12 +376,45 @@ struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); - zebra_pw_init(zvrf); - zvrf->table_id = RT_TABLE_MAIN; + zebra_pw_init_vrf(zvrf); + zvrf->table_id = rt_table_main_id; /* by default table ID is default one */ + + if (DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) { + zvrf->zebra_rnh_ip_default_route = true; + zvrf->zebra_rnh_ipv6_default_route = true; + } + return zvrf; } +/* + * Pending: create an efficient table_id (in a tree/hash) based lookup) + */ +vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + zvrf = vrf->info; + if (zvrf == NULL) + continue; + /* case vrf with netns : match the netnsid */ + if (vrf_is_backend_netns()) { + if (ns_id == zvrf_id(zvrf)) + return zvrf_id(zvrf); + } else { + /* VRF is VRF_BACKEND_VRF_LITE */ + if (zvrf->table_id != table_id) + continue; + return zvrf_id(zvrf); + } + } + + return VRF_DEFAULT; +} + /* Lookup VRF by identifier. */ struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) { @@ -411,124 +450,6 @@ struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) return zvrf->table[afi][safi]; } -static int vrf_config_write(struct vty *vty) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - zvrf = vrf->info; - - if (!zvrf) - continue; - - if (zvrf_id(zvrf) == VRF_DEFAULT) { - if (zvrf->l3vni) - vty_out(vty, "vni %u%s\n", zvrf->l3vni, - is_l3vni_for_prefix_routes_only( - zvrf->l3vni) - ? " prefix-routes-only" - : ""); - if (zvrf->zebra_rnh_ip_default_route) - vty_out(vty, "ip nht resolve-via-default\n"); - - if (zvrf->zebra_rnh_ipv6_default_route) - vty_out(vty, "ipv6 nht resolve-via-default\n"); - - if (zvrf->tbl_mgr - && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) - vty_out(vty, "ip table range %u %u\n", - zvrf->tbl_mgr->start, - zvrf->tbl_mgr->end); - } else { - vty_frame(vty, "vrf %s\n", zvrf_name(zvrf)); - if (zvrf->l3vni) - vty_out(vty, " vni %u%s\n", zvrf->l3vni, - is_l3vni_for_prefix_routes_only( - zvrf->l3vni) - ? " prefix-routes-only" - : ""); - zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); - if (zvrf->zebra_rnh_ip_default_route) - vty_out(vty, " ip nht resolve-via-default\n"); - - if (zvrf->zebra_rnh_ipv6_default_route) - vty_out(vty, " ipv6 nht resolve-via-default\n"); - - if (zvrf->tbl_mgr && vrf_is_backend_netns() - && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) - vty_out(vty, " ip table range %u %u\n", - zvrf->tbl_mgr->start, - zvrf->tbl_mgr->end); - } - - - zebra_routemap_config_write_protocol(vty, zvrf); - router_id_write(vty, zvrf); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - vty_endframe(vty, "exit-vrf\n!\n"); - else - vty_out(vty, "!\n"); - } - return 0; -} - -DEFPY (vrf_netns, - vrf_netns_cmd, - "netns NAME$netns_name", - "Attach VRF to a Namespace\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - char *pathname = ns_netns_pathname(vty, netns_name); - int ret; - - VTY_DECLVAR_CONTEXT(vrf, vrf); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - frr_with_privs(&zserv_privs) { - ret = zebra_vrf_netns_handler_create( - vty, vrf, pathname, NS_UNKNOWN, NS_UNKNOWN, NS_UNKNOWN); - } - - return ret; -} - -DEFUN (no_vrf_netns, - no_vrf_netns_cmd, - "no netns [NAME]", - NO_STR - "Detach VRF from a Namespace\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - struct ns *ns = NULL; - - VTY_DECLVAR_CONTEXT(vrf, vrf); - - if (!vrf_is_backend_netns()) { - vty_out(vty, "VRF backend is not Netns. Aborting\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (!vrf->ns_ctxt) { - vty_out(vty, "VRF %s(%u) is not configured with NetNS\n", - vrf->name, vrf->vrf_id); - return CMD_WARNING_CONFIG_FAILED; - } - - ns = (struct ns *)vrf->ns_ctxt; - - ns->vrf_ctxt = NULL; - vrf_disable(vrf); - /* vrf ID from VRF is necessary for Zebra - * so that propagate to other clients is done - */ - ns_delete(ns); - vrf->ns_ctxt = NULL; - return CMD_SUCCESS; -} - /* if ns_id is different and not VRF_UNKNOWN, * then update vrf identifier, and enable VRF */ @@ -627,12 +548,4 @@ void zebra_vrf_init(void) zebra_vrf_delete); hook_register(zserv_client_close, release_daemon_table_chunks); - - vrf_cmd_init(vrf_config_write); - - if (vrf_is_backend_netns() && ns_have_netns()) { - /* Install NS commands. */ - install_element(VRF_NODE, &vrf_netns_cmd); - install_element(VRF_NODE, &no_vrf_netns_cmd); - } } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index b23b728261..5cbfab1ddc 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -13,11 +13,17 @@ #include <zebra/zebra_pw.h> #include <zebra/rtadv.h> #include <lib/vxlan.h> +#include "defaults.h" #ifdef __cplusplus extern "C" { #endif +FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT, + { .val_bool = true, .match_profile = "traditional", }, + { .val_bool = false }, +); + /* MPLS (Segment Routing) global block */ struct mpls_srgb { uint32_t start_label; @@ -237,6 +243,7 @@ extern struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, extern void zebra_vrf_update_all(struct zserv *client); extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); 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); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index d100dc0e69..0b5362094e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -20,6 +20,7 @@ #include "vxlan.h" #include "termtable.h" #include "affinitymap.h" +#include "frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/zserv.h" @@ -50,6 +51,7 @@ #include "zebra/zebra_script.h" #include "zebra/rtadv.h" #include "zebra/zebra_neigh.h" +#include "zebra/zebra_ptm.h" /* context to manage dumps in multiple tables or vrfs */ struct route_show_ctx { @@ -58,18 +60,19 @@ struct route_show_ctx { }; static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, - safi_t safi, bool use_fib, bool use_json, - route_tag_t tag, + safi_t safi, bool use_fib, json_object *vrf_json, + bool use_json, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, bool show_ng, struct route_show_ctx *ctx); static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng); -static void vty_show_ip_route_summary(struct vty *vty, - struct route_table *table, bool use_json); +static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json); static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json); /* Helper api to format a nexthop in the 'detailed' output path. */ static void show_nexthop_detail_helper(struct vty *vty, @@ -146,8 +149,8 @@ DEFPY (show_ip_rpf, }; return do_show_ip_route(vty, VRF_DEFAULT_NAME, ip ? AFI_IP : AFI_IP6, - SAFI_MULTICAST, false, uj, 0, NULL, false, 0, 0, - 0, false, &ctx); + SAFI_MULTICAST, false, NULL, uj, 0, NULL, false, + 0, 0, 0, false, &ctx); } DEFPY (show_ip_rpf_addr, @@ -764,9 +767,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, } /* Distance and metric display. */ - if (((re->type == ZEBRA_ROUTE_CONNECT) && + if (((re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) && (re->distance || re->metric)) || - (re->type != ZEBRA_ROUTE_CONNECT)) + (re->type != ZEBRA_ROUTE_CONNECT && re->type != ZEBRA_ROUTE_LOCAL)) len += vty_out(vty, " [%u/%u]", re->distance, re->metric); @@ -853,14 +857,13 @@ static void vty_show_ip_route_detail_json(struct vty *vty, vty_json(vty, json); } -static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, - struct route_table *table, afi_t afi, - bool use_fib, route_tag_t tag, - const struct prefix *longer_prefix_p, - bool supernets_only, int type, - unsigned short ospf_instance_id, bool use_json, - uint32_t tableid, bool show_ng, - struct route_show_ctx *ctx) +static void +do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, + struct route_table *table, afi_t afi, bool use_fib, + json_object *vrf_json, route_tag_t tag, + const struct prefix *longer_prefix_p, bool supernets_only, + int type, unsigned short ospf_instance_id, bool use_json, + uint32_t tableid, bool show_ng, struct route_show_ctx *ctx) { struct route_node *rn; struct route_entry *re; @@ -882,7 +885,7 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, * => display the VRF and table if specific */ - if (use_json) + if (use_json && !vrf_json) json = json_object_new_object(); /* Show all routes. */ @@ -957,18 +960,28 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, if (json_prefix) { prefix2str(&rn->p, buf, sizeof(buf)); - json_object_object_add(json, buf, json_prefix); + if (!vrf_json) + json_object_object_add(json, buf, json_prefix); + else + json_object_object_add(vrf_json, buf, + json_prefix); json_prefix = NULL; } } - if (use_json) - vty_json(vty, json); + /* + * This is an extremely expensive operation at scale + * and non-pretty reduces memory footprint significantly. + */ + if (use_json && !vrf_json) { + vty_json_no_pretty(vty, json); + json = NULL; + } } static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, - afi_t afi, bool use_fib, bool use_json, - route_tag_t tag, + afi_t afi, bool use_fib, json_object *vrf_json, + bool use_json, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, bool show_ng, @@ -988,15 +1001,15 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, continue; do_show_ip_route(vty, zvrf_name(zvrf), afi, SAFI_UNICAST, - use_fib, use_json, tag, longer_prefix_p, - supernets_only, type, ospf_instance_id, - zrt->tableid, show_ng, ctx); + use_fib, vrf_json, use_json, tag, + longer_prefix_p, supernets_only, type, + ospf_instance_id, zrt->tableid, show_ng, ctx); } } static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, - safi_t safi, bool use_fib, bool use_json, - route_tag_t tag, + safi_t safi, bool use_fib, json_object *vrf_json, + bool use_json, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, @@ -1031,7 +1044,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, return CMD_SUCCESS; } - do_show_route_helper(vty, zvrf, table, afi, use_fib, tag, + do_show_route_helper(vty, zvrf, table, afi, use_fib, vrf_json, tag, longer_prefix_p, supernets_only, type, ospf_instance_id, use_json, tableid, show_ng, ctx); @@ -1063,16 +1076,22 @@ DEFPY (show_ip_nht, json_object *json = NULL; json_object *json_vrf = NULL; json_object *json_nexthop = NULL; + struct zebra_vrf *zvrf; + bool resolve_via_default = false; if (uj) json = json_object_new_object(); if (vrf_all) { struct vrf *vrf; - struct zebra_vrf *zvrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((zvrf = vrf->info) != NULL) { + resolve_via_default = + (afi == AFI_IP) + ? zvrf->zebra_rnh_ip_default_route + : zvrf->zebra_rnh_ipv6_default_route; + if (uj) { json_vrf = json_object_new_object(); json_nexthop = json_object_new_object(); @@ -1084,9 +1103,16 @@ DEFPY (show_ip_nht, ? "ipv4" : "ipv6", json_nexthop); + json_object_boolean_add(json_nexthop, + "resolveViaDefault", + resolve_via_default); } else { vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); + vty_out(vty, + " Resolve via default: %s\n", + resolve_via_default ? "on" + : "off"); } zebra_print_rnh_table(zvrf_id(zvrf), afi, safi, vty, NULL, json_nexthop); @@ -1111,6 +1137,11 @@ DEFPY (show_ip_nht, } } + zvrf = zebra_vrf_lookup_by_id(vrf_id); + resolve_via_default = (afi == AFI_IP) + ? zvrf->zebra_rnh_ip_default_route + : zvrf->zebra_rnh_ipv6_default_route; + if (uj) { json_vrf = json_object_new_object(); json_nexthop = json_object_new_object(); @@ -1122,6 +1153,13 @@ DEFPY (show_ip_nht, json_object_object_add(json_vrf, (afi == AFI_IP) ? "ipv4" : "ipv6", json_nexthop); + + json_object_boolean_add(json_nexthop, "resolveViaDefault", + resolve_via_default); + } else { + vty_out(vty, "VRF %s:\n", zvrf_name(zvrf)); + vty_out(vty, " Resolve via default: %s\n", + resolve_via_default ? "on" : "off"); } zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop); @@ -1132,27 +1170,6 @@ DEFPY (show_ip_nht, return CMD_SUCCESS; } -DEFUN (ip_nht_default_route, - ip_nht_default_route_cmd, - "ip nht resolve-via-default", - IP_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf->zebra_rnh_ip_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ip_default_route = true; - - zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json_object *json_nhe_hdr) { @@ -1209,7 +1226,12 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json_object_boolean_true_add(json, "valid"); else vty_out(vty, " Valid"); - + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) { + if (json) + json_object_boolean_true_add(json, "reInstall"); + else + vty_out(vty, ", Reinstall"); + } if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { if (json) json_object_boolean_true_add(json, "installed"); @@ -1465,17 +1487,18 @@ static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp) { struct zebra_if *zebra_if = NULL; struct nhg_connected *rb_node_dep = NULL; + bool first = true; zebra_if = ifp->info; - if (!if_nhg_dependents_is_empty(ifp)) { - vty_out(vty, "Interface %s:\n", ifp->name); - - frr_each(nhg_connected_tree, &zebra_if->nhg_dependents, - rb_node_dep) { - vty_out(vty, " "); - show_nexthop_group_out(vty, rb_node_dep->nhe, NULL); + frr_each (nhg_connected_tree, &zebra_if->nhg_dependents, rb_node_dep) { + if (first) { + vty_out(vty, "Interface %s:\n", ifp->name); + first = false; } + + vty_out(vty, " "); + show_nexthop_group_out(vty, rb_node_dep->nhe, NULL); } } @@ -1651,68 +1674,6 @@ DEFPY_HIDDEN(backup_nexthop_recursive_use_enable, return CMD_SUCCESS; } -DEFUN (no_ip_nht_default_route, - no_ip_nht_default_route_cmd, - "no ip nht resolve-via-default", - NO_STR - IP_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (!zvrf->zebra_rnh_ip_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ip_default_route = false; - zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - -DEFUN (ipv6_nht_default_route, - ipv6_nht_default_route_cmd, - "ipv6 nht resolve-via-default", - IP6_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf->zebra_rnh_ipv6_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ipv6_default_route = true; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nht_default_route, - no_ipv6_nht_default_route_cmd, - "no ipv6 nht resolve-via-default", - NO_STR - IP6_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (!zvrf->zebra_rnh_ipv6_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ipv6_default_route = false; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - DEFPY_HIDDEN(rnh_hide_backups, rnh_hide_backups_cmd, "[no] ip nht hide-backup-events", NO_STR @@ -1786,6 +1747,7 @@ DEFPY (show_route, struct route_show_ctx ctx = { .multi = vrf_all || table_all, }; + json_object *root_json = NULL; if (!vrf_is_backend_netns()) { if ((vrf_all || vrf_name) && (table || table_all)) { @@ -1807,24 +1769,42 @@ DEFPY (show_route, } if (vrf_all) { + if (!!json) + root_json = json_object_new_object(); RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + json_object *vrf_json = NULL; + if ((zvrf = vrf->info) == NULL || (zvrf->table[afi][SAFI_UNICAST] == NULL)) continue; + if (!!json) + vrf_json = json_object_new_object(); + if (table_all) - do_show_ip_route_all( - vty, zvrf, afi, !!fib, !!json, tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, !!ng, &ctx); + do_show_ip_route_all(vty, zvrf, afi, !!fib, + vrf_json, !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, !!ng, + &ctx); else - do_show_ip_route( - vty, zvrf_name(zvrf), afi, SAFI_UNICAST, - !!fib, !!json, tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, table, !!ng, &ctx); + do_show_ip_route(vty, zvrf_name(zvrf), afi, + SAFI_UNICAST, !!fib, vrf_json, + !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, table, !!ng, + &ctx); + + if (!!json) + json_object_object_add(root_json, + zvrf_name(zvrf), + vrf_json); + } + if (!!json) { + vty_json_no_pretty(vty, root_json); + root_json = NULL; } } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -1840,13 +1820,13 @@ DEFPY (show_route, return CMD_SUCCESS; if (table_all) - do_show_ip_route_all(vty, zvrf, afi, !!fib, !!json, tag, - prefix_str ? prefix : NULL, + do_show_ip_route_all(vty, zvrf, afi, !!fib, NULL, !!json, + tag, prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, !!ng, &ctx); else do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, - !!fib, !!json, tag, + !!fib, NULL, !!json, tag, prefix_str ? prefix : NULL, !!supernets_only, type, ospf_instance_id, table, !!ng, &ctx); @@ -2018,11 +1998,15 @@ DEFPY (show_route_summary, afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct route_table *table; bool uj = use_json(argc, argv); + json_object *vrf_json = NULL; if (vrf_all) { struct vrf *vrf; struct zebra_vrf *zvrf; + if (uj && !vrf_json) + vrf_json = json_object_new_object(); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((zvrf = vrf->info) == NULL) continue; @@ -2040,10 +2024,14 @@ DEFPY (show_route_summary, if (prefix) vty_show_ip_route_summary_prefix(vty, table, - uj); + vrf_json, uj); else - vty_show_ip_route_summary(vty, table, uj); + vty_show_ip_route_summary(vty, table, vrf_json, + uj); } + + if (uj) + vty_json(vty, vrf_json); } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -2059,9 +2047,9 @@ DEFPY (show_route_summary, return CMD_SUCCESS; if (prefix) - vty_show_ip_route_summary_prefix(vty, table, uj); + vty_show_ip_route_summary_prefix(vty, table, NULL, uj); else - vty_show_ip_route_summary(vty, table, uj); + vty_show_ip_route_summary(vty, table, NULL, uj); } return CMD_SUCCESS; @@ -2222,7 +2210,8 @@ static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table) vrf_id_to_name(re->vrf_id)); vty_out(vty, " flags: %u\n", re->flags); - if (re->type != ZEBRA_ROUTE_CONNECT) { + if (re->type != ZEBRA_ROUTE_CONNECT && + re->type != ZEBRA_ROUTE_LOCAL) { vty_out(vty, " distance: %u\n", re->distance); vty_out(vty, " metric: %u\n", re->metric); } @@ -2266,8 +2255,8 @@ static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table) } } -static void vty_show_ip_route_summary(struct vty *vty, - struct route_table *table, bool use_json) +static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json) { struct route_node *rn; struct route_entry *re; @@ -2281,6 +2270,8 @@ static void vty_show_ip_route_summary(struct vty *vty, uint32_t is_ibgp; json_object *json_route_summary = NULL; json_object *json_route_routes = NULL; + const char *vrf_name = zvrf_name( + ((struct rib_table_info *)route_table_get_info(table))->zvrf); memset(&rib_cnt, 0, sizeof(rib_cnt)); memset(&fib_cnt, 0, sizeof(fib_cnt)); @@ -2331,10 +2322,7 @@ static void vty_show_ip_route_summary(struct vty *vty, if (!use_json) vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source", - "Routes", "FIB", - zvrf_name(((struct rib_table_info *) - route_table_get_info(table)) - ->zvrf)); + "Routes", "FIB", vrf_name); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if ((rib_cnt[i] > 0) || (i == ZEBRA_ROUTE_BGP @@ -2426,7 +2414,11 @@ static void vty_show_ip_route_summary(struct vty *vty, json_object_int_add(json_route_summary, "routesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_json(vty, json_route_summary); + if (!vrf_json) + vty_json(vty, json_route_summary); + else + json_object_object_add(vrf_json, vrf_name, + json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2444,6 +2436,7 @@ static void vty_show_ip_route_summary(struct vty *vty, */ static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json) { struct route_node *rn; @@ -2457,6 +2450,8 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, int cnt; json_object *json_route_summary = NULL; json_object *json_route_routes = NULL; + const char *vrf_name = zvrf_name( + ((struct rib_table_info *)route_table_get_info(table))->zvrf); memset(&rib_cnt, 0, sizeof(rib_cnt)); memset(&fib_cnt, 0, sizeof(fib_cnt)); @@ -2496,10 +2491,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, if (!use_json) vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source", - "Prefix Routes", "FIB", - zvrf_name(((struct rib_table_info *) - route_table_get_info(table)) - ->zvrf)); + "Prefix Routes", "FIB", vrf_name); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rib_cnt[i] > 0) { @@ -2574,7 +2566,11 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, json_object_int_add(json_route_summary, "prefixRoutesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_json(vty, json_route_summary); + if (!vrf_json) + vty_json(vty, json_route_summary); + else + json_object_object_add(vrf_json, vrf_name, + json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2695,153 +2691,6 @@ DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd, return zebra_evpn_mh_redirect_off(vty, redirect_off); } -DEFUN (default_vrf_vni_mapping, - default_vrf_vni_mapping_cmd, - "vni " CMD_VNI_RANGE "[prefix-routes-only]", - "VNI corresponding to the DEFAULT VRF\n" - "VNI-ID\n" - "Prefix routes only \n") -{ - char xpath[XPATH_MAXLEN]; - struct zebra_vrf *zvrf = NULL; - int filter = 0; - - zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return CMD_WARNING; - - if (argc == 3) - filter = 1; - - snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg); - - if (filter) { - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); - } - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (no_default_vrf_vni_mapping, - no_default_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE "[prefix-routes-only]", - NO_STR - "VNI corresponding to DEFAULT VRF\n" - "VNI-ID\n" - "Prefix routes only \n") -{ - char xpath[XPATH_MAXLEN]; - int filter = 0; - vni_t vni = strtoul(argv[2]->arg, NULL, 10); - struct zebra_vrf *zvrf = NULL; - - zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - if (!zvrf) - return CMD_WARNING; - - if (argc == 4) - filter = 1; - - if (zvrf->l3vni != vni) { - vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, - zvrf->vrf->name); - return CMD_WARNING; - } - - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg); - - if (filter) { - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true"); - } - - snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (vrf_vni_mapping, - vrf_vni_mapping_cmd, - "vni " CMD_VNI_RANGE "[prefix-routes-only]", - "VNI corresponding to tenant VRF\n" - "VNI-ID\n" - "prefix-routes-only\n") -{ - int filter = 0; - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - assert(vrf); - assert(zvrf); - - if (argc == 3) - filter = 1; - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY, - argv[1]->arg); - - if (filter) - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", - NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (no_vrf_vni_mapping, - no_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE "[prefix-routes-only]", - NO_STR - "VNI corresponding to tenant VRF\n" - "VNI-ID\n" - "prefix-routes-only\n") -{ - int filter = 0; - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - vni_t vni = strtoul(argv[2]->arg, NULL, 10); - - assert(vrf); - assert(zvrf); - - if (argc == 4) - filter = 1; - - if (zvrf->l3vni != vni) { - vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, - zvrf->vrf->name); - return CMD_WARNING; - } - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY, - argv[2]->arg); - - if (filter) - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", - NB_OP_DESTROY, "true"); - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - /* show vrf */ DEFPY (show_vrf_vni, show_vrf_vni_cmd, @@ -4006,6 +3855,17 @@ static int config_write_protocol(struct vty *vty) return 1; } +static inline bool zebra_vty_v6_rr_semantics_used(void) +{ + if (zebra_nhg_kernel_nexthops_enabled()) + return true; + + if (zrouter.v6_rr_semantics) + return true; + + return false; +} + DEFUN (show_zebra, show_zebra_cmd, "show zebra", @@ -4025,7 +3885,9 @@ DEFUN (show_zebra, ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off"); ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off"); ttable_add_row(table, "Kernel socket buffer size|%d", rcvbufsize); - + ttable_add_row(table, "v6 Route Replace Semantics|%s", + zebra_vty_v6_rr_semantics_used() ? "Replace" + : "Delete then Add"); #ifdef GNU_LINUX if (!vrf_is_backend_netns()) @@ -4036,6 +3898,9 @@ DEFUN (show_zebra, ttable_add_row(table, "VRF|Not Available"); #endif + ttable_add_row(table, "v6 with v4 nexthop|%s", + zrouter.v6_with_v4_nexthop ? "Used" : "Unavaliable"); + ttable_add_row(table, "ASIC offload|%s", zrouter.asic_offloaded ? "Used" : "Unavailable"); @@ -4457,31 +4322,6 @@ DEFPY (no_zebra_protodown_bit, #endif /* HAVE_NETLINK */ -DEFUN(ip_table_range, ip_table_range_cmd, - "[no] ip table range (1-4294967295) (1-4294967295)", - NO_STR IP_STR - "table configuration\n" - "Configure table range\n" - "Start Routing Table\n" - "End Routing Table\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf_id(zvrf) != VRF_DEFAULT && !vrf_is_backend_netns()) { - vty_out(vty, - "VRF subcommand does not make any sense in l3mdev based vrf's\n"); - return CMD_WARNING; - } - - if (strmatch(argv[0]->text, "no")) - return table_manager_range(vty, false, zvrf, NULL, NULL); - - return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg); -} - #ifdef HAVE_SCRIPTING DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd, @@ -4593,14 +4433,6 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); install_element(VIEW_NODE, &show_ipv6_rpf_addr_cmd); - install_element(CONFIG_NODE, &ip_nht_default_route_cmd); - install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd); - install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); - install_element(CONFIG_NODE, &no_ipv6_nht_default_route_cmd); - install_element(VRF_NODE, &ip_nht_default_route_cmd); - install_element(VRF_NODE, &no_ip_nht_default_route_cmd); - install_element(VRF_NODE, &ipv6_nht_default_route_cmd); - install_element(VRF_NODE, &no_ipv6_nht_default_route_cmd); install_element(CONFIG_NODE, &rnh_hide_backups_cmd); install_element(VIEW_NODE, &show_frr_cmd); @@ -4652,19 +4484,12 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd); install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd); install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd); - install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd); - install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd); - install_element(VRF_NODE, &vrf_vni_mapping_cmd); - install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); install_element(VIEW_NODE, &show_dataplane_cmd); install_element(VIEW_NODE, &show_dataplane_providers_cmd); install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd); install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd); - install_element(CONFIG_NODE, &ip_table_range_cmd); - install_element(VRF_NODE, &ip_table_range_cmd); - #ifdef HAVE_NETLINK install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd); install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 36290f99e0..89b43f6d22 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -82,7 +82,7 @@ static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); static struct zebra_neigh *svd_nh_add(const struct ipaddr *vtep_ip, const struct ethaddr *rmac); -static int svd_nh_del(struct zebra_neigh *n); +static void svd_nh_del(struct zebra_neigh *n); static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); @@ -194,7 +194,7 @@ static int l3vni_rmac_nh_list_cmp(void *p1, void *p2) const struct ipaddr *vtep_ip1 = p1; const struct ipaddr *vtep_ip2 = p2; - return !ipaddr_cmp(vtep_ip1, vtep_ip2); + return ipaddr_cmp(vtep_ip1, vtep_ip2); } static void l3vni_rmac_nh_free(struct ipaddr *vtep_ip) @@ -308,7 +308,7 @@ static void zevpn_print_neigh_hash_all_evpn_detail(struct hash_bucket *bucket, zevpn = (struct zebra_evpn *)bucket->data; if (!zevpn) { if (json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); return; } num_neigh = hashcount(zevpn->neigh_table); @@ -515,7 +515,7 @@ static void zevpn_print_mac_hash_all_evpn_detail(struct hash_bucket *bucket, zevpn = (struct zebra_evpn *)bucket->data; if (!zevpn) { if (json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); return; } wctx->zevpn = zevpn; @@ -769,10 +769,6 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx) json_evpn_list = json_object_new_array(); json_object_int_add(json, "vni", zl3vni->vni); json_object_string_add(json, "type", "L3"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON outputs") -#endif - json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); json_object_string_add(json, "tenantVrf", zl3vni_vrf_name(zl3vni)); json_object_string_addf(json, "localVtepIp", "%pI4", @@ -891,6 +887,7 @@ static int zvni_map_to_svi_ns(struct ns *ns, if (vl->vid == in_param->vid) { *p_ifp = tmp_if; + route_unlock_node(rn); return NS_WALK_STOP; } } @@ -1589,17 +1586,24 @@ static struct zebra_neigh *svd_nh_add(const struct ipaddr *ip, /* * Del Single VXlan Device neighbor entry. */ -static int svd_nh_del(struct zebra_neigh *n) +static void svd_nh_del(struct zebra_neigh *n) { if (n->refcnt > 0) - return -1; + return; hash_release(svd_nh_table, n); XFREE(MTYPE_L3NEIGH, n); +} - return 0; +static void svd_nh_del_terminate(void *ptr) +{ + struct zebra_neigh *n = ptr; + + n->refcnt = 0; + svd_nh_del(n); } + /* * Common code to install remote nh as neigh into the kernel. */ @@ -2005,6 +2009,7 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns, zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip; *_pifp = (void *)ifp; + route_unlock_node(rn); return NS_WALK_STOP; } @@ -2116,6 +2121,7 @@ static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni) zif, in_param->br_if); if (vni_id) { found = 1; + route_unlock_node(rn); break; } } @@ -2255,14 +2261,13 @@ static int zl3vni_send_add_to_client(struct zebra_l3vni *zl3vni) stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Send L3_VNI_ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s", - zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), - &svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip, - CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) - ? "prefix-routes-only" - : "none", - zebra_route_string(client->proto)); + zlog_debug("Send L3VNI ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s", + zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), + &svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip, + CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) + ? "prefix-routes-only" + : "none", + zebra_route_string(client->proto)); client->l3vniadd_cnt++; return zserv_send_message(client, s); @@ -2290,7 +2295,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni) stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni, + zlog_debug("Send L3VNI DEL %u VRF %s to %s", zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), zebra_route_string(client->proto)); @@ -2402,6 +2407,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, vnip = zebra_vxlan_if_vni_find(zif, vni); if (vnip) { found = true; + route_unlock_node(rn); break; } } @@ -2586,14 +2592,15 @@ void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni); return; @@ -2627,14 +2634,15 @@ void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); return; @@ -2668,7 +2676,8 @@ void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2694,7 +2703,8 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2705,7 +2715,7 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_out(vty, "{}\n"); + vty_json(vty, json); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); @@ -2717,7 +2727,7 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, if (!n) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); else vty_out(vty, "%% Requested next-hop not present for L3-VNI %u\n", @@ -2738,13 +2748,16 @@ static void l3vni_print_nh_table(struct hash *nh_table, struct vty *vty, struct nh_walk_ctx wctx; json_object *json = NULL; - num_nh = hashcount(nh_table); - if (!num_nh) - return; - if (use_json) json = json_object_new_object(); + num_nh = hashcount(nh_table); + if (!num_nh) { + if (use_json) + vty_json_empty(vty, json); + return; + } + wctx.vty = vty; wctx.json = json; if (!use_json) { @@ -2766,14 +2779,14 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); return; @@ -2786,7 +2799,7 @@ void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json) { if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } @@ -2802,7 +2815,8 @@ void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2830,14 +2844,15 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -2901,14 +2916,15 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -2955,7 +2971,8 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2985,7 +3002,8 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3016,14 +3034,15 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3060,14 +3079,15 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3109,14 +3129,15 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3173,21 +3194,24 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3225,7 +3249,11 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, if (use_json) { json_object_object_add(json, "macs", json_mac); - vty_json(vty, json); + /* + * This is an extremely expensive operation at scale + * and non-pretty reduces memory footprint significantly. + */ + vty_json_no_pretty(vty, json); } } @@ -3242,7 +3270,8 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3270,7 +3299,8 @@ void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3299,7 +3329,8 @@ void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3329,7 +3360,8 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3369,22 +3401,34 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty, json_object *json = NULL; json_object *json_mac = NULL; - if (!is_evpn_enabled()) + if (!is_evpn_enabled()) { + if (use_json) + vty_json_empty(vty, NULL); return; + } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_json_empty(vty, NULL); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } num_macs = num_dup_detected_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3719,21 +3763,25 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, json_object *json_mac = NULL; if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, NULL); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3777,7 +3825,8 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3821,7 +3870,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (uj) + vty_json(vty, json); return; } @@ -3898,7 +3948,8 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3982,7 +4033,7 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } @@ -4010,8 +4061,12 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, void *))zl3vni_print_hash_detail, &zes); + /* + * This is an extremely expensive operation at scale + * and non-pretty reduces memory footprint significantly. + */ if (use_json) - vty_json(vty, json_array); + vty_json_no_pretty(vty, json_array); } /* @@ -5098,7 +5153,21 @@ void zebra_vxlan_macvlan_up(struct interface *ifp) zif = ifp->info; assert(zif); + + if (zif->link_nsid) + /* the link interface is another namespace */ + return; + link_ifp = zif->link; + if (!link_ifp) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "macvlan parent link is not found. Parent index %d ifp %s", + zif->link_ifindex, + ifindex2ifname(zif->link_ifindex, + ifp->vrf->vrf_id)); + return; + } link_zif = link_ifp->info; assert(link_zif); @@ -5115,9 +5184,8 @@ void zebra_vxlan_macvlan_up(struct interface *ifp) } } -int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, - char *err, int err_str_sz, int filter, - int add) +void zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, + int filter, int add) { struct zebra_l3vni *zl3vni = NULL; struct zebra_vrf *zvrf_evpn = NULL; @@ -5129,21 +5197,6 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, add ? "ADD" : "DEL"); if (add) { - /* check if the vni is already present under zvrf */ - if (zvrf->l3vni) { - snprintf(err, err_str_sz, - "VNI is already configured under the vrf"); - return -1; - } - - /* check if this VNI is already present in the system */ - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - snprintf(err, err_str_sz, - "VNI is already configured as L3-VNI"); - return -1; - } - /* Remove L2VNI if present */ zebra_vxlan_handle_vni_transition(zvrf, vni, add); @@ -5189,23 +5242,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, } else { zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - snprintf(err, err_str_sz, "VNI doesn't exist"); - return -1; - } - - if (zvrf->l3vni != vni) { - snprintf(err, err_str_sz, - "VNI %d doesn't exist in VRF: %s", - vni, zvrf->vrf->name); - return -1; - } - - if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) { - snprintf(err, ERR_STR_SZ, - "prefix-routes-only is not set for the vni"); - return -1; - } + assert(zl3vni); zebra_vxlan_process_l3vni_oper_down(zl3vni); @@ -5223,7 +5260,6 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, /* Add L2VNI for this VNI */ zebra_vxlan_handle_vni_transition(zvrf, vni, add); } - return 0; } int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf) @@ -5274,7 +5310,9 @@ int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) vni = zl3vni->vni; zl3vni_del(zl3vni); - zebra_vxlan_handle_vni_transition(zvrf, vni, 0); + + if (!zrouter.in_shutdown) + zebra_vxlan_handle_vni_transition(zvrf, vni, 0); return 0; } @@ -5758,6 +5796,11 @@ void zebra_vxlan_init(void) zebra_evpn_mh_init(); } +void zebra_vxlan_terminate(void) +{ + hash_clean_and_free(&svd_nh_table, svd_nh_del_terminate); +} + /* free l3vni table */ void zebra_vxlan_disable(void) { @@ -5935,8 +5978,6 @@ static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) struct zebra_vrf *zvrf; zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return; /* On SG entry deletion remove the reference to its parent XG * entry @@ -6006,8 +6047,6 @@ void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, return; zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return; zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp); } @@ -6021,8 +6060,7 @@ void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp) return; zvrf = vrf_info_lookup(VRF_DEFAULT); - if (!zvrf) - return; + zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp); } diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 98c2767eb2..eb02de6f7b 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -178,13 +178,13 @@ extern int zebra_vxlan_if_add(struct interface *ifp); extern int zebra_vxlan_if_update(struct interface *ifp, struct zebra_vxlan_if_update_ctx *ctx); extern int zebra_vxlan_if_del(struct interface *ifp); -extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, - char *err, int err_str_sz, - int filter, int add); +extern void zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, + int filter, int add); extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf); extern void zebra_vxlan_close_tables(struct zebra_vrf *); extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *); extern void zebra_vxlan_init(void); +extern void zebra_vxlan_terminate(void); extern void zebra_vxlan_disable(void); extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, diff --git a/zebra/zserv.c b/zebra/zserv.c index 6abd49310c..27668534ee 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -181,9 +181,10 @@ void zserv_log_message(const char *errmsg, struct stream *msg, */ static void zserv_client_fail(struct zserv *client) { - flog_warn(EC_ZEBRA_CLIENT_IO_ERROR, - "Client '%s' encountered an error and is shutting down.", - zebra_route_string(client->proto)); + flog_warn( + EC_ZEBRA_CLIENT_IO_ERROR, + "Client '%s' (session id %d) encountered an error and is shutting down.", + zebra_route_string(client->proto), client->session_id); atomic_store_explicit(&client->pthread->running, false, memory_order_relaxed); @@ -305,6 +306,14 @@ zwrite_fail: * this task reschedules itself. * * Any failure in any of these actions is handled by terminating the client. + * + * The client's input buffer ibuf_fifo can have a maximum items as configured + * in the packets_to_process. This way we are not filling up the FIFO more + * than the maximum when the zebra main is busy. If the fifo has space, we + * reschedule ourselves to read more. + * + * The main thread processes the items in ibuf_fifo and always signals the + * client IO thread. */ static void zserv_read(struct event *thread) { @@ -312,15 +321,25 @@ static void zserv_read(struct event *thread) int sock; size_t already; struct stream_fifo *cache; - uint32_t p2p_orig; - - uint32_t p2p; + uint32_t p2p; /* Temp p2p used to process */ + uint32_t p2p_orig; /* Configured p2p (Default-1000) */ + int p2p_avail; /* How much space is available for p2p */ struct zmsghdr hdr; + size_t client_ibuf_fifo_cnt = stream_fifo_count_safe(client->ibuf_fifo); p2p_orig = atomic_load_explicit(&zrouter.packets_to_process, memory_order_relaxed); + p2p_avail = p2p_orig - client_ibuf_fifo_cnt; + + /* + * Do nothing if ibuf_fifo count has reached its max limit. Otherwise + * proceed and reschedule ourselves if there is space in the ibuf_fifo. + */ + if (p2p_avail <= 0) + return; + + p2p = p2p_avail; cache = stream_fifo_new(); - p2p = p2p_orig; sock = EVENT_FD(thread); while (p2p) { @@ -420,7 +439,7 @@ static void zserv_read(struct event *thread) p2p--; } - if (p2p < p2p_orig) { + if (p2p < (uint32_t)p2p_avail) { uint64_t time_now = monotime(NULL); /* update session statistics */ @@ -434,19 +453,23 @@ static void zserv_read(struct event *thread) while (cache->head) stream_fifo_push(client->ibuf_fifo, stream_fifo_pop(cache)); + /* Need to update count as main thread could have processed few */ + client_ibuf_fifo_cnt = + stream_fifo_count_safe(client->ibuf_fifo); } /* Schedule job to process those packets */ zserv_event(client, ZSERV_PROCESS_MESSAGES); - } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets from client: %s", p2p_orig - p2p, - zebra_route_string(client->proto)); + zlog_debug("Read %d packets from client: %s. Current ibuf fifo count: %zu. Conf P2p %d", + p2p_avail - p2p, zebra_route_string(client->proto), + client_ibuf_fifo_cnt, p2p_orig); - /* Reschedule ourselves */ - zserv_client_event(client, ZSERV_CLIENT_READ); + /* Reschedule ourselves since we have space in ibuf_fifo */ + if (client_ibuf_fifo_cnt < p2p_orig) + zserv_client_event(client, ZSERV_CLIENT_READ); stream_fifo_free(cache); @@ -482,14 +505,20 @@ static void zserv_client_event(struct zserv *client, * as the task argument. * * Each message is popped off the client's input queue and the action associated - * with the message is executed. This proceeds until there are no more messages, - * an error occurs, or the processing limit is reached. + * with the message is executed. This proceeds until an error occurs, or the + * processing limit is reached. * * The client's I/O thread can push at most zrouter.packets_to_process messages * onto the input buffer before notifying us there are packets to read. As long * as we always process zrouter.packets_to_process messages here, then we can * rely on the read thread to handle queuing this task enough times to process * everything on the input queue. + * + * If the client ibuf always schedules a wakeup to the client IO to read more + * items from the socked buffer. This way we ensure + * - Client IO thread always tries to read the socket buffer and add more + * items to the ibuf_fifo (until max limit) + * - the hidden config change (zebra zapi-packets <>) is taken into account. */ static void zserv_process_messages(struct event *thread) { @@ -507,8 +536,6 @@ static void zserv_process_messages(struct event *thread) stream_fifo_push(cache, msg); } - msg = NULL; - /* Need to reschedule processing work if there are still * packets in the fifo. */ @@ -525,6 +552,9 @@ static void zserv_process_messages(struct event *thread) /* Reschedule ourselves if necessary */ if (need_resched) zserv_event(client, ZSERV_PROCESS_MESSAGES); + + /* Ensure to include the read socket in the select/poll/etc.. */ + zserv_client_event(client, ZSERV_CLIENT_READ); } int zserv_send_message(struct zserv *client, struct stream *msg) @@ -583,23 +613,27 @@ static void zserv_client_free(struct zserv *client) /* Close file descriptor. */ if (client->sock) { - unsigned long nroutes; - unsigned long nnhgs; + unsigned long nroutes = 0; + unsigned long nnhgs = 0; close(client->sock); if (DYNAMIC_CLIENT_GR_DISABLED(client)) { - zebra_mpls_client_cleanup_vrf_label(client->proto); + if (!client->synchronous) { + zebra_mpls_client_cleanup_vrf_label( + client->proto); - nroutes = rib_score_proto(client->proto, - client->instance); + nroutes = rib_score_proto(client->proto, + client->instance); + } zlog_notice( "client %d disconnected %lu %s routes removed from the rib", client->sock, nroutes, zebra_route_string(client->proto)); /* Not worrying about instance for now */ - nnhgs = zebra_nhg_score_proto(client->proto); + if (!client->synchronous) + nnhgs = zebra_nhg_score_proto(client->proto); zlog_notice( "client %d disconnected %lu %s nhgs removed from the rib", client->sock, nnhgs, @@ -628,23 +662,27 @@ static void zserv_client_free(struct zserv *client) /* Free bitmaps. */ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { - vrf_bitmap_free(client->redist[afi][i]); + vrf_bitmap_free(&client->redist[afi][i]); redist_del_all_instances(&client->mi_redist[afi][i]); } - vrf_bitmap_free(client->redist_default[afi]); - vrf_bitmap_free(client->ridinfo[afi]); - vrf_bitmap_free(client->nhrp_neighinfo[afi]); + vrf_bitmap_free(&client->redist_default[afi]); + vrf_bitmap_free(&client->ridinfo[afi]); + vrf_bitmap_free(&client->neighinfo[afi]); } /* * If any instance are graceful restart enabled, * client is not deleted */ - if (DYNAMIC_CLIENT_GR_DISABLED(client)) { + if (DYNAMIC_CLIENT_GR_DISABLED(client) || zebra_router_in_shutdown()) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Deleting client %s", __func__, zebra_route_string(client->proto)); + + if (zebra_router_in_shutdown()) + zebra_gr_client_final_shutdown(client); + zserv_client_delete(client); } else { /* Handle cases where client has GR instance. */ @@ -752,10 +790,10 @@ static struct zserv *zserv_client_create(int sock) /* Initialize flags */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - client->redist[afi][i] = vrf_bitmap_init(); - client->redist_default[afi] = vrf_bitmap_init(); - client->ridinfo[afi] = vrf_bitmap_init(); - client->nhrp_neighinfo[afi] = vrf_bitmap_init(); + vrf_bitmap_init(&client->redist[afi][i]); + vrf_bitmap_init(&client->redist_default[afi]); + vrf_bitmap_init(&client->ridinfo[afi]); + vrf_bitmap_init(&client->neighinfo[afi]); } /* Add this client to linked list. */ @@ -1058,6 +1096,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) 0, client->redist_v4_del_cnt); vty_out(vty, "Redist:v6 %-12u%-12u%-12u\n", client->redist_v6_add_cnt, 0, client->redist_v6_del_cnt); + vty_out(vty, "NHG %-12u%-12u%-12u\n", client->nhg_add_cnt, + client->nhg_upd8_cnt, client->nhg_del_cnt); vty_out(vty, "VRF %-12u%-12u%-12u\n", client->vrfadd_cnt, 0, client->vrfdel_cnt); vty_out(vty, "Connected %-12u%-12u%-12u\n", client->ifadd_cnt, 0, @@ -1085,12 +1125,10 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "ES-EVI %-12u%-12u%-12u\n", client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); - -#if defined DEV_BUILD vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); -#endif + vty_out(vty, "\n"); } diff --git a/zebra/zserv.h b/zebra/zserv.h index 90aa4d53f4..57d673060f 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -31,9 +31,6 @@ extern "C" { struct zebra_vrf; -/* Default port information. */ -#define ZEBRA_VTY_PORT 2601 - /* Default configuration filename. */ #define DEFAULT_CONFIG_FILE "zebra.conf" @@ -121,7 +118,7 @@ struct zserv { vrf_bitmap_t ridinfo[AFI_MAX]; /* Router-id information. */ - vrf_bitmap_t nhrp_neighinfo[AFI_MAX]; + vrf_bitmap_t neighinfo[AFI_MAX]; bool notify_owner; @@ -185,6 +182,9 @@ struct zserv { uint32_t local_es_evi_add_cnt; uint32_t local_es_evi_del_cnt; uint32_t error_cnt; + uint32_t nhg_add_cnt; + uint32_t nhg_upd8_cnt; + uint32_t nhg_del_cnt; time_t nh_reg_time; time_t nh_dereg_time; @@ -237,8 +237,7 @@ DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client)); DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client)); #define DYNAMIC_CLIENT_GR_DISABLED(_client) \ - ((_client->proto <= ZEBRA_ROUTE_CONNECT) \ - || !(_client->gr_instance_count)) + ((_client->proto <= ZEBRA_ROUTE_LOCAL) || !(_client->gr_instance_count)) /* * Initialize Zebra API server. @@ -379,6 +378,7 @@ __attribute__((__noreturn__)) void zebra_finalize(struct event *event); /* * Graceful restart functions. */ +extern void zebra_gr_client_final_shutdown(struct zserv *client); extern int zebra_gr_client_disconnect(struct zserv *client); extern void zebra_gr_client_reconnect(struct zserv *client); extern void zebra_gr_stale_client_cleanup(struct list *client_list); |
