diff options
author | Daniel Baumann <daniel@debian.org> | 2024-11-17 07:11:26 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-17 07:11:26 +0100 |
commit | d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6 (patch) | |
tree | 705ea89e798053f9c227b85512bc9f5b437b0093 /zebra | |
parent | Releasing debian version 10.1.1-3. (diff) | |
download | frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.tar.xz frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.zip |
Merging upstream version 10.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'zebra')
55 files changed, 4862 insertions, 1304 deletions
diff --git a/zebra/connected.c b/zebra/connected.c index 404f892f..ce26c14c 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -176,6 +176,40 @@ static void connected_update(struct interface *ifp, struct connected *ifc) connected_announce(ifp, ifc); } +/* + * This function goes through and handles the deletion of a kernel route that happened + * to be the exact same as the connected route, so that the connected route wins. + * This can happen during processing if we happen to receive events in a slightly + * unexpected order. This is similiar to code in the other direction where if we + * have a kernel route don't install it if it perfectly matches a connected route. + */ +static void connected_remove_kernel_for_connected(afi_t afi, safi_t safi, struct zebra_vrf *zvrf, + struct prefix *p, struct nexthop *nh) +{ + struct route_node *rn; + struct route_entry *re; + rib_dest_t *dest; + struct route_table *table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf->vrf->vrf_id); + + rn = route_node_match(table, p); + if (!rn) + return; + + if (!prefix_same(&rn->p, p)) + return; + + dest = rib_dest_from_rnode(rn); + if (!dest || !dest->selected_fib) + return; + + re = dest->selected_fib; + if (re->type != ZEBRA_ROUTE_KERNEL) + return; + + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_KERNEL, 0, 0, p, NULL, nh, 0, + zvrf->table_id, 0, 0, false); +} + /* Called from if_up(). */ void connected_up(struct interface *ifp, struct connected *ifc) { @@ -185,6 +219,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, .vrf_id = ifp->vrf->vrf_id, + .weight = 1, }; struct zebra_vrf *zvrf; uint32_t metric; @@ -283,10 +318,13 @@ void connected_up(struct interface *ifp, struct connected *ifc) } if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + connected_remove_kernel_for_connected(afi, SAFI_UNICAST, zvrf, &p, &nh); + 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); + connected_remove_kernel_for_connected(afi, SAFI_MULTICAST, zvrf, &p, &nh); 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); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 9ad92d62..c12a569f 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -36,13 +36,11 @@ #include "zebra/zebra_dplane.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_router.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" -#include "zebra/debug.h" #include "fpm/fpm.h" #include "zebra/dplane_fpm_nl_clippy.c" @@ -136,8 +134,6 @@ struct fpm_nl_ctx { /* Amount of data plane context processed. */ _Atomic uint32_t dplane_contexts; - /* Amount of data plane contexts enqueued. */ - _Atomic uint32_t ctxqueue_len; /* Peak amount of data plane contexts enqueued. */ _Atomic uint32_t ctxqueue_len_peak; @@ -385,7 +381,7 @@ DEFPY(fpm_show_status, out = ttable_dump(table, "\n"); vty_out(vty, "%s\n", out); - XFREE(MTYPE_TMP, out); + XFREE(MTYPE_TMP_TTABLE, out); ttable_del(table); } @@ -399,6 +395,12 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, FPM_STR "FPM statistic counters\n") { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + vty_out(vty, "%30s\n%30s\n", "FPM counters", "============"); #define SHOW_COUNTER(label, counter) \ @@ -412,8 +414,7 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors); SHOW_COUNTER("Data plane items processed", gfnc->counters.dplane_contexts); - SHOW_COUNTER("Data plane items enqueued", - gfnc->counters.ctxqueue_len); + SHOW_COUNTER("Data plane items enqueued", curr_queue_len); SHOW_COUNTER("Data plane items queue peak", gfnc->counters.ctxqueue_len_peak); SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full); @@ -432,6 +433,12 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, "FPM statistic counters\n" JSON_STR) { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + struct json_object *jo; jo = json_object_new_object(); @@ -445,8 +452,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, gfnc->counters.connection_errors); json_object_int_add(jo, "data-plane-contexts", gfnc->counters.dplane_contexts); - json_object_int_add(jo, "data-plane-contexts-queue", - gfnc->counters.ctxqueue_len); + json_object_int_add(jo, "data-plane-contexts-queue", curr_queue_len); json_object_int_add(jo, "data-plane-contexts-queue-peak", gfnc->counters.ctxqueue_len_peak); json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full); @@ -1330,7 +1336,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg) struct zebra_l3vni *zl3vni = bucket->data; fra->zl3vni = zl3vni; - hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni); + hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, fra); } static void fpm_rmac_send(struct event *t) @@ -1495,8 +1501,6 @@ static void fpm_process_queue(struct event *t) /* Account the processed entries. */ processed_contexts++; - atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1, - memory_order_relaxed); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(fnc->prov, ctx); @@ -1670,10 +1674,29 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) struct zebra_dplane_ctx *ctx; struct fpm_nl_ctx *fnc; int counter, limit; - uint64_t cur_queue, peak_queue = 0, stored_peak_queue; + uint64_t cur_queue = 0, peak_queue = 0, stored_peak_queue; fnc = dplane_provider_get_data(prov); limit = dplane_provider_get_work_limit(prov); + + frr_with_mutex (&fnc->ctxqueue_mutex) { + cur_queue = dplane_ctx_queue_count(&fnc->ctxqueue); + } + + if (cur_queue >= (uint64_t)limit) { + if (IS_ZEBRA_DEBUG_FPM) + zlog_debug("%s: Already at a limit(%" PRIu64 + ") of internal work, hold off", + __func__, cur_queue); + limit = 0; + } else if (cur_queue != 0) { + if (IS_ZEBRA_DEBUG_FPM) + zlog_debug("%s: current queue is %" PRIu64 + ", limiting to lesser amount of %" PRIu64, + __func__, cur_queue, limit - cur_queue); + limit -= cur_queue; + } + for (counter = 0; counter < limit; counter++) { ctx = dplane_provider_dequeue_in_ctx(prov); if (ctx == NULL) @@ -1684,25 +1707,27 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) * anyway. */ if (fnc->socket != -1 && fnc->connecting == false) { + enum dplane_op_e op = dplane_ctx_get_op(ctx); + /* - * Update the number of queued contexts *before* - * enqueueing, to ensure counter consistency. + * Just skip multicast routes and let them flow through */ - atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len, - 1, memory_order_relaxed); + if ((op == DPLANE_OP_ROUTE_DELETE || op == DPLANE_OP_ROUTE_INSTALL || + op == DPLANE_OP_ROUTE_UPDATE) && + dplane_ctx_get_safi(ctx) == SAFI_MULTICAST) + goto skip; frr_with_mutex (&fnc->ctxqueue_mutex) { dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx); + cur_queue = + dplane_ctx_queue_count(&fnc->ctxqueue); } - cur_queue = atomic_load_explicit( - &fnc->counters.ctxqueue_len, - memory_order_relaxed); if (peak_queue < cur_queue) peak_queue = cur_queue; continue; } - +skip: dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(prov, ctx); } @@ -1714,9 +1739,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) atomic_store_explicit(&fnc->counters.ctxqueue_len_peak, peak_queue, memory_order_relaxed); - if (atomic_load_explicit(&fnc->counters.ctxqueue_len, - memory_order_relaxed) - > 0) + if (cur_queue > 0) event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index d0aa2167..688a7f6e 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -296,6 +296,8 @@ void interface_list(struct zebra_ns *zns) /proc/net/if_inet6. */ ifaddr_proc_ipv6(); #endif /* HAVE_PROC_NET_IF_INET6 */ + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); } #endif /* OPEN_BSD */ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 32335198..8beae125 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1032,212 +1032,6 @@ netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) return netlink_batch_add_msg(bth, ctx, netlink_intf_msg_encoder, false); } -int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) -{ - int len; - struct ifaddrmsg *ifa; - struct rtattr *tb[IFA_MAX + 1]; - struct interface *ifp; - void *addr; - void *broad; - uint8_t flags = 0; - char *label = NULL; - struct zebra_ns *zns; - uint32_t metric = METRIC_MAX; - uint32_t kernel_flags = 0; - - frrtrace(3, frr_zebra, netlink_interface_addr, h, ns_id, startup); - - zns = zebra_ns_lookup(ns_id); - ifa = NLMSG_DATA(h); - - if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { - flog_warn( - EC_ZEBRA_UNKNOWN_FAMILY, - "Invalid address family: %u received from kernel interface addr change: %s", - ifa->ifa_family, nl_msg_type_to_str(h->nlmsg_type)); - return 0; - } - - if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) - return 0; - - len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - 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 ifaddrmsg))); - return -1; - } - - netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); - - ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index); - if (ifp == NULL) { - if (startup) { - /* During startup, failure to lookup the referenced - * interface should not be an error, so we have - * downgraded this condition to warning, and we permit - * the startup interface state retrieval to continue. - */ - flog_warn(EC_LIB_INTERFACE, - "%s: can't find interface by index %d", - __func__, ifa->ifa_index); - return 0; - } else { - flog_err(EC_LIB_INTERFACE, - "%s: can't find interface by index %d", - __func__, ifa->ifa_index); - return -1; - } - } - - /* Flags passed through */ - if (tb[IFA_FLAGS]) - kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]); - else - kernel_flags = ifa->ifa_flags; - - if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ - { - char buf[BUFSIZ]; - zlog_debug("%s %s %s flags 0x%x:", __func__, - nl_msg_type_to_str(h->nlmsg_type), ifp->name, - kernel_flags); - if (tb[IFA_LOCAL]) - zlog_debug(" IFA_LOCAL %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_LOCAL]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_ADDRESS]) - zlog_debug(" IFA_ADDRESS %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_ADDRESS]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_BROADCAST]) - zlog_debug(" IFA_BROADCAST %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_BROADCAST]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL]))) - zlog_debug(" IFA_LABEL %s", - (char *)RTA_DATA(tb[IFA_LABEL])); - - if (tb[IFA_CACHEINFO]) { - struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]); - zlog_debug(" IFA_CACHEINFO pref %d, valid %d", - ci->ifa_prefered, ci->ifa_valid); - } - } - - /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ - if (tb[IFA_LOCAL] == NULL) - tb[IFA_LOCAL] = tb[IFA_ADDRESS]; - if (tb[IFA_ADDRESS] == NULL) - tb[IFA_ADDRESS] = tb[IFA_LOCAL]; - - /* local interface address */ - addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); - - /* is there a peer address? */ - if (tb[IFA_ADDRESS] - && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), - RTA_PAYLOAD(tb[IFA_ADDRESS]))) { - broad = RTA_DATA(tb[IFA_ADDRESS]); - SET_FLAG(flags, ZEBRA_IFA_PEER); - } else - /* seeking a broadcast address */ - broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) - : NULL); - - /* addr is primary key, SOL if we don't have one */ - if (addr == NULL) { - zlog_debug("%s: Local Interface Address is NULL for %s", - __func__, ifp->name); - return -1; - } - - /* Flags. */ - if (kernel_flags & IFA_F_SECONDARY) - SET_FLAG(flags, ZEBRA_IFA_SECONDARY); - - /* Label */ - if (tb[IFA_LABEL]) - label = (char *)RTA_DATA(tb[IFA_LABEL]); - - if (label && strcmp(ifp->name, label) == 0) - label = NULL; - - if (tb[IFA_RT_PRIORITY]) - metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]); - - /* Register interface address to the interface. */ - if (ifa->ifa_family == AF_INET) { - if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { - zlog_err( - "Invalid prefix length: %u received from kernel interface addr change: %s", - ifa->ifa_prefixlen, - nl_msg_type_to_str(h->nlmsg_type)); - return -1; - } - - if (h->nlmsg_type == RTM_NEWADDR) - connected_add_ipv4(ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, - (struct in_addr *)broad, label, - metric); - else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) { - /* Delete with a peer address */ - connected_delete_ipv4( - ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, broad); - } else - connected_delete_ipv4( - ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, NULL); - } - - if (ifa->ifa_family == AF_INET6) { - if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { - zlog_err( - "Invalid prefix length: %u received from kernel interface addr change: %s", - ifa->ifa_prefixlen, - nl_msg_type_to_str(h->nlmsg_type)); - return -1; - } - if (h->nlmsg_type == RTM_NEWADDR) { - /* Only consider valid addresses; we'll not get a - * notification from - * the kernel till IPv6 DAD has completed, but at init - * time, Quagga - * does query for and will receive all addresses. - */ - if (!(kernel_flags - & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) - connected_add_ipv6(ifp, flags, - (struct in6_addr *)addr, - (struct in6_addr *)broad, - ifa->ifa_prefixlen, label, - metric); - } else - connected_delete_ipv6(ifp, (struct in6_addr *)addr, - NULL, ifa->ifa_prefixlen); - } - - /* - * Linux kernel does not send route delete on interface down/addr del - * so we have to re-process routes it owns (i.e. kernel routes) - */ - if (h->nlmsg_type != RTM_NEWADDR) - rib_update(RIB_UPDATE_KERNEL); - - return 0; -} - /* * Parse and validate an incoming interface address change message, * generating a dplane context object. @@ -1799,14 +1593,18 @@ int netlink_tunneldump_read(struct zebra_ns *zns) ret = netlink_request_tunneldump(zns, PF_BRIDGE, tmp_if->ifindex); - if (ret < 0) + if (ret < 0) { + route_unlock_node(rn); return ret; + } ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true); - if (ret < 0) + if (ret < 0) { + route_unlock_node(rn); return ret; + } } return 0; diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 9b31906a..dc1f71cb 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -12,9 +12,6 @@ extern "C" { #endif -extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, - int startup); - /* * Parse an incoming interface address change message, generate a dplane * context object for processing. diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index 9db95989..28cbb041 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -128,6 +128,8 @@ void interface_list(struct zebra_ns *zns) /* Free sysctl buffer. */ XFREE(MTYPE_TMP, ref); + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); } #endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) */ diff --git a/zebra/interface.c b/zebra/interface.c index b3adc448..d1460047 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -32,7 +32,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" @@ -1059,6 +1058,8 @@ void if_down(struct interface *ifp) /* Delete all neighbor addresses learnt through IPv6 RA */ if_down_del_nbr_connected(ifp); + + rib_update_handle_vrf_all(RIB_UPDATE_INTERFACE_DOWN, ZEBRA_ROUTE_KERNEL); } void if_refresh(struct interface *ifp) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d2f1db67..84aabc42 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -672,21 +672,6 @@ void netlink_parse_rtattr_nested(struct rtattr **tb, int max, netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } -bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, const void *data, - unsigned int len) -{ - if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { - zlog_err("ERROR message exceeded bound of %d", maxlen); - return false; - } - - memcpy(NLMSG_TAIL(n), data, len); - memset((uint8_t *)NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); - - return true; -} - bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type, const void *data, unsigned int alen) { diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index e37bba0c..9db4e578 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -77,14 +77,6 @@ extern void netlink_parse_rtattr_flags(struct rtattr **tb, int max, unsigned short flags); extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max, struct rtattr *rta); -/* - * nl_addraw_l copies raw form the netlink message buffer into netlink - * message header pointer. It ensures the aligned data buffer does not - * override past max length. - * return value is 0 if its successful - */ -extern bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, - const void *data, unsigned int len); 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); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index d50e7de2..5cfbe7a8 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1468,10 +1468,12 @@ static void routing_socket(struct zebra_ns *zns) void interface_list_second(struct zebra_ns *zns) { + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ); } void interface_list_tunneldump(struct zebra_ns *zns) { + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ); } /* Exported interface function. This function simply calls diff --git a/zebra/main.c b/zebra/main.c index ea1e1cbd..4d9b7c3b 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -65,8 +65,6 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -88,7 +86,6 @@ const struct option longopts[] = { { "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 @@ -96,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -241,7 +238,7 @@ void zebra_finalize(struct event *dummy) zebra_ns_notify_close(); /* Final shutdown of ns resources */ - ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_walk_func(zebra_ns_kernel_shutdown, NULL, NULL); zebra_rib_terminate(); zebra_router_terminate(); @@ -254,6 +251,8 @@ void zebra_finalize(struct event *dummy) label_manager_terminate(); + ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_terminate(); frr_fini(); exit(0); @@ -326,7 +325,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -342,9 +340,8 @@ int main(int argc, char **argv) " -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" + " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops\n" #ifdef HAVE_NETLINK " -s, --nl-bufsize Set netlink receive buffer size\n" " -n, --vrfwnetns Use NetNS as VRF backend\n" @@ -352,8 +349,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -397,9 +393,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -488,11 +481,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 11c13303..2de0917a 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -290,6 +290,7 @@ void redistribute_delete(const struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { uint8_t old_inst, new_inst; uint32_t table = 0; + struct vrf *vrf = vrf_lookup_by_id(vrfid); old_inst = new_inst = 0; @@ -302,8 +303,8 @@ 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, + zlog_debug("(%s:%u):%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", + VRF_LOGNAME(vrf), 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"); diff --git a/zebra/rib.h b/zebra/rib.h index a721f4ba..5fedb073 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -108,8 +108,8 @@ struct route_entry { uint32_t nexthop_mtu; /* Flags of this route. - * This flag's definition is in lib/zebra.h ZEBRA_FLAG_* and is exposed - * to clients via Zserv + * This flag's definition is in lib/zclient.h ZEBRA_FLAG_* and is + * exposed to clients via Zserv */ uint32_t flags; @@ -326,6 +326,7 @@ typedef struct rib_tables_iter_t_ { /* Events/reasons triggering a RIB update. */ enum rib_update_event { + RIB_UPDATE_INTERFACE_DOWN, RIB_UPDATE_KERNEL, RIB_UPDATE_RMAP_CHANGE, RIB_UPDATE_OTHER, @@ -395,7 +396,7 @@ extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, - struct prefix *p, struct prefix_ipv6 *src_p, + const struct prefix *p, const struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint8_t distance, bool fromkernel); @@ -407,9 +408,6 @@ extern struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id, union g_addr *gaddr, struct route_node **rn_out); -extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, - vrf_id_t vrf_id); - extern void rib_update(enum rib_update_event event); extern void rib_update_table(struct route_table *table, enum rib_update_event event, int rtype); @@ -477,6 +475,8 @@ extern uint8_t route_distance(int type); extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, bool rt_delete); +extern void rib_update_handle_vrf_all(enum rib_update_event event, int rtype); + /* * rib_find_rn_from_ctx * @@ -622,17 +622,22 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern void zebra_vty_init(void); +extern uint32_t zebra_rib_dplane_results_count(void); extern pid_t pid; extern uint32_t rt_table_main_id; +void route_entry_dump_nh(const struct route_entry *re, const char *straddr, + const struct vrf *re_vrf, + const struct nexthop *nexthop); + /* Name of hook calls */ #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 01b527ea..ab07ef8d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -506,7 +506,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, void *gate, afi_t afi, vrf_id_t vrf_id) { struct interface *ifp = NULL; - struct nexthop nh = {0}; + struct nexthop nh = {.weight = 1}; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; @@ -591,12 +591,9 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, return nh; } -static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, - struct nexthop_group *ng, - struct rtmsg *rtm, - struct rtnexthop *rtnh, - struct rtattr **tb, - void *prefsrc, vrf_id_t vrf_id) +static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_group *ng, + struct rtmsg *rtm, struct rtnexthop *rtnh, + struct rtattr **tb, void *prefsrc, vrf_id_t vrf_id) { void *gate = NULL; struct interface *ifp = NULL; @@ -721,7 +718,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, rtnh = RTNH_NEXT(rtnh); } - uint8_t nhop_num = nexthop_group_nexthop_num(ng); + uint16_t nhop_num = nexthop_group_nexthop_num(ng); return nhop_num; } @@ -799,8 +796,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; - if (rtm->rtm_protocol == RTPROT_KERNEL) - return 0; selfroute = is_selfroute(rtm->rtm_protocol); @@ -1002,7 +997,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); if (!nhe_id) { - uint8_t nhop_num; + uint16_t nhop_num; /* Use temporary list of nexthops; parse * message payload's nexthops. @@ -1040,7 +1035,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", __func__, &p); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } } else { if (ctx) { @@ -1690,7 +1685,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, return false; if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in_addr))) + sizeof(struct in6_addr))) return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: @@ -2646,11 +2641,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) /* Char length to debug ID with */ #define ID_LENGTH 10 -static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, - uint32_t id, - const struct nh_grp *z_grp, - const uint8_t count, bool resilient, - const struct nhg_resilience *nhgr) +static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, uint32_t id, + const struct nh_grp *z_grp, const uint16_t count, + bool resilient, const struct nhg_resilience *nhgr) { struct nexthop_grp grp[count]; /* Need space for max group size, "/", and null term */ @@ -2981,7 +2974,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, if (!nl_attr_put(&req->n, buflen, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in_addr))) + sizeof(struct in6_addr))) return 0; break; case SEG6_LOCAL_ACTION_END_DT6: @@ -3185,6 +3178,9 @@ netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) } else return FRR_NETLINK_ERROR; + if (dplane_ctx_get_safi(ctx) == SAFI_MULTICAST) + return FRR_NETLINK_SUCCESS; + if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) return FRR_NETLINK_SUCCESS; @@ -3210,7 +3206,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, struct interface **ifp, ns_id_t ns_id) { - struct nexthop nh = {}; + struct nexthop nh = {.weight = 1}; void *gate = NULL; enum nexthop_types_t type = 0; int if_index = 0; @@ -3287,7 +3283,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, struct nh_grp *z_grp, int z_grp_size, struct nhg_resilience *nhgr) { - uint8_t count = 0; + uint16_t count = 0; /* linux/nexthop.h group struct */ struct nexthop_grp *n_grp = NULL; @@ -3357,10 +3353,10 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) vrf_id_t vrf_id = VRF_DEFAULT; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; - struct nexthop nh = {}; + struct nexthop nh = {.weight = 1}; struct nh_grp grp[MULTIPATH_NUM] = {}; /* Count of nexthops in group array */ - uint8_t grp_count = 0; + uint16_t grp_count = 0; struct rtattr *tb[NHA_MAX + 1] = {}; frrtrace(3, frr_zebra, netlink_nexthop_change, h, ns_id, startup); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0bfcd518..4444eda9 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -317,12 +317,12 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) frr_with_privs(&zserv_privs) { if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); @@ -330,12 +330,12 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) /* Must do delete and add separately - * no update available */ - if (!RSYSTEM_ROUTE(old_type)) + if (!RSYSTEM_ROUTE(old_type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), dplane_ctx_get_old_ng(ctx), dplane_ctx_get_old_metric(ctx)); - if (!RSYSTEM_ROUTE(type)) + if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST) kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), dplane_ctx_get_ng(ctx), dplane_ctx_get_metric(ctx)); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 470391de..8f671351 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -1960,7 +1960,7 @@ uint32_t rtadv_get_interfaces_configured_from_bgp(void) 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", + zlog_debug("%s: RTADV_ADATA_SIZE chosen will not work on this platform, please use a larger size", __func__); exit(-1); diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index 19667e66..3c4db009 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -661,27 +661,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, } /* - * Request filters from the kernel - */ -static int netlink_request_filters(struct zebra_ns *zns, int family, int type, - ifindex_t ifindex) -{ - struct { - struct nlmsghdr n; - struct tcmsg tc; - } req; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_type = type; - req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.tc.tcm_family = family; - req.tc.tcm_ifindex = ifindex; - - return netlink_request(&zns->netlink_cmd, &req); -} - -/* * Request queue discipline from the kernel */ static int netlink_request_qdiscs(struct zebra_ns *zns, int family, int type) @@ -852,23 +831,4 @@ int netlink_qdisc_read(struct zebra_ns *zns) return 0; } -int netlink_tfilter_read_for_interface(struct zebra_ns *zns, ifindex_t ifindex) -{ - int ret; - struct zebra_dplane_info dp_info; - - zebra_dplane_info_from_zns(&dp_info, zns, true); - - ret = netlink_request_filters(zns, AF_UNSPEC, RTM_GETTFILTER, ifindex); - if (ret < 0) - return ret; - - ret = netlink_parse_info(netlink_tfilter_change, &zns->netlink_cmd, - &dp_info, 0, true); - if (ret < 0) - return ret; - - return 0; -} - #endif /* HAVE_NETLINK */ diff --git a/zebra/tc_netlink.h b/zebra/tc_netlink.h index 5e95e6c1..300c53b6 100644 --- a/zebra/tc_netlink.h +++ b/zebra/tc_netlink.h @@ -50,8 +50,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, */ extern int netlink_qdisc_read(struct zebra_ns *zns); -extern int netlink_tfilter_read_for_interface(struct zebra_ns *zns, - ifindex_t ifindex); extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d585ef99..7dae75ba 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -517,7 +517,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct zapi_nexthop *api_nh; struct nexthop *nexthop; const struct prefix *p, *src_p; - uint8_t count = 0; + uint16_t count = 0; afi_t afi; size_t stream_size = MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); @@ -735,11 +735,13 @@ static int route_notify_internal(const struct route_node *rn, int type, client = zserv_find_client(type, instance); if (!client || !client->notify_owner) { - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug( - "Not Notifying Owner: %s about prefix %pRN(%u) %d vrf: %u", - zebra_route_string(type), rn, table_id, note, - vrf_id); + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + + zlog_debug("Not Notifying Owner: %s about prefix %pRN(%u) %d vrf: %s", + zebra_route_string(type), rn, table_id, note, + VRF_LOGNAME(vrf)); + } return 0; } @@ -999,6 +1001,48 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp, } } +void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note) + +{ + struct stream *s; + uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)", + __func__, zserv_command_string(cmd), + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, + zapi_srv6_sid_notify2str(note), client->proto, + client->instance, client->session_id); + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */ + stream_put(s, ¬e, sizeof(note)); + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + /* SRv6 SID value (i.e. IPv6 address) */ + stream_put(s, sid_value, sizeof(struct in6_addr)); + /* SRv6 SID function */ + stream_putl(s, func); + /* SRv6 wide SID function */ + stream_putl(s, wide_func); + /* SRv6 locator name optional */ + if (locator_name) { + stream_putw(s, strlen(locator_name)); + stream_put(s, locator_name, strlen(locator_name)); + } else + stream_putw(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, @@ -1136,9 +1180,25 @@ static int zsend_table_manager_connect_response(struct zserv *client, int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct srv6_locator locator = {}; + struct srv6_sid_format *format = loc->sid_format; + + /* + * Copy the locator and fill locator block/node/func/arg length from the format + * before sending the locator to the zclient + */ + srv6_locator_copy(&locator, loc); + if (format) { + locator.block_bits_length = format->block_len; + locator.node_bits_length = format->node_len; + locator.function_bits_length = format->function_len; + locator.argument_bits_length = format->argument_len; + if (format->type == SRV6_SID_FORMAT_TYPE_USID) + SET_FLAG(locator.flags, SRV6_LOCATOR_USID); + } zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT); - zapi_srv6_locator_encode(s, loc); + zapi_srv6_locator_encode(s, &locator); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); @@ -2071,8 +2131,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) vrf_id = zvrf_id(zvrf); if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: p=(%u:%u)%pFX, msg flags=0x%x, flags=0x%x", - __func__, vrf_id, api.tableid, &api.prefix, + zlog_debug("%s: p=(%s:%u)%pFX, msg flags=0x%x, flags=0x%x", + __func__, zvrf_name(zvrf), api.tableid, &api.prefix, (int)api.message, api.flags); /* Allocate new route. */ @@ -2090,7 +2150,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2115,7 +2175,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2134,8 +2194,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) @@ -2147,8 +2206,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2177,8 +2235,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } /* At this point, these allocations are not needed: 're' has been @@ -2206,9 +2263,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } -void zapi_re_opaque_free(struct re_opaque *opaque) +void zapi_re_opaque_free(struct route_entry *re) { - XFREE(MTYPE_RE_OPAQUE, opaque); + XFREE(MTYPE_RE_OPAQUE, re->opaque); + re->opaque = NULL; } static void zread_route_del(ZAPI_HANDLER_ARGS) @@ -2356,6 +2414,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -2418,22 +2477,6 @@ stream_failure: return; } -/* Unregister all information in a VRF. */ -static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) -{ - int i; - afi_t afi; - - 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->neighinfo[afi], zvrf_id(zvrf)); - } -} - /* * Validate incoming zapi mpls lsp / labels message */ @@ -2990,6 +3033,96 @@ stream_failure: return; } +/** + * Handle SRv6 SID request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct in6_addr *sid_value_ptr = NULL; + char locator[SRV6_LOCNAME_SIZE] = { 0 }; + uint16_t len; + struct zebra_srv6_sid *sid = NULL; + uint8_t flags; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GETC(s, flags); + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) { + STREAM_GET(&sid_value, s, sizeof(struct in6_addr)); + sid_value_ptr = &sid_value; + } + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + STREAM_GETW(s, len); + STREAM_GET(locator, s, len); + } + + /* Call hook to get a SID using wrapper */ + srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator); + +stream_failure: + return; +} + +/** + * Handle SRv6 SID release request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_release_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + + /* Call hook to release a SID using wrapper */ + srv6_manager_release_sid_call(client, &ctx); + +stream_failure: + return; +} + +/** + * Handle SRv6 locator get request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_locator(struct zserv *client, + struct stream *msg) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = { 0 }; + struct srv6_locator *locator = NULL; + + /* Get data */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* Call hook to get the locator info using wrapper */ + srv6_manager_get_locator_call(&locator, client, locator_name); + +stream_failure: + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { @@ -3001,6 +3134,15 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_SRV6_SID: + zread_srv6_manager_get_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID: + zread_srv6_manager_release_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR: + zread_srv6_manager_get_locator(client, msg); + break; default: zlog_err("%s: unknown SRv6 Manager command", __func__); break; @@ -3897,7 +4039,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { #if HAVE_BFDD > 0 [ZEBRA_BFD_DEST_REPLAY] = zebra_ptm_bfd_dst_replay, #endif /* HAVE_BFDD */ - [ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister, [ZEBRA_VRF_LABEL] = zread_vrf_label, [ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register, [ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable, @@ -3949,6 +4090,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 43f734d2..a59ccc83 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -94,6 +94,11 @@ extern int zsend_sr_policy_notify_status(uint32_t color, 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 void zsend_srv6_sid_notify(struct zserv *client, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); @@ -101,7 +106,7 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); -extern void zapi_re_opaque_free(struct re_opaque *opaque); +extern void zapi_re_opaque_free(struct route_entry *re); extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); @@ -110,6 +115,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client, extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_response(struct zserv *client, + struct srv6_locator *locator); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c index 3e03d747..6ee0fdbb 100644 --- a/zebra/zebra_cli.c +++ b/zebra/zebra_cli.c @@ -2221,6 +2221,37 @@ static void lib_vrf_zebra_ipv6_resolve_via_default_cli_write( } } +DEFPY_YANG (mpls_fec_nexthop_resolution, mpls_fec_nexthop_resolution_cmd, + "[no$no] mpls fec nexthop-resolution", + NO_STR + MPLS_STR + "MPLS FEC table\n" + "Authorise nexthop resolution over all labeled routes.\n") +{ + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/mpls/fec-nexthop-resolution", + 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_mpls_fec_nexthop_resolution_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool fec_nexthop_resolution = yang_dnode_get_bool(dnode, NULL); + + if (fec_nexthop_resolution || show_defaults) { + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "%smpls fec nexthop-resolution\n", + fec_nexthop_resolution ? "" : "no "); + } +} + DEFPY_YANG (vrf_netns, vrf_netns_cmd, "[no] netns ![NAME$netns_name]", @@ -2852,6 +2883,10 @@ const struct frr_yang_module_info frr_zebra_cli_info = { .cbs.cli_show = lib_vrf_zebra_netns_table_range_cli_write, }, { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution", + .cbs.cli_show = lib_vrf_mpls_fec_nexthop_resolution_cli_write, + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id", .cbs.cli_show = lib_vrf_zebra_l3vni_id_cli_write, }, @@ -2957,6 +2992,9 @@ void zebra_cli_init(void) install_element(VRF_NODE, &ip_nht_default_route_cmd); install_element(VRF_NODE, &ipv6_nht_default_route_cmd); + install_element(CONFIG_NODE, &mpls_fec_nexthop_resolution_cmd); + install_element(VRF_NODE, &mpls_fec_nexthop_resolution_cmd); + install_element(CONFIG_NODE, &vni_mapping_cmd); install_element(VRF_NODE, &vni_mapping_cmd); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 39448764..00e990e8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -86,7 +86,7 @@ struct dplane_nexthop_info { struct nexthop_group ng; struct nh_grp nh_grp[MULTIPATH_NUM]; - uint8_t nh_grp_count; + uint16_t nh_grp_count; }; /* @@ -483,10 +483,8 @@ struct zebra_dplane_provider { int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p); _Atomic uint32_t dp_in_counter; - _Atomic uint32_t dp_in_queued; _Atomic uint32_t dp_in_max; _Atomic uint32_t dp_out_counter; - _Atomic uint32_t dp_out_queued; _Atomic uint32_t dp_out_max; _Atomic uint32_t dp_error_counter; @@ -969,6 +967,11 @@ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q) return ctx; } +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q) +{ + return dplane_ctx_list_count(q); +} + /* * Accessors for information from the context object */ @@ -2313,7 +2316,7 @@ dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.nhe.nh_grp; } -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return ctx->u.rinfo.nhe.nh_grp_count; @@ -4310,6 +4313,10 @@ dplane_route_update_internal(struct route_node *rn, continue; if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -4494,8 +4501,21 @@ dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) ctx = dplane_ctx_alloc(); ret = dplane_ctx_nexthop_init(ctx, op, nhe); - if (ret == AOK) + if (ret == AOK) { + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + + dplane_ctx_free(&ctx); + atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, + 1, memory_order_relaxed); + + return ZEBRA_DPLANE_REQUEST_SUCCESS; + } + ret = dplane_update_enqueue(ctx); + } /* Update counter */ atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1, @@ -5994,6 +6014,14 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_nexthops_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_nexthop_errors, + memory_order_relaxed); + vty_out(vty, "Nexthop updates: %" PRIu64 "\n", incoming); + vty_out(vty, "Nexthop update errors: %" PRIu64 "\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); @@ -6099,35 +6127,45 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed) struct zebra_dplane_provider *prov; uint64_t in, in_q, in_max, out, out_q, out_max; - vty_out(vty, "Zebra dataplane providers:\n"); - DPLANE_LOCK(); prov = dplane_prov_list_first(&zdplane_info.dg_providers); + in = dplane_ctx_queue_count(&zdplane_info.dg_update_list); DPLANE_UNLOCK(); + vty_out(vty, "dataplane Incoming Queue from Zebra: %" PRIu64 "\n", in); + vty_out(vty, "Zebra dataplane providers:\n"); + /* Show counters, useful info from each registered provider */ while (prov) { + dplane_provider_lock(prov); + in_q = dplane_ctx_queue_count(&prov->dp_ctx_in_list); + out_q = dplane_ctx_queue_count(&prov->dp_ctx_out_list); + dplane_provider_unlock(prov); in = atomic_load_explicit(&prov->dp_in_counter, memory_order_relaxed); - in_q = atomic_load_explicit(&prov->dp_in_queued, - memory_order_relaxed); + in_max = atomic_load_explicit(&prov->dp_in_max, memory_order_relaxed); out = atomic_load_explicit(&prov->dp_out_counter, memory_order_relaxed); - out_q = atomic_load_explicit(&prov->dp_out_queued, - memory_order_relaxed); + out_max = atomic_load_explicit(&prov->dp_out_max, memory_order_relaxed); - vty_out(vty, "%s (%u): in: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64"\n", - prov->dp_name, prov->dp_id, in, in_q, in_max, - out, out_q, out_max); + vty_out(vty, + " %s (%u): in: %" PRIu64 ", q: %" PRIu64 + ", q_max: %" PRIu64 ", out: %" PRIu64 ", q: %" PRIu64 + ", q_max: %" PRIu64 "\n", + prov->dp_name, prov->dp_id, in, in_q, in_max, out, + out_q, out_max); prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov); } + out = zebra_rib_dplane_results_count(); + vty_out(vty, "dataplane Outgoing Queue to Zebra: %" PRIu64 "\n", out); + return CMD_SUCCESS; } @@ -6269,10 +6307,6 @@ struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx( dplane_provider_lock(prov); ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list)); - if (ctx) { - atomic_fetch_sub_explicit(&prov->dp_in_queued, 1, - memory_order_relaxed); - } dplane_provider_unlock(prov); @@ -6300,10 +6334,6 @@ int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov, break; } - if (ret > 0) - atomic_fetch_sub_explicit(&prov->dp_in_queued, ret, - memory_order_relaxed); - dplane_provider_unlock(prov); return ret; @@ -6328,10 +6358,7 @@ void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov, dplane_ctx_list_add_tail(&(prov->dp_ctx_out_list), ctx); /* Maintain out-queue counters */ - atomic_fetch_add_explicit(&(prov->dp_out_queued), 1, - memory_order_relaxed); - curr = atomic_load_explicit(&prov->dp_out_queued, - memory_order_relaxed); + curr = dplane_ctx_queue_count(&prov->dp_ctx_out_list); high = atomic_load_explicit(&prov->dp_out_max, memory_order_relaxed); if (curr > high) @@ -6353,9 +6380,6 @@ dplane_provider_dequeue_out_ctx(struct zebra_dplane_provider *prov) if (!ctx) return NULL; - atomic_fetch_sub_explicit(&(prov->dp_out_queued), 1, - memory_order_relaxed); - return ctx; } @@ -7301,10 +7325,10 @@ static void dplane_thread_loop(struct event *event) { struct dplane_ctx_list_head work_list; struct dplane_ctx_list_head error_list; - struct zebra_dplane_provider *prov; + struct zebra_dplane_provider *prov, *next_prov; struct zebra_dplane_ctx *ctx; int limit, counter, error_counter; - uint64_t curr, high; + uint64_t curr, out_curr, high; bool reschedule = false; /* Capture work limit per cycle */ @@ -7328,18 +7352,48 @@ static void dplane_thread_loop(struct event *event) /* Locate initial registered provider */ prov = dplane_prov_list_first(&zdplane_info.dg_providers); - /* Move new work from incoming list to temp list */ - for (counter = 0; counter < limit; counter++) { - ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); - if (ctx) { - ctx->zd_provider = prov->dp_id; + curr = dplane_ctx_queue_count(&prov->dp_ctx_in_list); + out_curr = dplane_ctx_queue_count(&prov->dp_ctx_out_list); - dplane_ctx_list_add_tail(&work_list, ctx); - } else { - break; + if (curr >= (uint64_t)limit) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%s: Current first provider(%s) Input queue is %" PRIu64 + ", holding off work", + __func__, prov->dp_name, curr); + counter = 0; + } else if (out_curr >= (uint64_t)limit) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%s: Current first provider(%s) Output queue is %" PRIu64 + ", holding off work", + __func__, prov->dp_name, out_curr); + counter = 0; + } else { + int tlimit; + /* + * Let's limit the work to how what can be put on the + * in or out queue without going over + */ + tlimit = limit - MAX(curr, out_curr); + /* Move new work from incoming list to temp list */ + for (counter = 0; counter < tlimit; counter++) { + ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); + if (ctx) { + ctx->zd_provider = prov->dp_id; + + dplane_ctx_list_add_tail(&work_list, ctx); + } else { + break; + } } } + /* + * If there is anything still on the two input queues reschedule + */ + if (dplane_ctx_queue_count(&prov->dp_ctx_in_list) > 0 || + dplane_ctx_queue_count(&zdplane_info.dg_update_list) > 0) + reschedule = true; + DPLANE_UNLOCK(); atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter, @@ -7358,8 +7412,9 @@ static void dplane_thread_loop(struct event *event) * items. */ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) - zlog_debug("dplane enqueues %d new work to provider '%s'", - counter, dplane_provider_get_name(prov)); + zlog_debug("dplane enqueues %d new work to provider '%s' curr is %" PRIu64, + counter, dplane_provider_get_name(prov), + curr); /* Capture current provider id in each context; check for * error status. @@ -7392,10 +7447,7 @@ static void dplane_thread_loop(struct event *event) atomic_fetch_add_explicit(&prov->dp_in_counter, counter, memory_order_relaxed); - atomic_fetch_add_explicit(&prov->dp_in_queued, counter, - memory_order_relaxed); - curr = atomic_load_explicit(&prov->dp_in_queued, - memory_order_relaxed); + curr = dplane_ctx_queue_count(&prov->dp_ctx_in_list); high = atomic_load_explicit(&prov->dp_in_max, memory_order_relaxed); if (curr > high) @@ -7420,18 +7472,61 @@ static void dplane_thread_loop(struct event *event) if (!zdplane_info.dg_run) break; + /* Locate next provider */ + next_prov = dplane_prov_list_next(&zdplane_info.dg_providers, + prov); + if (next_prov) { + curr = dplane_ctx_queue_count( + &next_prov->dp_ctx_in_list); + out_curr = dplane_ctx_queue_count( + &next_prov->dp_ctx_out_list); + } else + out_curr = curr = 0; + /* Dequeue completed work from the provider */ dplane_provider_lock(prov); - while (counter < limit) { - ctx = dplane_provider_dequeue_out_ctx(prov); - if (ctx) { - dplane_ctx_list_add_tail(&work_list, ctx); - counter++; - } else - break; + if (curr >= (uint64_t)limit) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%s: Next Provider(%s) Input queue is %" PRIu64 + ", holding off work", + __func__, next_prov->dp_name, curr); + counter = 0; + } else if (out_curr >= (uint64_t)limit) { + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%s: Next Provider(%s) Output queue is %" PRIu64 + ", holding off work", + __func__, next_prov->dp_name, + out_curr); + counter = 0; + } else { + int tlimit; + + /* + * Let's limit the work to how what can be put on the + * in or out queue without going over + */ + tlimit = limit - MAX(curr, out_curr); + while (counter < tlimit) { + ctx = dplane_provider_dequeue_out_ctx(prov); + if (ctx) { + dplane_ctx_list_add_tail(&work_list, + ctx); + counter++; + } else + break; + } } + /* + * Let's check if there are still any items on the + * input or output queus of the current provider + * if so then we know we need to reschedule. + */ + if (dplane_ctx_queue_count(&prov->dp_ctx_in_list) > 0 || + dplane_ctx_queue_count(&prov->dp_ctx_out_list) > 0) + reschedule = true; + dplane_provider_unlock(prov); if (counter >= limit) @@ -7447,7 +7542,7 @@ static void dplane_thread_loop(struct event *event) } /* Locate next provider */ - prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov); + prov = next_prov; } /* diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 060b1c8b..a3318bf5 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -323,6 +323,8 @@ struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q); /* Init a list of contexts */ void dplane_ctx_q_init(struct dplane_ctx_list_head *q); +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q); + /* * Accessors for information from the context object */ @@ -595,7 +597,7 @@ const struct nexthop_group * dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); const struct nh_grp * dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx); -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); /* Accessors for LSP information */ diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 09b369e2..dcfa37d2 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -788,6 +788,18 @@ static struct log_ref ferr_zebra_err[] = { "Wait for Zebra to reattempt update.", }, { + .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + .title = "SRv6 manager unable to assign SID", + .description = "Zebra's SRv6 manager was unable to assign a SID to client.", + .suggestion = "Ensure that Zebra has a sufficient SID range available.", + }, + { + .code = EC_ZEBRA_SM_DAEMON_MISMATCH, + .title = "Daemon mismatch when releasing SRV6 SIDs", + .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.", + .suggestion = "Ignore this error.", + }, + { .code = END_FERR, } }; diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 3ac654bd..84632e1a 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -124,6 +124,8 @@ enum zebra_log_refs { EC_ZEBRA_GRE_SET_UPDATE, EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, EC_ZEBRA_INTF_UPDATE_FAILURE, + EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + EC_ZEBRA_SM_DAEMON_MISMATCH, }; void zebra_error_init(void); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index ebb5a422..a733b591 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -663,6 +663,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; + route_unlock_node(rn); break; } } @@ -757,6 +758,7 @@ static int zebra_evpn_from_svi_ns(struct ns *ns, zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; + route_unlock_node(rn); break; } } @@ -842,6 +844,7 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) if (zif->link == in_param->svi_if) { *p_ifp = tmp_if; + route_unlock_node(rn); return NS_WALK_STOP; } } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index bfc060db..0d535913 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -47,9 +47,9 @@ uint32_t num_valid_macs(struct zebra_evpn *zevpn) for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = hb->next) { mac = (struct zebra_mac *)hb->data; - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) - || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) || + !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) num_macs++; } } @@ -103,7 +103,8 @@ 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); @@ -117,16 +118,17 @@ void zebra_evpn_mac_ifp_del(struct interface *ifp) struct listnode *node; struct zebra_mac *zmac; - 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); + if (!zif->mac_list) + return; - for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) { - zebra_evpn_mac_ifp_unlink(zmac); - } - list_delete(&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); + + for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) + zebra_evpn_mac_ifp_unlink(zmac); + + list_delete(&zif->mac_list); } /* Link local mac to destination access port. This is done only if the @@ -159,7 +161,8 @@ 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); @@ -201,7 +204,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 @@ -245,14 +248,14 @@ 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 && !CHECK_FLAG(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) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "VNI %u hash %p couldn't be uninstalled - no intf", - zevpn->vni, zevpn); + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zevpn->vni, zevpn); return -1; } @@ -278,7 +281,8 @@ 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 @@ -297,9 +301,9 @@ void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac) /* If all remote neighbors referencing a remote MAC go away, * we need to uninstall the MAC. */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - && remote_neigh_count(mac) == 0) { - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + remote_neigh_count(mac) == 0) { + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); zebra_evpn_es_mac_deref_entry(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); } @@ -336,7 +340,8 @@ 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); } } @@ -350,18 +355,26 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf, } 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_DEF_GW) ? "Default 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_PROXY) ? "PROXY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "LOC Inactive " : ""); + 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_DEF_GW) ? "Default 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_PROXY) ? "PROXY " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) + ? "LOC Inactive " + : ""); return buf; } @@ -391,11 +404,11 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - 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)), - mac->dad_count, listcount(mac->neigh_list)); + 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)), + mac->dad_count, listcount(mac->neigh_list)); } /* Remove all IPs as duplicate associcated with this MAC */ @@ -404,7 +417,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); } UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); @@ -423,11 +436,12 @@ 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); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -445,7 +459,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, { struct zebra_neigh *nbr; struct listnode *node = NULL; - struct timeval elapsed = {0, 0}; + struct timeval elapsed = { 0, 0 }; bool reset_params = false; if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad)) @@ -459,11 +473,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - 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)), - mac->dad_count, zvrf->dad_freeze_time); + 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)), + mac->dad_count, zvrf->dad_freeze_time); } /* For duplicate MAC do not update * client but update neigh due to @@ -495,11 +509,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - 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)), - mac->dad_count); + 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)), + mac->dad_count); } mac->dad_count = 0; @@ -526,10 +540,11 @@ 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); @@ -540,7 +555,6 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, * associcated with this MAC */ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { - /* Ony Mark IPs which are Local */ if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) continue; @@ -561,16 +575,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - 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)), - zvrf->dad_freeze_time); + 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)), + 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), @@ -592,7 +608,7 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; - struct timeval detect_start_time = {0, 0}; + struct timeval detect_start_time = { 0, 0 }; char timebuf[MONOTIME_STRLEN]; char thread_buf[EVENT_TIMER_STRLEN]; time_t uptime; @@ -617,18 +633,22 @@ 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_object_string_addf(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"); @@ -642,7 +662,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) 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); @@ -663,30 +684,42 @@ 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_nbrs, "active", + json_active_nbrs); + json_object_object_add(json_nbrs, "inactive", + json_inactive_nbrs); json_object_object_add(json_mac, "neighbors", json_nbrs); } @@ -704,7 +737,8 @@ 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); @@ -712,7 +746,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) if (mac->es) 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 "); } @@ -739,18 +774,24 @@ 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); @@ -765,7 +806,8 @@ 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")); } } @@ -817,12 +859,14 @@ 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) @@ -831,35 +875,41 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) json_object_int_add(json_mac, "vlan", vid); } else /* No vid? fill out the space */ if (json_mac_hdr == NULL) - vty_out(vty, " %-5s", ""); + vty_out(vty, " %-5s", ""); if (json_mac_hdr == NULL) { 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); } wctx->count++; } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - - if (CHECK_FLAG(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 (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) - && (wctx->count == 0)) { + 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, @@ -867,24 +917,32 @@ 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)), - mac->es ? mac->es->esi_str : addr_buf, - "", mac->loc_seq, mac->rem_seq); + 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_object_string_addf(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++; @@ -917,8 +975,7 @@ void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) /* * Inform BGP about local MACIP. */ -int zebra_evpn_macip_send_msg_to_client(vni_t vni, - const struct ethaddr *macaddr, +int zebra_evpn_macip_send_msg_to_client(vni_t vni, const struct ethaddr *macaddr, const struct ipaddr *ip, uint8_t flags, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd) @@ -966,13 +1023,12 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, if (IS_ZEBRA_DEBUG_VXLAN) { char flag_buf[MACIP_BUF_SIZE]; - 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 : "-", - zebra_route_string(client->proto)); + 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 : "-", + zebra_route_string(client->proto)); } if (cmd == ZEBRA_MACIP_ADD) @@ -1005,7 +1061,8 @@ 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); } /* @@ -1046,7 +1103,8 @@ struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn, 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))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } return mac; } @@ -1062,7 +1120,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *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))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* force de-ref any ES entry linked to the MAC */ @@ -1087,10 +1146,10 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) */ if (!list_isempty(mac->neigh_list)) { 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)); + 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)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); return 0; @@ -1127,25 +1186,26 @@ 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 (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return true; - else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) - && CHECK_FLAG(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 (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)) + 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 (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) - && !listcount(mac->neigh_list)) { + 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))); + zlog_debug("%s: Del MAC %pEA flags %s", __func__, + &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } wctx->uninstall = 0; @@ -1163,23 +1223,25 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct mac_walk_ctx *wctx = arg; struct zebra_mac *mac = bucket->data; - if (zebra_evpn_check_mac_del_from_db(wctx, mac)) { - 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); - } - 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__); + if (!zebra_evpn_check_mac_del_from_db(wctx, mac)) + return; - if (mac->flags & ZEBRA_MAC_REMOTE) - zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false /*force*/); - } + 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); + } + if (wctx->uninstall) { + if (zebra_evpn_mac_is_static(mac)) + zebra_evpn_sync_mac_dp_install(mac, false, true, + __func__); - zebra_evpn_mac_del(wctx->zevpn, mac); + if (mac->flags & ZEBRA_MAC_REMOTE) + zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false); } + zebra_evpn_mac_del(wctx->zevpn, mac); + return; } @@ -1249,7 +1311,8 @@ 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); } /* @@ -1261,8 +1324,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, int state = ZEBRA_NEIGH_ACTIVE; if (!force) { - if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) - && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE)) + if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) && + !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE)) /* the host was not advertised - nothing to delete */ return 0; @@ -1275,8 +1338,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, 0, + state, NULL, ZEBRA_MACIP_DEL); } /* @@ -1308,12 +1371,11 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn); if (!es_evi) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi", - caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - mac->flags, - set_inactive ? "inactive " : ""); + zlog_debug("%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi", + caller, zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + mac->flags, + set_inactive ? "inactive " : ""); return -1; } } @@ -1325,12 +1387,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%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)), - set_inactive ? "inactive " : ""); + zlog_debug("%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)), + set_inactive ? "inactive " : ""); } return -1; } @@ -1341,12 +1403,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%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)), - set_inactive ? "inactive " : ""); + zlog_debug("%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)), + set_inactive ? "inactive " : ""); } return -1; } @@ -1365,21 +1427,21 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s", - 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)), - set_inactive ? "inactive " : ""); + zlog_debug("dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s", + 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)), + 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); else - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /* force */); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); return 0; } @@ -1390,13 +1452,14 @@ 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; } @@ -1406,11 +1469,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 */); + zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, &mac->macaddr, + mac->flags, true); } /* MAC hold timer is used to age out peer-active flag. @@ -1443,23 +1506,23 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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))); + zlog_debug("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))); } /* re-program the local mac in the dataplane if the mac is no * longer static */ if (old_static != new_static) - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __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) @@ -1470,11 +1533,11 @@ static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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))); + zlog_debug("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))); } event_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac, zmh_info->mac_hold_time, &mac->hold_timer); @@ -1488,11 +1551,11 @@ void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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))); + zlog_debug("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))); } EVENT_OFF(mac->hold_timer); @@ -1506,11 +1569,11 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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))); + zlog_debug("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))); } old_static = zebra_evpn_mac_is_static(mac); @@ -1521,8 +1584,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__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __func__); } static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, @@ -1543,44 +1605,41 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, n_type = "remote"; } - if (seq < tmp_seq) { - - if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) - 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); - return true; - } - - /* if the mac was never advertised to bgp we must accept - * whatever sequence number bgp sends - */ - if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || - 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))); - } + if (seq >= tmp_seq) + return true; - return true; - } + if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) + 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); + return true; + } + /* if the mac was never advertised to bgp we must accept + * whatever sequence number bgp sends + */ + if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { 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))); + 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))); } - return false; + return true; } - return true; + 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))); + } + + return false; } struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, @@ -1644,13 +1703,14 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW); if (sticky || remote_gw) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug( - "Ignore sync-macip vni %u mac %pEA%s%s%s%s", - zevpn->vni, macaddr, - ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", - sticky ? " sticky" : "", - remote_gw ? " remote_gw" : ""); + zlog_debug("Ignore sync-macip vni %u mac %pEA%s%s%s%s", + zevpn->vni, macaddr, + ipa_len ? " IP " : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, + sizeof(ipbuf)) + : "", + sticky ? " sticky" : "", + remote_gw ? " remote_gw" : ""); return NULL; } if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true)) @@ -1664,7 +1724,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, SET_FLAG(new_flags, ZEBRA_MAC_LOCAL); /* retain old local activity flag */ if (CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL)) - SET_FLAG (new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL_INACTIVE)); + SET_FLAG(new_flags, + CHECK_FLAG(old_flags, + ZEBRA_MAC_LOCAL_INACTIVE)); else SET_FLAG(new_flags, ZEBRA_MAC_LOCAL_INACTIVE); @@ -1672,7 +1734,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, /* if mac-ip route do NOT update the peer flags * i.e. retain only flags as is */ - SET_FLAG(new_flags, CHECK_FLAG(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)) { @@ -1682,8 +1746,10 @@ 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 { @@ -1703,11 +1769,13 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, struct zebra_mac omac; omac.flags = old_flags; - 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))); + 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))); } /* update es */ @@ -1747,24 +1815,25 @@ 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); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, + seq_change, + es_change); if (inform_dataplane && !ipa_len) { /* program the local mac in the kernel. when the ES @@ -1772,8 +1841,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, false, + __func__); } return mac; @@ -1783,7 +1852,8 @@ 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; @@ -1825,8 +1895,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 */ @@ -1840,7 +1910,8 @@ 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) @@ -1857,7 +1928,7 @@ void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) * go away, we need to uninstall the MAC. */ if (remote_neigh_count(mac) == 0) { - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); zebra_evpn_es_mac_deref_entry(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); } @@ -1917,12 +1988,11 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, mac = zebra_evpn_mac_lookup(zevpn, macaddr); /* Ignore if the mac is already present as a gateway mac */ - if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) - && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) && + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC", - zevpn->vni, macaddr); + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC", + zevpn->vni, macaddr); return -1; } @@ -1932,13 +2002,11 @@ 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) { @@ -1954,7 +2022,8 @@ 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; @@ -1981,8 +2050,9 @@ 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) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) + if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + mac->dad_count) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) do_dad = true; /* Remove local MAC from BGP. */ @@ -1992,17 +2062,18 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac->remote vni %u mac %pEA es %s seq %d f %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))); + zlog_debug("sync-mac->remote vni %u mac %pEA es %s seq %d f %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_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); } /* Set "auto" and "remote" forwarding info. */ @@ -2021,8 +2092,10 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, else 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); + zebra_evpn_dup_addr_detect_for_mac(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); @@ -2049,7 +2122,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, bool inform_client = false; bool upd_neigh = false; bool is_dup_detect = false; - struct in_addr vtep_ip = {.s_addr = 0}; + struct in_addr vtep_ip = { .s_addr = 0 }; bool es_change = false; bool new_bgp_ready; /* assume inactive if not present or if not local */ @@ -2064,11 +2137,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { 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, - local_inactive ? " local-inactive" : ""); + zlog_debug("ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", + sticky ? "sticky " : "", macaddr, ifp->name, + ifp->ifindex, vid, zevpn->vni, + local_inactive ? " local-inactive" : ""); mac = zebra_evpn_mac_add(zevpn, macaddr); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); @@ -2080,12 +2152,12 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", - 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))); + zlog_debug("UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", + 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))); } if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { @@ -2094,27 +2166,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" : ""); + 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" + : ""); return 0; } if (mac_sticky != sticky) { @@ -2139,9 +2218,11 @@ 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 @@ -2150,8 +2231,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, inform_dataplane = true; } } - } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { bool do_dad = false; /* @@ -2161,16 +2242,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, * operator error. */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { - 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); + 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); 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; @@ -2179,7 +2261,9 @@ 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 @@ -2191,8 +2275,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, inform_client = true; upd_neigh = true; - zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, vtep_ip, do_dad, &is_dup_detect, true); + zebra_evpn_dup_addr_detect_for_mac(zvrf, mac, vtep_ip, + do_dad, + &is_dup_detect, true); if (is_dup_detect) { inform_client = false; upd_neigh = false; @@ -2218,17 +2303,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* if local-activity has changed we need update bgp * even if bgp already knows about the mac */ - if ((old_local_inactive != local_inactive) - || (new_bgp_ready != old_bgp_ready)) { + if ((old_local_inactive != local_inactive) || + (new_bgp_ready != old_bgp_ready)) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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)), - local_inactive ? "local-inactive" : ""); + zlog_debug("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)), + local_inactive ? "local-inactive" : ""); } if (!is_dup_detect) @@ -2242,16 +2327,17 @@ 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__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __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; } @@ -2277,24 +2363,25 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "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))); + zlog_debug("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))); } /* 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); - zebra_evpn_mac_send_add_del_to_client( - mac, old_bgp_ready, new_bgp_ready); + 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); } /* re-install the inactive entry in the kernel */ - zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, true, false, __func__); return 0; } @@ -2307,7 +2394,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, /* Remove MAC from BGP. */ zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags, - clear_static /* force */); + clear_static); zebra_evpn_es_mac_deref_entry(mac); @@ -2329,8 +2416,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, return 0; } -void zebra_evpn_mac_gw_macip_add(struct interface *ifp, - struct zebra_evpn *zevpn, +void zebra_evpn_mac_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn, const struct ipaddr *ip, struct zebra_mac **macp, const struct ethaddr *macaddr, @@ -2376,15 +2462,17 @@ void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn) memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); mac = zebra_evpn_mac_lookup(zevpn, &macaddr); - if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("SVI %s mac free", ifp->name); - - 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_deref_ip2mac(mac->zevpn, mac); - } + + if (!mac || CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("SVI %s mac free", ifp->name); + + 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_deref_ip2mac(mac->zevpn, mac); } void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) @@ -2395,8 +2483,8 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) bool old_bgp_ready; bool new_bgp_ready; - if (!zebra_evpn_mh_do_adv_svi_mac() - || !zebra_evpn_send_to_client_ok(zevpn)) + if (!zebra_evpn_mh_do_adv_svi_mac() || + !zebra_evpn_send_to_client_ok(zevpn)) return; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); @@ -2410,8 +2498,9 @@ 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); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index cee66cc0..07391b7a 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -420,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -455,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -486,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -532,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -567,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time; - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -641,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -654,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -676,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index d1c9cd54..9549af5f 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -37,6 +37,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object"); DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object"); DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object"); +DEFINE_MTYPE_STATIC(ZEBRA, NH_LABEL, "Nexthop label"); bool mpls_enabled; bool mpls_pw_reach_strict; /* Strict reachability checking */ @@ -50,7 +51,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, struct route_node *rn, struct route_entry *re); static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label); static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec, - mpls_label_t old_label); + mpls_label_t old_label, bool uninstall); static int fec_send(struct zebra_fec *fec, struct zserv *client); static void fec_update_clients(struct zebra_fec *fec); static void fec_print(struct zebra_fec *fec, struct vty *vty); @@ -161,12 +162,14 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, enum lsp_types_t lsp_type; char buf[BUFSIZ]; int added, changed; + bool zvrf_nexthop_resolution; /* Lookup table. */ lsp_table = zvrf->lsp_table; if (!lsp_table) return -1; + zvrf_nexthop_resolution = zvrf->zebra_mpls_fec_nexthop_resolution; lsp_type = lsp_type_from_re_type(re->type); added = changed = 0; @@ -180,13 +183,20 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, * the label advertised by the recursive nexthop (plus we don't have the * logic yet to push multiple labels). */ - for (nexthop = re->nhe->nhg.nexthop; - nexthop; nexthop = nexthop->next) { - /* Skip inactive and recursive entries. */ - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + nexthop = re->nhe->nhg.nexthop; + while (nexthop) { + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { + nexthop = + nexthop_next_resolution(nexthop, + zvrf_nexthop_resolution); continue; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { + nexthop = + nexthop_next_resolution(nexthop, + zvrf_nexthop_resolution); continue; + } nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type, nexthop->type, &nexthop->gate, @@ -194,9 +204,13 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, if (nhlfe) { /* Clear deleted flag (in case it was set) */ UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); - if (nexthop_labels_match(nhlfe->nexthop, nexthop)) + if (nexthop_labels_match(nhlfe->nexthop, nexthop)) { /* No change */ + nexthop = + nexthop_next_resolution(nexthop, + zvrf_nexthop_resolution); continue; + } if (IS_ZEBRA_DEBUG_MPLS) { @@ -221,11 +235,18 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, return -1; if (IS_ZEBRA_DEBUG_MPLS) { + char label_str[MPLS_LABEL_STRLEN]; + nhlfe2str(nhlfe, buf, BUFSIZ); - zlog_debug( - "Add LSP in-label %u type %d nexthop %s out-label %u", - lsp->ile.in_label, lsp_type, buf, - nexthop->nh_label->label[0]); + zlog_debug("Add LSP in-label %u type %d nexthop %s out-label %s", + lsp->ile.in_label, lsp_type, buf, + mpls_label2str(nexthop->nh_label + ->num_labels, + nexthop->nh_label->label, + label_str, + sizeof(label_str), + nexthop->nh_label_type, + 0)); } lsp->addr_family = NHLFE_FAMILY(nhlfe); @@ -234,6 +255,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED); added++; } + nexthop = nexthop_next_resolution(nexthop, + zvrf_nexthop_resolution); } /* Queue LSP for processing if necessary. If no NHLFE got added (special @@ -245,6 +268,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, return -1; } else { lsp_check_free(lsp_table, &lsp); + /* failed to install a new LSP */ + return -1; } return 0; @@ -353,7 +378,7 @@ static void fec_evaluate(struct zebra_vrf *zvrf) fec_update_clients(fec); /* Update label forwarding entries appropriately */ - fec_change_update_lsp(zvrf, fec, old_label); + fec_change_update_lsp(zvrf, fec, old_label, false); } } } @@ -384,7 +409,7 @@ static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf, * entries, as appropriate. */ static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec, - mpls_label_t old_label) + mpls_label_t old_label, bool uninstall) { struct route_table *table; struct route_node *rn; @@ -416,11 +441,17 @@ static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec, break; } - if (!re || !zebra_rib_labeled_unicast(re)) + if (!re || !zebra_rib_labeled_unicast(re)) { + if (uninstall) + lsp_uninstall(zvrf, fec->label); return 0; + } - if (lsp_install(zvrf, fec->label, rn, re)) + if (lsp_install(zvrf, fec->label, rn, re)) { + if (uninstall) + lsp_uninstall(zvrf, fec->label); return -1; + } return 0; } @@ -448,6 +479,30 @@ static int fec_send(struct zebra_fec *fec, struct zserv *client) } /* + * Upon reconfiguring nexthop-resolution updates, update the + * lsp entries accordingly. + */ +void zebra_mpls_fec_nexthop_resolution_update(struct zebra_vrf *zvrf) +{ + int af; + struct route_node *rn; + struct zebra_fec *fec; + + for (af = AFI_IP; af < AFI_MAX; af++) { + if (zvrf->fec_table[af] == NULL) + continue; + for (rn = route_top(zvrf->fec_table[af]); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; + fec = rn->info; + fec_change_update_lsp(zvrf, fec, MPLS_INVALID_LABEL, + true); + } + } +} + +/* * Update all registered clients about this FEC. Caller should've updated * FEC and ensure no duplicate updates. */ @@ -1398,7 +1453,31 @@ static int nhlfe_del(struct zebra_nhlfe *nhlfe) static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe, struct mpls_label_stack *nh_label) { - nhlfe->nexthop->nh_label->label[0] = nh_label->label[0]; + struct mpls_label_stack *nh_label_tmp; + int i; + + /* Enforce limit on label stack size */ + if (nh_label->num_labels > MPLS_MAX_LABELS) + nh_label->num_labels = MPLS_MAX_LABELS; + + /* Resize the array to accommodate the new label stack */ + if (nh_label->num_labels > nhlfe->nexthop->nh_label->num_labels) { + nh_label_tmp = XREALLOC(MTYPE_NH_LABEL, nhlfe->nexthop->nh_label, + sizeof(struct mpls_label_stack) + + nh_label->num_labels * + sizeof(mpls_label_t)); + if (nh_label_tmp) { + nhlfe->nexthop->nh_label = nh_label_tmp; + nhlfe->nexthop->nh_label->num_labels = + nh_label->num_labels; + } else + nh_label->num_labels = + nhlfe->nexthop->nh_label->num_labels; + } + + /* Copy the label stack into the array */ + for (i = 0; i < nh_label->num_labels; i++) + nhlfe->nexthop->nh_label->label[i] = nh_label->label[i]; } static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp, @@ -2117,7 +2196,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) /* * Install dynamic LSP entry. */ -int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, +void zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *re) { struct route_table *table; @@ -2125,23 +2204,20 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))]; if (!table) - return -1; + return; /* See if there is a configured label binding for this FEC. */ fec = fec_find(table, &rn->p); if (!fec || fec->label == MPLS_INVALID_LABEL) - return 0; + return; /* We cannot install a label forwarding entry if local label is the * implicit-null label. */ if (fec->label == MPLS_LABEL_IMPLICIT_NULL) - return 0; - - if (lsp_install(zvrf, fec->label, rn, re)) - return -1; + return; - return 0; + lsp_install(zvrf, fec->label, rn, re); } /* @@ -2345,7 +2421,7 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, } if (new_client || label_change) - return fec_change_update_lsp(zvrf, fec, old_label); + return fec_change_update_lsp(zvrf, fec, old_label, false); return 0; } @@ -2386,7 +2462,7 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, 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); + fec_change_update_lsp(zvrf, fec, old_label, false); fec_del(fec); } @@ -2556,7 +2632,7 @@ int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p, fec_update_clients(fec); /* Update label forwarding entries appropriately */ - ret = fec_change_update_lsp(zvrf, fec, old_label); + ret = fec_change_update_lsp(zvrf, fec, old_label, false); } return ret; @@ -2609,7 +2685,7 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p) fec_update_clients(fec); /* Update label forwarding entries appropriately */ - return fec_change_update_lsp(zvrf, fec, old_label); + return fec_change_update_lsp(zvrf, fec, old_label, false); } /* @@ -3794,7 +3870,7 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, if (tt->nrows > 1) { char *table = ttable_dump(tt, "\n"); vty_out(vty, "%s\n", table); - XFREE(MTYPE_TMP, table); + XFREE(MTYPE_TMP_TTABLE, table); } ttable_del(tt); } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index dd6f9601..27f5bdbc 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -146,7 +146,7 @@ int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *vrf); /* * Install dynamic LSP entry. */ -int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, +void zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *re); /* @@ -257,6 +257,12 @@ void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf, const struct zapi_labels *zl); /* + * Upon reconfiguring nexthop-resolution updates, update the + * lsp entries accordingly. + */ +void zebra_mpls_fec_nexthop_resolution_update(struct zebra_vrf *zvrf); + +/* * Uninstall all NHLFEs bound to a single FEC. * * mpls_ftn_uninstall -> Called to enqueue into early label processing diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index eee93230..0a7ed5db 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -884,6 +884,13 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution", + .cbs = { + .modify = lib_vrf_zebra_mpls_fec_nexthop_resolution_modify, + .destroy = lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib", .cbs = { .get_next = lib_vrf_zebra_ribs_rib_get_next, diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index b40ed682..785291bc 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -309,6 +309,10 @@ 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); +int lib_vrf_zebra_mpls_fec_nexthop_resolution_modify( + struct nb_cb_modify_args *args); +int lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy( + struct nb_cb_destroy_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 * diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index ae6232a1..09c0091e 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -3781,6 +3781,59 @@ int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args) } /* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/mpls/fec-nexthop-resolution + */ +int lib_vrf_zebra_mpls_fec_nexthop_resolution_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool fec_nexthop_resolution; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + fec_nexthop_resolution = yang_dnode_get_bool(args->dnode, NULL); + + if (zvrf->zebra_mpls_fec_nexthop_resolution == fec_nexthop_resolution) + return NB_OK; + + zvrf->zebra_mpls_fec_nexthop_resolution = fec_nexthop_resolution; + + zebra_mpls_fec_nexthop_resolution_update(zvrf); + + return NB_OK; +} + +int lib_vrf_zebra_mpls_fec_nexthop_resolution_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool fec_nexthop_resolution; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + fec_nexthop_resolution = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT; + + if (zvrf->zebra_mpls_fec_nexthop_resolution == fec_nexthop_resolution) + return NB_OK; + + zvrf->zebra_mpls_fec_nexthop_resolution = fec_nexthop_resolution; + + zebra_mpls_fec_nexthop_resolution_update(zvrf); + + 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) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 6235ecad..1519246c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -356,18 +356,23 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi, */ if (nh && (nh->next == NULL)) { switch (nh->type) { - case NEXTHOP_TYPE_IFINDEX: - case NEXTHOP_TYPE_BLACKHOLE: /* * This switch case handles setting the afi different - * for ipv4/v6 routes. Ifindex/blackhole nexthop + * for ipv4/v6 routes. Ifindex nexthop * objects cannot be ambiguous, they must be Address - * Family specific. If we get here, we will either use - * the AF of the route, or the one we got passed from - * here from the kernel. + * Family specific as that the kernel relies on these + * for some reason. blackholes can be v6 because the + * v4 kernel infrastructure allows the usage of v6 + * blackholes in this case. if we get here, we will + * either use the AF of the route, or the one we got + * passed from here from the kernel. */ + case NEXTHOP_TYPE_IFINDEX: nhe->afi = afi; break; + case NEXTHOP_TYPE_BLACKHOLE: + nhe->afi = AFI_IP6; + break; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: nhe->afi = AFI_IP; @@ -414,6 +419,14 @@ struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig, if (orig->backup_info) nhe->backup_info = nhg_backup_copy(orig->backup_info); + /* + * This is a special case, Zebra needs to track + * whether or not this flag was set on a initial + * unresolved NHG + */ + if (CHECK_FLAG(orig->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); + return nhe; } @@ -612,9 +625,8 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -static int zebra_nhg_process_grp(struct nexthop_group *nhg, - struct nhg_connected_tree_head *depends, - struct nh_grp *grp, uint8_t count, +static int zebra_nhg_process_grp(struct nexthop_group *nhg, struct nhg_connected_tree_head *depends, + struct nh_grp *grp, uint16_t count, struct nhg_resilience *resilience) { nhg_connected_tree_init(depends); @@ -969,7 +981,7 @@ static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx) return &ctx->u.nh; } -static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx) +static uint16_t nhg_ctx_get_count(const struct nhg_ctx *ctx) { return ctx->count; } @@ -1015,9 +1027,8 @@ done: XFREE(MTYPE_NHG_CTX, *ctx); } -static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, vrf_id_t vrf_id, - afi_t afi, int type, uint8_t count, +static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + vrf_id_t vrf_id, afi_t afi, int type, uint16_t count, struct nhg_resilience *resilience) { struct nhg_ctx *ctx = NULL; @@ -1088,11 +1099,15 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) bool valid = false; /* - * If I have other nhe's depending on me, then this is a + * If I have other nhe's depending on me, or I have nothing + * I am depending on then this is a * singleton nhe so set this nexthops flag as appropriate. */ - if (nhg_connected_tree_count(&nhe->nhg_depends)) + if (nhg_connected_tree_count(&nhe->nhg_depends) || + nhg_connected_tree_count(&nhe->nhg_dependents) == 0) { + UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_FIB); UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } /* If anthing else in the group is valid, the group is valid */ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { @@ -1154,7 +1169,8 @@ static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install) "%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); + zebra_nhg_install_kernel(rb_node_dep->nhe, + ZEBRA_ROUTE_MAX); } } } @@ -1173,7 +1189,7 @@ static void zebra_nhg_handle_kernel_state_change(struct nhg_hash_entry *nhe, (is_delete ? "deleted" : "updated"), nhe); UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_install_kernel(nhe); + zebra_nhg_install_kernel(nhe, ZEBRA_ROUTE_MAX); } else zebra_nhg_handle_uninstall(nhe); } @@ -1186,7 +1202,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) struct nhg_hash_entry *nhe = NULL; uint32_t id = nhg_ctx_get_id(ctx); - uint8_t count = nhg_ctx_get_count(ctx); + uint16_t count = nhg_ctx_get_count(ctx); vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx); int type = nhg_ctx_get_type(ctx); afi_t afi = nhg_ctx_get_afi(ctx); @@ -1338,9 +1354,9 @@ int nhg_ctx_process(struct nhg_ctx *ctx) } /* Kernel-side, you either get a single new nexthop or a array of ID's */ -int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, - uint8_t count, vrf_id_t vrf_id, afi_t afi, int type, - int startup, struct nhg_resilience *nhgr) +int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, uint16_t count, + vrf_id_t vrf_id, afi_t afi, int type, int startup, + struct nhg_resilience *nhgr) { struct nhg_ctx *ctx = NULL; @@ -1417,6 +1433,11 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, */ nexthop_copy_no_recurse(&lookup, nh, NULL); + /* + * So this is to intentionally cause the singleton nexthop + * to be created with a weight of 1. + */ + lookup.weight = 1; nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane); /* The copy may have allocated labels; free them if necessary. */ @@ -1782,6 +1803,12 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); resolved_hop->vrf_id = nexthop->vrf_id; + + /* Using weighted ECMP, we should respect the weight and use + * the same value for non-recursive next-hop. + */ + resolved_hop->weight = nexthop->weight; + switch (newhop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -2645,13 +2672,6 @@ static unsigned nexthop_active_check(struct route_node *rn, UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: - family = AFI_IP6; - if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags, - &mtu, vrf_id)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - break; case NEXTHOP_TYPE_IPV6_IFINDEX: /* RFC 5549, v4 prefix with v6 NH */ if (rn->p.family != AF_INET) @@ -2904,13 +2924,162 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg) } /* + * This function takes the start of two comparable nexthops from two different + * nexthop groups and walks them to see if they can be considered the same + * or not. This is being used to determine if zebra should reuse a nhg + * from the old_re to the new_re, when an interface goes down and the + * new nhg sent down from the upper level protocol would resolve to it + */ +static bool zebra_nhg_nexthop_compare(const struct nexthop *nhop, + const struct nexthop *old_nhop, + const struct route_node *rn) +{ + bool same = true; + + while (nhop && old_nhop) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN Comparing %pNHvv(%u) to old: %pNHvv(%u)", + __func__, rn, nhop, nhop->flags, old_nhop, + old_nhop->flags); + if (!CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN Old is not active going to the next one", + __func__, rn); + old_nhop = old_nhop->next; + continue; + } + + if (nexthop_same(nhop, old_nhop)) { + struct nexthop *new_recursive, *old_recursive; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN New and old are same, continuing search", + __func__, rn); + + new_recursive = nhop->resolved; + old_recursive = old_nhop->resolved; + + while (new_recursive && old_recursive) { + if (!nexthop_same(new_recursive, old_recursive)) { + same = false; + break; + } + + new_recursive = new_recursive->next; + old_recursive = old_recursive->next; + } + + if (new_recursive) + same = false; + else if (old_recursive) { + while (old_recursive) { + if (CHECK_FLAG(old_recursive->flags, + NEXTHOP_FLAG_ACTIVE)) + break; + old_recursive = old_recursive->next; + } + + if (old_recursive) + same = false; + } + + if (!same) + break; + + nhop = nhop->next; + old_nhop = old_nhop->next; + continue; + } else { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s:%pRN They are not the same, stopping using new nexthop entry", + __func__, rn); + same = false; + break; + } + } + + if (nhop) + same = false; + else if (old_nhop) { + while (old_nhop) { + if (CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) + break; + old_nhop = old_nhop->next; + } + + if (old_nhop) + same = false; + } + + return same; +} + +static struct nhg_hash_entry *zebra_nhg_rib_compare_old_nhe( + const struct route_node *rn, const struct route_entry *re, + struct nhg_hash_entry *new_nhe, struct nhg_hash_entry *old_nhe) +{ + struct nexthop *nhop, *old_nhop; + bool same = true; + struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) { + char straddr[PREFIX_STRLEN]; + + prefix2str(&rn->p, straddr, sizeof(straddr)); + zlog_debug("%s: %pRN new id: %u old id: %u", __func__, rn, + new_nhe->id, old_nhe->id); + zlog_debug("%s: %pRN NEW", __func__, rn); + for (ALL_NEXTHOPS(new_nhe->nhg, nhop)) + route_entry_dump_nh(re, straddr, vrf, nhop); + + zlog_debug("%s: %pRN OLD", __func__, rn); + for (ALL_NEXTHOPS(old_nhe->nhg, nhop)) + route_entry_dump_nh(re, straddr, vrf, nhop); + } + + nhop = new_nhe->nhg.nexthop; + old_nhop = old_nhe->nhg.nexthop; + + same = zebra_nhg_nexthop_compare(nhop, old_nhop, rn); + + if (same) { + struct nexthop_group *bnhg, *old_bnhg; + + bnhg = zebra_nhg_get_backup_nhg(new_nhe); + old_bnhg = zebra_nhg_get_backup_nhg(old_nhe); + + if (bnhg || old_bnhg) { + if (bnhg && !old_bnhg) + same = false; + else if (!bnhg && old_bnhg) + same = false; + else + same = zebra_nhg_nexthop_compare(bnhg->nexthop, + old_bnhg->nexthop, + rn); + } + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s:%pRN They are %sthe same, using the %s nhg entry", + __func__, rn, same ? "" : "not ", + same ? "old" : "new"); + + if (same) + return old_nhe; + else + return new_nhe; +} + +/* * Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag, * the whole re structure is flagged with ROUTE_ENTRY_CHANGED. * * Return value is the new number of active nexthops. */ -int nexthop_active_update(struct route_node *rn, struct route_entry *re) +int nexthop_active_update(struct route_node *rn, struct route_entry *re, + struct route_entry *old_re) { struct nhg_hash_entry *curr_nhe; uint32_t curr_active = 0, backup_active = 0; @@ -2966,6 +3135,11 @@ backups_done: new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi); + if (old_re && old_re->type == re->type && + old_re->instance == re->instance) + new_nhe = zebra_nhg_rib_compare_old_nhe(rn, re, new_nhe, + old_re->nhe); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)", @@ -3004,14 +3178,14 @@ backups_done: * I'm pretty sure we only allow ONE level of group within group currently. * But making this recursive just in case that ever changes. */ -static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, - uint8_t curr_index, - struct nhg_hash_entry *nhe, - int max_num) +static uint16_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, uint16_t curr_index, + struct nhg_hash_entry *nhe, + struct nhg_hash_entry *original, int max_num) { struct nhg_connected *rb_node_dep = NULL; struct nhg_hash_entry *depend = NULL; - uint8_t i = curr_index; + struct nexthop *nexthop; + uint16_t i = curr_index; frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { bool duplicate = false; @@ -3037,8 +3211,11 @@ static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, if (!zebra_nhg_depends_is_empty(depend)) { /* This is a group within a group */ - i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num); + i = zebra_nhg_nhe2grp_internal(grp, i, depend, nhe, + max_num); } else { + bool found; + if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG) @@ -3079,8 +3256,37 @@ static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, continue; } + /* + * So we need to create the nexthop group with + * the appropriate weights. The nexthops weights + * are stored in the fully resolved nexthops for + * the nhg so we need to find the appropriate + * nexthop associated with this and set the weight + * appropriately + */ + found = false; + for (ALL_NEXTHOPS_PTR(&original->nhg, nexthop)) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (nexthop_cmp_no_weight(depend->nhg.nexthop, + nexthop) != 0) + continue; + + found = true; + break; + } + + if (!found) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED || + IS_ZEBRA_DEBUG_NHG) + zlog_debug("%s: Nexthop ID (%u) unable to find nexthop in Nexthop Gropu Entry, something is terribly wrong", + __func__, depend->id); + continue; + } grp[i].id = depend->id; - grp[i].weight = depend->nhg.nexthop->weight; + grp[i].weight = nexthop->weight; i++; } } @@ -3100,14 +3306,13 @@ done: } /* Convert a nhe into a group array */ -uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int max_num) +uint16_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int max_num) { /* Call into the recursive function */ - return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num); + return zebra_nhg_nhe2grp_internal(grp, 0, nhe, nhe, max_num); } -void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) +void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type) { struct nhg_connected *rb_node_dep = NULL; @@ -3120,9 +3325,16 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) nhe); } + if ((type != ZEBRA_ROUTE_CONNECT && type != ZEBRA_ROUTE_LOCAL && + type != ZEBRA_ROUTE_KERNEL) && + CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } + /* 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); + zebra_nhg_install_kernel(rb_node_dep->nhe, type); } if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) && @@ -3146,9 +3358,6 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) nhe); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: - flog_err(EC_ZEBRA_DP_INVALID_RC, - "DPlane returned an invalid result code for attempt of installation of %pNG into the kernel", - nhe); break; } } @@ -3474,7 +3683,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, zebra_nhg_set_valid_if_active(new); - zebra_nhg_install_kernel(new); + zebra_nhg_install_kernel(new, ZEBRA_ROUTE_MAX); if (old) { /* @@ -3710,7 +3919,8 @@ void zebra_interface_nhg_reinstall(struct interface *ifp) "%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); + zebra_nhg_install_kernel(rb_node_dep->nhe, + ZEBRA_ROUTE_MAX); /* Don't need to modify dependents if installed */ if (CHECK_FLAG(rb_node_dep->nhe->flags, @@ -3723,6 +3933,17 @@ void zebra_interface_nhg_reinstall(struct interface *ifp) frr_each_safe (nhg_connected_tree, &rb_node_dep->nhe->nhg_dependents, rb_node_dependent) { + struct nexthop *nhop_dependent = + rb_node_dependent->nhe->nhg.nexthop; + + while (nhop_dependent && + !nexthop_same(nhop_dependent, nh)) + nhop_dependent = nhop_dependent->next; + + if (nhop_dependent) + SET_FLAG(nhop_dependent->flags, + NEXTHOP_FLAG_ACTIVE); + if (IS_ZEBRA_DEBUG_NHG) zlog_debug("%s dependent nhe %pNG Setting Reinstall flag", __func__, diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 3bb697aa..0f90627a 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -152,6 +152,25 @@ struct nhg_hash_entry { * when installation is successful. */ #define NEXTHOP_GROUP_REINSTALL (1 << 8) + +/* + * Connected routes and kernel routes received + * from the kernel or created by Zebra do no + * need to be installed. For connected, this + * is because the routes are in the local table + * but not imported and we create an amalgram + * route for it. For kernel routes if the route + * is an pre-nhg route, there is no nexthop associated + * with it and we should not create it until it + * is used by something else. + * The reason for this is because is that this just + * fills up the DPlane's nexthop slots when there + * are a bunch of interfaces or pre-existing routes + * As such let's not initially install it ( but + * pretend it was successful ) and if another route + * chooses this NHG then we can install it then. + */ +#define NEXTHOP_GROUP_INITIAL_DELAY_INSTALL (1 << 9) }; /* Upper 4 bits of the NHG are reserved for indicating the NHG type */ @@ -212,7 +231,7 @@ struct nhg_ctx { int type; /* If its a group array, how many? */ - uint8_t count; + uint16_t count; /* Its either a single nexthop or an array of ID's */ union { @@ -298,10 +317,8 @@ extern int nhg_ctx_process(struct nhg_ctx *ctx); void nhg_ctx_free(struct nhg_ctx **ctx); /* Find via kernel nh creation */ -extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, uint8_t count, - vrf_id_t vrf_id, afi_t afi, int type, - int startup, +extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + uint16_t count, vrf_id_t vrf_id, afi_t afi, int type, int startup, struct nhg_resilience *resilience); /* Del via kernel */ extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id); @@ -360,11 +377,10 @@ extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe); /* Convert nhe depends to a grp context that can be passed around safely */ -extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int size); +extern uint16_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int size); /* Dataplane install/uninstall */ -extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe); +extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type); extern void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe); extern void zebra_interface_nhg_reinstall(struct interface *ifp); @@ -385,7 +401,8 @@ extern void zebra_nhg_mark_keep(void); /* Nexthop resolution processing */ struct route_entry; /* Forward ref to avoid circular includes */ -extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); +extern int nexthop_active_update(struct route_node *rn, struct route_entry *re, + struct route_entry *old_re); #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pNG" (const struct nhg_hash_entry *) diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 803d8f00..ffd749fc 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -175,6 +175,22 @@ int zebra_ns_early_shutdown(struct ns *ns, return NS_WALK_CONTINUE; } +/* During zebra shutdown, do kernel cleanup + * netlink sockets, .. + */ +int zebra_ns_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))) +{ + struct zebra_ns *zns = ns->info; + + if (zns == NULL) + return NS_WALK_CONTINUE; + + kernel_terminate(zns, true); + + return NS_WALK_CONTINUE; +} + /* During zebra shutdown, do final cleanup * after all dataplane work is complete. */ @@ -185,9 +201,7 @@ int zebra_ns_final_shutdown(struct ns *ns, struct zebra_ns *zns = ns->info; if (zns == NULL) - return 0; - - kernel_terminate(zns, true); + return NS_WALK_CONTINUE; zebra_ns_delete(ns); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 8d988c3f..d5fd5869 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -70,6 +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_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))); void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index deed3b6a..6adc0b1b 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -147,7 +147,6 @@ void zebra_pw_update(struct zebra_pw *pw) { if (zebra_pw_check_reachability(pw) < 0) { zebra_pw_uninstall(pw); - zebra_pw_install_failure(pw, PW_NOT_FORWARDING); /* wait for NHT and try again later */ } else { /* @@ -167,12 +166,17 @@ static void zebra_pw_install(struct zebra_pw *pw) hook_call(pw_install, pw); if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { + /* + * Realistically this is never going to fail passing + * the pw data down to the dplane. The failure modes + * look like impossible events but we still return + * on them.... but I don't see a real clean way to remove this + * at all. So let's just leave the retry mechanism for + * the moment. + */ zebra_pw_install_failure(pw, PW_NOT_FORWARDING); return; } - - if (pw->status != PW_FORWARDING) - zebra_pw_update_status(pw, PW_FORWARDING); } static void zebra_pw_uninstall(struct zebra_pw *pw) @@ -188,9 +192,30 @@ static void zebra_pw_uninstall(struct zebra_pw *pw) /* ignore any possible error */ hook_call(pw_uninstall, pw); dplane_pw_uninstall(pw); +} + +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx) +{ + struct zebra_pw *pw; + struct zebra_vrf *vrf; + enum dplane_op_e op; + + op = dplane_ctx_get_op(ctx); + + vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); + + if (!pw) + return; - if (zebra_pw_enabled(pw)) - zebra_pw_update_status(pw, PW_NOT_FORWARDING); + if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { + zebra_pw_install_failure(pw, dplane_ctx_get_pw_status(ctx)); + } else { + if (op == DPLANE_OP_PW_INSTALL && pw->status != PW_FORWARDING) + zebra_pw_update_status(pw, PW_FORWARDING); + else if (op == DPLANE_OP_PW_UNINSTALL && zebra_pw_enabled(pw)) + zebra_pw_update_status(pw, PW_NOT_FORWARDING); + } } /* diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 431d663f..e037a550 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -64,6 +64,7 @@ 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); +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx); #ifdef __cplusplus } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b95d866..752f8282 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -316,12 +316,18 @@ static ssize_t printfrr_zebra_node(struct fbuf *buf, struct printfrr_eargs *ea, } #define rnode_debug(node, vrf_id, msg, ...) \ - zlog_debug("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \ - ##__VA_ARGS__) + do { \ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); \ + zlog_debug("%s: (%s:%pZNt):%pZN: " msg, __func__, \ + VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \ + } while (0) #define rnode_info(node, vrf_id, msg, ...) \ - zlog_info("%s: (%u:%pZNt):%pZN: " msg, __func__, vrf_id, node, node, \ - ##__VA_ARGS__) + do { \ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); \ + zlog_info("%s: (%s:%pZNt):%pZN: " msg, __func__, \ + VRF_LOGNAME(vrf), node, node, ##__VA_ARGS__); \ + } while (0) static char *_dump_re_status(const struct route_entry *re, char *buf, size_t len) @@ -605,45 +611,6 @@ struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id, return re; } -struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *match = NULL; - rib_dest_t *dest; - - /* Lookup table. */ - table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); - if (!table) - return 0; - - rn = route_node_lookup(table, (struct prefix *)p); - - /* No route for this prefix. */ - if (!rn) - return NULL; - - /* Unlock node. */ - route_unlock_node(rn); - dest = rib_dest_from_rnode(rn); - - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED)) - match = dest->selected_fib; - - if (!match) - return NULL; - - if (match->type == ZEBRA_ROUTE_CONNECT || - match->type == ZEBRA_ROUTE_LOCAL) - return match; - - if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) - return match; - - return NULL; -} - /* * Is this RIB labeled-unicast? It must be of type BGP and all paths * (nexthops) must have a label. @@ -651,8 +618,10 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) int zebra_rib_labeled_unicast(struct route_entry *re) { struct nexthop *nexthop = NULL; + struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); - if (re->type != ZEBRA_ROUTE_BGP) + if ((re->type != ZEBRA_ROUTE_BGP) && + !zvrf->zebra_mpls_fec_nexthop_resolution) return 0; for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) @@ -668,7 +637,6 @@ int zebra_rib_labeled_unicast(struct route_entry *re) void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct route_entry *old) { - struct nexthop *nexthop; struct rib_table_info *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(re->vrf_id); const struct prefix *p, *src_p; @@ -678,17 +646,10 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); - if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return; - } - - /* * Install the resolved nexthop object first. */ - zebra_nhg_install_kernel(re->nhe); + zebra_nhg_install_kernel(re->nhe, re->type); /* * If this is a replace to a new RE let the originator of the RE @@ -751,17 +712,8 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, /* Uninstall the route from kernel. */ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) { - struct nexthop *nexthop; - struct rib_table_info *info = srcdest_rnode_table_info(rn); struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - if (info->safi != SAFI_UNICAST) { - UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - return; - } - /* * Make sure we update the FPM any time we send new information to * the dataplane. @@ -1235,8 +1187,15 @@ static void rib_process(struct route_node *rn) struct zebra_vrf *zvrf = NULL; struct vrf *vrf; struct route_entry *proto_re_changed = NULL; - vrf_id_t vrf_id = VRF_UNKNOWN; + safi_t safi = SAFI_UNICAST; + + if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct rib_table_info *info = srcdest_rnode_table_info(rn); + + assert(info); + safi = info->safi; + } assert(rn); @@ -1262,9 +1221,8 @@ static void rib_process(struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB_DETAILED) { struct route_entry *re = re_list_first(&dest->routes); - zlog_debug("%s(%u:%u):%pRN: Processing rn %p", - VRF_LOGNAME(vrf), vrf_id, re->table, rn, - rn); + zlog_debug("%s(%u:%u:%u):%pRN: Processing rn %p", VRF_LOGNAME(vrf), vrf_id, + re->table, safi, rn, rn); } old_fib = dest->selected_fib; @@ -1274,15 +1232,12 @@ static void rib_process(struct route_node *rn) char flags_buf[128]; char status_buf[128]; - zlog_debug( - "%s(%u:%u):%pRN: Examine re %p (%s) status: %sflags: %sdist %d metric %d", - VRF_LOGNAME(vrf), vrf_id, re->table, rn, re, - zebra_route_string(re->type), - _dump_re_status(re, status_buf, - sizeof(status_buf)), - zclient_dump_route_flags(re->flags, flags_buf, - sizeof(flags_buf)), - re->distance, re->metric); + zlog_debug("%s(%u:%u:%u):%pRN: Examine re %p (%s) status: %sflags: %sdist %d metric %d", + VRF_LOGNAME(vrf), vrf_id, re->table, safi, rn, re, + zebra_route_string(re->type), + _dump_re_status(re, status_buf, sizeof(status_buf)), + zclient_dump_route_flags(re->flags, flags_buf, sizeof(flags_buf)), + re->distance, re->metric); } /* Currently selected re. */ @@ -1305,7 +1260,7 @@ static void rib_process(struct route_node *rn) */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { proto_re_changed = re; - if (!nexthop_active_update(rn, re)) { + if (!nexthop_active_update(rn, re, old_fib)) { const struct prefix *p; struct rib_table_info *info; @@ -1408,11 +1363,10 @@ static void rib_process(struct route_node *rn) : old_fib ? old_fib : new_fib ? new_fib : NULL; - zlog_debug( - "%s(%u:%u):%pRN: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", - VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, rn, - (void *)old_selected, (void *)new_selected, - (void *)old_fib, (void *)new_fib); + zlog_debug("%s(%u:%u:%u):%pRN: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", + VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, safi, rn, + (void *)old_selected, (void *)new_selected, (void *)old_fib, + (void *)new_fib); } /* Buffer ROUTE_ENTRY_CHANGED here, because it will get cleared if @@ -1619,6 +1573,10 @@ 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 && + (re1->nhe->nhg.nexthop->ifindex == re2->nhe->nhg.nexthop->ifindex)) + return true; + if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL) return true; @@ -1659,6 +1617,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, @@ -2693,8 +2654,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); + zebra_rib_route_entry_free(ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -2861,10 +2821,11 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug( - rn, re->vrf_id, - "Inserting route rn %p, re %p (%s) existing %p, same_count %d", - rn, re, zebra_route_string(re->type), same, same_count); + rnode_debug(rn, re->vrf_id, + "Inserting route rn %p, re %p (%s/%s/%s) existing %p, same_count %d", + rn, re, zebra_route_string(re->type), + afi2str(ere->afi), safi2str(ere->safi), same, + same_count); if (IS_ZEBRA_DEBUG_RIB_DETAILED) route_entry_dump( @@ -3159,6 +3120,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3166,7 +3128,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -3833,7 +3795,8 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, } static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, - struct zebra_vrf *zvrf) + const struct zebra_vrf *zvrf, + uint8_t proto, uint8_t instance) { struct zebra_early_route *ere; struct listnode *node, *nnode; @@ -3842,6 +3805,10 @@ static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id) continue; + if (proto != ZEBRA_ROUTE_ALL && + (proto != ere->re->type && instance != ere->re->instance)) + continue; + early_route_memory_free(ere); node->data = NULL; list_delete_node(l, node); @@ -3880,7 +3847,8 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) evpn_meta_queue_free(mq, mq->subq[i], zvrf); break; case META_QUEUE_EARLY_ROUTE: - early_route_meta_queue_free(mq, mq->subq[i], zvrf); + early_route_meta_queue_free(mq, mq->subq[i], zvrf, + ZEBRA_ROUTE_ALL, 0); break; case META_QUEUE_EARLY_LABEL: early_label_meta_queue_free(mq, mq->subq[i], zvrf); @@ -4060,9 +4028,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) rib_re_nhg_free(re); - zapi_re_opaque_free(re->opaque); - - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } void rib_delnode(struct route_node *rn, struct route_entry *re) @@ -4098,9 +4064,8 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) /* * Helper that debugs a single nexthop within a route-entry */ -static void _route_entry_dump_nh(const struct route_entry *re, - const char *straddr, - const struct nexthop *nexthop) +void route_entry_dump_nh(const struct route_entry *re, const char *straddr, + const struct vrf *re_vrf, const struct nexthop *nexthop) { char nhname[PREFIX_STRLEN]; char backup_str[50]; @@ -4154,35 +4119,32 @@ static void _route_entry_dump_nh(const struct route_entry *re, if (nexthop->weight) snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight); - zlog_debug("%s: %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s", - straddr, (nexthop->rparent ? " NH" : "NH"), nhname, - nexthop->ifindex, label_str, vrf ? vrf->name : "Unknown", - nexthop->vrf_id, + zlog_debug("%s(%s): %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s%s", + straddr, VRF_LOGNAME(re_vrf), + (nexthop->rparent ? " NH" : "NH"), nhname, nexthop->ifindex, + label_str, vrf ? vrf->name : "Unknown", nexthop->vrf_id, wgt_str, backup_str, - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) - ? "ACTIVE " - : ""), - (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) - ? "FIB " - : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " + : ""), + (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "FIB " : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) - ? "RECURSIVE " - : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) - ? "ONLINK " - : ""), + ? "RECURSIVE " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) ? "ONLINK " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE) - ? "DUPLICATE " - : ""), + ? "DUPLICATE " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED) - ? "FILTERED " : ""), + ? "FILTERED " + : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) - ? "BACKUP " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) - ? "SRTE " : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN) - ? "EVPN " : "")); - + ? "BACKUP " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) ? "SRTE " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN) ? "EVPN " + : "")); } /* This function dumps the contents of a given RE entry into @@ -4211,32 +4173,33 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "", VRF_LOGNAME(vrf), re->vrf_id); - zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", - straddr, (unsigned long)re->uptime, re->type, re->instance, - re->table); - zlog_debug( - "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s", - straddr, re->metric, re->mtu, re->distance, - zclient_dump_route_flags(re->flags, flags_buf, - sizeof(flags_buf)), - _dump_re_status(re, status_buf, sizeof(status_buf))); - zlog_debug("%s: tag == %u, nexthop_num == %u, nexthop_active_num == %u", - straddr, re->tag, nexthop_group_nexthop_num(&(re->nhe->nhg)), + zlog_debug("%s(%s): uptime == %lu, type == %u, instance == %d, table == %d", + straddr, VRF_LOGNAME(vrf), (unsigned long)re->uptime, + re->type, re->instance, re->table); + zlog_debug("%s(%s): metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s", + straddr, VRF_LOGNAME(vrf), re->metric, re->mtu, re->distance, + zclient_dump_route_flags(re->flags, flags_buf, + sizeof(flags_buf)), + _dump_re_status(re, status_buf, sizeof(status_buf))); + zlog_debug("%s(%s): tag == %u, nexthop_num == %u, nexthop_active_num == %u", + straddr, VRF_LOGNAME(vrf), re->tag, + nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); /* Dump nexthops */ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - _route_entry_dump_nh(re, straddr, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); if (zebra_nhg_get_backup_nhg(re->nhe)) { - zlog_debug("%s: backup nexthops:", straddr); + zlog_debug("%s(%s): backup nexthops:", straddr, + VRF_LOGNAME(vrf)); nhg = zebra_nhg_get_backup_nhg(re->nhe); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) - _route_entry_dump_nh(re, straddr, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); } - zlog_debug("%s: dump complete", straddr); + zlog_debug("%s(%s): dump complete", straddr, VRF_LOGNAME(vrf)); } static int rib_meta_queue_gr_run_add(struct meta_queue *mq, void *data) @@ -4257,16 +4220,20 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) listnode_add(mq->subq[META_QUEUE_EARLY_ROUTE], data); mq->size++; - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("Route %pFX(%u) (%s) queued for processing into sub-queue %s", - &ere->p, ere->re->vrf_id, + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct vrf *vrf = vrf_lookup_by_id(ere->re->vrf_id); + + zlog_debug("Route %pFX(%s) (%s) queued for processing into sub-queue %s", + &ere->p, VRF_LOGNAME(vrf), ere->deletion ? "delete" : "add", subqueue2str(META_QUEUE_EARLY_ROUTE)); + } return 0; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4276,6 +4243,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4307,6 +4275,7 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, void zebra_rib_route_entry_free(struct route_entry *re) { + zapi_re_opaque_free(re); XFREE(MTYPE_RE, re); } @@ -4360,31 +4329,67 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, return -1; /* We either need nexthop(s) or an existing nexthop id */ - if (ng == NULL && re->nhe_id == 0) + if (ng == NULL && re->nhe_id == 0) { + zebra_rib_route_entry_free(re); return -1; + } /* * Use a temporary nhe to convey info to the common/main api. */ zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL)); - if (ng) + if (ng) { nhe.nhg.nexthop = ng->nexthop; - else if (re->nhe_id > 0) + + if (re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL || + re->type == ZEBRA_ROUTE_KERNEL) + SET_FLAG(nhe.flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); + } else if (re->nhe_id > 0) nhe.id = re->nhe_id; n = zebra_nhe_copy(&nhe, 0); + + if (re->type == ZEBRA_ROUTE_KERNEL) { + struct interface *ifp; + struct connected *connected; + + if (p->family == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) { + zebra_nhg_free(n); + zebra_rib_route_entry_free(re); + return -1; + } + + ifp = if_lookup_prefix(p, re->vrf_id); + if (ifp) { + connected = connected_lookup_prefix(ifp, p); + + if (connected && !CHECK_FLAG(connected->flags, + ZEBRA_IFA_NOPREFIXROUTE)) { + zebra_nhg_free(n); + zebra_rib_route_entry_free(re); + return -1; + } + + if (ng && ng->nexthop && + ifp->ifindex == ng->nexthop->ifindex) + re->type = ZEBRA_ROUTE_CONNECT; + } + } + ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, n, startup); /* In error cases, free the route also */ if (ret < 0) - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return ret; } void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, - unsigned short instance, uint32_t flags, struct prefix *p, - struct prefix_ipv6 *src_p, const struct nexthop *nh, + unsigned short instance, uint32_t flags, const struct prefix *p, + const struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint8_t distance, bool fromkernel) { @@ -4448,6 +4453,9 @@ static const char *rib_update_event2str(enum rib_update_event event) const char *ret = "UNKNOWN"; switch (event) { + case RIB_UPDATE_INTERFACE_DOWN: + ret = "RIB_UPDATE_INTERFACE_DOWN"; + break; case RIB_UPDATE_KERNEL: ret = "RIB_UPDATE_KERNEL"; break; @@ -4464,15 +4472,56 @@ static const char *rib_update_event2str(enum rib_update_event event) return ret; } +/* + * We now keep kernel routes, but we don't have any + * trigger events for them when they are implicitly + * deleted. Since we are already walking the + * entire table on a down event let's look at + * the few kernel routes we may have + */ +static void +rib_update_handle_kernel_route_down_possibility(struct route_node *rn, + struct route_entry *re) +{ + struct nexthop *nexthop = NULL; + bool alive = false; + + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { + struct interface *ifp = if_lookup_by_index(nexthop->ifindex, + nexthop->vrf_id); + + if ((ifp && if_is_up(ifp)) || nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + alive = true; + break; + } + } + + if (!alive) { + struct rib_table_info *rib_table = srcdest_rnode_table_info(rn); + const struct prefix *p; + const struct prefix_ipv6 *src_p; + + srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p); + + rib_delete(rib_table->afi, rib_table->safi, re->vrf_id, + re->type, re->instance, re->flags, p, src_p, NULL, 0, + re->table, re->metric, re->distance, true); + } +} + /* Schedule route nodes to be processed if they match the type */ -static void rib_update_route_node(struct route_node *rn, int type) +static void rib_update_route_node(struct route_node *rn, int type, + enum rib_update_event event) { struct route_entry *re, *next; bool re_changed = false; RNODE_FOREACH_RE_SAFE (rn, re, next) { - if (type == ZEBRA_ROUTE_ALL || type == re->type) { + if (event == RIB_UPDATE_INTERFACE_DOWN && type == re->type && + type == ZEBRA_ROUTE_KERNEL) + rib_update_handle_kernel_route_down_possibility(rn, re); + else if (type == ZEBRA_ROUTE_ALL || type == re->type) { SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); re_changed = true; } @@ -4512,20 +4561,24 @@ void rib_update_table(struct route_table *table, enum rib_update_event event, /* * If we are looking at a route node and the node * has already been queued we don't - * need to queue it up again + * need to queue it up again, unless it is + * an interface down event as that we need + * to process this no matter what. */ - if (rn->info - && CHECK_FLAG(rib_dest_from_rnode(rn)->flags, - RIB_ROUTE_ANY_QUEUED)) + if (rn->info && + CHECK_FLAG(rib_dest_from_rnode(rn)->flags, + RIB_ROUTE_ANY_QUEUED) && + event != RIB_UPDATE_INTERFACE_DOWN) continue; switch (event) { + case RIB_UPDATE_INTERFACE_DOWN: case RIB_UPDATE_KERNEL: - rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL); + rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL, event); break; case RIB_UPDATE_RMAP_CHANGE: case RIB_UPDATE_OTHER: - rib_update_route_node(rn, rtype); + rib_update_route_node(rn, rtype, event); break; case RIB_UPDATE_MAX: break; @@ -4533,7 +4586,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event, } } -static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype) +void rib_update_handle_vrf_all(enum rib_update_event event, int rtype) { struct zebra_router_table *zrt; @@ -4694,6 +4747,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; @@ -4742,6 +4799,10 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance) if (!zvrf) continue; + early_route_meta_queue_free(zrouter.mq, + zrouter.mq->subq[META_QUEUE_EARLY_ROUTE], + zvrf, proto, instance); + cnt += rib_score_proto_table(proto, instance, zvrf->table[AFI_IP][SAFI_UNICAST]) + rib_score_proto_table( @@ -4775,29 +4836,6 @@ void rib_close_table(struct route_table *table) } /* - * Handler for async dataplane results after a pseudowire installation - */ -static void handle_pw_result(struct zebra_dplane_ctx *ctx) -{ - struct zebra_pw *pw; - struct zebra_vrf *vrf; - - /* The pseudowire code assumes success - we act on an error - * result for installation attempts here. - */ - if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) - return; - - if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { - vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); - pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); - if (pw) - zebra_pw_install_failure(pw, - dplane_ctx_get_pw_status(ctx)); - } -} - -/* * Handle results from the dataplane system. Dequeue update context * structs, dispatch to appropriate internal handlers. */ @@ -4903,7 +4941,7 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: - handle_pw_result(ctx); + zebra_pw_handle_dplane_results(ctx); break; case DPLANE_OP_SYS_ROUTE_ADD: @@ -5001,6 +5039,17 @@ static int rib_dplane_results(struct dplane_ctx_list_head *ctxlist) return 0; } +uint32_t zebra_rib_dplane_results_count(void) +{ + uint32_t count; + + frr_with_mutex (&dplane_mutex) { + count = dplane_ctx_queue_count(&rib_dplane_q); + } + + return count; +} + /* * Ensure there are no empty slots in the route_info array. * Every route type in zebra should be present there. diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index bff82588..7c25fb3e 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -220,10 +220,9 @@ void zebra_free_rnh(struct rnh *rnh) if (rern) { rib_dest_t *dest; - route_unlock_node(rern); - dest = rib_dest_from_rnode(rern); rnh_list_del(&dest->nht, rnh); + route_unlock_node(rern); } } free_state(rnh->vrf_id, rnh->state, rnh->node); @@ -826,7 +825,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, /* free RE and nexthops */ zebra_nhg_free(re->nhe); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } static void copy_state(struct rnh *rnh, const struct route_entry *re, @@ -1344,13 +1343,17 @@ static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) } if (rnh->state) { - if (json) + if (json) { json_object_string_add( json_nht, "resolvedProtocol", zebra_route_string(rnh->state->type)); - else - vty_out(vty, " resolved via %s\n", - zebra_route_string(rnh->state->type)); + json_object_string_addf(json_nht, "prefix", "%pFX", + &rnh->resolved_route); + } else { + vty_out(vty, " resolved via %s, prefix %pFX\n", + zebra_route_string(rnh->state->type), + &rnh->resolved_route); + } for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index c1ec5067..46afbcec 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -650,9 +650,8 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3fd4e6eb..4022c1a2 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -238,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); @@ -343,7 +343,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack, #endif zrouter.asic_notification_nexthop_control = false; - zrouter.nexthop_weight_scale_value = 255; + zrouter.nexthop_weight_scale_value = 254; #ifdef HAVE_SCRIPTING zebra_script_init(); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 30417074..c86c6be1 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 1c6d5815..4b4f5232 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -229,6 +229,8 @@ static int proto_trans(int type) return 3; /* static route */ case ZEBRA_ROUTE_RIP: return 8; /* rip */ + case ZEBRA_ROUTE_ISIS: + return 9; case ZEBRA_ROUTE_RIPNG: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_OSPF: @@ -237,6 +239,8 @@ static int proto_trans(int type) return 1; /* shouldn't happen */ case ZEBRA_ROUTE_BGP: return 14; /* bgp */ + case ZEBRA_ROUTE_EIGRP: + return 16; default: return 1; /* other */ } @@ -253,9 +257,11 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (prefix_cmp(&(*np)->p, &np2->p) < 0) + if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, + (uint8_t *)&np2->p.u.prefix4) < 0) return; - if (prefix_cmp(&(*np)->p, &np2->p) > 0) { + if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, + (uint8_t *)&np2->p.u.prefix4) > 0) { *np = np2; *re = re2; return; @@ -298,14 +304,8 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], int i; /* Init index variables */ - - pnt = (uint8_t *)&dest; - for (i = 0; i < 4; i++) - *pnt++ = 0; - - pnt = (uint8_t *)&nexthop; - for (i = 0; i < 4; i++) - *pnt++ = 0; + memset(&dest, 0, sizeof(dest)); + memset(&nexthop, 0, sizeof(nexthop)); proto = 0; policy = 0; @@ -497,23 +497,23 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC1: - result = 0; + result = re->metric; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC2: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC3: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC4: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC5: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; default: diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index bb872ef9..082d4609 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -18,11 +18,6 @@ #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" #include "zebra/ge_netlink.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <arpa/inet.h> -#include <netinet/in.h> #include <stdio.h> #include <string.h> @@ -33,6 +28,16 @@ DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, + "SRv6 uSID Wide LIB information"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); + +/* Prototypes */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -55,6 +60,18 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DEFINE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DEFINE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); + /* define wrappers to be called in zapi_msg.c (as hooks must be called in * source file where they were defined) */ @@ -85,11 +102,502 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } + +void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value, + locator_name); +} + +void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + hook_call(srv6_manager_release_sid, client, ctx); +} + +void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + hook_call(srv6_manager_get_locator, locator, client, locator_name); +} + static int zebra_srv6_cleanup(struct zserv *client) { + /* Client has disconnected, let's release all the SIDs allocated by it. */ + release_daemon_srv6_sids(client); return 0; } +/* --- Zebra SRv6 SID context management functions -------------------------- */ + +struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void) +{ + struct zebra_srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX, + sizeof(struct zebra_srv6_sid_ctx)); + + return ctx; +} + +void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx); +} + +/** + * Free an SRv6 SID context. + * + * @param val SRv6 SID context to be freed + */ +void delete_zebra_srv6_sid_ctx(void *val) +{ + zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val); +} + +/* --- Zebra SRv6 SID format management functions --------------------------- */ + +void srv6_sid_format_register(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + /* Ensure that the format is registered only once */ + assert(!srv6_sid_format_lookup(format->name)); + + listnode_add(srv6->sid_formats, format); +} + +void srv6_sid_format_unregister(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + listnode_delete(srv6->sid_formats, format); +} + +struct srv6_sid_format *srv6_sid_format_lookup(const char *name) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_sid_format *format; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) + if (!strncmp(name, format->name, sizeof(format->name))) + return format; + + return NULL; +} + +/* + * Called to change the SID format of a locator. + * + * After switching the locator to a different format, the SIDs allocated + * from the locator may no longer be valid; we need to notify the + * interested zclient that the locator has changed, so that the + * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program + * the new SIDs. + */ +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block_old, *block_new; + struct prefix_ipv6 block_pfx_new; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (!locator) + return; + + locator->sid_format = format; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, old=%s new=%s", + __func__, locator->name, + locator->sid_format ? ((struct srv6_sid_format *) + locator->sid_format) + ->name + : NULL, + format ? format->name : NULL); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients", + __func__, locator->name); + + /* Release the current parent block */ + block_old = locator->sid_block; + if (block_old) { + block_old->refcnt--; + if (block_old->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block_old); + zebra_srv6_sid_block_free(block_old); + } + } + locator->sid_block = NULL; + + block_pfx_new = locator->prefix; + if (format) + block_pfx_new.prefixlen = format->block_len; + else + block_pfx_new.prefixlen = locator->block_bits_length; + apply_mask(&block_pfx_new); + + /* Allocate the new parent block */ + block_new = zebra_srv6_sid_block_lookup(&block_pfx_new); + if (!block_new) { + block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new); + listnode_add(srv6->sid_blocks, block_new); + } + + block_new->refcnt++; + locator->sid_block = block_new; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients", + __func__, locator->name); + + /* Notify zclients about the updated locator */ + zebra_srv6_locator_add(locator); +} + +/* + * Called when a SID format is modified by the user. + * + * After modifying a SID format, the SIDs that are using that format may no + * longer be valid. + * This function walks through the list of locators that are using the SID format + * and notifies the zclients that the locator has changed, so that the zclients + * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs. + */ +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SID format %s has changed. Notifying zclients.", + __func__, format->name); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->sid_format == format) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.", + __func__, locator->name, + format->name); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + /* Notify zclients about the updated locator */ + zebra_notify_srv6_locator_add(locator); + } + } +} + +/* + * Helper function to create the SRv6 compressed format `usid-f3216`. + */ +static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_USID; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return format; +} + +/* + * Helper function to create the SRv6 uncompressed format. + */ +static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return format; +} + +/* --- Zebra SRv6 SID function management functions ---------------------------- */ + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func) +{ + uint32_t *sid_func_ptr; + + sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t)); + *sid_func_ptr = func; + + return sid_func_ptr; +} + +void zebra_srv6_sid_func_free(uint32_t *func) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func); +} + +/** + * Free an SRv6 SID function. + * + * @param val SRv6 SID function to be freed + */ +void delete_zebra_srv6_sid_func(void *val) +{ + zebra_srv6_sid_func_free((uint32_t *)val); +} + +/* --- Zebra SRv6 SID block management functions ---------------------------- */ + +static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void) +{ + struct zebra_srv6_sid_block *block = NULL; + + block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK, + sizeof(struct zebra_srv6_sid_block)); + + return block; +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix) +{ + struct zebra_srv6_sid_block *block; + + block = zebra_srv6_sid_block_alloc_internal(); + block->sid_format = format; + block->prefix = *prefix; + + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Init uSID LIB */ + block->u.usid.lib.func_allocated = list_new(); + block->u.usid.lib.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.func_released = list_new(); + block->u.usid.lib.func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.first_available_func = + format->config.usid.lib_start; + + /* Init uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + block->u.usid.wide_lib = + XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB, + (wlib_end - wlib_start + 1) * + sizeof(struct wide_lib)); + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + block->u.usid.wide_lib[func].func_allocated = + list_new(); + block->u.usid.wide_lib[func].func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func_released = + list_new(); + block->u.usid.wide_lib[func].func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func = func; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + } else { + /* We should never arrive here */ + assert(0); + } + } else { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = 1; + } + + return block; +} + +void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block) +{ + if (block->sid_format) { + if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Free uSID LIB */ + list_delete(&block->u.usid.lib.func_allocated); + list_delete(&block->u.usid.lib.func_released); + + /* Free uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + list_delete(&block->u.usid.wide_lib[func] + .func_allocated); + list_delete(&block->u.usid.wide_lib[func] + .func_released); + } + XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB, + block->u.usid.wide_lib); + } else if (block->sid_format->type == + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } + + XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block); +} + +/** + * Free an SRv6 SID block. + * + * @param val SRv6 SID block to be freed + */ +void delete_zebra_srv6_sid_block(void *val) +{ + zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val); +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) + if (prefix_match(prefix, &block->prefix)) + return block; + + return NULL; +} + +/* --- Zebra SRv6 SID management functions ---------------------------------- */ + +/** + * Alloc and fill an SRv6 SID. + * + * @param ctx Context associated with the SID to be created + * @param sid_value IPv6 address associated with the SID to be created + * @param locator Parent locator of the SID to be created + * @param sid_block Block from which the SID value has been allocated + * @param sid_func Function part of the SID to be created + * @param alloc_mode Allocation mode of the Function (dynamic vs explicit) + * @return The requested SID + */ +struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode) +{ + struct zebra_srv6_sid *sid; + + if (!ctx || !sid_value) + return NULL; + + sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid)); + sid->ctx = ctx; + sid->value = *sid_value; + sid->locator = locator; + sid->block = sid_block; + sid->func = sid_func; + sid->alloc_mode = alloc_mode; + sid->client_list = list_new(); + + return sid; +} + +void zebra_srv6_sid_free(struct zebra_srv6_sid *sid) +{ + list_delete(&sid->client_list); + XFREE(MTYPE_ZEBRA_SRV6_SID, sid); +} + +/** + * Free an SRv6 SID. + * + * @param val SRv6 SID to be freed + */ +void delete_zebra_srv6_sid(void *val) +{ + zebra_srv6_sid_free((struct zebra_srv6_sid *)val); +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -121,7 +629,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct zserv *client; @@ -136,18 +643,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn( - "%s: Not found zclient(proto=%u, instance=%u).", - __func__, c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } listnode_delete(srv6->locators, locator); srv6_locator_free(locator); @@ -190,7 +687,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator) void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zserv *client; /* @@ -204,17 +700,8 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn("Not found zclient(proto=%u, instance=%u).", - c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } } struct zebra_srv6 srv6; @@ -222,10 +709,32 @@ struct zebra_srv6 srv6; struct zebra_srv6 *zebra_srv6_get_default(void) { static bool first_execution = true; + struct srv6_sid_format *format_usidf3216; + struct srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; srv6.locators = list_new(); + + /* Initialize list of SID formats */ + srv6.sid_formats = list_new(); + srv6.sid_formats->del = delete_srv6_sid_format; + + /* Create SID format `usid-f3216` */ + format_usidf3216 = create_srv6_sid_format_usid_f3216(); + srv6_sid_format_register(format_usidf3216); + + /* Create SID format `uncompressed` */ + format_uncompressed = create_srv6_sid_format_uncompressed(); + srv6_sid_format_register(format_uncompressed); + + /* Init list to store SRv6 SIDs */ + srv6.sids = list_new(); + srv6.sids->del = delete_zebra_srv6_sid_ctx; + + /* Init list to store SRv6 SID blocks */ + srv6.sid_blocks = list_new(); + srv6.sid_blocks->del = delete_zebra_srv6_sid_block; } return &srv6; } @@ -427,21 +936,1507 @@ void zebra_srv6_encap_src_addr_unset(void) memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); } +/* --- SRv6 SID Allocation/Release functions -------------------------------- */ + +/** + * Return the SRv6 SID obtained composing the locator and function. + * + * @param sid_value SRv6 SID address returned + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, + struct srv6_locator *locator, + uint32_t sid_func) +{ + uint8_t offset, func_len; + struct srv6_sid_format *format; + + if (!sid_value || !locator) + return false; + + format = locator->sid_format; + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = locator->block_bits_length + locator->node_bits_length; + func_len = locator->function_bits_length; + } + + *sid_value = locator->prefix.prefix; + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + + sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (sid_func >> (func_len - 1 - idx) & 0x1) + sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); + } + + return true; +} + +/** + * Return the parent locator and function of an SRv6 SID. + * + * @param sid_value SRv6 SID address to be decomposed + * @param sid_block Parent block of the SRv6 SID + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @param sid_wide_func Wide function of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value, + struct zebra_srv6_sid_block **sid_block, + struct srv6_locator **locator, + uint32_t *sid_func, uint32_t *sid_wide_func) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *l; + struct zebra_srv6_sid_block *b; + struct srv6_sid_format *format; + struct listnode *node; + struct prefix_ipv6 tmp_prefix; + uint8_t offset, func_len; + + if (!sid_value || !sid_func) + return false; + + *sid_func = 0; + *sid_wide_func = 0; + + /* + * Build a temporary prefix_ipv6 object representing the SRv6 SID. + * This temporary prefix object is used below by the prefix_match + * function to check if the SID belongs to a specific locator. + */ + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = *sid_value; + + /* + * Lookup the parent locator of the SID and return the locator and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) { + /* + * Check if the locator prefix includes the temporary prefix + * representing the SID. + */ + if (prefix_match((struct prefix *)&l->prefix, + (struct prefix *)&tmp_prefix)) { + format = l->sid_format; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = l->block_bits_length + + l->node_bits_length; + func_len = l->function_bits_length; + } + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((func_len - 1 - idx) / 8) * 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = l->sid_format; + + offset = format->block_len + + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / + 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * + 8); + } + } + } + + *locator = l; + *sid_block = l->sid_block; + + return true; + } + } + + /* + * If we arrive here, the SID does not belong to any locator. + * Then, let's try to find the parent block from which the SID + * has been allocated. + */ + + /* + * Lookup the parent block of the SID and return the block and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) { + /* + * Check if the block prefix includes the temporary prefix + * representing the SID + */ + if (prefix_match((struct prefix *)&b->prefix, + (struct prefix *)&tmp_prefix)) { + format = b->sid_format; + + if (!format) + continue; + + offset = format->block_len + format->node_len; + func_len = format->function_len; + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << ((func_len - 1 - idx) / 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = b->sid_format; + + offset = format->block_len + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * 8); + } + } + + *sid_block = b; + + return true; + } + } + + return false; +} + +/** + * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function to be allocated + * @param sid_wide_func SID wide function to be allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t wlib_end = format->config.usid.wlib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function has to be allocated from the ELIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = + zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.usid.lib.func_allocated, + sid_func_ptr); + block->u.usid.lib.num_func_allocated++; + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function has to be allocated from the EWLIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, + sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + if (sid_wide_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_wide_func_ptr = zebra_srv6_sid_func_alloc( + sid_wide_func); + listnode_add(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + block->u.usid.wide_lib[sid_func] + .num_func_allocated++; + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)", + __func__, sid_func, explicit_start, + explicit_end); + return false; + } + + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, + sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return true; +} + +/** + * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t *sid_func) +{ + struct srv6_sid_format *format; + uint32_t *sid_func_ptr = NULL; + + if (!block || !sid_func) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate dynamic SID function from block %pFX", + __func__, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + /* Format is uSID and behavior => allocate SID function from LIB range */ + + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.usid.lib.first_available_func > dlib_end) { + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted", + __func__); + return false; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.usid.lib.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.usid.lib.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.usid.lib.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = + block->u.usid.lib.first_available_func; + block->u.usid.lib.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.usid.lib.num_func_allocated++; + + if (block->u.usid.lib.first_available_func > dlib_end) + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail", + __func__); + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + /* Format is uncompressed => allocate SID function from Dynamic range */ + + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.uncompressed.first_available_func > + dynamic_end) { + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted", + __func__); + return NULL; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed + .first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + + if (block->u.uncompressed.first_available_func > + dynamic_end) + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail", + __func__); + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed.first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated dynamic SID function %u from block %pFX", + __func__, *sid_func, &block->prefix); + + return true; +} + +/** + * Get an explicit SID (i.e., a specific SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be + * allocated explicitly + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx = NULL; + struct listnode *node; + uint32_t sid_func = 0, sid_func_wide = 0; + struct srv6_locator *locator = NULL; + struct zebra_srv6_sid_block *block = NULL; + char buf[256]; + + if (!ctx || !sid_value) + return -1; + + /* Check if we already have a SID associated with the provided context */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + /* + * If the context is already associated with a SID that has the same SID value, then + * return the existing SID + */ + if (sid_same(&s->sid->value, sid_value)) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s", + __func__, &s->sid->value, + srv6_sid_ctx2str(buf, + sizeof(buf), + ctx)); + *sid = s->sid; + return 0; + } + + /* + * It is not allowed to allocate an explicit SID for a given context if the context + * is already associated with an explicit SID + */ + if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6", + __func__, sid_value, + srv6_sid_ctx2str(buf, sizeof(buf), + &s->ctx), + &s->sid->value); + return -1; + } + + zctx = s; + break; + } + } + + /* Get parent locator and function of the provided SID */ + if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func, + &sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6", + __func__, sid_value); + return -1; + } + + if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", + __func__); + return -1; + } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + if (!zctx) { + /* If we don't have a zebra SID context for this context, allocate a new one */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + } else { + /* + * If we already have a SID associated with this context, we need to + * deallocate the current SID function before allocating the new one + */ + if (zctx->sid) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &zctx->sid->value); + + release_srv6_sid_func_dynamic(block, zctx->sid->func); + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + } + } + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_EXPLICIT); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get a dynamic SID (i.e., any available SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param locator SRv6 locator from which the SID has to be allocated + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct srv6_sid_format *format; + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node; + struct in6_addr sid_value; + uint32_t sid_func = 0; + char buf[256]; + + if (!ctx || !locator) + return -1; + + block = locator->sid_block; + format = locator->sid_format; + + /* + * If we already have a SID for the provided context, we return the existing + * SID instead of allocating a new one. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (locator && s->sid && s->sid->locator) { + if (strncmp(s->sid->locator->name, locator->name, + SRV6_LOCNAME_SIZE)) { + continue; + } + } + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SID %s %pI6", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &s->sid->value); + *sid = s->sid; + return 0; + } + } + + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID && + ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else { + /* Allocate a dynamic SID function for the SID */ + if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + /* Compose the SID as the locator followed by the SID function */ + zebra_srv6_sid_compose(&sid_value, locator, sid_func); + } + + /* Allocate a zebra SID context to store SID context information */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_DYNAMIC); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get an SRv6 SID for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * If the sid_value parameter is non-NULL, it allocates the requested SID value + * if it is available (explicit SID allocation). + * If the sid_value parameter is NULL, it allocates any available SID value + * (dynamic SID allocation). + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation) + * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name) +{ + int ret = -1; + struct srv6_locator *locator; + char buf[256]; + + enum srv6_sid_alloc_mode alloc_mode = + (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT + : SRV6_SID_ALLOC_MODE_DYNAMIC; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, srv6_sid_alloc_mode2str(alloc_mode)); + + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + /* + * Explicit SID allocation: allocate a specific SID value + */ + + if (!sid_value) { + zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation", + __func__); + return -1; + } + + ret = get_srv6_sid_explicit(sid, ctx, sid_value); + } else { + /* + * Dynamic SID allocation: allocate any available SID value + */ + + if (!locator_name) { + zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation", + __func__); + return -1; + } + + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) { + zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist", + __func__, locator_name); + return -1; + } + + ret = get_srv6_sid_dynamic(sid, ctx, locator); + } + + return ret; +} + +/** + * Release an explicit SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = format->config.usid.wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function comes from the ELIB range */ + + /* Lookup SID function in the functions allocated list of ELIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the ELIB range */ + listnode_delete(block->u.usid.lib.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function comes from the EWLIB range */ + + /* Lookup SID function in the functions allocated list of EWLIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_wide_func_ptr) { + zlog_warn("%s: failed to release wide SID function %u, function is not allocated", + __func__, sid_wide_func); + return -1; + } + + /* Release the SID function from the EWLIB range */ + listnode_delete(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + zebra_srv6_sid_func_free(sid_wide_func_ptr); + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]", + __func__, sid_func, explicit_start, + explicit_end); + return -1; + } + + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Release a dynamic SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func) +{ + struct srv6_sid_format *format; + struct listnode *node, *nnode; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t dlib_start = format->config.usid.lib_start; + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */ + if (!(sid_func >= dlib_start && sid_func <= dlib_end)) { + zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]", + __func__, sid_func, dlib_start, dlib_end); + return -1; + } + + if (sid_func == block->u.usid.lib.first_available_func - 1) { + /* + * The SID function to be released precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.usid.lib.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.usid.lib + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.usid.lib.first_available_func - + 1) { + listnode_delete(block->u.usid + .lib + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.usid.lib + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The SID function to be released does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.usid.lib.func_released, + sid_func_ptr); + } + } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t dynamic_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + /* The Dynamic range ends where the Explicit range begins */ + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic range */ + if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) { + zlog_warn("%s: function %u is outside dynamic range [%u/%u]", + __func__, sid_func, dynamic_start, + dynamic_end); + return -1; + } + + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } else if (!format) { + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Core function, release the SRv6 SID associated with a given context. + * + * @param client The client for which the SID has to be released + * @param ctx Context associated with the SRv6 SID to be released + * @return 0 on success, -1 otherwise + */ +int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + char buf[256]; + + if (!zctx || !zctx->sid) + return -1; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* Ensures the SID is in use by the client */ + if (!listnode_lookup(zctx->sid->client_list, client)) { + flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!", + __func__); + return -1; + } + + /* Remove the client from the list of clients using the SID */ + listnode_delete(zctx->sid->client_list, client); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* + * If the SID is not used by any other client, then deallocate it + * and remove it from the SRv6 database. + */ + if (listcount(zctx->sid->client_list) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), + &zctx->ctx)); + + if (!(zctx->sid->block->sid_format && + zctx->sid->block->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) && + !(!zctx->sid->block->sid_format && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) { + if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_EXPLICIT) + /* Release SRv6 SID function */ + release_srv6_sid_func_explicit(zctx->sid->block, + zctx->sid->func, + zctx->sid->wide_func); + else if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_DYNAMIC) + /* Release SRv6 SID function */ + release_srv6_sid_func_dynamic(zctx->sid->block, + zctx->sid->func); + else + /* We should never arrive here */ + assert(0); + } + + /* Free the SID */ + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + + /* Remove the SID context from the list and free memory */ + listnode_delete(srv6->sids, zctx); + zebra_srv6_sid_ctx_free(zctx); + } + + return 0; +} + +/** + * Handle a get SRv6 Locator request received from a client. + * + * It looks up the requested locator and send it to the client. + * + * @param locator SRv6 locator returned by this function + * @param client The client that sent the Get SRv6 Locator request + * @param locator_name Name of the locator to look up + * + * @return 0 on success + */ +static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + *locator = zebra_srv6_locator_lookup(locator_name); + if (!*locator) + return -1; + + return zsend_zebra_srv6_locator_add(client, *locator); +} + +/** + * Handle a get SID request received from a client. + * + * It gets a SID for a given context. If there is no SID associated with the context yet, + * we allocate one and return it to the client. Otherwise, we return the existing SID. + * + * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value + * if it is available (explicit SID allocation). + * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value + * (dynamic SID allocation). + * + * Finally, notify the client whether the SID allocation was successful or failed. + * + * @param sid SID returned by this function + * @param client The client that requested the SID + * @param ctx Context for which the SID was requested + * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID + * (for explicit SID allocation) + * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 on success, -1 otherwise + */ +static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret = -1; + struct listnode *node; + struct zserv *c; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + ret = get_srv6_sid(sid, ctx, sid_value, locator_name); + if (ret < 0) { + zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + /* Notify client about SID alloc failure */ + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL, + ZAPI_SRV6_SID_FAIL_ALLOC); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, + (*sid)->wide_func, + (*sid)->locator ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } else { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) + zsend_srv6_sid_notify(c, ctx, &(*sid)->value, + (*sid)->func, (*sid)->wide_func, + (*sid)->locator + ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } + + return ret; +} + +/** + * Release SRv6 SIDs from a client. + * + * Called on client disconnection or reconnection. + * + * @param client The client to release SIDs from + * @return Number of SIDs released + */ +int release_daemon_srv6_sids(struct zserv *client) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + int count = 0; + int ret; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + /* Iterate over the SIDs and release SIDs used by the client daemon */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!listnode_lookup(ctx->sid->client_list, client)) + continue; + + ret = release_srv6_sid(client, ctx); + if (ret == 0) + count++; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released %d SRv6 SIDs", __func__, count); + + return count; +} + +/** + * Release SRv6 SIDs from a client. + * + * @param client The client zapi session + * @param ctx Context associated with the SRv6 SID + * @return 0 on success, -1 on failure + */ +static int srv6_manager_release_sid_internal(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + int ret = -1; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node, *nnode; + char buf[256]; + const char *locator_name = NULL; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID associated with ctx %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* Lookup Zebra SID context and release it */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) + if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (zctx->sid && zctx->sid->locator) + locator_name = + (const char *)zctx->sid->locator->name; + ret = release_srv6_sid(client, zctx); + break; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: no SID associated with ctx %s", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + if (ret == 0) + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_RELEASED); + else + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_FAIL_RELEASE); + + return ret; +} + void zebra_srv6_terminate(void) { struct srv6_locator *locator; + struct srv6_sid_format *format; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *sid_ctx; - if (!srv6.locators) - return; + if (srv6.locators) { + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); + + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } - while (listcount(srv6.locators)) { - locator = listnode_head(srv6.locators); + list_delete(&srv6.locators); + } + + /* Free SRv6 SIDs */ + if (srv6.sids) { + while (listcount(srv6.sids)) { + sid_ctx = listnode_head(srv6.sids); - listnode_delete(srv6.locators, locator); - srv6_locator_free(locator); + listnode_delete(srv6.sids, sid_ctx); + zebra_srv6_sid_ctx_free(sid_ctx); + } + + list_delete(&srv6.sids); } - list_delete(&srv6.locators); + /* Free SRv6 SID blocks */ + if (srv6.sid_blocks) { + while (listcount(srv6.sid_blocks)) { + block = listnode_head(srv6.sid_blocks); + + listnode_delete(srv6.sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + + list_delete(&srv6.sid_blocks); + } + + /* Free SRv6 SID formats */ + if (srv6.sid_formats) { + while (listcount(srv6.sid_formats)) { + format = listnode_head(srv6.sid_formats); + + srv6_sid_format_unregister(format); + srv6_sid_format_free(format); + } + + list_delete(&srv6.sid_formats); + } } void zebra_srv6_init(void) @@ -451,6 +2446,12 @@ void zebra_srv6_init(void) zebra_srv6_manager_get_locator_chunk); hook_register(srv6_manager_release_chunk, zebra_srv6_manager_release_locator_chunk); + + hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal); + hook_register(srv6_manager_release_sid, + srv6_manager_release_sid_internal); + hook_register(srv6_manager_get_locator, + srv6_manager_get_srv6_locator_internal); } bool zebra_srv6_is_enable(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 21936c33..1599fd7a 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -16,12 +16,197 @@ #include <pthread.h> #include <plist.h> +/* Default config for SRv6 SID `usid-f3216` format */ +#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 + +/* Default config for SRv6 SID `uncompressed` format */ +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 + +/* uSID Wide LIB */ +struct wide_lib { + uint32_t func; + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; +}; + +/* + * SRv6 SID block. + * + * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated. + * Example: + * SID block = fc00:0::/32 + * SID 1 = fc00:0:1:e000:: + * SID 2 = fc00:0:1:fe00:: + * ... + */ +struct zebra_srv6_sid_block { + /* Prefix of this block, e.g. fc00:0::/32 */ + struct prefix_ipv6 prefix; + + /* Reference counter */ + unsigned long refcnt; + + /* + * Pointer to the SID format that defines the structure of the SIDs + * allocated from this block + */ + struct srv6_sid_format *sid_format; + + /* + * Run-time information/state of this SID block. + * + * This includes stuff like how many SID functions have been allocated + * from this block, which functions are still available to be allocated + * and so on... + */ + union { + /* Information/state for compressed uSID format */ + struct { + /* uSID Local ID Block (LIB) */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } lib; + + /* uSID Wide LIB */ + struct wide_lib *wide_lib; + } usid; + + /* Information/state for uncompressed SID format */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } uncompressed; + } u; +}; + +/** + * The function part of an SRv6 SID can be allocated in one + * of the following ways: + * - dynamic: allocate any available function + * - explicit: allocate a specific function + */ +enum srv6_sid_alloc_mode { + SRV6_SID_ALLOC_MODE_UNSPEC = 0, + /* Dynamic SID allocation */ + SRV6_SID_ALLOC_MODE_DYNAMIC = 1, + /* Explicit SID allocation */ + SRV6_SID_ALLOC_MODE_EXPLICIT = 2, + SRV6_SID_ALLOC_MODE_MAX = 3, +}; + +/** + * Convert SID allocation mode to string. + * + * @param alloc_mode SID allocation mode + * @return String representing the allocation mode + */ +static inline const char * +srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode) +{ + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + return "explicit"; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + return "dynamic"; + case SRV6_SID_ALLOC_MODE_UNSPEC: + return "unspec"; + case SRV6_SID_ALLOC_MODE_MAX: + default: + return "unknown"; + } +} + +/* SRv6 SID instance. */ +struct zebra_srv6_sid { + /* + * SID context associated with the SID. + * Defines behavior and attributes of the SID. + */ + struct zebra_srv6_sid_ctx *ctx; + + /* SID value (e.g. fc00:0:1:e000::) */ + struct in6_addr value; + + /* Pointer to the SRv6 locator from which the SID has been allocated */ + struct srv6_locator *locator; + + /* Pointer to the SRv6 block from which the SID has been allocated */ + struct zebra_srv6_sid_block *block; + + /* + * Function part of the SID + * Example: + * SID = fc00:0:1:e000:: => func = e000 + */ + uint32_t func; + + /* SID wide function. */ + uint32_t wide_func; + + /* SID allocation mode: dynamic or explicit */ + enum srv6_sid_alloc_mode alloc_mode; + + /* List of clients that are using the SID */ + struct list *client_list; +}; + +/* + * Zebra SRv6 SID context. + * A context defines a behavior and (optionally) some behavior-specific + * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate + * a SID for a particular context. SRv6 Manager is responsible for allocating + * a SID from a given SID block and associating with the context. + * + * Example: + * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}. + * SRv6 Manager allocate SID fc00:0:1:e000:: for that context. + */ +struct zebra_srv6_sid_ctx { + /* SRv6 SID context information. */ + struct srv6_sid_ctx ctx; + + /* SID associated with the context. */ + struct zebra_srv6_sid *sid; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; /* Source address for SRv6 encapsulation */ struct in6_addr encap_src_addr; + + /* SRv6 SID formats */ + struct list *sid_formats; + + /* SRv6 SIDs */ + struct list *sids; + + /* SRv6 SID blocks */ + struct list *sid_blocks; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -46,6 +231,17 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DECLARE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DECLARE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); @@ -74,4 +270,55 @@ 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); +void srv6_sid_format_register(struct srv6_sid_format *format); +void srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format); +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format); + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); +void zebra_srv6_sid_func_free(uint32_t *func); +void delete_zebra_srv6_sid_func(void *val); + +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix); +extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); +extern void delete_zebra_srv6_sid_block(void *val); +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); + +extern struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode); +extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); +extern void delete_zebra_srv6_sid(void *val); + +extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx); + +extern void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name); + +extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name); +extern int release_srv6_sid(struct zserv *client, + struct zebra_srv6_sid_ctx *zctx); +extern int release_daemon_srv6_sids(struct zserv *client); +extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid, + struct zserv *client); + +extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); +extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); +extern void delete_zebra_srv6_sid_ctx(void *val); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index d5cd30e6..5a805241 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -68,6 +68,27 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + DEFPY (show_srv6_manager, show_srv6_manager_cmd, "show segment-routing srv6 manager [json]", @@ -198,15 +219,32 @@ DEFUN (show_srv6_locator_detail, prefix2str(&locator->prefix, str, sizeof(str)); vty_out(vty, "Name: %s\n", locator->name); vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); - vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - vty_out(vty, "Argument-Bit-Len: %u\n", - locator->argument_bits_length); + if (locator->sid_format) { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->sid_format->block_len); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->sid_format->node_len); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->sid_format->function_len); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->sid_format->argument_len); + + if (locator->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID) + vty_out(vty, "Behavior: uSID\n"); + } else { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->block_bits_length); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->node_bits_length); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->argument_bits_length); - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, "Behavior: uSID\n"); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, @@ -248,9 +286,30 @@ DEFUN (no_srv6, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node, *nnode; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *ctx; + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) { + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } - for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) zebra_srv6_locator_delete(locator); + } return CMD_SUCCESS; } @@ -297,12 +356,37 @@ DEFUN (no_srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); if (!locator) { vty_out(vty, "%% Can't find SRv6 locator\n"); return CMD_WARNING_CONFIG_FAILED; } + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + zebra_srv6_locator_delete(locator); return CMD_SUCCESS; } @@ -323,14 +407,37 @@ DEFPY (locator_prefix, VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; + uint8_t expected_prefixlen; + struct srv6_sid_format *format; locator->prefix = *prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; + expected_prefixlen = prefix->prefixlen; + format = locator->sid_format; + if (format) { + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format->name, + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + } + + if (prefix->prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + prefix->prefixlen, format->name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = - prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = prefix->prefixlen - + ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { block_bit_len = prefix->prefixlen - node_bit_len; @@ -401,7 +508,8 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); + zebra_srv6_locator_format_set(locator, locator->sid_format); + return CMD_SUCCESS; } @@ -422,8 +530,9 @@ DEFPY (locator_behavior, /* SRv6 locator uSID flag already set, nothing to do */ return CMD_SUCCESS; - /* Remove old locator from zclients */ - zebra_notify_srv6_locator_delete(locator); + if (!locator->sid_format) + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); /* Set/Unset the SRV6_LOCATOR_USID */ if (no) @@ -431,8 +540,75 @@ DEFPY (locator_behavior, else SET_FLAG(locator->flags, SRV6_LOCATOR_USID); - /* Notify the new locator to zclients */ - zebra_notify_srv6_locator_add(locator); + if (!locator->sid_format) + /* Notify the new locator to zclients */ + zebra_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + +DEFPY(locator_sid_format, + locator_sid_format_cmd, + "format <usid-f3216|uncompressed-f4024>$format", + "Configure SRv6 SID format\n" + "Specify usid-f3216 format\n" + "Specify uncompressed-f4024 format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct srv6_sid_format *sid_format = NULL; + uint8_t expected_prefixlen; + + expected_prefixlen = locator->prefix.prefixlen; + if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + + if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) { + vty_out(vty, + "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (locator->prefix.prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + locator->prefix.prefixlen, format); + return CMD_WARNING_CONFIG_FAILED; + } + + sid_format = srv6_sid_format_lookup(format); + if (!sid_format) { + vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sid_format == locator->sid_format) + /* Format has not changed, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, sid_format); + + return CMD_SUCCESS; +} + +DEFPY (no_locator_sid_format, + no_locator_sid_format_cmd, + "no format [WORD]", + NO_STR + "Configure SRv6 SID format\n" + "Specify SRv6 SID format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (!locator->sid_format) + /* SID format already unset, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, NULL); return CMD_SUCCESS; } @@ -469,11 +645,312 @@ DEFPY (no_srv6_src_addr, return CMD_SUCCESS; } +DEFUN_NOSH(srv6_sid_formats, + srv6_sid_formats_cmd, + "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f3216_usid, + srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f3216_usid, + no_srv6_sid_format_f3216_usid_cmd, + "no format usid-f3216", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f4024_uncompressed, + srv6_sid_format_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f4024_uncompressed, + no_srv6_sid_format_f4024_uncompressed_cmd, + "no format uncompressed-f4024", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib, + srv6_sid_format_usid_lib_cmd, + "local-id-block start (0-4294967295)$start", + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.lib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib, + no_srv6_sid_format_usid_lib_cmd, + "no local-id-block [start (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.lib_start = + SRV6_SID_FORMAT_USID_F3216_LIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib_explicit, + srv6_sid_format_usid_lib_explicit_cmd, + "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end", + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.elib_start = start; + format->config.usid.elib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib_explicit, + no_srv6_sid_format_usid_lib_explicit_cmd, + "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.elib_start = + SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = + SRV6_SID_FORMAT_USID_F3216_ELIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wlib, + srv6_sid_format_usid_wlib_cmd, + "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end", + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.wlib_start = start; + format->config.usid.wlib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wlib, + no_srv6_sid_format_usid_wlib_cmd, + "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.wlib_start = + SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = + SRV6_SID_FORMAT_USID_F3216_WLIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wide_lib_explicit, + srv6_sid_format_usid_wide_lib_explicit_cmd, + "wide-local-id-block explicit start (0-4294967295)$start", + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.ewlib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, + no_srv6_sid_format_usid_wide_lib_explicit_cmd, + "no wide-local-id-block explicit [start (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_explicit, + srv6_sid_format_explicit_cmd, + "explicit start (0-4294967295)$start", + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.uncompressed.explicit_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_explicit, + no_srv6_sid_format_explicit_cmd, + "no explicit [start (0-4294967295)$start]", + NO_STR + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct listnode *node; struct srv6_locator *locator; + struct srv6_sid_format *format; char str[256]; bool display_source_srv6 = false; @@ -492,7 +969,7 @@ static int zebra_sr_config(struct vty *vty) &srv6->encap_src_addr); } } - if (zebra_srv6_is_enable()) { + if (srv6 && zebra_srv6_is_enable()) { vty_out(vty, " locators\n"); for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { inet_ntop(AF_INET6, &locator->prefix.prefix, @@ -515,6 +992,54 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + if (locator->sid_format) { + format = locator->sid_format; + vty_out(vty, " format %s\n", format->name); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + vty_out(vty, " formats\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) { + if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + vty_out(vty, " format %s\n", format->name); + if (format->config.uncompressed.explicit_start != + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START) + vty_out(vty, " explicit start %u\n", + format->config.uncompressed + .explicit_start); + } + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + vty_out(vty, " format %s\n", format->name); + if (format->config.usid.lib_start != + SRV6_SID_FORMAT_USID_F3216_LIB_START) + vty_out(vty, + " local-id-block start %u\n", + format->config.usid.lib_start); + if (format->config.usid.elib_start != + SRV6_SID_FORMAT_USID_F3216_ELIB_START || + format->config.usid.elib_end != + SRV6_SID_FORMAT_USID_F3216_ELIB_END) + vty_out(vty, + " local-id-block explicit start %u end %u\n", + format->config.usid.elib_start, + format->config.usid.elib_end); + if (format->config.usid.wlib_start != + SRV6_SID_FORMAT_USID_F3216_WLIB_START || + format->config.usid.wlib_end != + SRV6_SID_FORMAT_USID_F3216_WLIB_END) + vty_out(vty, + " wide-local-id-block start %u end %u\n", + format->config.usid.wlib_start, + format->config.usid.wlib_end); + if (format->config.usid.ewlib_start != + SRV6_SID_FORMAT_USID_F3216_EWLIB_START) + vty_out(vty, + " wide-local-id-block explicit start %u\n", + format->config.usid.ewlib_start); + } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -538,11 +1063,17 @@ void zebra_srv6_vty_init(void) install_node(&srv6_locs_node); install_node(&srv6_loc_node); install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_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); + install_default(SRV6_SID_FORMATS_NODE); + install_default(SRV6_SID_FORMAT_USID_F3216_NODE); + install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); @@ -550,14 +1081,44 @@ void zebra_srv6_vty_init(void) 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_NODE, &srv6_sid_formats_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); + install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &srv6_sid_format_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &no_srv6_sid_format_explicit_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h index 17528c4b..64515624 100644 --- a/zebra/zebra_trace.h +++ b/zebra/zebra_trace.h @@ -70,20 +70,6 @@ TRACEPOINT_EVENT( TRACEPOINT_EVENT( frr_zebra, - netlink_interface_addr, - TP_ARGS( - struct nlmsghdr *, header, - ns_id_t, ns_id, - int, startup), - TP_FIELDS( - ctf_integer_hex(intptr_t, header, header) - ctf_integer(uint32_t, ns_id, ns_id) - ctf_integer(uint32_t, startup, startup) - ) - ) - -TRACEPOINT_EVENT( - frr_zebra, netlink_route_change_read_unicast, TP_ARGS( struct nlmsghdr *, header, diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 5cbfab1d..f97138c8 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -173,6 +173,7 @@ struct zebra_vrf { bool zebra_rnh_ip_default_route; bool zebra_rnh_ipv6_default_route; + bool zebra_mpls_fec_nexthop_resolution; }; #define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name #define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ae82d201..303146c2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -891,6 +891,9 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { dest = rib_dest_from_rnode(rn); + if (longer_prefix_p && !prefix_match(longer_prefix_p, &rn->p)) + continue; + RNODE_FOREACH_RE (rn, re) { if (use_fib && re != dest->selected_fib) continue; @@ -898,10 +901,6 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, if (tag && re->tag != tag) continue; - if (longer_prefix_p - && !prefix_match(longer_prefix_p, &rn->p)) - continue; - /* This can only be true when the afi is IPv4 */ if (supernets_only) { addr = ntohl(rn->p.u.prefix4.s_addr); @@ -1196,6 +1195,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json_object_string_add(json, "uptime", up_str); json_object_string_add(json, "vrf", vrf_id_to_name(nhe->vrf_id)); + json_object_string_add(json, "afi", afi2str(nhe->afi)); } else { vty_out(vty, "ID: %u (%s)\n", nhe->id, @@ -1209,7 +1209,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, vty_out(vty, "\n"); vty_out(vty, " Uptime: %s\n", up_str); - vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id)); + vty_out(vty, " VRF: %s(%s)\n", vrf_id_to_name(nhe->vrf_id), + afi2str(nhe->afi)); } if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { @@ -1229,6 +1230,13 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, else vty_out(vty, ", Installed"); } + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) { + if (json) + json_object_boolean_true_add(json, + "initialDelay"); + else + vty_out(vty, ", Initial Delay"); + } if (!json) vty_out(vty, "\n"); } @@ -3794,6 +3802,10 @@ static int config_write_protocol(struct vty *vty) if (!zebra_nhg_recursive_use_backups()) vty_out(vty, "no zebra nexthop resolve-via-backup\n"); +#ifdef HAVE_SCRIPTING + frrscript_names_config_write(vty); +#endif + if (rnh_get_hide_backups()) vty_out(vty, "ip nht hide-backup-events\n"); @@ -3825,6 +3837,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); @@ -3895,7 +3921,7 @@ DEFUN (show_zebra, out = ttable_dump(table, "\n"); vty_out(vty, "%s\n", out); - XFREE(MTYPE_TMP, out); + XFREE(MTYPE_TMP_TTABLE, out); ttable_del(table); vty_out(vty, @@ -4129,12 +4155,6 @@ DEFUN (zebra_show_routing_tables_summary, return CMD_SUCCESS; } -/* Table configuration write function. */ -static int config_write_table(struct vty *vty) -{ - return 0; -} - /* IPForwarding configuration write function. */ static int config_write_forwarding(struct vty *vty) { @@ -4311,14 +4331,6 @@ static struct cmd_node protocol_node = { .prompt = "", .config_write = config_write_protocol, }; -/* table node for routing tables. */ -static int config_write_table(struct vty *vty); -static struct cmd_node table_node = { - .name = "table", - .node = TABLE_NODE, - .prompt = "", - .config_write = config_write_table, -}; static int config_write_forwarding(struct vty *vty); static struct cmd_node forwarding_node = { .name = "forwarding", @@ -4331,7 +4343,6 @@ static struct cmd_node forwarding_node = { void zebra_vty_init(void) { /* Install configuration write function. */ - install_node(&table_node); install_node(&forwarding_node); install_element(VIEW_NODE, &show_ip_forwarding_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index b8c11e18..f1ae42e3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1356,6 +1356,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, { struct zebra_mac *zrmac = NULL; struct ipaddr *vtep = NULL; + struct ipaddr ipv4_vtep; + + /* vtep_ip may be v4 or v6-mapped-v4. But zrmac->fwd_info + * can only contain v4 version. So convert if needed + */ + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4); zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { @@ -1369,7 +1381,7 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1383,14 +1395,14 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &vtep_ip->ipaddr_v4)) { + &(ipv4_vtep.ipaddr_v4))) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA", zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, vtep_ip, rmac); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1410,36 +1422,29 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac, struct ipaddr *vtep_ip) { - struct ipaddr ipv4_vtep; - if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) { - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &ipv4_vtep.ipaddr_v4); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - /* remove nh from rmac's list */ - l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep); - /* delete nh is same as current selected, fall back to - * one present in the list - */ - if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &ipv4_vtep.ipaddr_v4) && - listcount(zrmac->nh_list)) { + l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, vtep_ip); + /* If there are remaining entries, use IPv4 from one */ + if (listcount(zrmac->nh_list)) { struct ipaddr *vtep; + struct ipaddr ipv4_vtep; vtep = listgetdata(listhead(zrmac->nh_list)); - zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4; + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), + &vtep->ipaddr_v4); + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", - zl3vni->vni, &ipv4_vtep, - &zrmac->fwd_info.r_vtep_ip, - &zrmac->macaddr); + zlog_debug("L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", + zl3vni->vni, vtep_ip, + &zrmac->fwd_info.r_vtep_ip, + &zrmac->macaddr); /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); @@ -2531,7 +2536,6 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, const struct prefix *host_prefix) { struct zebra_l3vni *zl3vni = NULL; - struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) @@ -2547,24 +2551,10 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - - /* - * add the rmac - remote rmac to be installed is against the ipv4 + * add the rmac - remote rmac to be installed is against the * nexthop address */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep); + zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip); } /* handle evpn vrf route delete */ diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index f4b859b8..17ab05c1 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -208,13 +208,13 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); return 0; } - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_MAC_CHANGE) && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -224,7 +224,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; @@ -242,7 +242,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * local-ip change - process oper down, associate with new * local-ip and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; @@ -262,7 +262,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) { if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } @@ -285,7 +285,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ /* Also, free up all MACs and neighbors. */ @@ -298,7 +298,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, } /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { /* Remove all existing local neigh and MACs for this VNI * (including from BGP) */ @@ -341,9 +341,10 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, return 0; /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + if (CHECK_FLAG(chgflags, (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | + ZEBRA_VXLIF_VLAN_CHANGE))) zebra_evpn_send_add_to_client(zevpn); /* If there is a valid new master or a VLAN mapping change, @@ -351,9 +352,9 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * Also, reinstall any remote MACs and neighbors * for this VNI (based on new VLAN). */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + else if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { struct neigh_walk_ctx n_wctx; zebra_evpn_read_mac_neigh(zevpn, ifp); diff --git a/zebra/zserv.c b/zebra/zserv.c index 27668534..07e39966 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -161,9 +161,11 @@ void zserv_log_message(const char *errmsg, struct stream *msg, if (errmsg) zlog_debug("%s", errmsg); if (hdr) { + struct vrf *vrf = vrf_lookup_by_id(hdr->vrf_id); + zlog_debug(" Length: %d", hdr->length); zlog_debug("Command: %s", zserv_command_string(hdr->command)); - zlog_debug(" VRF: %u", hdr->vrf_id); + zlog_debug(" VRF: %s(%u)", VRF_LOGNAME(vrf), hdr->vrf_id); } stream_hexdump(msg); } @@ -425,11 +427,13 @@ static void zserv_read(struct event *thread) } /* Debug packet information. */ - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]", + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(hdr.vrf_id); + + zlog_debug("zebra message[%s:%s:%u] comes from socket [%d]", zserv_command_string(hdr.command), - hdr.vrf_id, hdr.length, - sock); + VRF_LOGNAME(vrf), hdr.length, sock); + } stream_set_getp(client->ibuf_work, 0); struct stream *msg = stream_dup(client->ibuf_work); @@ -1031,6 +1035,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1125,6 +1130,45 @@ 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); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + 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); diff --git a/zebra/zserv.h b/zebra/zserv.h index 57d67306..87d2b4ad 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -64,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; }; |