summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/debug.c38
-rw-r--r--zebra/debug.h5
-rw-r--r--zebra/dplane_fpm_nl.c127
-rw-r--r--zebra/if_netlink.c8
-rw-r--r--zebra/interface.c12
-rw-r--r--zebra/irdp_packet.c6
-rw-r--r--zebra/kernel_netlink.c38
-rw-r--r--zebra/kernel_netlink.h3
-rw-r--r--zebra/kernel_socket.c4
-rw-r--r--zebra/label_manager.c28
-rw-r--r--zebra/label_manager.h11
-rw-r--r--zebra/redistribute.c6
-rw-r--r--zebra/rib.h9
-rw-r--r--zebra/rt_netlink.c110
-rw-r--r--zebra/rule_netlink.c10
-rw-r--r--zebra/sample_plugin.c1
-rw-r--r--zebra/subdir.am11
-rw-r--r--zebra/zapi_msg.c51
-rw-r--r--zebra/zapi_msg.h3
-rw-r--r--zebra/zebra_dplane.c57
-rw-r--r--zebra/zebra_evpn.c6
-rw-r--r--zebra/zebra_evpn_mac.c368
-rw-r--r--zebra/zebra_evpn_mac.h4
-rw-r--r--zebra/zebra_evpn_mh.c25
-rw-r--r--zebra/zebra_evpn_mh.h11
-rw-r--r--zebra/zebra_evpn_neigh.c74
-rw-r--r--zebra/zebra_evpn_neigh.h3
-rw-r--r--zebra/zebra_fpm.c32
-rw-r--r--zebra/zebra_fpm_netlink.c10
-rw-r--r--zebra/zebra_nhg.c42
-rw-r--r--zebra/zebra_nhg.h7
-rw-r--r--zebra/zebra_pbr.c25
-rw-r--r--zebra/zebra_rib.c180
-rw-r--r--zebra/zebra_rnh.c2
-rw-r--r--zebra/zebra_routemap.c76
-rw-r--r--zebra/zebra_routemap.h4
-rw-r--r--zebra/zebra_vty.c8
-rw-r--r--zebra/zebra_vxlan.c169
-rw-r--r--zebra/zserv.c13
40 files changed, 995 insertions, 606 deletions
diff --git a/zebra/connected.c b/zebra/connected.c
index 70ea2e3805..c885c533e6 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -402,10 +402,10 @@ void connected_down(struct interface *ifp, struct connected *ifc)
* head.
*/
rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
- 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+ 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+ 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
diff --git a/zebra/debug.c b/zebra/debug.c
index 87a10ea65d..21fa765c63 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -41,6 +41,7 @@ unsigned long zebra_debug_dplane;
unsigned long zebra_debug_mlag;
unsigned long zebra_debug_nexthop;
unsigned long zebra_debug_evpn_mh;
+unsigned long zebra_debug_pbr;
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
@@ -122,6 +123,9 @@ DEFUN_NOSH (show_debugging_zebra,
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
vty_out(vty, " Zebra EVPN-MH Neigh debugging is on\n");
+ if (IS_ZEBRA_DEBUG_PBR)
+ vty_out(vty, " Zebra PBR debugging is on\n");
+
hook_call(zebra_debug_show_debugging, vty);
return CMD_SUCCESS;
}
@@ -318,6 +322,17 @@ DEFUN (debug_zebra_dplane,
return CMD_SUCCESS;
}
+DEFUN (debug_zebra_pbr,
+ debug_zebra_pbr_cmd,
+ "debug zebra pbr",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug zebra pbr events\n")
+{
+ SET_FLAG(zebra_debug_pbr, ZEBRA_DEBUG_PBR);
+ return CMD_SUCCESS;
+}
+
DEFPY (debug_zebra_mlag,
debug_zebra_mlag_cmd,
"[no$no] debug zebra mlag",
@@ -508,6 +523,18 @@ DEFUN (no_debug_zebra_dplane,
return CMD_SUCCESS;
}
+DEFUN (no_debug_zebra_pbr,
+ no_debug_zebra_pbr_cmd,
+ "no debug zebra pbr",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug zebra pbr events\n")
+{
+ zebra_debug_pbr = 0;
+ return CMD_SUCCESS;
+}
+
DEFPY (debug_zebra_nexthop,
debug_zebra_nexthop_cmd,
"[no$no] debug zebra nexthop [detail$detail]",
@@ -650,6 +677,11 @@ static int config_write_debug(struct vty *vty)
write++;
}
+ if (IS_ZEBRA_DEBUG_PBR) {
+ vty_out(vty, "debug zebra pbr\n");
+ write++;
+ }
+
return write;
}
@@ -668,6 +700,7 @@ void zebra_debug_init(void)
zebra_debug_evpn_mh = 0;
zebra_debug_nht = 0;
zebra_debug_nexthop = 0;
+ zebra_debug_pbr = 0;
install_node(&debug_node);
@@ -686,6 +719,7 @@ void zebra_debug_init(void)
install_element(ENABLE_NODE, &debug_zebra_dplane_cmd);
install_element(ENABLE_NODE, &debug_zebra_mlag_cmd);
install_element(ENABLE_NODE, &debug_zebra_nexthop_cmd);
+ install_element(ENABLE_NODE, &debug_zebra_pbr_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd);
@@ -696,6 +730,7 @@ void zebra_debug_init(void)
install_element(ENABLE_NODE, &no_debug_zebra_rib_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_fpm_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_dplane_cmd);
+ install_element(ENABLE_NODE, &no_debug_zebra_pbr_cmd);
install_element(ENABLE_NODE, &debug_zebra_evpn_mh_cmd);
install_element(CONFIG_NODE, &debug_zebra_events_cmd);
@@ -710,6 +745,8 @@ void zebra_debug_init(void)
install_element(CONFIG_NODE, &debug_zebra_fpm_cmd);
install_element(CONFIG_NODE, &debug_zebra_dplane_cmd);
install_element(CONFIG_NODE, &debug_zebra_nexthop_cmd);
+ install_element(CONFIG_NODE, &debug_zebra_pbr_cmd);
+
install_element(CONFIG_NODE, &no_debug_zebra_events_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_nht_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_mpls_cmd);
@@ -720,6 +757,7 @@ void zebra_debug_init(void)
install_element(CONFIG_NODE, &no_debug_zebra_rib_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_fpm_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_dplane_cmd);
+ install_element(CONFIG_NODE, &no_debug_zebra_pbr_cmd);
install_element(CONFIG_NODE, &debug_zebra_mlag_cmd);
install_element(CONFIG_NODE, &debug_zebra_evpn_mh_cmd);
}
diff --git a/zebra/debug.h b/zebra/debug.h
index 8402224f19..86506846ad 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -67,6 +67,8 @@ extern "C" {
#define ZEBRA_DEBUG_EVPN_MH_MAC 0x04
#define ZEBRA_DEBUG_EVPN_MH_NEIGH 0x08
+#define ZEBRA_DEBUG_PBR 0x01
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -114,6 +116,8 @@ extern "C" {
#define IS_ZEBRA_DEBUG_EVPN_MH_NEIGH \
(zebra_debug_evpn_mh & ZEBRA_DEBUG_EVPN_MH_NEIGH)
+#define IS_ZEBRA_DEBUG_PBR (zebra_debug_pbr & ZEBRA_DEBUG_PBR)
+
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
extern unsigned long zebra_debug_kernel;
@@ -127,6 +131,7 @@ extern unsigned long zebra_debug_dplane;
extern unsigned long zebra_debug_mlag;
extern unsigned long zebra_debug_nexthop;
extern unsigned long zebra_debug_evpn_mh;
+extern unsigned long zebra_debug_pbr;
extern void zebra_debug_init(void);
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 261b859bf6..79a5d148a6 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -75,9 +75,6 @@ struct fpm_nl_ctx {
int socket;
bool disabled;
bool connecting;
- bool nhg_complete;
- bool rib_complete;
- bool rmac_complete;
bool use_nhg;
struct sockaddr_storage addr;
@@ -377,7 +374,6 @@ static int fpm_write_config(struct vty *vty)
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int written = 0;
- char addrstr[INET6_ADDRSTRLEN];
if (gfnc->disabled)
return written;
@@ -386,8 +382,7 @@ static int fpm_write_config(struct vty *vty)
case AF_INET:
written = 1;
sin = (struct sockaddr_in *)&gfnc->addr;
- inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr));
- vty_out(vty, "fpm address %s", addrstr);
+ vty_out(vty, "fpm address %pI4", &sin->sin_addr);
if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT))
vty_out(vty, " port %d", ntohs(sin->sin_port));
@@ -396,8 +391,7 @@ static int fpm_write_config(struct vty *vty)
case AF_INET6:
written = 1;
sin6 = (struct sockaddr_in6 *)&gfnc->addr;
- inet_ntop(AF_INET, &sin6->sin6_addr, addrstr, sizeof(addrstr));
- vty_out(vty, "fpm address %s", addrstr);
+ vty_out(vty, "fpm address %pI6", &sin6->sin6_addr);
if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT))
vty_out(vty, " port %d", ntohs(sin6->sin6_port));
@@ -542,6 +536,13 @@ static int fpm_write(struct thread *t)
fnc->connecting = false;
+ /*
+ * Starting with LSPs walk all FPM objects, marking them
+ * as unsent and then replaying them.
+ */
+ thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0,
+ &fnc->t_lspreset);
+
/* Permit receiving messages now. */
thread_add_read(fnc->fthread->master, fpm_read, fnc,
fnc->socket, &fnc->t_read);
@@ -664,9 +665,12 @@ static int fpm_connect(struct thread *t)
/*
* Starting with LSPs walk all FPM objects, marking them
* as unsent and then replaying them.
+ *
+ * If we are not connected, then delay the objects reset/send.
*/
- thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0,
- &fnc->t_lspreset);
+ if (!fnc->connecting)
+ thread_add_timer(zrouter.master, fpm_lsp_reset, fnc, 0,
+ &fnc->t_lspreset);
return 0;
}
@@ -908,12 +912,8 @@ static int fpm_lsp_send(struct thread *t)
WALK_FINISH(fnc, FNE_LSP_FINISHED);
/* Now move onto routes */
- if (fnc->use_nhg)
- thread_add_timer(zrouter.master, fpm_nhg_reset, fnc, 0,
- &fnc->t_nhgreset);
- else
- thread_add_timer(zrouter.master, fpm_rib_reset, fnc, 0,
- &fnc->t_ribreset);
+ thread_add_timer(zrouter.master, fpm_nhg_reset, fnc, 0,
+ &fnc->t_nhgreset);
} else {
/* Didn't finish - reschedule LSP walk */
thread_add_timer(zrouter.master, fpm_lsp_send, fnc, 0,
@@ -966,7 +966,8 @@ static int fpm_nhg_send(struct thread *t)
fna.complete = true;
/* Send next hops. */
- hash_walk(zrouter.nhgs_id, fpm_nhg_send_cb, &fna);
+ if (fnc->use_nhg)
+ hash_walk(zrouter.nhgs_id, fpm_nhg_send_cb, &fna);
/* `free()` allocated memory. */
dplane_ctx_fini(&fna.ctx);
@@ -1051,10 +1052,10 @@ struct fpm_rmac_arg {
bool complete;
};
-static void fpm_enqueue_rmac_table(struct hash_bucket *backet, void *arg)
+static void fpm_enqueue_rmac_table(struct hash_bucket *bucket, void *arg)
{
struct fpm_rmac_arg *fra = arg;
- zebra_mac_t *zrmac = backet->data;
+ zebra_mac_t *zrmac = bucket->data;
struct zebra_if *zif = fra->zl3vni->vxlan_if->info;
const struct zebra_l2info_vxlan *vxl = &zif->l2info.vxl;
struct zebra_if *br_zif;
@@ -1083,10 +1084,10 @@ static void fpm_enqueue_rmac_table(struct hash_bucket *backet, void *arg)
}
}
-static void fpm_enqueue_l3vni_table(struct hash_bucket *backet, void *arg)
+static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg)
{
struct fpm_rmac_arg *fra = arg;
- zebra_l3vni_t *zl3vni = backet->data;
+ zebra_l3vni_t *zl3vni = bucket->data;
fra->zl3vni = zl3vni;
hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni);
@@ -1124,7 +1125,6 @@ static int fpm_nhg_reset(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
- fnc->nhg_complete = false;
hash_iterate(zrouter.nhgs_id, fpm_nhg_reset_cb, NULL);
/* Schedule next step: send next hop groups. */
@@ -1167,8 +1167,6 @@ static int fpm_rib_reset(struct thread *t)
struct route_table *rt;
rib_tables_iter_t rt_iter;
- fnc->rib_complete = false;
-
rt_iter.state = RIB_TABLES_ITER_S_INIT;
while ((rt = rib_tables_iter_next(&rt_iter))) {
for (rn = route_top(rt); rn; rn = srcdest_route_next(rn)) {
@@ -1190,16 +1188,16 @@ static int fpm_rib_reset(struct thread *t)
/*
* The next three function will handle RMAC table reset.
*/
-static void fpm_unset_rmac_table(struct hash_bucket *backet, void *arg)
+static void fpm_unset_rmac_table(struct hash_bucket *bucket, void *arg)
{
- zebra_mac_t *zrmac = backet->data;
+ zebra_mac_t *zrmac = bucket->data;
UNSET_FLAG(zrmac->flags, ZEBRA_MAC_FPM_SENT);
}
-static void fpm_unset_l3vni_table(struct hash_bucket *backet, void *arg)
+static void fpm_unset_l3vni_table(struct hash_bucket *bucket, void *arg)
{
- zebra_l3vni_t *zl3vni = backet->data;
+ zebra_l3vni_t *zl3vni = bucket->data;
hash_iterate(zl3vni->rmac_table, fpm_unset_rmac_table, zl3vni);
}
@@ -1208,7 +1206,6 @@ static int fpm_rmac_reset(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
- fnc->rmac_complete = false;
hash_iterate(zrouter.l3vni_table, fpm_unset_l3vni_table, NULL);
/* Schedule next event: send RMAC entries. */
@@ -1222,24 +1219,33 @@ static int fpm_process_queue(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
struct zebra_dplane_ctx *ctx;
-
- frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
+ bool no_bufs = false;
+ uint64_t processed_contexts = 0;
while (true) {
/* No space available yet. */
- if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE)
+ if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE) {
+ no_bufs = true;
break;
+ }
/* Dequeue next item or quit processing. */
- ctx = dplane_ctx_dequeue(&fnc->ctxqueue);
+ frr_with_mutex (&fnc->ctxqueue_mutex) {
+ ctx = dplane_ctx_dequeue(&fnc->ctxqueue);
+ }
if (ctx == NULL)
break;
- fpm_nl_enqueue(fnc, ctx);
+ /*
+ * Intentionally ignoring the return value
+ * as that we are ensuring that we can write to
+ * the output data in the STREAM_WRITEABLE
+ * check above, so we can ignore the return
+ */
+ (void)fpm_nl_enqueue(fnc, ctx);
/* Account the processed entries. */
- atomic_fetch_add_explicit(&fnc->counters.dplane_contexts, 1,
- memory_order_relaxed);
+ processed_contexts++;
atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1,
memory_order_relaxed);
@@ -1247,10 +1253,12 @@ static int fpm_process_queue(struct thread *t)
dplane_provider_enqueue_out_ctx(fnc->prov, ctx);
}
- /* Check for more items in the queue. */
- if (atomic_load_explicit(&fnc->counters.ctxqueue_len,
- memory_order_relaxed)
- > 0)
+ /* Update count of processed contexts */
+ atomic_fetch_add_explicit(&fnc->counters.dplane_contexts,
+ processed_contexts, memory_order_relaxed);
+
+ /* Re-schedule if we ran out of buffer space */
+ if (no_bufs)
thread_add_timer(fnc->fthread->master, fpm_process_queue,
fnc, 0, &fnc->t_dequeue);
@@ -1312,20 +1320,14 @@ static int fpm_process_event(struct thread *t)
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: next hop groups walk finished",
__func__);
-
- fnc->nhg_complete = true;
break;
case FNE_RIB_FINISHED:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: RIB walk finished", __func__);
-
- fnc->rib_complete = true;
break;
case FNE_RMAC_FINISHED:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: RMAC walk finished", __func__);
-
- fnc->rmac_complete = true;
break;
case FNE_LSP_FINISHED:
if (IS_ZEBRA_DEBUG_FPM)
@@ -1421,7 +1423,7 @@ 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;
+ uint64_t cur_queue, peak_queue = 0, stored_peak_queue;
fnc = dplane_provider_get_data(prov);
limit = dplane_provider_get_work_limit(prov);
@@ -1435,22 +1437,22 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
* anyway.
*/
if (fnc->socket != -1 && fnc->connecting == false) {
- frr_mutex_lock_autounlock(&fnc->ctxqueue_mutex);
- dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx);
-
- /* Account the number of contexts. */
+ /*
+ * Update the number of queued contexts *before*
+ * enqueueing, to ensure counter consistency.
+ */
atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len,
1, memory_order_relaxed);
+
+ frr_with_mutex (&fnc->ctxqueue_mutex) {
+ dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx);
+ }
+
cur_queue = atomic_load_explicit(
&fnc->counters.ctxqueue_len,
memory_order_relaxed);
- peak_queue = atomic_load_explicit(
- &fnc->counters.ctxqueue_len_peak,
- memory_order_relaxed);
if (peak_queue < cur_queue)
- atomic_store_explicit(
- &fnc->counters.ctxqueue_len_peak,
- cur_queue, memory_order_relaxed);
+ peak_queue = cur_queue;
continue;
}
@@ -1458,12 +1460,23 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov)
dplane_provider_enqueue_out_ctx(prov, ctx);
}
+ /* Update peak queue length, if we just observed a new peak */
+ stored_peak_queue = atomic_load_explicit(
+ &fnc->counters.ctxqueue_len_peak, memory_order_relaxed);
+ if (stored_peak_queue < peak_queue)
+ 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)
thread_add_timer(fnc->fthread->master, fpm_process_queue,
fnc, 0, &fnc->t_dequeue);
+ /* Ensure dataplane thread is rescheduled if we hit the work limit */
+ if (counter >= limit)
+ dplane_provider_work_ready();
+
return 0;
}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index e4dd745f42..00471b9645 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -301,7 +301,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
struct ifinfomsg *ifi;
struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
struct rtattr *attr[IFLA_VRF_MAX + 1];
- struct vrf *vrf;
+ struct vrf *vrf = NULL;
struct zebra_vrf *zvrf;
uint32_t nl_table_id;
@@ -350,11 +350,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
}
}
- /*
- * vrf_get is implied creation if it does not exist
- */
- vrf = vrf_get((vrf_id_t)ifi->ifi_index,
- name); // It would create vrf
+ vrf = vrf_update((vrf_id_t)ifi->ifi_index, name);
if (!vrf) {
flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created",
name, ifi->ifi_index);
diff --git a/zebra/interface.c b/zebra/interface.c
index 4072eb1568..fc34a6fb9e 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1029,7 +1029,7 @@ void if_up(struct interface *ifp)
/* Notify the protocol daemons. */
if (ifp->ptm_enable && (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)) {
flog_warn(EC_ZEBRA_PTM_NOT_READY,
- "%s: interface %s hasn't passed ptm check\n",
+ "%s: interface %s hasn't passed ptm check",
__func__, ifp->name);
return;
}
@@ -2977,7 +2977,7 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
dplane_res = dplane_intf_addr_set(ifp, ifc);
if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
zlog_debug(
- "dplane can't set interface IP address: %s.\n",
+ "dplane can't set interface IP address: %s.",
dplane_res2str(dplane_res));
return NB_ERR;
}
@@ -3095,7 +3095,7 @@ int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix)
/* Check current interface address. */
ifc = connected_check_ptp(ifp, prefix, NULL);
if (!ifc) {
- zlog_debug("interface %s Can't find address\n",
+ zlog_debug("interface %s Can't find address",
ifp->name);
return -1;
}
@@ -3106,7 +3106,7 @@ int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix)
}
if (!ifc) {
- zlog_debug("interface %s Can't find address\n", ifp->name);
+ zlog_debug("interface %s Can't find address", ifp->name);
return -1;
}
UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
@@ -3122,7 +3122,7 @@ int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix)
/* This is real route. */
dplane_res = dplane_intf_addr_unset(ifp, ifc);
if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
- zlog_debug("Can't unset interface IP address: %s.\n",
+ zlog_debug("Can't unset interface IP address: %s.",
dplane_res2str(dplane_res));
return -1;
}
@@ -3335,7 +3335,7 @@ int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
dplane_res = dplane_intf_addr_set(ifp, ifc);
if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
zlog_debug(
- "dplane can't set interface IP address: %s.\n",
+ "dplane can't set interface IP address: %s.",
dplane_res2str(dplane_res));
return NB_ERR;
}
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c
index 56fd35a736..6134df9c41 100644
--- a/zebra/irdp_packet.c
+++ b/zebra/irdp_packet.c
@@ -105,7 +105,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
if (iplen < ICMP_MINLEN) {
flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
- "IRDP: RX ICMP packet too short from %pI4\n",
+ "IRDP: RX ICMP packet too short from %pI4",
&src);
return;
}
@@ -116,7 +116,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
len of IP-header) 14+20 */
if (iplen > IRDP_RX_BUF - 34) {
flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
- "IRDP: RX ICMP packet too long from %pI4\n",
+ "IRDP: RX ICMP packet too long from %pI4",
&src);
return;
}
@@ -153,7 +153,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
&& !(irdp->flags & IF_BROADCAST))) {
flog_warn(
EC_ZEBRA_IRDP_BAD_RX_FLAGS,
- "IRDP: RX illegal from %pI4 to %s while %s operates in %s; Please correct settings\n",
+ "IRDP: RX illegal from %pI4 to %s while %s operates in %s; Please correct settings",
&src,
ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
? "multicast"
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 5d64f57b3e..c77a357e9f 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -383,7 +383,7 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
* it to be sent up to us
*/
flog_err(EC_ZEBRA_UNKNOWN_NLMSG,
- "Unknown netlink nlmsg_type %s(%d) vrf %u\n",
+ "Unknown netlink nlmsg_type %s(%d) vrf %u",
nl_msg_type_to_str(h->nlmsg_type), h->nlmsg_type,
ns_id);
break;
@@ -485,10 +485,23 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog))
< 0)
- flog_err_sys(EC_LIB_SOCKET, "Can't install socket filter: %s\n",
+ flog_err_sys(EC_LIB_SOCKET, "Can't install socket filter: %s",
safe_strerror(errno));
}
+void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
+ struct rtattr *rta, int len, unsigned short flags)
+{
+ unsigned short type;
+
+ while (RTA_OK(rta, len)) {
+ type = rta->rta_type & ~flags;
+ if ((type <= max) && (!tb[type]))
+ tb[type] = rta;
+ rta = RTA_NEXT(rta, len);
+ }
+}
+
void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta,
int len)
{
@@ -1123,9 +1136,11 @@ static int nl_batch_read_resp(struct nl_batch *bth)
* associated with any dplane context object.
*/
if (ctx == NULL) {
- zlog_debug(
- "%s: skipping unassociated response, seq number %d NS %u",
- __func__, h->nlmsg_seq, bth->zns->ns_id);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s: skipping unassociated response, seq number %d NS %u",
+ __func__, h->nlmsg_seq,
+ bth->zns->ns_id);
continue;
}
@@ -1136,8 +1151,9 @@ static int nl_batch_read_resp(struct nl_batch *bth)
dplane_ctx_set_status(
ctx, ZEBRA_DPLANE_REQUEST_FAILURE);
- zlog_debug("%s: netlink error message seq=%d ",
- __func__, h->nlmsg_seq);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: netlink error message seq=%d ",
+ __func__, h->nlmsg_seq);
continue;
}
@@ -1146,9 +1162,11 @@ static int nl_batch_read_resp(struct nl_batch *bth)
* the error and instead received some other message in an
* unexpected way.
*/
- zlog_debug("%s: ignoring message type 0x%04x(%s) NS %u",
- __func__, h->nlmsg_type,
- nl_msg_type_to_str(h->nlmsg_type), bth->zns->ns_id);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: ignoring message type 0x%04x(%s) NS %u",
+ __func__, h->nlmsg_type,
+ nl_msg_type_to_str(h->nlmsg_type),
+ bth->zns->ns_id);
}
return 0;
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 696f9be4f6..a7b152b31b 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -79,6 +79,9 @@ extern void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh);
extern void netlink_parse_rtattr(struct rtattr **tb, int max,
struct rtattr *rta, int len);
+extern void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
+ struct rtattr *rta, int len,
+ unsigned short flags);
extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max,
struct rtattr *rta);
extern const char *nl_msg_type_to_str(uint16_t msg_type);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 9d74aeca28..adbdf54c1f 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1107,7 +1107,7 @@ void rtm_read(struct rt_msghdr *rtm)
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0,
- 0, true, false);
+ 0, true);
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
@@ -1116,7 +1116,7 @@ void rtm_read(struct rt_msghdr *rtm)
else
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
- 0, true, false);
+ 0, true);
}
/* Interface function for the kernel routing table updates. Support
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index feec49ecc2..2634a333ee 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -91,11 +91,8 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc,
vrf_id_t vrf_id);
static int label_manager_release_label_chunk(struct zserv *client,
uint32_t start, uint32_t end);
-static int release_label_chunk(uint8_t proto, unsigned short instance,
- uint32_t session_id, uint32_t start,
- uint32_t end);
-static void delete_label_chunk(void *val)
+void delete_label_chunk(void *val)
{
XFREE(MTYPE_LM_CHUNK, val);
}
@@ -178,11 +175,9 @@ void label_manager_init(void)
}
/* alloc and fill a label chunk */
-static struct label_manager_chunk *create_label_chunk(uint8_t proto,
- unsigned short instance,
- uint32_t session_id,
- uint8_t keep, uint32_t start,
- uint32_t end)
+struct label_manager_chunk *
+create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+ uint8_t keep, uint32_t start, uint32_t end)
{
/* alloc chunk, fill it and return it */
struct label_manager_chunk *lmc =
@@ -305,15 +300,13 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
* @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply
* @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied
*/
-static struct label_manager_chunk *assign_label_chunk(uint8_t proto,
- unsigned short instance,
- uint32_t session_id,
- uint8_t keep, uint32_t size,
- uint32_t base)
+struct label_manager_chunk *
+assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+ uint8_t keep, uint32_t size, uint32_t base)
{
struct label_manager_chunk *lmc;
struct listnode *node;
- uint32_t prev_end = 0;
+ uint32_t prev_end = MPLS_LABEL_UNRESERVED_MIN;
/* handle chunks request with a specific base label */
if (base != MPLS_LABEL_BASE_ANY)
@@ -335,8 +328,7 @@ static struct label_manager_chunk *assign_label_chunk(uint8_t proto,
}
/* check if we hadve a "hole" behind us that we can squeeze into
*/
- if ((lmc->start > prev_end)
- && (lmc->start - prev_end >= size)) {
+ if ((lmc->start > prev_end) && (lmc->start - prev_end > size)) {
lmc = create_label_chunk(proto, instance, session_id,
keep, prev_end + 1,
prev_end + size);
@@ -398,7 +390,7 @@ static int label_manager_release_label_chunk(struct zserv *client,
* @param end Last label of the chunk
* @return 0 on success, -1 otherwise
*/
-static int release_label_chunk(uint8_t proto, unsigned short instance,
+int release_label_chunk(uint8_t proto, unsigned short instance,
uint32_t session_id, uint32_t start, uint32_t end)
{
struct listnode *node;
diff --git a/zebra/label_manager.h b/zebra/label_manager.h
index 094155f714..8636c79219 100644
--- a/zebra/label_manager.h
+++ b/zebra/label_manager.h
@@ -94,6 +94,12 @@ int lm_client_connect_response(uint8_t proto, uint16_t instance,
int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client,
vrf_id_t vrf_id);
+/* convenience function to allocate an lmc to be consumed by the above API */
+struct label_manager_chunk *
+create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+ uint8_t keep, uint32_t start, uint32_t end);
+void delete_label_chunk(void *val);
+
/* register/unregister callbacks for hooks */
void lm_hooks_register(void);
void lm_hooks_unregister(void);
@@ -107,6 +113,11 @@ struct label_manager {
};
void label_manager_init(void);
+struct label_manager_chunk *
+assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id,
+ uint8_t keep, uint32_t size, uint32_t base);
+int release_label_chunk(uint8_t proto, unsigned short instance,
+ uint32_t session_id, uint32_t start, uint32_t end);
int lm_client_disconnect_cb(struct zserv *client);
int release_daemon_label_chunks(struct zserv *client);
void label_manager_close(void);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 1f075cfb4b..b0f124ed55 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -206,7 +206,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
afi = family2afi(p->family);
if (!afi) {
flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF,
- "%s: Unknown AFI/SAFI prefix received\n", __func__);
+ "%s: Unknown AFI/SAFI prefix received", __func__);
return;
}
if (!zebra_check_addr(p)) {
@@ -276,7 +276,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
afi = family2afi(p->family);
if (!afi) {
flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF,
- "%s: Unknown AFI/SAFI prefix received\n",
+ "%s: Unknown AFI/SAFI prefix received",
__func__);
return;
}
@@ -715,7 +715,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE,
re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop,
re->nhe_id, zvrf->table_id, re->metric, re->distance,
- false, false);
+ false);
return 0;
}
diff --git a/zebra/rib.h b/zebra/rib.h
index fe7073656c..86766b8175 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -343,8 +343,8 @@ int route_entry_update_nhe(struct route_entry *re,
struct nhg_hash_entry *new_nhghe);
/* NHG replace has happend, we have to update route_entry pointers to new one */
-void rib_handle_nhg_replace(struct nhg_hash_entry *old,
- struct nhg_hash_entry *new);
+void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+ struct nhg_hash_entry *new_entry);
#define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
extern void _route_entry_dump(const char *func, union prefixconstptr pp,
@@ -393,7 +393,7 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
struct prefix *p, 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, bool connected_down);
+ bool fromkernel);
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr,
@@ -406,9 +406,8 @@ 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_vrf(vrf_id_t vrf_id, enum rib_update_event event);
extern void rib_update_table(struct route_table *table,
- enum rib_update_event event);
+ enum rib_update_event event, int rtype);
extern int rib_sweep_route(struct thread *t);
extern void rib_sweep_table(struct route_table *table);
extern void rib_close_table(struct route_table *table);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index f59fbae3af..1cae0b1f9b 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -77,16 +77,7 @@
/* Re-defining as I am unable to include <linux/if_bridge.h> which has the
* UAPI for MAC sync. */
#ifndef _UAPI_LINUX_IF_BRIDGE_H
-/* FDB notification bits for NDA_NOTIFY:
- * - BR_FDB_NFY_STATIC - notify on activity/expire even for a static entry
- * - BR_FDB_NFY_INACTIVE - mark as inactive to avoid double notification,
- * used with BR_FDB_NFY_STATIC (kernel controlled)
- */
-enum {
- BR_FDB_NFY_STATIC,
- BR_FDB_NFY_INACTIVE,
- BR_FDB_NFY_MAX
-};
+#define BR_SPH_LIST_SIZE 10
#endif
static vlanid_t filter_vlan = 0;
@@ -266,6 +257,10 @@ static inline int zebra2proto(int proto)
case ZEBRA_ROUTE_NHG:
proto = RTPROT_ZEBRA;
break;
+ case ZEBRA_ROUTE_CONNECT:
+ case ZEBRA_ROUTE_KERNEL:
+ proto = RTPROT_KERNEL;
+ break;
default:
/*
* When a user adds a new protocol this will show up
@@ -869,7 +864,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (nhe_id) {
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
&p, &src_p, NULL, nhe_id, table, metric,
- distance, true, false);
+ distance, true);
} else {
if (!tb[RTA_MULTIPATH]) {
struct nexthop nh;
@@ -879,13 +874,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
gate, afi, vrf_id);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, &nh, 0, table,
- metric, distance, true, false);
+ metric, distance, true);
} else {
/* XXX: need to compare the entire list of
* nexthops here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, NULL, 0, table,
- metric, distance, true, false);
+ metric, distance, true);
}
}
}
@@ -2486,13 +2481,6 @@ static int netlink_nexthop_process_group(struct rtattr **tb,
return count;
}
-#if 0
- // TODO: Need type for something?
- zlog_debug("Nexthop group type: %d",
- *((uint16_t *)RTA_DATA(tb[NHA_GROUP_TYPE])));
-
-#endif
-
for (int i = 0; ((i < count) && (i < z_grp_size)); i++) {
z_grp[i].id = n_grp[i].id;
z_grp[i].weight = n_grp[i].weight + 1;
@@ -2762,11 +2750,23 @@ static ssize_t netlink_neigh_update_msg_encode(
}
if (nfy) {
- if (!nl_attr_put(&req->n, datalen, NDA_NOTIFY,
- &nfy_flags, sizeof(nfy_flags)))
+ struct rtattr *nest;
+
+ nest = nl_attr_nest(&req->n, datalen,
+ NDA_FDB_EXT_ATTRS | NLA_F_NESTED);
+ if (!nest)
+ return 0;
+
+ if (!nl_attr_put(&req->n, datalen, NFEA_ACTIVITY_NOTIFY,
+ &nfy_flags, sizeof(nfy_flags)))
+ return 0;
+ if (!nl_attr_put(&req->n, datalen, NFEA_DONT_REFRESH, NULL, 0))
return 0;
+
+ nl_attr_nest_end(&req->n, nest);
}
+
if (ext) {
if (!nl_attr_put(&req->n, datalen, NDA_EXT_FLAGS, &ext_flags,
sizeof(ext_flags)))
@@ -2851,7 +2851,8 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
* validation of the fields.
*/
memset(tb, 0, sizeof tb);
- netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
+ netlink_parse_rtattr_flags(tb, NDA_MAX, NDA_RTA(ndm), len,
+ NLA_F_NESTED);
if (!tb[NDA_LLADDR]) {
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2893,14 +2894,21 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
if (ndm->ndm_state & NUD_STALE)
local_inactive = true;
- if (tb[NDA_NOTIFY]) {
- uint8_t nfy_flags;
+ if (tb[NDA_FDB_EXT_ATTRS]) {
+ struct rtattr *attr = tb[NDA_FDB_EXT_ATTRS];
+ struct rtattr *nfea_tb[NFEA_MAX + 1] = {0};
- dp_static = true;
- nfy_flags = *(uint8_t *)RTA_DATA(tb[NDA_NOTIFY]);
- /* local activity has not been detected on the entry */
- if (nfy_flags & (1 << BR_FDB_NFY_INACTIVE))
- local_inactive = true;
+ netlink_parse_rtattr_nested(nfea_tb, NFEA_MAX, attr);
+ if (nfea_tb[NFEA_ACTIVITY_NOTIFY]) {
+ uint8_t nfy_flags;
+
+ nfy_flags = *(uint8_t *)RTA_DATA(
+ nfea_tb[NFEA_ACTIVITY_NOTIFY]);
+ if (nfy_flags & FDB_NOTIFY_BIT)
+ dp_static = true;
+ if (nfy_flags & FDB_NOTIFY_INACTIVE_BIT)
+ local_inactive = true;
+ }
}
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -3202,12 +3210,12 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
} else {
/* local mac */
if (update_flags & DPLANE_MAC_SET_STATIC) {
- nfy_flags |= (1 << BR_FDB_NFY_STATIC);
+ nfy_flags |= FDB_NOTIFY_BIT;
state |= NUD_NOARP;
}
if (update_flags & DPLANE_MAC_SET_INACTIVE)
- nfy_flags |= (1 << BR_FDB_NFY_INACTIVE);
+ nfy_flags |= FDB_NOTIFY_INACTIVE_BIT;
nfy = true;
}
@@ -3300,6 +3308,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
bool is_ext;
bool is_router;
bool local_inactive;
+ uint32_t ext_flags = 0;
+ bool dp_static = false;
ndm = NLMSG_DATA(h);
@@ -3333,7 +3343,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
netlink_handle_5549(ndm, zif, ifp, &ip, false);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "\tNeighbor Entry Received is a 5549 entry, finished");
+ " Neighbor Entry Received is a 5549 entry, finished");
return 0;
}
@@ -3362,7 +3372,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
else {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "\tNeighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
+ " Neighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
return 0;
}
@@ -3391,9 +3401,15 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
is_ext = !!(ndm->ndm_flags & NTF_EXT_LEARNED);
is_router = !!(ndm->ndm_flags & NTF_ROUTER);
+ if (tb[NDA_EXT_FLAGS]) {
+ ext_flags = *(uint32_t *)RTA_DATA(tb[NDA_EXT_FLAGS]);
+ if (ext_flags & NTF_E_MH_PEER_SYNC)
+ dp_static = true;
+ }
+
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
+ "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x ext_flags 0x%x",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(ndm->ndm_family), ifp->name,
ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id,
@@ -3401,7 +3417,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
mac_present
? prefix_mac2str(&mac, buf, sizeof(buf))
: "",
- ndm->ndm_state, ndm->ndm_flags);
+ ndm->ndm_state, ndm->ndm_flags, ext_flags);
/* If the neighbor state is valid for use, process as an add or
* update
@@ -3410,15 +3426,19 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
* in re-adding the neighbor if it is a valid "remote" neighbor.
*/
if (ndm->ndm_state & NUD_VALID) {
- local_inactive = !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
+ if (zebra_evpn_mh_do_adv_reachable_neigh_only())
+ local_inactive =
+ !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
+ else
+ /* If EVPN-MH is not enabled we treat STALE
+ * neighbors as locally-active and advertise
+ * them
+ */
+ local_inactive = false;
- /* XXX - populate dp-static based on the sync flags
- * in the kernel
- */
return zebra_vxlan_handle_kernel_neigh_update(
- ifp, link_if, &ip, &mac, ndm->ndm_state,
- is_ext, is_router, local_inactive,
- false /* dp_static */);
+ ifp, link_if, &ip, &mac, ndm->ndm_state, is_ext,
+ is_router, local_inactive, dp_static);
}
return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
@@ -3689,12 +3709,12 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
char buf2[ETHER_ADDR_STRLEN];
zlog_debug(
- "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
+ "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x %sext_flags 0x%x",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
ipaddr2str(ip, buf, sizeof(buf)),
mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) : "null",
- flags, state);
+ flags, state, ext ? "ext " : "", ext_flags);
}
return netlink_neigh_update_msg_encode(
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index a63504992e..08a675ef3a 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -79,7 +79,15 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
if (buflen < sizeof(*req))
return 0;
memset(req, 0, sizeof(*req));
- family = PREFIX_FAMILY(src_ip);
+
+ /* Assume ipv4 if no src/dst set, we only support ipv4/ipv6 */
+ if (PREFIX_FAMILY(src_ip))
+ family = PREFIX_FAMILY(src_ip);
+ else if (PREFIX_FAMILY(dst_ip))
+ family = PREFIX_FAMILY(dst_ip);
+ else
+ family = AF_INET;
+
bytelen = (family == AF_INET ? 4 : 16);
req->n.nlmsg_type = cmd;
diff --git a/zebra/sample_plugin.c b/zebra/sample_plugin.c
index c96a86cc73..464205f2f3 100644
--- a/zebra/sample_plugin.c
+++ b/zebra/sample_plugin.c
@@ -92,7 +92,6 @@ static int sample_process(struct zebra_dplane_provider *prov)
static int init_sample_plugin(struct thread_master *tm)
{
int ret;
- struct zebra_dplane_provider *prov = NULL;
/* Note that we don't use or store the thread_master 'tm'. We
* don't use the zebra main pthread: our plugin code will run in
diff --git a/zebra/subdir.am b/zebra/subdir.am
index cdacabc102..f842a8c0f3 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -40,6 +40,11 @@ if LINUX
module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la
endif
+# Dataplane sample plugin
+if DEV_BUILD
+module_LTLIBRARIES += zebra/dplane_sample_plugin.la
+endif
+
man8 += $(MANBUILD)/frr-zebra.8
## endif ZEBRA
endif
@@ -206,6 +211,12 @@ zebra/zebra_fpm_dt.lo: fpm/fpm.pb-c.h qpb/qpb.pb-c.h
endif
endif
+# Sample dataplane plugin
+if DEV_BUILD
+zebra_dplane_sample_plugin_la_SOURCES = zebra/sample_plugin.c
+zebra_dplane_sample_plugin_la_LDFLAGS = -module -shared -avoid-version -export-dynamic
+endif
+
nodist_zebra_zebra_SOURCES = \
yang/frr-zebra.yang.c \
# end
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index f2ff8d53f2..46171df848 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -62,6 +62,8 @@
#include "zebra/zebra_opaque.h"
#include "zebra/zebra_srte.h"
+static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
+
/* Encoding helpers -------------------------------------------------------- */
static void zserv_encode_interface(struct stream *s, struct interface *ifp)
@@ -102,6 +104,7 @@ static void zserv_encode_vrf(struct stream *s, struct zebra_vrf *zvrf)
struct vrf_data data;
const char *netns_name = zvrf_ns_name(zvrf);
+ memset(&data, 0, sizeof(data));
data.l.table_id = zvrf->table_id;
if (netns_name)
@@ -707,13 +710,13 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
return zserv_send_message(client, s);
}
-static int nhg_notify(uint16_t type, uint16_t instance, uint32_t id,
- enum zapi_nhg_notify_owner note)
+int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id,
+ uint32_t id, enum zapi_nhg_notify_owner note)
{
struct zserv *client;
struct stream *s;
- client = zserv_find_client(type, instance);
+ client = zserv_find_client_session(type, instance, session_id);
if (!client) {
if (IS_ZEBRA_DEBUG_PACKET) {
zlog_debug("Not Notifying Owner: %u(%u) about %u(%d)",
@@ -722,6 +725,10 @@ static int nhg_notify(uint16_t type, uint16_t instance, uint32_t id,
return 0;
}
+ if (IS_ZEBRA_DEBUG_SEND)
+ zlog_debug("%s: type %d, id %d, note %d",
+ __func__, type, id, note);
+
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
stream_reset(s);
@@ -1139,7 +1146,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
} else {
flog_err(
EC_ZEBRA_UNKNOWN_FAMILY,
- "rnh_register: Received unknown family type %d\n",
+ "rnh_register: Received unknown family type %d",
p.family);
return;
}
@@ -1230,7 +1237,7 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS)
} else {
flog_err(
EC_ZEBRA_UNKNOWN_FAMILY,
- "rnh_register: Received unknown family type %d\n",
+ "rnh_register: Received unknown family type %d",
p.family);
return;
}
@@ -1280,7 +1287,7 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
if (p.family != AF_INET && p.family != AF_INET6) {
flog_err(
EC_ZEBRA_UNKNOWN_FAMILY,
- "fec_register: Received unknown family type %d\n",
+ "fec_register: Received unknown family type %d",
p.family);
return;
}
@@ -1346,7 +1353,7 @@ static void zread_fec_unregister(ZAPI_HANDLER_ARGS)
if (p.family != AF_INET && p.family != AF_INET6) {
flog_err(
EC_ZEBRA_UNKNOWN_FAMILY,
- "fec_unregister: Received unknown family type %d\n",
+ "fec_unregister: Received unknown family type %d",
p.family);
return;
}
@@ -1742,7 +1749,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
return true;
}
-int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
+static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
{
uint16_t i;
struct zapi_nexthop *znh;
@@ -1820,16 +1827,17 @@ static void zread_nhg_del(ZAPI_HANDLER_ARGS)
/*
* Delete the received nhg id
*/
-
nhe = zebra_nhg_proto_del(api_nhg.id, api_nhg.proto);
if (nhe) {
zebra_nhg_decrement_ref(nhe);
- nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
- ZAPI_NHG_REMOVED);
+ zsend_nhg_notify(api_nhg.proto, client->instance,
+ client->session_id, api_nhg.id,
+ ZAPI_NHG_REMOVED);
} else
- nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
- ZAPI_NHG_REMOVE_FAIL);
+ zsend_nhg_notify(api_nhg.proto, client->instance,
+ client->session_id, api_nhg.id,
+ ZAPI_NHG_REMOVE_FAIL);
}
static void zread_nhg_add(ZAPI_HANDLER_ARGS)
@@ -1863,7 +1871,8 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS)
/*
* Create the nhg
*/
- nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, nhg, 0);
+ nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, client->instance,
+ client->session_id, nhg, 0);
nexthop_group_delete(&nhg);
zebra_nhg_backup_free(&bnhg);
@@ -1874,12 +1883,12 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS)
*
* Resolution is going to need some more work.
*/
- if (nhe)
- nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
- ZAPI_NHG_INSTALLED);
- else
- nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
- ZAPI_NHG_FAIL_INSTALL);
+
+ /* If there's a failure, notify sender immediately */
+ if (nhe == NULL)
+ zsend_nhg_notify(api_nhg.proto, client->instance,
+ client->session_id, api_nhg.id,
+ ZAPI_NHG_FAIL_INSTALL);
}
static void zread_route_add(ZAPI_HANDLER_ARGS)
@@ -2080,7 +2089,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric,
- api.distance, false, false);
+ api.distance, false);
/* Stats */
switch (api.prefix.family) {
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 9822d72022..c03278669a 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -108,6 +108,9 @@ extern int zsend_sr_policy_notify_status(uint32_t color,
extern int zsend_client_close_notify(struct zserv *client,
struct zserv *closed_client);
+int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id,
+ uint32_t id, enum zapi_nhg_notify_owner note);
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index fad3c16244..db2b9e002e 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -2014,16 +2014,6 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- /* Check for available encapsulations. */
- if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
- continue;
-
- zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
- if (zl3vni && is_l3vni_oper_up(zl3vni)) {
- nexthop->nh_encap_type = NET_VXLAN;
- nexthop->nh_encap.vni = zl3vni->vni;
- }
-
/* Optionally capture extra interface info while we're in the
* main zebra pthread - a plugin has to ask for this info.
*/
@@ -2044,6 +2034,16 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
if_extra, link);
}
}
+
+ /* Check for available evpn encapsulations. */
+ if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE))
+ continue;
+
+ zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
+ if (zl3vni && is_l3vni_oper_up(zl3vni)) {
+ nexthop->nh_encap_type = NET_VXLAN;
+ nexthop->nh_encap.vni = zl3vni->vni;
+ }
}
/* Don't need some info when capturing a system notification */
@@ -3684,7 +3684,7 @@ int dplane_show_helper(struct vty *vty, bool detailed)
int dplane_show_provs_helper(struct vty *vty, bool detailed)
{
struct zebra_dplane_provider *prov;
- uint64_t in, in_max, out, out_max;
+ uint64_t in, in_q, in_max, out, out_q, out_max;
vty_out(vty, "Zebra dataplane providers:\n");
@@ -3697,17 +3697,20 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
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_max: %" PRIu64
- ", out: %" PRIu64 ", q_max: %" PRIu64 "\n",
- prov->dp_name, prov->dp_id, in, in_max, out, 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);
DPLANE_LOCK();
prov = TAILQ_NEXT(prov, dp_prov_link);
@@ -3912,11 +3915,24 @@ uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov)
void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
struct zebra_dplane_ctx *ctx)
{
+ uint64_t curr, high;
+
dplane_provider_lock(prov);
TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
zd_q_entries);
+ /* 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);
+ high = atomic_load_explicit(&prov->dp_out_max,
+ memory_order_relaxed);
+ if (curr > high)
+ atomic_store_explicit(&prov->dp_out_max, curr,
+ memory_order_relaxed);
+
dplane_provider_unlock(prov);
atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
@@ -4537,6 +4553,7 @@ static int dplane_thread_loop(struct thread *event)
struct zebra_dplane_ctx *ctx, *tctx;
int limit, counter, error_counter;
uint64_t curr, high;
+ bool reschedule = false;
/* Capture work limit per cycle */
limit = zdplane_info.dg_updates_per_cycle;
@@ -4673,6 +4690,9 @@ static int dplane_thread_loop(struct thread *event)
dplane_provider_unlock(prov);
+ if (counter >= limit)
+ reschedule = true;
+
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug("dplane dequeues %d completed work from provider %s",
counter, dplane_provider_get_name(prov));
@@ -4683,6 +4703,13 @@ static int dplane_thread_loop(struct thread *event)
DPLANE_UNLOCK();
}
+ /*
+ * We hit the work limit while processing at least one provider's
+ * output queue - ensure we come back and finish it.
+ */
+ if (reschedule)
+ dplane_provider_work_ready();
+
/* After all providers have been serviced, enqueue any completed
* work and any errors back to zebra so it can process the results.
*/
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 67df841b21..b232c664bc 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -1046,6 +1046,9 @@ int zebra_evpn_del(zebra_evpn_t *zevpn)
hash_free(zevpn->mac_table);
zevpn->mac_table = NULL;
+ /* Remove references to the zevpn in the MH databases */
+ if (zevpn->vxlan_if)
+ zebra_evpn_vxl_evpn_set(zevpn->vxlan_if->info, zevpn, false);
zebra_evpn_es_evi_cleanup(zevpn);
/* Free the EVPN hash entry and allocated memory. */
@@ -1333,7 +1336,8 @@ zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
if (ipa_len) {
n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
if (n
- && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq))
+ && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq,
+ true))
return;
}
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 44394b95aa..5227a480fc 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -29,6 +29,7 @@
#include "prefix.h"
#include "vlan.h"
#include "json.h"
+#include "printfrr.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
@@ -254,6 +255,37 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
}
}
+#define MAC_BUF_SIZE 256
+static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac_t_ *mac, char *buf,
+ size_t len)
+{
+ if (mac->flags == 0) {
+ snprintfrr(buf, len, "None ");
+ return 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) ? "LOC Active "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
+ ? "LOC Inactive "
+ : "");
+ return buf;
+}
+
static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
{
struct zebra_vrf *zvrf = NULL;
@@ -278,12 +310,17 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
if (!mac)
return 0;
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
+ "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count, listcount(mac->neigh_list));
+ 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 */
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
@@ -350,14 +387,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
* Remote MAC event -> hold on installing it.
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
+ "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count,
- zvrf->dad_freeze_time);
-
+ 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
* this MAC update.
@@ -385,12 +425,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
}
if (reset_params) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
+ "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ mac->dad_count);
+ }
mac->dad_count = 0;
/* Start dup. addr detection (DAD) start time,
@@ -452,13 +497,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
/* Start auto recovery timer for this MAC */
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
+ "%s: duplicate addr MAC %s flags %sauto recovery time %u start",
__func__,
prefix_mac2str(&mac->macaddr, buf,
sizeof(buf)),
- mac->flags, zvrf->dad_freeze_time);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)),
+ zvrf->dad_freeze_time);
+ }
thread_add_timer(zrouter.master,
zebra_evpn_dad_mac_auto_recovery_exp,
@@ -694,7 +744,7 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
}
static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
- uint32_t flags_buf_sz)
+ size_t flags_buf_sz)
{
snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
mac->sync_neigh_cnt ?
@@ -903,14 +953,19 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char flag_buf[MACIP_BUF_SIZE];
+
zlog_debug(
- "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
- (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
+ "Send MACIP %s f %s MAC %s IP %s 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)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
es ? es->esi_str : "-",
zebra_route_string(client->proto));
+ }
if (cmd == ZEBRA_MACIP_ADD)
client->macipadd_cnt++;
@@ -982,10 +1037,12 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr)
mac->uptime = monotime(NULL);
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
- zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ zlog_debug("%s: MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
return mac;
}
@@ -999,10 +1056,12 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
- zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ zlog_debug("%s: MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
/* If the MAC is freed before the neigh we will end up
@@ -1047,11 +1106,13 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
&& !listcount(mac->neigh_list)) {
if (IS_ZEBRA_DEBUG_VXLAN) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
zlog_debug(
- "%s: Del MAC %s flags 0x%x", __func__,
+ "%s: Del MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
}
wctx->uninstall = 0;
@@ -1204,24 +1265,34 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
if (!ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ 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 0x%x %sskipped, no access-port",
+ "%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 : "-", mac->flags,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
set_inactive ? "inactive " : "");
+ }
return -1;
}
zif = ifp->info;
br_ifp = zif->brslave_info.br_if;
if (!br_ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ 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 0x%x %sskipped, no br",
+ "%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 : "-", mac->flags,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
set_inactive ? "inactive " : "");
+ }
return -1;
}
@@ -1236,13 +1307,18 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
* supported and if the local ES is oper-down.
*/
if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ 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 0x%x %s",
+ "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 : "-", mac->flags,
+ 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
@@ -1256,13 +1332,17 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
return 0;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "dp-install sync-mac vni %u mac %pEA es %s 0x%x %s%s",
- zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->flags,
- set_static ? "static " : "",
- set_inactive ? "inactive " : "");
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
+ 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)),
+ set_static ? "static " : "",
+ set_inactive ? "inactive " : "");
+ }
dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
set_static, set_inactive);
@@ -1310,12 +1390,17 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t)
new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
new_static = zebra_evpn_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold expired",
+ "sync-mac vni %u mac %s es %s %shold expired",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ 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
@@ -1340,12 +1425,17 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac)
if (mac->hold_timer)
return;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold started",
+ "sync-mac vni %u mac %s es %s %shold started",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
zmh_info->mac_hold_time, &mac->hold_timer);
}
@@ -1357,12 +1447,18 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac)
if (!mac->hold_timer)
return;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold stopped",
+ "sync-mac vni %u mac %s es %s %shold stopped",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
+
THREAD_OFF(mac->hold_timer);
}
@@ -1372,13 +1468,18 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
bool old_static;
bool new_static;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+ "sync-mac del vni %u mac %s es %s seq %d f %s",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
+
old_static = zebra_evpn_mac_is_static(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
@@ -1395,16 +1496,21 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
zebra_mac_t *mac, uint32_t seq,
uint16_t ipa_len,
- struct ipaddr *ipaddr)
+ struct ipaddr *ipaddr,
+ bool sync)
{
char macbuf[ETHER_ADDR_STRLEN];
char ipbuf[INET6_ADDRSTRLEN];
uint32_t tmp_seq;
+ const char *n_type;
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
tmp_seq = mac->loc_seq;
- else
+ n_type = "local";
+ } else {
tmp_seq = mac->rem_seq;
+ n_type = "remote";
+ }
if (seq < tmp_seq) {
/* if the mac was never advertised to bgp we must accept
@@ -1413,31 +1519,44 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
+ || IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-macip accept vni %u mac %s%s%s lower seq %u f 0x%x",
- zevpn->vni,
+ "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s",
+ sync ? "sync" : "rem", zevpn->vni,
+ n_type,
prefix_mac2str(&mac->macaddr, macbuf,
sizeof(macbuf)),
ipa_len ? " IP " : "",
ipa_len ? ipaddr2str(ipaddr, ipbuf,
sizeof(ipbuf))
: "",
- tmp_seq, mac->flags);
+ tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
+
return true;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-macip ignore vni %u mac %s%s%s as existing has higher seq %u f 0x%x",
- zevpn->vni,
+ "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s",
+ sync ? "sync" : "rem", zevpn->vni, n_type,
prefix_mac2str(&mac->macaddr, macbuf,
sizeof(macbuf)),
ipa_len ? " IP " : "",
ipa_len ? ipaddr2str(ipaddr, ipbuf,
sizeof(ipbuf))
: "",
- tmp_seq, mac->flags);
+ tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
return false;
}
@@ -1518,7 +1637,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
return NULL;
}
if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
- ipaddr)) {
+ ipaddr, true)) {
ctx->ignore_macip = true;
return NULL;
}
@@ -1568,12 +1687,20 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->flags = new_flags;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags))
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
+ char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
+ struct zebra_mac_t_ omac;
+
+ omac.flags = old_flags;
zlog_debug(
- "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+ "sync-mac vni %u mac %s old_f %snew_f %s",
zevpn->vni,
prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
- old_flags, mac->flags);
+ 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 */
es_change = zebra_evpn_es_mac_ref(mac, esi);
@@ -1607,13 +1734,18 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
inform_bgp = true;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s",
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
+ zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s",
ctx->mac_created ? "created" : "updated", zevpn->vni,
prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags, inform_bgp ? " inform_bgp" : "",
+ 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,
@@ -1768,7 +1900,6 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
{
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
- uint32_t tmp_seq;
bool sticky;
bool remote_gw;
int update_mac = 0;
@@ -1828,8 +1959,6 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
if (ipa_len)
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
} else {
- zebra_evpn_es_mac_ref(mac, esi);
-
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
* corresponds to "older" location of the host
@@ -1838,26 +1967,11 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
* the sequence number and ignore this update
* if appropriate.
*/
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
- tmp_seq = mac->loc_seq;
- else
- tmp_seq = mac->rem_seq;
-
- if (seq < tmp_seq) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x",
- zevpn->vni,
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(
- ipaddr, buf1,
- sizeof(buf1))
- : "",
- tmp_seq, mac->flags);
+ if (!zebra_evpn_mac_is_bgp_seq_ok(
+ zevpn, mac, seq, ipa_len, ipaddr, false))
return -1;
- }
+
+ zebra_evpn_es_mac_ref(mac, esi);
}
/* Check MAC's curent state is local (this is the case
@@ -1881,14 +1995,20 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* force drop the sync flags */
old_static = zebra_evpn_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+ "sync-mac->remote vni %u mac %s es %s seq %d f %s",
zevpn->vni,
prefix_mac2str(macaddr, buf,
sizeof(buf)),
mac->es ? mac->es->esi_str : "-",
- mac->loc_seq, mac->flags);
+ 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,
@@ -1982,14 +2102,18 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
inform_client = true;
} else {
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
+ "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid, zevpn->vni,
local_inactive ? "local-inactive " : "",
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
struct interface *old_ifp;
@@ -2137,14 +2261,19 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
*/
if ((old_local_inactive != local_inactive)
|| (new_bgp_ready != old_bgp_ready)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "local mac vni %u mac %s es %s seq %d f 0x%x%s",
+ "local mac vni %u mac %s es %s seq %d f %s%s",
zevpn->vni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
mac->es ? mac->es->esi_str : "", mac->loc_seq,
- mac->flags,
- local_inactive ? " local-inactive" : "");
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ local_inactive ? "local-inactive" : "");
+ }
+
if (!is_dup_detect)
inform_client = true;
}
@@ -2173,28 +2302,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
return 0;
}
-int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
- struct interface *ifp)
+int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
{
- zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
bool old_bgp_ready;
bool new_bgp_ready;
- /* If entry doesn't exist, nothing to do. */
- mac = zebra_evpn_mac_lookup(zevpn, macaddr);
- if (!mac)
- return 0;
-
- /* Is it a local entry? */
- if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
- return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, mac->fwd_info.local.vid, zevpn->vni,
- mac->loc_seq, mac->flags, listcount(mac->neigh_list));
+ zlog_debug("DEL MAC %s VNI %u seq %u flags 0x%x nbr count %u",
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ zevpn->vni, mac->loc_seq, mac->flags,
+ listcount(mac->neigh_list));
old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
if (zebra_evpn_mac_is_static(mac)) {
@@ -2203,13 +2321,17 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
*/
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "re-add sync-mac vni %u mac %s es %s seq %d f 0x%x",
+ "re-add sync-mac vni %u mac %s es %s seq %d f %s",
zevpn->vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags);
+ 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)) {
@@ -2232,7 +2354,7 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
/* Remove MAC from BGP. */
- zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags,
+ zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
false /* force */);
zebra_evpn_es_mac_deref_entry(mac);
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index 1730991f1e..242097907f 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -56,6 +56,7 @@ struct zebra_mac_t_ {
/* MAC address. */
struct ethaddr macaddr;
+ /* When modifying flags please fixup zebra_evpn_zebra_mac_flag_dump */
uint32_t flags;
#define ZEBRA_MAC_LOCAL 0x01
#define ZEBRA_MAC_REMOTE 0x02
@@ -252,8 +253,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
struct ethaddr *macaddr, vlanid_t vid,
bool sticky, bool local_inactive,
bool dp_static);
-int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
- struct interface *ifp);
+int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac);
int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
struct ipaddr *ip, zebra_mac_t **macp,
struct ethaddr *macaddr, vlanid_t vlan_id);
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 3a0df1c015..7e712bf1ee 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -417,15 +417,12 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
vty_out(vty, "Type: L local, R remote\n");
vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
}
+ zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
} else {
if (!uj)
vty_out(vty, "VNI %d doesn't exist\n", vni);
-
- return;
}
- zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
-
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
@@ -1867,6 +1864,8 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
uint16_t vid;
struct zebra_evpn_access_bd *acc_bd;
+ if (!bf_is_inited(zif->vlan_bitmap))
+ return;
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
acc_bd = zebra_evpn_acc_vl_find(vid);
@@ -1944,6 +1943,23 @@ static void zebra_evpn_mh_dup_addr_detect_off(void)
}
}
+/* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
+ * neighbors
+ */
+static void zebra_evpn_mh_advertise_reach_neigh_only(void)
+{
+ if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
+ return;
+
+ zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("evpn-mh: only REACHABLE neigh advertised");
+
+ /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
+ * need to withdraw them
+ */
+}
+
static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
{
struct zebra_evpn_es *es;
@@ -1969,6 +1985,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
es->nhg_id, zif->ifp->name);
zebra_evpn_mh_dup_addr_detect_off();
+ zebra_evpn_mh_advertise_reach_neigh_only();
es->flags |= ZEBRA_EVPNES_LOCAL;
listnode_init(&es->local_es_listnode, es);
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 14b2987574..81ae740d49 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -195,6 +195,11 @@ struct zebra_evpn_mh_info {
* first local ES, DAD is turned off
*/
#define ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF (1 << 1)
+/* If EVPN MH is enabled we only advertise REACHABLE neigh entries as Type-2
+ * routes. As there is no global config knob for enabling EVPN MH we turn
+ * this flag when the first local ES is detected.
+ */
+#define ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY (1 << 2)
/* RB tree of Ethernet segments (used for EVPN-MH) */
struct zebra_es_rb_head es_rb_tree;
@@ -275,6 +280,12 @@ static inline bool zebra_evpn_mh_do_dup_addr_detect(void)
return !(zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF);
}
+static inline bool zebra_evpn_mh_do_adv_reachable_neigh_only(void)
+{
+ return !!(zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY);
+}
+
+
/*****************************************************************************/
extern esi_t *zero_esi;
extern void zebra_evpn_mh_init(void);
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 6d72bc570e..1f45b72e3a 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -529,16 +529,21 @@ static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n,
}
bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
- struct ethaddr *macaddr, uint32_t seq)
+ struct ethaddr *macaddr, uint32_t seq,
+ bool sync)
{
char macbuf[ETHER_ADDR_STRLEN];
char ipbuf[INET6_ADDRSTRLEN];
uint32_t tmp_seq;
+ const char *n_type;
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
tmp_seq = n->loc_seq;
- else
+ n_type = "local";
+ } else {
tmp_seq = n->rem_seq;
+ n_type = "remote";
+ }
if (seq < tmp_seq) {
/* if the neigh was never advertised to bgp we must accept
@@ -547,10 +552,12 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
*/
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
&& !zebra_evpn_neigh_is_ready_for_bgp(n)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
+ || IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "sync-macip accept vni %u mac %s IP %s lower seq %u f 0x%x",
- zevpn->vni,
+ "%s-macip accept vni %u %s mac %s IP %s lower seq %u f 0x%x",
+ sync ? "sync" : "remote", zevpn->vni,
+ n_type,
prefix_mac2str(macaddr, macbuf,
sizeof(macbuf)),
ipaddr2str(&n->ip, ipbuf,
@@ -559,10 +566,10 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
return true;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "sync-macip ignore vni %u mac %s IP %s as existing has higher seq %u f 0x%x",
- zevpn->vni,
+ "%s-macip ignore vni %u %s mac %s IP %s as existing has higher seq %u f 0x%x",
+ sync ? "sync" : "remote", zevpn->vni, n_type,
prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
tmp_seq, n->flags);
@@ -1453,6 +1460,9 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
new_bgp_ready =
zebra_evpn_neigh_is_ready_for_bgp(n);
+ if (dp_static != new_static)
+ inform_dataplane = true;
+
/* Neigh is in freeze state and freeze action
* is enabled, do not send update to client.
*/
@@ -1467,6 +1477,12 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
old_bgp_ready, new_bgp_ready, false,
false, "flag-update");
+ if (inform_dataplane)
+ zebra_evpn_sync_neigh_dp_install(
+ n, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
/* if the neigh can no longer be advertised
* remove it from bgp
*/
@@ -1578,15 +1594,11 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
else
UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
- /* if the dataplane thinks that this is a sync entry but
- * zebra doesn't we need to re-concile the diff
- * by re-installing the dataplane entry
- */
- if (dp_static) {
- new_static = zebra_evpn_neigh_is_static(n);
- if (!new_static)
- inform_dataplane = true;
- }
+ /* if zebra and dataplane don't agree this is a sync entry
+ * re-install in the dataplane */
+ new_static = zebra_evpn_neigh_is_static(n);
+ if (dp_static != new_static)
+ inform_dataplane = true;
/* Check old and/or new MAC detected as duplicate mark
* the neigh as duplicate
@@ -2128,7 +2140,6 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
{
zebra_neigh_t *n;
int update_neigh = 0;
- uint32_t tmp_seq;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
zebra_mac_t *old_mac = NULL;
@@ -2165,8 +2176,6 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
}
} else {
- const char *n_type;
-
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
* corresponds to "older" location of the host
@@ -2175,27 +2184,10 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
* the sequence number and ignore this update
* if appropriate.
*/
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- tmp_seq = n->loc_seq;
- n_type = "local";
- } else {
- tmp_seq = n->rem_seq;
- n_type = "remote";
- }
- if (seq < tmp_seq) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u",
- zevpn->vni,
- prefix_mac2str(&mac->macaddr,
- buf,
- sizeof(buf)),
- " IP ",
- ipaddr2str(ipaddr, buf1,
- sizeof(buf1)),
- n_type, tmp_seq);
+
+ if (!zebra_evpn_neigh_is_bgp_seq_ok(
+ zevpn, n, &mac->macaddr, seq, false))
return;
- }
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
old_static = zebra_evpn_neigh_is_static(n);
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
index 50efdc0e0d..eac17a09b4 100644
--- a/zebra/zebra_evpn_neigh.h
+++ b/zebra/zebra_evpn_neigh.h
@@ -237,7 +237,8 @@ int zebra_evpn_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
struct ethaddr *macaddr, uint32_t flags,
int state, bool force);
bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
- struct ethaddr *macaddr, uint32_t seq);
+ struct ethaddr *macaddr, uint32_t seq,
+ bool sync);
int zebra_evpn_neigh_del(zebra_evpn_t *zevpn, zebra_neigh_t *n);
void zebra_evpn_sync_neigh_del(zebra_neigh_t *n);
zebra_neigh_t *
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 2bf48c6277..73534c4332 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -70,7 +70,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, FPM_MAC_INFO, "FPM_MAC_INFO");
#define ZFPM_STATS_IVL_SECS 10
#define FPM_MAX_MAC_MSG_LEN 512
-static void zfpm_iterate_rmac_table(struct hash_bucket *backet, void *args);
+static void zfpm_iterate_rmac_table(struct hash_bucket *bucket, void *args);
/*
* Structure that holds state for iterating over all route_node
@@ -273,6 +273,11 @@ struct zfpm_glob {
* If non-zero, the last time when statistics were cleared.
*/
time_t last_stats_clear_time;
+
+ /*
+ * Flag to track the MAC dump status to FPM
+ */
+ bool fpm_mac_dump_done;
};
static struct zfpm_glob zfpm_glob_space;
@@ -517,8 +522,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
struct zfpm_rnodes_iter *iter;
rib_dest_t *dest;
- zfpm_g->t_conn_up = NULL;
-
iter = &zfpm_g->t_conn_up_state.iter;
if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) {
@@ -528,8 +531,13 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
goto done;
}
- /* Enqueue FPM updates for all the RMAC entries */
- hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, NULL);
+ if (!zfpm_g->fpm_mac_dump_done) {
+ /* Enqueue FPM updates for all the RMAC entries */
+ hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table,
+ NULL);
+ /* mark dump done so that its not repeated after yield */
+ zfpm_g->fpm_mac_dump_done = true;
+ }
while ((rnode = zfpm_rnodes_iter_next(iter))) {
dest = rib_dest_from_rnode(rnode);
@@ -547,7 +555,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
zfpm_g->stats.t_conn_up_yields++;
zfpm_rnodes_iter_pause(iter);
- zfpm_g->t_conn_up = NULL;
thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb,
NULL, 0, &zfpm_g->t_conn_up);
return 0;
@@ -575,12 +582,13 @@ static void zfpm_connection_up(const char *detail)
/*
* Start thread to push existing routes to the FPM.
*/
- assert(!zfpm_g->t_conn_up);
+ thread_cancel(&zfpm_g->t_conn_up);
zfpm_rnodes_iter_init(&zfpm_g->t_conn_up_state.iter);
+ zfpm_g->fpm_mac_dump_done = false;
zfpm_debug("Starting conn_up thread");
- zfpm_g->t_conn_up = NULL;
+
thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0,
&zfpm_g->t_conn_up);
zfpm_g->stats.t_conn_up_starts++;
@@ -1627,10 +1635,10 @@ static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
* Iterate over all the RMAC entries for the given L3VNI
* and enqueue the RMAC for FPM processing.
*/
-static void zfpm_trigger_rmac_update_wrapper(struct hash_bucket *backet,
+static void zfpm_trigger_rmac_update_wrapper(struct hash_bucket *bucket,
void *args)
{
- zebra_mac_t *zrmac = (zebra_mac_t *)backet->data;
+ zebra_mac_t *zrmac = (zebra_mac_t *)bucket->data;
zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)args;
zfpm_trigger_rmac_update(zrmac, zl3vni, false, "RMAC added");
@@ -1641,9 +1649,9 @@ static void zfpm_trigger_rmac_update_wrapper(struct hash_bucket *backet,
* This function iterates over all the L3VNIs to trigger
* FPM updates for RMACs currently available.
*/
-static void zfpm_iterate_rmac_table(struct hash_bucket *backet, void *args)
+static void zfpm_iterate_rmac_table(struct hash_bucket *bucket, void *args)
{
- zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)backet->data;
+ zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)bucket->data;
hash_iterate(zl3vni->rmac_table, zfpm_trigger_rmac_update_wrapper,
(void *)zl3vni);
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 44f574073c..f7c5da5dec 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -133,6 +133,7 @@ struct netlink_nh_info {
* A structure for holding information for a netlink route message.
*/
struct netlink_route_info {
+ uint32_t nlmsg_pid;
uint16_t nlmsg_type;
uint8_t rtm_type;
uint32_t rtm_table;
@@ -244,14 +245,20 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
rib_dest_t *dest, struct route_entry *re)
{
struct nexthop *nexthop;
+ struct rib_table_info *table_info =
+ rib_table_info(rib_dest_table(dest));
+ struct zebra_vrf *zvrf = table_info->zvrf;
memset(ri, 0, sizeof(*ri));
ri->prefix = rib_dest_prefix(dest);
ri->af = rib_dest_af(dest);
+ if (zvrf && zvrf->zns)
+ ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid;
+
ri->nlmsg_type = cmd;
- ri->rtm_table = rib_table_info(rib_dest_table(dest))->table_id;
+ ri->rtm_table = table_info->table_id;
ri->rtm_protocol = RTPROT_UNSPEC;
/*
@@ -357,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri,
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_pid = ri->nlmsg_pid;
req->n.nlmsg_type = ri->nlmsg_type;
req->r.rtm_family = ri->af;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 375be45df0..2864b96c83 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -43,6 +43,7 @@
#include "zebra_errors.h"
#include "zebra_dplane.h"
#include "zebra/interface.h"
+#include "zebra/zapi_msg.h"
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
@@ -1759,6 +1760,10 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
if (!CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_ACTIVE))
return false;
+ /* Must not be duplicate */
+ if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_DUPLICATE))
+ return false;
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -2105,10 +2110,10 @@ done_with_match:
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. The nexthop->ifindex will be updated
- * appropriately as well. An existing route map can turn
- * (otherwise active) nexthop into inactive, but not vice versa.
+ * appropriately as well. An existing route map can turn an
+ * otherwise active nexthop into inactive, but not vice versa.
*
- * If it finds a nexthop recursivedly, set the resolved_id
+ * If it finds a nexthop recursively, set the resolved_id
* to match that nexthop's nhg_hash_entry ID;
*
* The return value is the final value of 'ACTIVE' flag.
@@ -2119,8 +2124,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
{
struct interface *ifp;
route_map_result_t ret = RMAP_PERMITMATCH;
- int family;
- char buf[SRCDEST2STR_BUFFER];
+ afi_t family;
const struct prefix *p, *src_p;
struct zebra_vrf *zvrf;
@@ -2132,6 +2136,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
family = AFI_IP6;
else
family = 0;
+
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
@@ -2230,10 +2235,9 @@ static unsigned nexthop_active_check(struct route_node *rn,
zvrf, re->tag);
if (ret == RMAP_DENYMATCH) {
if (IS_ZEBRA_DEBUG_RIB) {
- srcdest_rnode2str(rn, buf, sizeof(buf));
zlog_debug(
- "%u:%s: Filtering out with NH out %s due to route map",
- re->vrf_id, buf,
+ "%u:%pRN: Filtering out with NH out %s due to route map",
+ re->vrf_id, rn,
ifindex2ifname(nexthop->ifindex,
nexthop->vrf_id));
}
@@ -2643,6 +2647,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
EC_ZEBRA_DP_DELETE_FAIL,
"Failed to uninstall Nexthop ID (%u) from the kernel",
id);
+
/* We already free'd the data, nothing to do */
break;
case DPLANE_OP_NH_INSTALL:
@@ -2663,12 +2668,26 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
zebra_nhg_handle_install(nhe);
- } else
+
+ /* If daemon nhg, send it an update */
+ if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_INSTALLED);
+ } else {
+ /* If daemon nhg, send it an update */
+ if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_FAIL_INSTALL);
+
flog_err(
EC_ZEBRA_DP_INSTALL_FAIL,
"Failed to install Nexthop ID (%u) into the kernel",
nhe->id);
+ }
break;
+
case DPLANE_OP_ROUTE_INSTALL:
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
@@ -2777,6 +2796,7 @@ bool zebra_nhg_proto_nexthops_only(void)
/* Add NHE from upper level proto */
struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ uint16_t instance, uint32_t session,
struct nexthop_group *nhg, afi_t afi)
{
struct nhg_hash_entry lookup;
@@ -2860,6 +2880,10 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
zebra_nhg_increment_ref(new);
+ /* Capture zapi client info */
+ new->zapi_instance = instance;
+ new->zapi_session = session;
+
zebra_nhg_set_valid_if_active(new);
zebra_nhg_install_kernel(new);
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index 9382b8c65d..db20f2beaf 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -50,8 +50,14 @@ struct nhg_hash_entry {
uint32_t id;
afi_t afi;
vrf_id_t vrf_id;
+
+ /* Source protocol - zebra or another daemon */
int type;
+ /* zapi instance and session id, for groups from other daemons */
+ uint16_t zapi_instance;
+ uint32_t zapi_session;
+
struct nexthop_group nhg;
/* If supported, a mapping of backup nexthops. */
@@ -292,6 +298,7 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
* Returns allocated NHE on success, otherwise NULL.
*/
struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ uint16_t instance, uint32_t session,
struct nexthop_group *nhg,
afi_t afi);
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index c244d2a955..87ab900092 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -32,6 +32,7 @@
#include "zebra/zapi_msg.h"
#include "zebra/zebra_memory.h"
#include "zebra/zserv.h"
+#include "zebra/debug.h"
/* definitions */
DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
@@ -499,10 +500,14 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
*/
found = pbr_rule_lookup_unique(rule);
- (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
-
/* If found, this is an update */
if (found) {
+ if (IS_ZEBRA_DEBUG_PBR)
+ zlog_debug(
+ "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- update",
+ __func__, rule->rule.seq, rule->rule.priority,
+ rule->rule.unique, rule->rule.ifname);
+
(void)dplane_pbr_rule_update(found, rule);
if (pbr_rule_release(found))
@@ -510,12 +515,26 @@ void zebra_pbr_add_rule(struct zebra_pbr_rule *rule)
"%s: Rule being updated we know nothing about",
__PRETTY_FUNCTION__);
- } else
+ } else {
+ if (IS_ZEBRA_DEBUG_PBR)
+ zlog_debug(
+ "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- new",
+ __func__, rule->rule.seq, rule->rule.priority,
+ rule->rule.unique, rule->rule.ifname);
+
(void)dplane_pbr_rule_add(rule);
+ }
+
+ (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern);
}
void zebra_pbr_del_rule(struct zebra_pbr_rule *rule)
{
+ if (IS_ZEBRA_DEBUG_PBR)
+ zlog_debug("%s: seq: %d, prior: %d, unique: %d, ifname: %s",
+ __func__, rule->rule.seq, rule->rule.priority,
+ rule->rule.unique, rule->rule.ifname);
+
(void)dplane_pbr_rule_delete(rule);
if (pbr_rule_release(rule))
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 0aea0b6cfa..c5d977017e 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -38,6 +38,7 @@
#include "workqueue.h"
#include "nexthop_group_private.h"
#include "frr_pthread.h"
+#include "printfrr.h"
#include "zebra/zebra_router.h"
#include "zebra/connected.h"
@@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf);
}
+static char *_dump_re_status(const struct route_entry *re, char *buf,
+ size_t len)
+{
+ if (re->status == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(
+ buf, len, "%s%s%s%s%s%s%s",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
+ ? "Label Changed "
+ : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
+ : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG "
+ : "");
+ return buf;
+}
+
#define rnode_debug(node, vrf_id, ...) \
_rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__)
#define rnode_info(node, ...) \
@@ -250,8 +275,8 @@ done:
return ret;
}
-void rib_handle_nhg_replace(struct nhg_hash_entry *old,
- struct nhg_hash_entry *new)
+void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+ struct nhg_hash_entry *new_entry)
{
struct zebra_router_table *zrt;
struct route_node *rn;
@@ -259,15 +284,15 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old,
if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p",
- __func__, new->id, new, old);
+ __func__, new_entry->id, new_entry, old_entry);
/* We have to do them ALL */
RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
for (rn = route_top(zrt->table); rn;
rn = srcdest_route_next(rn)) {
RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (re->nhe && re->nhe == old)
- route_entry_update_nhe(re, new);
+ if (re->nhe && re->nhe == old_entry)
+ route_entry_update_nhe(re, new_entry);
}
}
}
@@ -720,7 +745,7 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
if (rnh->seqno == seq) {
if (IS_ZEBRA_DEBUG_NHT_DETAILED)
zlog_debug(
- "\tNode processed and moved already");
+ " Node processed and moved already");
continue;
}
@@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn)
}
RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ char flags_buf[128];
+ char status_buf[128];
+
zlog_debug(
- "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+ "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d",
VRF_LOGNAME(vrf), vrf_id, re->table, buf, re,
- zebra_route_string(re->type), re->status,
- re->flags, re->distance, re->metric);
+ 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. */
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -1107,6 +1140,9 @@ static void rib_process(struct route_node *rn)
*/
if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
if (!nexthop_active_update(rn, re)) {
+ const struct prefix *p;
+ struct rib_table_info *info;
+
if (re->type == ZEBRA_ROUTE_TABLE) {
/* XXX: HERE BE DRAGONS!!!!!
* In all honesty, I have not yet
@@ -1136,6 +1172,11 @@ static void rib_process(struct route_node *rn)
ROUTE_ENTRY_REMOVED);
}
+ info = srcdest_rnode_table_info(rn);
+ srcdest_rnode_prefixes(rn, &p, NULL);
+ zsend_route_notify_owner(re, p,
+ ZAPI_ROUTE_FAIL_INSTALL,
+ info->afi, info->safi);
continue;
}
} else {
@@ -2282,14 +2323,6 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex)
UNSET_FLAG(rib_dest_from_rnode(rnode)->flags,
RIB_ROUTE_QUEUED(qindex));
-#if 0
- else
- {
- zlog_debug ("%s: called for route_node (%p, %d) with no ribs",
- __func__, rnode, route_node_get_lock_count(rnode));
- zlog_backtrace(LOG_DEBUG);
- }
-#endif
route_unlock_node(rnode);
}
@@ -2791,6 +2824,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
bool is_srcdst = src_p && src_p->prefixlen;
char straddr[PREFIX_STRLEN];
char srcaddr[PREFIX_STRLEN];
+ char flags_buf[128];
+ char status_buf[128];
struct nexthop *nexthop;
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
struct nexthop_group *nhg;
@@ -2804,9 +2839,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
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 == %u, status == %u",
- straddr, re->metric, re->mtu, re->distance, re->flags,
- re->status);
+ 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: nexthop_num == %u, nexthop_active_num == %u", straddr,
nexthop_group_nexthop_num(&(re->nhe->nhg)),
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
@@ -2941,8 +2979,10 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
struct nhg_hash_entry *nhe = NULL;
struct route_table *table;
struct route_node *rn;
- struct route_entry *same = NULL;
+ struct route_entry *same = NULL, *first_same = NULL;
int ret = 0;
+ int same_count = 0;
+ rib_dest_t *dest;
if (!re || !re_nhe)
return -1;
@@ -3010,14 +3050,22 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
* for the install don't do a route replace.
*/
RNODE_FOREACH_RE (rn, same) {
- if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED))
+ if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) {
+ same_count++;
continue;
+ }
/* Compare various route_entry properties */
- if (rib_compare_routes(re, same))
- break;
+ if (rib_compare_routes(re, same)) {
+ same_count++;
+
+ if (first_same == NULL)
+ first_same = same;
+ }
}
+ same = first_same;
+
/* If this route is kernel/connected route, notify the dataplane. */
if (RIB_SYSTEM_ROUTE(re)) {
/* Notify dataplane */
@@ -3027,8 +3075,9 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
/* 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",
- rn, re, zebra_route_string(re->type), same);
+ "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
+ rn, re, zebra_route_string(re->type), same,
+ same_count);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(p, src_p, re);
@@ -3042,6 +3091,24 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
if (same)
rib_delnode(rn, same);
+ /* See if we can remove some RE entries that are queued for
+ * removal, but won't be considered in rib processing.
+ */
+ dest = rib_dest_from_rnode(rn);
+ RNODE_FOREACH_RE_SAFE (rn, re, same) {
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+ /* If the route was used earlier, must retain it. */
+ if (dest && re == dest->selected_fib)
+ continue;
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p",
+ rn, re);
+
+ rib_unlink(rn, re);
+ }
+ }
+
route_unlock_node(rn);
return ret;
}
@@ -3088,7 +3155,7 @@ 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,
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
- uint8_t distance, bool fromkernel, bool connected_down)
+ uint8_t distance, bool fromkernel)
{
struct route_table *table;
struct route_node *rn;
@@ -3294,19 +3361,6 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
rib_delnode(rn, same);
}
- /*
- * This is to force an immediate re-eval of this particular
- * node via nexthop tracking. Why? Because there are scenarios
- * where the interface is flapping and the normal queuing methodology
- * will cause down/up events to very very rarely be combined into
- * a non-event from nexthop tracking perspective. Leading
- * to some fun timing situations with upper level routing protocol
- * trying to and failing to install routes during this blip. Especially
- * when zebra is under load.
- */
- if (connected_down)
- zebra_rib_evaluate_rn_nexthops(rn,
- zebra_router_get_next_sequence());
route_unlock_node(rn);
return;
}
@@ -3391,7 +3445,8 @@ static void rib_update_route_node(struct route_node *rn, int type)
}
/* Schedule routes of a particular table (address-family) based on event. */
-void rib_update_table(struct route_table *table, enum rib_update_event event)
+void rib_update_table(struct route_table *table, enum rib_update_event event,
+ int rtype)
{
struct route_node *rn;
@@ -3404,12 +3459,12 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
: NULL;
vrf = zvrf ? zvrf->vrf : NULL;
- zlog_debug("%s: %s VRF %s Table %u event %s", __func__,
+ zlog_debug("%s: %s VRF %s Table %u event %s Route type: %s", __func__,
table->info ? afi2str(
((struct rib_table_info *)table->info)->afi)
: "Unknown",
VRF_LOGNAME(vrf), zvrf ? zvrf->table_id : 0,
- rib_update_event2str(event));
+ rib_update_event2str(event), zebra_route_string(rtype));
}
/* Walk all routes and queue for processing, if appropriate for
@@ -3432,7 +3487,7 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
- rib_update_route_node(rn, ZEBRA_ROUTE_ALL);
+ rib_update_route_node(rn, rtype);
break;
default:
break;
@@ -3440,7 +3495,8 @@ void rib_update_table(struct route_table *table, enum rib_update_event event)
}
}
-static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event)
+static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event,
+ int rtype)
{
struct route_table *table;
@@ -3451,14 +3507,14 @@ static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event)
/* Process routes of interested address-families. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
if (table)
- rib_update_table(table, event);
+ rib_update_table(table, event, rtype);
table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id);
if (table)
- rib_update_table(table, event);
+ rib_update_table(table, event, rtype);
}
-static void rib_update_handle_vrf_all(enum rib_update_event event)
+static void rib_update_handle_vrf_all(enum rib_update_event event, int rtype)
{
struct zebra_router_table *zrt;
@@ -3468,7 +3524,7 @@ static void rib_update_handle_vrf_all(enum rib_update_event event)
/* Just iterate over all the route tables, rather than vrf lookups */
RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables)
- rib_update_table(zrt->table, event);
+ rib_update_table(zrt->table, event, rtype);
}
struct rib_update_ctx {
@@ -3502,9 +3558,9 @@ static int rib_update_handler(struct thread *thread)
ctx = THREAD_ARG(thread);
if (ctx->vrf_all)
- rib_update_handle_vrf_all(ctx->event);
+ rib_update_handle_vrf_all(ctx->event, ZEBRA_ROUTE_ALL);
else
- rib_update_handle_vrf(ctx->vrf_id, ctx->event);
+ rib_update_handle_vrf(ctx->vrf_id, ctx->event, ZEBRA_ROUTE_ALL);
rib_update_ctx_fini(&ctx);
@@ -3517,26 +3573,6 @@ static int rib_update_handler(struct thread *thread)
*/
static struct thread *t_rib_update_threads[RIB_UPDATE_MAX];
-/* Schedule a RIB update event for specific vrf */
-void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event)
-{
- struct rib_update_ctx *ctx;
-
- ctx = rib_update_ctx_init(vrf_id, event);
-
- /* Don't worry about making sure multiple rib updates for specific vrf
- * are scheduled at once for now. If it becomes a problem, we can use a
- * lookup of some sort to keep track of running threads via t_vrf_id
- * like how we are doing it in t_rib_update_threads[].
- */
- thread_add_event(zrouter.master, rib_update_handler, ctx, 0, NULL);
-
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s: Scheduled VRF %s, event %s", __func__,
- vrf_id_to_name(ctx->vrf_id),
- rib_update_event2str(event));
-}
-
/* Schedule a RIB update event for all vrfs */
void rib_update(enum rib_update_event event)
{
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 3c4dbc5e9c..48e2bafe44 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1124,7 +1124,7 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
break;
default:
flog_err(EC_ZEBRA_RNH_UNKNOWN_FAMILY,
- "%s: Unknown family (%d) notification attempted\n",
+ "%s: Unknown family (%d) notification attempted",
__func__, rn->p.family);
goto failure;
}
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 0ce724f608..17a9bf97f9 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -267,7 +267,8 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap,
/* Process routes of interested address-families. */
table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
if (table)
- rib_update_table(table, RIB_UPDATE_RMAP_CHANGE);
+ rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
+ rtype);
}
return CMD_SUCCESS;
@@ -294,7 +295,8 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap,
/* Process routes of interested address-families. */
table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
if (table)
- rib_update_table(table, RIB_UPDATE_RMAP_CHANGE);
+ rib_update_table(table, RIB_UPDATE_RMAP_CHANGE,
+ rtype);
}
XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype));
}
@@ -576,7 +578,7 @@ DEFUN (zebra_route_map_timer,
ZEBRA_STR
"Set route-map parameters\n"
"Time to wait before route-map updates are processed\n"
- "0 means event-driven updates are disabled\n")
+ "0 means route-map changes are run immediately instead of delaying\n")
{
int idx_number = 3;
uint32_t rmap_delay_timer;
@@ -594,7 +596,7 @@ DEFUN (no_zebra_route_map_timer,
ZEBRA_STR
"Set route-map parameters\n"
"Reset delay-timer to default value, 30 secs\n"
- "0 means event-driven updates are disabled\n")
+ "0 means route-map changes are run immediately instead of delaying\n")
{
zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER);
@@ -1454,8 +1456,6 @@ static void zebra_rib_table_rm_update(const char *rmap)
struct vrf *vrf = NULL;
struct zebra_vrf *zvrf = NULL;
char *rmap_name;
- char afi_ip = 0;
- char afi_ipv6 = 0;
struct route_map *old = NULL;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
@@ -1486,16 +1486,12 @@ static void zebra_rib_table_rm_update(const char *rmap)
PROTO_RM_MAP(zvrf, AFI_IP, i));
/* There is single rib table for all protocols
*/
- if (afi_ip == 0) {
- table = zvrf->table[AFI_IP]
- [SAFI_UNICAST];
- if (table) {
-
- afi_ip = 1;
- rib_update_table(
- table,
- RIB_UPDATE_RMAP_CHANGE);
- }
+ table = zvrf->table[AFI_IP][SAFI_UNICAST];
+ if (table) {
+ rib_update_table(
+ table,
+ RIB_UPDATE_RMAP_CHANGE,
+ i);
}
}
rmap_name = PROTO_RM_NAME(zvrf, AFI_IP6, i);
@@ -1515,16 +1511,12 @@ static void zebra_rib_table_rm_update(const char *rmap)
PROTO_RM_MAP(zvrf, AFI_IP6, i));
/* There is single rib table for all protocols
*/
- if (afi_ipv6 == 0) {
- table = zvrf->table[AFI_IP6]
- [SAFI_UNICAST];
- if (table) {
-
- afi_ipv6 = 1;
- rib_update_table(
- table,
- RIB_UPDATE_RMAP_CHANGE);
- }
+ table = zvrf->table[AFI_IP6][SAFI_UNICAST];
+ if (table) {
+ rib_update_table(
+ table,
+ RIB_UPDATE_RMAP_CHANGE,
+ i);
}
}
}
@@ -1628,8 +1620,6 @@ static void zebra_route_map_process_update_cb(char *rmap_name)
static int zebra_route_map_update_timer(struct thread *thread)
{
- zebra_t_rmap_update = NULL;
-
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("Event driven route-map update triggered");
@@ -1654,8 +1644,8 @@ static void zebra_route_map_set_delay_timer(uint32_t value)
if (!value && zebra_t_rmap_update) {
/* Event driven route map updates is being disabled */
/* But there's a pending timer. Fire it off now */
- thread_cancel(&zebra_t_rmap_update);
- zebra_route_map_update_timer(zebra_t_rmap_update);
+ THREAD_OFF(zebra_t_rmap_update);
+ zebra_route_map_update_timer(NULL);
}
}
@@ -1664,20 +1654,12 @@ void zebra_routemap_finish(void)
/* Set zebra_rmap_update_timer to 0 so that it wont schedule again */
zebra_rmap_update_timer = 0;
/* Thread off if any scheduled already */
- thread_cancel(&zebra_t_rmap_update);
+ THREAD_OFF(zebra_t_rmap_update);
route_map_finish();
}
-void zebra_route_map_write_delay_timer(struct vty *vty)
-{
- if (vty && (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER))
- vty_out(vty, "zebra route-map delay-timer %d\n",
- zebra_rmap_update_timer);
- return;
-}
-
route_map_result_t
-zebra_route_map_check(int family, int rib_type, uint8_t instance,
+zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
const struct prefix *p, struct nexthop *nexthop,
struct zebra_vrf *zvrf, route_tag_t tag)
{
@@ -1788,12 +1770,11 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
static void zebra_route_map_mark_update(const char *rmap_name)
{
/* rmap_update_timer of 0 means don't do route updates */
- if (zebra_rmap_update_timer && !zebra_t_rmap_update) {
- zebra_t_rmap_update = NULL;
- thread_add_timer(zrouter.master, zebra_route_map_update_timer,
- NULL, zebra_rmap_update_timer,
- &zebra_t_rmap_update);
- }
+ if (zebra_rmap_update_timer)
+ THREAD_OFF(zebra_t_rmap_update);
+
+ thread_add_timer(zrouter.master, zebra_route_map_update_timer,
+ NULL, zebra_rmap_update_timer, &zebra_t_rmap_update);
}
static void zebra_route_map_add(const char *rmap_name)
@@ -1870,7 +1851,8 @@ void zebra_routemap_config_write_protocol(struct vty *vty,
vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any",
NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX));
- if (zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
+ if (zvrf_id(zvrf) == VRF_DEFAULT
+ && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER)
vty_out(vty, "zebra route-map delay-timer %d\n",
zebra_rmap_update_timer);
}
diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h
index 56e805ea03..c016d95875 100644
--- a/zebra/zebra_routemap.h
+++ b/zebra/zebra_routemap.h
@@ -36,15 +36,13 @@ extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
uint32_t table);
extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table);
-extern void zebra_route_map_write_delay_timer(struct vty *);
-
extern route_map_result_t
zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance,
const struct prefix *p,
struct nexthop *nexthop, vrf_id_t vrf_id,
route_tag_t tag, const char *rmap_name);
extern route_map_result_t
-zebra_route_map_check(int family, int rib_type, uint8_t instance,
+zebra_route_map_check(afi_t family, int rib_type, uint8_t instance,
const struct prefix *p, struct nexthop *nexthop,
struct zebra_vrf *zvrf, route_tag_t tag);
extern route_map_result_t
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 266050784a..f18d8fbb6d 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1331,7 +1331,7 @@ DEFUN (ip_nht_default_route,
zvrf->zebra_rnh_ip_default_route = 1;
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1653,7 +1653,7 @@ DEFUN (no_ip_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ip_default_route = 0;
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1673,7 +1673,7 @@ DEFUN (ipv6_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ipv6_default_route = 1;
- zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1695,7 +1695,7 @@ DEFUN (no_ipv6_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ipv6_default_route = 0;
- zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 28bed846cf..424c00d5eb 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -1992,7 +1992,10 @@ static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
}
/*
- * handle transition of vni from l2 to l3 and vice versa
+ * Handle transition of vni from l2 to l3 and vice versa.
+ * This function handles only the L2VNI add/delete part of
+ * the above transition.
+ * L3VNI add/delete is handled by the calling functions.
*/
static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
int add)
@@ -2033,11 +2036,71 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
return -1;
}
} else {
- /* TODO_MITESH: This needs to be thought through. We don't have
- * enough information at this point to reprogram the vni as
- * l2-vni. One way is to store the required info in l3-vni and
- * used it solely for this purpose
- */
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *ifp;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct interface *vlan_if;
+ bool found = false;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Adding L2-VNI %u - transition from L3-VNI",
+ vni);
+
+ /* Find VxLAN interface for this VNI. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ ifp = (struct interface *)rn->info;
+ if (!ifp)
+ continue;
+ zif = ifp->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+
+ vxl = &zif->l2info.vxl;
+ if (vxl->vni == vni) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_err(
+ "Adding L2-VNI - Failed to find VxLAN interface for VNI %u",
+ vni);
+ return -1;
+ }
+
+ /* Create VNI hash entry for L2VNI */
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn)
+ return 0;
+
+ zevpn = zebra_evpn_add(vni);
+ if (!zevpn) {
+ flog_err(EC_ZEBRA_VNI_ADD_FAILED,
+ "Adding L2-VNI - Failed to add VNI hash, VNI %u",
+ vni);
+
+ return -1;
+ }
+
+ /* Find bridge interface for the VNI */
+ vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if)
+ zevpn->vrf_id = vlan_if->vrf_id;
+
+ zevpn->vxlan_if = ifp;
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+
+ /* Inform BGP if the VNI is up and mapped to a bridge. */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if) {
+ zebra_evpn_send_add_to_client(zevpn);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+ }
}
return 0;
@@ -3270,7 +3333,7 @@ int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni)
zevpn = zebra_evpn_lookup(vni);
if (!zevpn) {
- zlog_warn("VNI %u does not exist\n", vni);
+ zlog_warn("VNI %u does not exist", vni);
return CMD_WARNING;
}
@@ -3678,13 +3741,13 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
zlog_debug(
- "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s-> L2-VNI %u",
+ "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, state, is_ext ? "ext-learned " : "",
is_router ? "router " : "",
local_inactive ? "local_inactive " : "",
- zevpn->vni);
+ dp_static ? "peer_sync " : "", zevpn->vni);
/* Is this about a local neighbor or a remote one? */
if (!is_ext)
@@ -4008,7 +4071,6 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
* 1. readd the remote MAC if we have it
* 2. local MAC with does ES may also need to be re-installed
*/
-static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac);
int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
@@ -4059,72 +4121,7 @@ int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr,
vni);
- zebra_vxlan_do_local_mac_del(zevpn, mac);
- }
-
- return 0;
-}
-
-static int zebra_vxlan_do_local_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
-{
- bool old_bgp_ready;
- bool new_bgp_ready;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
- &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
- listcount(mac->neigh_list));
-
- old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
- if (zebra_evpn_mac_is_static(mac)) {
- /* this is a synced entry and can only be removed when the
- * es-peers stop advertising it.
- */
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "re-add sync-mac vni %u mac %pEA es %s seq %d f 0x%x",
- zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags);
-
- /* 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);
- }
-
- /* re-install the entry in the kernel */
- zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */,
- __func__);
-
- return 0;
- }
-
- /* Update all the neigh entries associated with this mac */
- zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
-
- /* Remove MAC from BGP. */
- zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
- false /* force */);
-
- zebra_evpn_es_mac_deref_entry(mac);
-
- /*
- * If there are no neigh associated with the mac delete the mac
- * else mark it as AUTO for forward reference
- */
- if (!listcount(mac->neigh_list)) {
- zebra_evpn_mac_del(zevpn, mac);
- } else {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ return zebra_evpn_del_local_mac(zevpn, mac);
}
return 0;
@@ -4161,7 +4158,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
- return zebra_vxlan_do_local_mac_del(zevpn, mac);
+ return zebra_evpn_del_local_mac(zevpn, mac);
}
/*
@@ -5201,6 +5198,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
if (add) {
+ /* Remove L2VNI if present */
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
/* check if the vni is already present under zvrf */
@@ -5295,6 +5293,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
zvrf->l3vni = 0;
zl3vni_del(zl3vni);
+ /* Add L2VNI for this VNI */
zebra_vxlan_handle_vni_transition(zvrf, vni, add);
}
return 0;
@@ -6050,9 +6049,9 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
}
-static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *backet, void *arg)
+static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg)
{
- zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)bucket->data;
/* increment the ref count against (*,G) to prevent them from being
* deleted
@@ -6061,9 +6060,9 @@ static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *backet, void *arg)
++vxlan_sg->ref_cnt;
}
-static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *backet, void *arg)
+static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *bucket, void *arg)
{
- zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)bucket->data;
/* decrement the dummy ref count against (*,G) to delete them */
if (vxlan_sg->sg.src.s_addr == INADDR_ANY) {
@@ -6074,9 +6073,9 @@ static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *backet, void *arg)
}
}
-static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg)
+static void zebra_vxlan_sg_cleanup(struct hash_bucket *bucket, void *arg)
{
- zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)bucket->data;
zebra_vxlan_sg_del(vxlan_sg);
}
@@ -6094,9 +6093,9 @@ static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf)
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_post_cleanup, NULL);
}
-static void zebra_vxlan_sg_replay_send(struct hash_bucket *backet, void *arg)
+static void zebra_vxlan_sg_replay_send(struct hash_bucket *bucket, void *arg)
{
- zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)bucket->data;
zebra_vxlan_sg_send(vxlan_sg->zvrf, &vxlan_sg->sg,
vxlan_sg->sg_str, ZEBRA_VXLAN_SG_ADD);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 484d94fac8..6c5eebe6fe 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -55,6 +55,7 @@
#include "lib/frr_pthread.h" /* for frr_pthread_new, frr_pthread_stop... */
#include "lib/frratomic.h" /* for atomic_load_explicit, atomic_stor... */
#include "lib/lib_errors.h" /* for generic ferr ids */
+#include "lib/printfrr.h" /* for string functions */
#include "zebra/debug.h" /* for various debugging macros */
#include "zebra/rib.h" /* for rib_score_proto */
@@ -1186,6 +1187,7 @@ static void zebra_show_stale_client_detail(struct vty *vty,
static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
{
+ char client_string[80];
char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
char wbuf[ZEBRA_TIME_BUF];
time_t connect_time, last_read_time, last_write_time;
@@ -1197,8 +1199,15 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
last_write_time = (time_t)atomic_load_explicit(&client->last_write_time,
memory_order_relaxed);
- vty_out(vty, "%-10s%12s %12s%12s%8d/%-8d%8d/%-8d\n",
- zebra_route_string(client->proto),
+ if (client->instance || client->session_id)
+ snprintfrr(client_string, sizeof(client_string), "%s[%u:%u]",
+ zebra_route_string(client->proto), client->instance,
+ client->session_id);
+ else
+ snprintfrr(client_string, sizeof(client_string), "%s",
+ zebra_route_string(client->proto));
+
+ vty_out(vty, "%-10s%12s %12s%12s%8d/%-8d%8d/%-8d\n", client_string,
zserv_time_buf(&connect_time, cbuf, ZEBRA_TIME_BUF),
zserv_time_buf(&last_read_time, rbuf, ZEBRA_TIME_BUF),
zserv_time_buf(&last_write_time, wbuf, ZEBRA_TIME_BUF),