summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-11-17 07:11:26 +0100
committerDaniel Baumann <daniel@debian.org>2024-11-17 07:11:26 +0100
commitd5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6 (patch)
tree705ea89e798053f9c227b85512bc9f5b437b0093 /zebra
parentReleasing debian version 10.1.1-3. (diff)
downloadfrr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.tar.xz
frr-d5587ccda8edb748ca8bfd1f0ed92a801ac5bfc6.zip
Merging upstream version 10.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'zebra')
-rw-r--r--zebra/connected.c38
-rw-r--r--zebra/dplane_fpm_nl.c71
-rw-r--r--zebra/if_ioctl.c2
-rw-r--r--zebra/if_netlink.c214
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/if_sysctl.c2
-rw-r--r--zebra/interface.c3
-rw-r--r--zebra/kernel_netlink.c15
-rw-r--r--zebra/kernel_netlink.h8
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/main.c39
-rw-r--r--zebra/redistribute.c5
-rw-r--r--zebra/rib.h21
-rw-r--r--zebra/rt_netlink.c42
-rw-r--r--zebra/rt_socket.c8
-rw-r--r--zebra/rtadv.c2
-rw-r--r--zebra/tc_netlink.c40
-rw-r--r--zebra/tc_netlink.h2
-rw-r--r--zebra/zapi_msg.c216
-rw-r--r--zebra/zapi_msg.h10
-rw-r--r--zebra/zebra_cli.c38
-rw-r--r--zebra/zebra_dplane.c201
-rw-r--r--zebra/zebra_dplane.h4
-rw-r--r--zebra/zebra_errors.c12
-rw-r--r--zebra/zebra_errors.h2
-rw-r--r--zebra/zebra_evpn.c3
-rw-r--r--zebra/zebra_evpn_mac.c857
-rw-r--r--zebra/zebra_gr.c81
-rw-r--r--zebra/zebra_mpls.c134
-rw-r--r--zebra/zebra_mpls.h8
-rw-r--r--zebra/zebra_nb.c7
-rw-r--r--zebra/zebra_nb.h4
-rw-r--r--zebra/zebra_nb_config.c53
-rw-r--r--zebra/zebra_nhg.c313
-rw-r--r--zebra/zebra_nhg.h35
-rw-r--r--zebra/zebra_ns.c20
-rw-r--r--zebra/zebra_ns.h2
-rw-r--r--zebra/zebra_pw.c37
-rw-r--r--zebra/zebra_pw.h1
-rw-r--r--zebra/zebra_rib.c405
-rw-r--r--zebra/zebra_rnh.c17
-rw-r--r--zebra/zebra_routemap.c5
-rw-r--r--zebra/zebra_router.c4
-rw-r--r--zebra/zebra_router.h10
-rw-r--r--zebra/zebra_snmp.c30
-rw-r--r--zebra/zebra_srv6.c2071
-rw-r--r--zebra/zebra_srv6.h247
-rw-r--r--zebra/zebra_srv6_vty.c595
-rw-r--r--zebra/zebra_trace.h14
-rw-r--r--zebra/zebra_vrf.h1
-rw-r--r--zebra/zebra_vty.c53
-rw-r--r--zebra/zebra_vxlan.c78
-rw-r--r--zebra/zebra_vxlan_if.c25
-rw-r--r--zebra/zserv.c54
-rw-r--r--zebra/zserv.h2
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, &note, 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;
};