summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs1
-rw-r--r--bfdd/bfd.c152
-rw-r--r--bfdd/bfd.h25
-rw-r--r--bfdd/bfd_packet.c39
-rw-r--r--bfdd/bfdctl.h4
-rw-r--r--bfdd/bfdd_cli.c79
-rw-r--r--bfdd/bfdd_nb.c37
-rw-r--r--bfdd/bfdd_nb.h13
-rw-r--r--bfdd/bfdd_nb_config.c153
-rw-r--r--bfdd/bfdd_vty.c10
-rw-r--r--bfdd/ptm_adapter.c14
-rw-r--r--bgpd/bgp_attr.c2
-rw-r--r--bgpd/bgp_evpn.c69
-rw-r--r--bgpd/bgp_packet.c4
-rw-r--r--bgpd/bgp_updgrp_packet.c4
-rw-r--r--bgpd/bgp_vty.c4
-rw-r--r--bgpd/bgpd.c3
-rw-r--r--doc/user/bfd.rst27
-rw-r--r--doc/user/ospfd.rst11
-rw-r--r--grpc/frr-northbound.proto36
-rw-r--r--isisd/fabricd.c2
-rw-r--r--isisd/isis_adjacency.c43
-rw-r--r--isisd/isis_adjacency.h4
-rw-r--r--isisd/isis_bfd.c8
-rw-r--r--isisd/isis_circuit.c21
-rw-r--r--isisd/isis_circuit.h45
-rw-r--r--isisd/isis_cli.c55
-rw-r--r--isisd/isis_csm.c30
-rw-r--r--isisd/isis_dr.c8
-rw-r--r--isisd/isis_dynhn.c18
-rw-r--r--isisd/isis_dynhn.h4
-rw-r--r--isisd/isis_lsp.c58
-rw-r--r--isisd/isis_lsp.h12
-rw-r--r--isisd/isis_main.c6
-rw-r--r--isisd/isis_misc.c7
-rw-r--r--isisd/isis_misc.h2
-rw-r--r--isisd/isis_nb_config.c48
-rw-r--r--isisd/isis_pdu.c43
-rw-r--r--isisd/isis_redist.c12
-rw-r--r--isisd/isis_redist.h9
-rw-r--r--isisd/isis_spf.c118
-rw-r--r--isisd/isis_sr.c103
-rw-r--r--isisd/isis_te.c101
-rw-r--r--isisd/isis_vty_fabricd.c33
-rw-r--r--isisd/isis_zebra.c18
-rw-r--r--isisd/isisd.c911
-rw-r--r--isisd/isisd.h43
-rw-r--r--lib/filter_nb.c38
-rw-r--r--lib/linklist.c17
-rw-r--r--lib/linklist.h13
-rw-r--r--lib/nexthop_group.c2
-rw-r--r--lib/northbound.c26
-rw-r--r--lib/northbound.h18
-rw-r--r--lib/northbound_cli.c17
-rw-r--r--lib/northbound_confd.c7
-rw-r--r--lib/northbound_grpc.cpp24
-rw-r--r--lib/northbound_sysrepo.c323
-rw-r--r--lib/stream.c24
-rw-r--r--lib/stream.h14
-rw-r--r--lib/yang.h1
-rw-r--r--ospfd/ospf_packet.c2
-rw-r--r--ospfd/ospf_vty.c37
-rw-r--r--ospfd/ospfd.c2
-rw-r--r--ospfd/ospfd.h4
-rw-r--r--python/makevars.py2
-rw-r--r--staticd/static_vty.c5
-rw-r--r--tests/isisd/test_isis_lspdb.c1
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/bfdd.conf2
-rw-r--r--tests/topotests/bfd-isis-topo1/rt2/bfdd.conf1
-rw-r--r--tests/topotests/bfd-isis-topo1/rt3/bfdd.conf1
-rw-r--r--tests/topotests/bfd-topo3/__init__.py0
-rw-r--r--tests/topotests/bfd-topo3/r1/bfd-peers.json68
-rw-r--r--tests/topotests/bfd-topo3/r1/bfdd.conf17
-rw-r--r--tests/topotests/bfd-topo3/r1/bgpd.conf20
-rw-r--r--tests/topotests/bfd-topo3/r1/zebra.conf10
-rw-r--r--tests/topotests/bfd-topo3/r2/bfd-peers.json46
-rw-r--r--tests/topotests/bfd-topo3/r2/bfdd.conf15
-rw-r--r--tests/topotests/bfd-topo3/r2/bgpd.conf15
-rw-r--r--tests/topotests/bfd-topo3/r2/zebra.conf14
-rw-r--r--tests/topotests/bfd-topo3/r3/bfd-peers.json68
-rw-r--r--tests/topotests/bfd-topo3/r3/bfdd.conf11
-rw-r--r--tests/topotests/bfd-topo3/r3/bgpd.conf19
-rw-r--r--tests/topotests/bfd-topo3/r3/zebra.conf14
-rw-r--r--tests/topotests/bfd-topo3/r4/bfd-peers.json46
-rw-r--r--tests/topotests/bfd-topo3/r4/bfdd.conf16
-rw-r--r--tests/topotests/bfd-topo3/r4/bgpd.conf16
-rw-r--r--tests/topotests/bfd-topo3/r4/zebra.conf10
-rw-r--r--tests/topotests/bfd-topo3/test_bfd_topo3.dot73
-rw-r--r--tests/topotests/bfd-topo3/test_bfd_topo3.jpgbin0 -> 34705 bytes
-rw-r--r--tests/topotests/bfd-topo3/test_bfd_topo3.py191
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE1/evpn.vni.json3
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE1/zebra.conf2
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE2/evpn.vni.json3
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE2/zebra.conf2
-rwxr-xr-xtests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py119
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/isisd.conf1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/isisd.conf1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/isisd.conf1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/isisd.conf1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/isisd.conf1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/isisd.conf1
-rwxr-xr-xtools/frr-reload.py58
-rw-r--r--yang/frr-bfdd.yang21
-rw-r--r--yang/frr-bgp-bmp.yang203
-rw-r--r--yang/frr-bgp-common-multiprotocol.yang209
-rw-r--r--yang/frr-bgp-common-structure.yang807
-rw-r--r--yang/frr-bgp-common.yang1108
-rw-r--r--yang/frr-bgp-neighbor.yang137
-rw-r--r--yang/frr-bgp-peer-group.yang89
-rw-r--r--yang/frr-bgp-rpki.yang209
-rw-r--r--yang/frr-bgp-types.yang154
-rw-r--r--yang/frr-bgp.yang1239
-rw-r--r--yang/frr-deviations-bgp-datacenter.yang106
-rw-r--r--yang/frr-ospfd.yang7
-rw-r--r--yang/frr-routing.yang70
-rw-r--r--yang/ietf/ietf-bgp-types.yang525
-rw-r--r--zebra/dplane_fpm_nl.c2
-rw-r--r--zebra/redistribute.c16
-rw-r--r--zebra/subdir.am7
-rw-r--r--zebra/zapi_msg.c19
-rw-r--r--zebra/zebra_dplane.c19
-rw-r--r--zebra/zebra_dplane.h3
-rw-r--r--zebra/zebra_evpn.c1448
-rw-r--r--zebra/zebra_evpn.h208
-rw-r--r--zebra/zebra_evpn_mac.c2231
-rw-r--r--zebra/zebra_evpn_mac.h263
-rw-r--r--zebra/zebra_evpn_mh.c264
-rw-r--r--zebra/zebra_evpn_mh.h28
-rw-r--r--zebra/zebra_evpn_neigh.c2453
-rw-r--r--zebra/zebra_evpn_neigh.h294
-rw-r--r--zebra/zebra_evpn_vxlan.h71
-rw-r--r--zebra/zebra_rib.c178
-rw-r--r--zebra/zebra_vrf.h4
-rw-r--r--zebra/zebra_vxlan.c7407
-rw-r--r--zebra/zebra_vxlan_private.h332
135 files changed, 15599 insertions, 8424 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000..e8a364050a
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1 @@
+d62a17aedeb0eebdba98238874bb13d62c48dbf9
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index caa80ed51d..c16912060c 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -88,6 +88,8 @@ static void bfd_profile_set_default(struct bfd_profile *bp)
bp->admin_shutdown = true;
bp->detection_multiplier = BFD_DEFDETECTMULT;
bp->echo_mode = false;
+ bp->passive = false;
+ bp->minimum_ttl = BFD_DEF_MHOP_TTL;
bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO;
bp->min_rx = BFD_DEFREQUIREDMINRX;
bp->min_tx = BFD_DEFDESIREDMINTX;
@@ -124,53 +126,12 @@ void bfd_profile_free(struct bfd_profile *bp)
XFREE(MTYPE_BFDD_PROFILE, bp);
}
-/**
- * Removes a profile and tests whether it needs to apply the changes or not.
- *
- * \param bs the BFD session.
- * \param apply whether or not to apply configurations immediately.
- */
-static void _bfd_profile_remove(struct bfd_session *bs, bool apply)
-{
- struct bfd_profile *bp;
-
- /* No profile applied, nothing to do. */
- bp = bs->profile;
- if (bp == NULL)
- return;
-
- /* Remove the profile association. */
- bs->profile = NULL;
-
- /* Set multiplier to the default. */
- bs->detect_mult = bs->peer_profile.detection_multiplier;
-
- /* Set timers back to user configuration. */
- bs->timers.desired_min_tx = bs->peer_profile.min_tx;
- bs->timers.required_min_rx = bs->peer_profile.min_rx;
-
- /* We can only apply echo options on single hop sessions. */
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
- /* Set default echo timer. */
- bs->timers.required_min_echo = bs->peer_profile.min_echo_rx;
-
- /* Default is no echo mode. */
- if (apply)
- bfd_set_echo(bs, bs->peer_profile.echo_mode);
- }
-
- if (apply)
- bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
-}
-
void bfd_profile_apply(const char *profname, struct bfd_session *bs)
{
struct bfd_profile *bp;
/* Remove previous profile if any. */
if (bs->profile_name) {
- _bfd_profile_remove(bs, false);
-
/* We are changing profiles. */
if (strcmp(bs->profile_name, profname)) {
XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
@@ -182,12 +143,23 @@ void bfd_profile_apply(const char *profname, struct bfd_session *bs)
/* Look up new profile to apply. */
bp = bfd_profile_lookup(profname);
- if (bp == NULL)
- return;
/* Point to profile if it exists. */
bs->profile = bp;
+ /* Apply configuration. */
+ bfd_session_apply(bs);
+}
+
+void bfd_session_apply(struct bfd_session *bs)
+{
+ struct bfd_profile *bp;
+ uint32_t min_tx = bs->timers.desired_min_tx;
+ uint32_t min_rx = bs->timers.required_min_rx;
+
+ /* Pick the source of configuration. */
+ bp = bs->profile ? bs->profile : &bs->peer_profile;
+
/* Set multiplier if not the default. */
if (bs->peer_profile.detection_multiplier == BFD_DEFDETECTMULT)
bs->detect_mult = bp->detection_multiplier;
@@ -219,21 +191,40 @@ void bfd_profile_apply(const char *profname, struct bfd_session *bs)
bfd_set_echo(bs, bp->echo_mode);
else
bfd_set_echo(bs, bs->peer_profile.echo_mode);
+ } else {
+ /* Configure the TTL packet filter. */
+ if (bs->peer_profile.minimum_ttl == BFD_DEF_MHOP_TTL)
+ bs->mh_ttl = bp->minimum_ttl;
+ else
+ bs->mh_ttl = bs->peer_profile.minimum_ttl;
}
+ /* Toggle 'passive-mode' if default value. */
+ if (bs->peer_profile.passive == false)
+ bfd_set_passive_mode(bs, bp->passive);
+ else
+ bfd_set_passive_mode(bs, bs->peer_profile.passive);
+
/* Toggle 'no shutdown' if default value. */
if (bs->peer_profile.admin_shutdown)
bfd_set_shutdown(bs, bp->admin_shutdown);
else
bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
+
+ /* If session interval changed negotiate new timers. */
+ if (bs->ses_state == PTM_BFD_UP
+ && (bs->timers.desired_min_tx != min_tx
+ || bs->timers.required_min_rx != min_rx))
+ bfd_set_polling(bs);
}
void bfd_profile_remove(struct bfd_session *bs)
{
/* Remove any previous set profile name. */
XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
+ bs->profile = NULL;
- _bfd_profile_remove(bs, true);
+ bfd_session_apply(bs);
}
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
@@ -374,8 +365,12 @@ int bfd_session_enable(struct bfd_session *bs)
* protocol.
*/
bs->sock = psock;
- bfd_recvtimer_update(bs);
- ptm_bfd_start_xmt_timer(bs, false);
+
+ /* Only start timers if we are using active mode. */
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE) == 0) {
+ bfd_recvtimer_update(bs);
+ ptm_bfd_start_xmt_timer(bs, false);
+ }
return 0;
}
@@ -536,6 +531,12 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
ptm_bfd_echo_stop(bfd);
+ /* Stop attempting to transmit or expect control packets if passive. */
+ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_PASSIVE)) {
+ bfd_recvtimer_delete(bfd);
+ bfd_xmttimer_delete(bfd);
+ }
+
if (old_state != bfd->ses_state) {
bfd->stats.session_down++;
if (bglobal.debug_peer_event)
@@ -758,6 +759,11 @@ static void _bfd_session_update(struct bfd_session *bs,
else
UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
+ if (bpc->bpc_has_minimum_ttl) {
+ bs->mh_ttl = bpc->bpc_minimum_ttl;
+ bs->peer_profile.minimum_ttl = bpc->bpc_minimum_ttl;
+ }
+
bs->peer_profile.echo_mode = bpc->bpc_echo;
bfd_set_echo(bs, bpc->bpc_echo);
@@ -766,6 +772,7 @@ static void _bfd_session_update(struct bfd_session *bs,
* the session is disabled.
*/
bs->peer_profile.admin_shutdown = bpc->bpc_shutdown;
+ bfd_set_passive_mode(bs, bpc->bpc_passive);
bfd_set_shutdown(bs, bpc->bpc_shutdown);
/*
@@ -986,6 +993,10 @@ static void bs_down_handler(struct bfd_session *bs, int nstate)
* bring it up.
*/
bs->ses_state = PTM_BFD_INIT;
+
+ /* Answer peer with INIT immediately in passive mode. */
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE))
+ ptm_bfd_snd(bs, 0);
break;
case PTM_BFD_INIT:
@@ -1312,9 +1323,39 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
bs->ses_state = PTM_BFD_DOWN;
control_notify(bs, bs->ses_state);
- /* Enable all timers. */
- bfd_recvtimer_update(bs);
+ /* Enable timers if non passive, otherwise stop them. */
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) {
+ bfd_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ } else {
+ bfd_recvtimer_update(bs);
+ bfd_xmttimer_update(bs, bs->xmt_TO);
+ }
+ }
+}
+
+void bfd_set_passive_mode(struct bfd_session *bs, bool passive)
+{
+ if (passive) {
+ SET_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE);
+
+ /* Session is already up and running, nothing to do now. */
+ if (bs->ses_state != PTM_BFD_DOWN)
+ return;
+
+ /* Lets disable the timers since we are now passive. */
+ bfd_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ } else {
+ UNSET_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE);
+
+ /* Session is already up and running, nothing to do now. */
+ if (bs->ses_state != PTM_BFD_DOWN)
+ return;
+
+ /* Session is down, let it attempt to start the connection. */
bfd_xmttimer_update(bs, bs->xmt_TO);
+ bfd_recvtimer_update(bs);
}
}
@@ -2011,16 +2052,16 @@ static int bfd_vrf_enable(struct vrf *vrf)
if (!bvrf->bg_ev[1])
thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop,
&bvrf->bg_ev[1]);
- if (!bvrf->bg_ev[2])
+ if (!bvrf->bg_ev[2] && bvrf->bg_shop6 != -1)
thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6,
&bvrf->bg_ev[2]);
- if (!bvrf->bg_ev[3])
+ if (!bvrf->bg_ev[3] && bvrf->bg_mhop6 != -1)
thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6,
&bvrf->bg_ev[3]);
if (!bvrf->bg_ev[4])
thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo,
&bvrf->bg_ev[4]);
- if (!bvrf->bg_ev[5])
+ if (!bvrf->bg_ev[5] && bvrf->bg_echov6 != -1)
thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6,
&bvrf->bg_ev[5]);
}
@@ -2059,10 +2100,13 @@ static int bfd_vrf_disable(struct vrf *vrf)
socket_close(&bvrf->bg_echo);
socket_close(&bvrf->bg_shop);
socket_close(&bvrf->bg_mhop);
- socket_close(&bvrf->bg_shop6);
- socket_close(&bvrf->bg_mhop6);
+ if (bvrf->bg_shop6 != -1)
+ socket_close(&bvrf->bg_shop6);
+ if (bvrf->bg_mhop6 != -1)
+ socket_close(&bvrf->bg_mhop6);
socket_close(&bvrf->bg_echo);
- socket_close(&bvrf->bg_echov6);
+ if (bvrf->bg_echov6 != -1)
+ socket_close(&bvrf->bg_echov6);
/* free context */
XFREE(MTYPE_BFDD_VRF, bvrf);
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 492334a670..af3f92d6a8 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -170,6 +170,7 @@ enum bfd_session_flags {
BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */
BFD_SESS_FLAG_CONFIG = 1 << 8, /* Session configured with bfd NB API */
BFD_SESS_FLAG_CBIT = 1 << 9, /* CBIT is set */
+ BFD_SESS_FLAG_PASSIVE = 1 << 10, /* Passive mode */
};
/* BFD session hash keys */
@@ -207,6 +208,10 @@ struct bfd_profile {
uint32_t min_rx;
/** Administrative state. */
bool admin_shutdown;
+ /** Passive mode. */
+ bool passive;
+ /** Minimum expected TTL value. */
+ uint8_t minimum_ttl;
/** Echo mode (only applies to single hop). */
bool echo_mode;
@@ -328,7 +333,8 @@ TAILQ_HEAD(obslist, bfd_session_observer);
#define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */
#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */
#define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */
-#define BFD_DEF_MHOP_TTL 5
+/** Minimum multi hop TTL. */
+#define BFD_DEF_MHOP_TTL 254
#define BFD_PKT_LEN 24 /* Length of control packet */
#define BFD_TTL_VAL 255
#define BFD_RCV_TTL_VAL 1
@@ -607,6 +613,23 @@ void bfd_set_echo(struct bfd_session *bs, bool echo);
*/
void bfd_set_shutdown(struct bfd_session *bs, bool shutdown);
+/**
+ * Set the BFD session passive mode.
+ *
+ * \param bs the BFD session.
+ * \param passive the passive mode.
+ */
+void bfd_set_passive_mode(struct bfd_session *bs, bool passive);
+
+/**
+ * Picks the BFD session configuration from the appropriated source:
+ * if using the default peer configuration prefer profile (if it exists),
+ * otherwise use session.
+ *
+ * \param bs the BFD session.
+ */
+void bfd_session_apply(struct bfd_session *bs);
+
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 68bdd89bb7..5cc47d5a44 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -147,6 +147,8 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
bep.my_discr = htonl(bfd->discrs.my_discr);
if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
+ if (bvrf->bg_echov6 == -1)
+ return;
sd = bvrf->bg_echov6;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
@@ -577,7 +579,7 @@ int bfd_recv_cb(struct thread *t)
return 0;
}
- /* Validate packet TTL. */
+ /* Validate single hop packet TTL. */
if ((!is_mhop) && (ttl != BFD_TTL_VAL)) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"invalid TTL: %d expected %d", ttl, BFD_TTL_VAL);
@@ -630,10 +632,10 @@ int bfd_recv_cb(struct thread *t)
* Single hop: set local address that received the packet.
*/
if (is_mhop) {
- if ((BFD_TTL_VAL - bfd->mh_ttl) > BFD_TTL_VAL) {
+ if (ttl < bfd->mh_ttl) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"exceeded max hop count (expected %d, got %d)",
- bfd->mh_ttl, BFD_TTL_VAL);
+ bfd->mh_ttl, ttl);
return 0;
}
} else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
@@ -1145,8 +1147,14 @@ int bp_udp6_shop(const struct vrf *vrf)
sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id,
vrf->name);
}
- if (sd == -1)
- zlog_fatal("udp6-shop: socket: %s", strerror(errno));
+ if (sd == -1) {
+ if (errno != EAFNOSUPPORT)
+ zlog_fatal("udp6-shop: socket: %s", strerror(errno));
+ else
+ zlog_warn("udp6-shop: V6 is not supported, continuing");
+
+ return -1;
+ }
bp_set_ipv6opts(sd);
bp_bind_ipv6(sd, BFD_DEFDESTPORT);
@@ -1162,8 +1170,14 @@ int bp_udp6_mhop(const struct vrf *vrf)
sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id,
vrf->name);
}
- if (sd == -1)
- zlog_fatal("udp6-mhop: socket: %s", strerror(errno));
+ if (sd == -1) {
+ if (errno != EAFNOSUPPORT)
+ zlog_fatal("udp6-mhop: socket: %s", strerror(errno));
+ else
+ zlog_warn("udp6-mhop: V6 is not supported, continuing");
+
+ return -1;
+ }
bp_set_ipv6opts(sd);
bp_bind_ipv6(sd, BFD_DEF_MHOP_DEST_PORT);
@@ -1194,8 +1208,15 @@ int bp_echov6_socket(const struct vrf *vrf)
frr_with_privs(&bglobal.bfdd_privs) {
s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name);
}
- if (s == -1)
- zlog_fatal("echov6-socket: socket: %s", strerror(errno));
+ if (s == -1) {
+ if (errno != EAFNOSUPPORT)
+ zlog_fatal("echov6-socket: socket: %s",
+ strerror(errno));
+ else
+ zlog_warn("echov6-socket: V6 is not supported, continuing");
+
+ return -1;
+ }
bp_set_ipv6opts(s);
bp_bind_ipv6(s, BFD_DEF_ECHO_PORT);
diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h
index 95cfcb1105..e1cff9a31c 100644
--- a/bfdd/bfdctl.h
+++ b/bfdd/bfdctl.h
@@ -84,11 +84,15 @@ struct bfd_peer_cfg {
bool bpc_has_echointerval;
uint64_t bpc_echointerval;
+ bool bpc_has_minimum_ttl;
+ uint8_t bpc_minimum_ttl;
+
bool bpc_echo;
bool bpc_createonly;
bool bpc_shutdown;
bool bpc_cbit;
+ bool bpc_passive;
bool bpc_has_profile;
char bpc_profile[64];
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 0dd021d475..058ce7d1f2 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -266,6 +266,63 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
}
DEFPY_YANG(
+ bfd_peer_passive, bfd_peer_passive_cmd,
+ "[no] passive-mode",
+ NO_STR
+ "Don't attempt to start sessions\n")
+{
+ nb_cli_enqueue_change(vty, "./passive-mode", NB_OP_MODIFY,
+ no ? "false" : "true");
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (show_defaults)
+ vty_out(vty, " no passive-mode\n");
+ else
+ vty_out(vty, " %spassive-mode\n",
+ yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
+}
+
+DEFPY_YANG(
+ bfd_peer_minimum_ttl, bfd_peer_minimum_ttl_cmd,
+ "[no] minimum-ttl (1-254)$ttl",
+ NO_STR
+ "Expect packets with at least this TTL\n"
+ "Minimum TTL expected\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY,
+ NULL);
+ else
+ nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_MODIFY,
+ ttl_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(
+ no_bfd_peer_minimum_ttl, no_bfd_peer_minimum_ttl_cmd,
+ "no minimum-ttl",
+ NO_STR
+ "Expect packets with at least this TTL\n")
+{
+ nb_cli_enqueue_change(vty, "./minimum-ttl", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (show_defaults)
+ vty_out(vty, " minimum-ttl 254\n");
+ else
+ vty_out(vty, " minimum-ttl %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+DEFPY_YANG(
bfd_peer_mult, bfd_peer_mult_cmd,
"detect-multiplier (2-255)$multiplier",
"Configure peer detection multiplier\n"
@@ -462,6 +519,22 @@ ALIAS_YANG(bfd_peer_shutdown, bfd_profile_shutdown_cmd,
NO_STR
"Disable BFD peer\n")
+ALIAS_YANG(bfd_peer_passive, bfd_profile_passive_cmd,
+ "[no] passive-mode",
+ NO_STR
+ "Don't attempt to start sessions\n")
+
+ALIAS_YANG(bfd_peer_minimum_ttl, bfd_profile_minimum_ttl_cmd,
+ "[no] minimum-ttl (1-254)$ttl",
+ NO_STR
+ "Expect packets with at least this TTL\n"
+ "Minimum TTL expected\n")
+
+ALIAS_YANG(no_bfd_peer_minimum_ttl, no_bfd_profile_minimum_ttl_cmd,
+ "no minimum-ttl",
+ NO_STR
+ "Expect packets with at least this TTL\n")
+
ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd,
"[no] echo-mode",
NO_STR
@@ -530,6 +603,9 @@ bfdd_cli_init(void)
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd);
+ install_element(BFD_PEER_NODE, &no_bfd_peer_minimum_ttl_cmd);
/* Profile commands. */
cmd_variable_handler_register(bfd_vars);
@@ -546,4 +622,7 @@ bfdd_cli_init(void)
install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd);
+ install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd);
}
diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c
index 2ff99ca608..64ba3cf811 100644
--- a/bfdd/bfdd_nb.c
+++ b/bfdd/bfdd_nb.c
@@ -78,6 +78,21 @@ const struct frr_yang_module_info frr_bfdd_info = {
}
},
{
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/passive-mode",
+ .cbs = {
+ .modify = bfdd_bfd_profile_passive_mode_modify,
+ .cli_show = bfd_cli_show_passive,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/minimum-ttl",
+ .cbs = {
+ .modify = bfdd_bfd_profile_minimum_ttl_modify,
+ .destroy = bfdd_bfd_profile_minimum_ttl_destroy,
+ .cli_show = bfd_cli_show_minimum_ttl,
+ }
+ },
+ {
.xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode",
.cbs = {
.modify = bfdd_bfd_profile_echo_mode_modify,
@@ -147,6 +162,13 @@ const struct frr_yang_module_info frr_bfdd_info = {
}
},
{
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/passive-mode",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_passive_mode_modify,
+ .cli_show = bfd_cli_show_passive,
+ }
+ },
+ {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode",
.cbs = {
.modify = bfdd_bfd_sessions_single_hop_echo_mode_modify,
@@ -329,6 +351,21 @@ const struct frr_yang_module_info frr_bfdd_info = {
}
},
{
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/passive-mode",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_passive_mode_modify,
+ .cli_show = bfd_cli_show_passive,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_multi_hop_minimum_ttl_modify,
+ .destroy = bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy,
+ .cli_show = bfd_cli_show_minimum_ttl,
+ }
+ },
+ {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator",
.cbs = {
.get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h
index a379c2135e..fbd557b6b1 100644
--- a/bfdd/bfdd_nb.h
+++ b/bfdd/bfdd_nb.h
@@ -37,6 +37,9 @@ int bfdd_bfd_profile_desired_transmission_interval_modify(
int bfdd_bfd_profile_required_receive_interval_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args);
int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
struct nb_cb_modify_args *args);
@@ -62,6 +65,8 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_administrative_down_modify(
struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_single_hop_passive_mode_modify(
+ struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_echo_mode_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
@@ -131,6 +136,10 @@ int bfdd_bfd_sessions_multi_hop_required_receive_interval_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_multi_hop_administrative_down_modify(
struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify(
+ struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy(
+ struct nb_cb_destroy_args *args);
struct yang_data *
bfdd_bfd_sessions_multi_hop_stats_local_discriminator_get_elem(
struct nb_cb_get_elem_args *args);
@@ -206,5 +215,9 @@ void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
#endif /* _FRR_BFDD_NB_H_ */
diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c
index 970b5f2d65..0046bc625b 100644
--- a/bfdd/bfdd_nb_config.c
+++ b/bfdd/bfdd_nb_config.c
@@ -360,6 +360,64 @@ int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args)
}
/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/passive-mode
+ */
+int bfdd_bfd_profile_passive_mode_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ bool passive;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ passive = yang_dnode_get_bool(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->passive == passive)
+ return NB_OK;
+
+ bp->passive = passive;
+ bfd_profile_update(bp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/minimum-ttl
+ */
+int bfdd_bfd_profile_minimum_ttl_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ uint8_t minimum_ttl;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->minimum_ttl == minimum_ttl)
+ return NB_OK;
+
+ bp->minimum_ttl = minimum_ttl;
+ bfd_profile_update(bp);
+
+ return NB_OK;
+}
+
+int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args)
+{
+ struct bfd_profile *bp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ bp->minimum_ttl = BFD_DEF_MHOP_TTL;
+ bfd_profile_update(bp);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode
*/
int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args)
@@ -497,8 +555,8 @@ int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
case NB_EV_APPLY:
bs = nb_running_get_entry(args->dnode, NULL, true);
- bs->detect_mult = detection_multiplier;
bs->peer_profile.detection_multiplier = detection_multiplier;
+ bfd_session_apply(bs);
break;
case NB_EV_ABORT:
@@ -533,9 +591,8 @@ int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
if (tx_interval == bs->timers.desired_min_tx)
return NB_OK;
- bs->timers.desired_min_tx = tx_interval;
bs->peer_profile.min_tx = tx_interval;
- bfd_set_polling(bs);
+ bfd_session_apply(bs);
break;
case NB_EV_ABORT:
@@ -570,9 +627,8 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
if (rx_interval == bs->timers.required_min_rx)
return NB_OK;
- bs->timers.required_min_rx = rx_interval;
bs->peer_profile.min_rx = rx_interval;
- bfd_set_polling(bs);
+ bfd_session_apply(bs);
break;
case NB_EV_ABORT:
@@ -606,7 +662,37 @@ int bfdd_bfd_sessions_single_hop_administrative_down_modify(
bs = nb_running_get_entry(args->dnode, NULL, true);
bs->peer_profile.admin_shutdown = shutdown;
- bfd_set_shutdown(bs, shutdown);
+ bfd_session_apply(bs);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/passive-mode
+ */
+int bfdd_bfd_sessions_single_hop_passive_mode_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct bfd_session *bs;
+ bool passive;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ break;
+
+ case NB_EV_ABORT:
+ return NB_OK;
+ }
+
+ passive = yang_dnode_get_bool(args->dnode, NULL);
+
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ bs->peer_profile.passive = passive;
+ bfd_session_apply(bs);
return NB_OK;
}
@@ -634,7 +720,7 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify(
bs = nb_running_get_entry(args->dnode, NULL, true);
bs->peer_profile.echo_mode = echo;
- bfd_set_echo(bs, echo);
+ bfd_session_apply(bs);
return NB_OK;
}
@@ -664,8 +750,8 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
if (echo_interval == bs->timers.required_min_echo)
return NB_OK;
- bs->timers.required_min_echo = echo_interval;
bs->peer_profile.min_echo_rx = echo_interval;
+ bfd_session_apply(bs);
break;
case NB_EV_ABORT:
@@ -689,3 +775,54 @@ int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args)
{
return bfd_session_destroy(args->event, args->dnode, true);
}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop/minimum-ttl
+ */
+int bfdd_bfd_sessions_multi_hop_minimum_ttl_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct bfd_session *bs;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ break;
+
+ case NB_EV_ABORT:
+ return NB_OK;
+ }
+
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ bs->peer_profile.minimum_ttl = yang_dnode_get_uint8(args->dnode, NULL);
+ bfd_session_apply(bs);
+
+ return NB_OK;
+}
+
+int bfdd_bfd_sessions_multi_hop_minimum_ttl_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct bfd_session *bs;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ break;
+
+ case NB_EV_ABORT:
+ return NB_OK;
+ }
+
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ bs->peer_profile.minimum_ttl = BFD_DEF_MHOP_TTL;
+ bfd_session_apply(bs);
+
+ return NB_OK;
+}
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 8318ea9665..a3f1638e5f 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -111,6 +111,12 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE))
+ vty_out(vty, "\t\tPassive mode\n");
+ else
+ vty_out(vty, "\t\tActive mode\n");
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ vty_out(vty, "\t\tMinimum TTL: %d\n", bs->mh_ttl);
vty_out(vty, "\t\tStatus: ");
switch (bs->ses_state) {
@@ -203,6 +209,10 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
json_object_int_add(jo, "id", bs->discrs.my_discr);
json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
+ json_object_boolean_add(jo, "passive-mode",
+ CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE));
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ json_object_int_add(jo, "minimum-ttl", bs->mh_ttl);
switch (bs->ses_state) {
case PTM_BFD_ADM_DOWN:
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 8134807a14..48e55bce37 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -303,7 +303,6 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
struct bfd_peer_cfg *bpc, struct ptm_client **pc)
{
uint32_t pid;
- uint8_t ttl __attribute__((unused));
size_t ifnamelen;
/*
@@ -375,7 +374,18 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
if (bpc->bpc_mhop) {
/* Read multihop source address and TTL. */
_ptm_msg_read_address(msg, &bpc->bpc_local);
- STREAM_GETC(msg, ttl);
+ STREAM_GETC(msg, bpc->bpc_minimum_ttl);
+ if (bpc->bpc_minimum_ttl >= BFD_TTL_VAL
+ || bpc->bpc_minimum_ttl == 0) {
+ zlog_warn("%s: received invalid TTL configuration %d",
+ __func__, bpc->bpc_has_minimum_ttl);
+ bpc->bpc_minimum_ttl = BFD_DEF_MHOP_TTL;
+ bpc->bpc_has_minimum_ttl = false;
+ } else {
+ bpc->bpc_minimum_ttl =
+ (BFD_TTL_VAL + 1) - bpc->bpc_minimum_ttl;
+ bpc->bpc_has_minimum_ttl = true;
+ }
} else {
/* If target is IPv6, then we must obtain local address. */
if (bpc->bpc_ipv4 == false)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 27be7787f3..2c7091f2e4 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1161,7 +1161,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
if (bgp_debug_update(peer, NULL, NULL, 1)) {
char attr_str[BUFSIZ] = {0};
- bgp_dump_attr(attr, attr_str, BUFSIZ);
+ bgp_dump_attr(attr, attr_str, sizeof(attr_str));
zlog_debug("%s: attributes: %s", __func__, attr_str);
}
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 4a5d5c3b6e..3bcef1a555 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2836,7 +2836,7 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
char buf1[PREFIX_STRLEN];
char attr_str[BUFSIZ] = {0};
- bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
+ bgp_dump_attr(pi->attr, attr_str, sizeof(attr_str));
zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
__func__, bgp_vrf->vrf_id,
@@ -3590,11 +3590,12 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
uint32_t addpath_id)
{
struct prefix_rd prd;
- struct prefix_evpn p;
- struct bgp_route_evpn evpn;
+ struct prefix_evpn p = {};
+ struct bgp_route_evpn evpn = {};
uint8_t ipaddr_len;
uint8_t macaddr_len;
- mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
+ /* holds the VNI(s) as in packet */
+ mpls_label_t label[BGP_MAX_LABELS] = {};
uint32_t num_labels = 0;
uint32_t eth_tag;
int ret;
@@ -3613,60 +3614,61 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
return -1;
}
- memset(&evpn, 0, sizeof(evpn));
+ struct stream *pkt = stream_new(psize);
+ stream_put(pkt, pfx, psize);
/* Make prefix_rd */
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- memcpy(&prd.val, pfx, 8);
- pfx += 8;
+
+ STREAM_GET(&prd.val, pkt, 8);
/* Make EVPN prefix. */
- memset(&p, 0, sizeof(struct prefix_evpn));
p.family = AF_EVPN;
p.prefixlen = EVPN_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
/* Copy Ethernet Seg Identifier */
if (attr) {
- memcpy(&attr->esi, pfx, sizeof(esi_t));
+ STREAM_GET(&attr->esi, pkt, sizeof(esi_t));
+
if (bgp_evpn_is_esi_local(&attr->esi))
attr->es_flags |= ATTR_ES_IS_LOCAL;
else
attr->es_flags &= ~ATTR_ES_IS_LOCAL;
+ } else {
+ STREAM_FORWARD_GETP(pkt, sizeof(esi_t));
}
- pfx += sizeof(esi_t);
/* Copy Ethernet Tag */
- memcpy(&eth_tag, pfx, 4);
+ STREAM_GET(&eth_tag, pkt, 4);
p.prefix.macip_addr.eth_tag = ntohl(eth_tag);
- pfx += 4;
/* Get the MAC Addr len */
- macaddr_len = *pfx++;
+ STREAM_GETC(pkt, macaddr_len);
/* Get the MAC Addr */
if (macaddr_len == (ETH_ALEN * 8)) {
- memcpy(&p.prefix.macip_addr.mac.octet, pfx, ETH_ALEN);
- pfx += ETH_ALEN;
+ STREAM_GET(&p.prefix.macip_addr.mac.octet, pkt, ETH_ALEN);
} else {
flog_err(
EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
peer->bgp->vrf_id, peer->host, macaddr_len);
- return -1;
+ goto fail;
}
/* Get the IP. */
- ipaddr_len = *pfx++;
+ STREAM_GETC(pkt, ipaddr_len);
+
if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN
&& ipaddr_len != IPV6_MAX_BITLEN) {
flog_err(
EC_BGP_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d",
peer->bgp->vrf_id, peer->host, ipaddr_len);
- return -1;
+ goto fail;
}
if (ipaddr_len) {
@@ -3674,25 +3676,17 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefix.macip_addr.ip.ipa_type = (ipaddr_len == IPV4_MAX_BYTELEN)
? IPADDR_V4
: IPADDR_V6;
- memcpy(&p.prefix.macip_addr.ip.ip.addr, pfx, ipaddr_len);
+ STREAM_GET(&p.prefix.macip_addr.ip.ip.addr, pkt, ipaddr_len);
}
- pfx += ipaddr_len;
/* Get the VNI(s). Stored as bytes here. */
+ STREAM_GET(&label[0], pkt, BGP_LABEL_BYTES);
num_labels++;
- memset(label, 0, sizeof(label));
- memcpy(&label[0], pfx, BGP_LABEL_BYTES);
- pfx += BGP_LABEL_BYTES;
- psize -= (33 + ipaddr_len);
+
/* Do we have a second VNI? */
- if (psize) {
+ if (STREAM_READABLE(pkt)) {
num_labels++;
- memcpy(&label[1], pfx, BGP_LABEL_BYTES);
- /*
- * If in future, we are required to access additional fields,
- * we MUST increment pfx by BGP_LABEL_BYTES in before reading
- * the next field
- */
+ STREAM_GET(&label[1], pkt, BGP_LABEL_BYTES);
}
/* Process the route. */
@@ -3704,6 +3698,16 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
&prd, &label[0], num_labels, &evpn);
+ goto done;
+
+fail:
+stream_failure:
+ flog_err(EC_BGP_EVPN_ROUTE_INVALID,
+ "%u:%s - Rx EVPN Type-2 NLRI - corrupt, discarding",
+ peer->bgp->vrf_id, peer->host);
+ ret = -1;
+done:
+ stream_free(pkt);
return ret;
}
@@ -5190,7 +5194,8 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
char attr_str[BUFSIZ] = {0};
bgp_dump_attr(pi->attr,
- attr_str, BUFSIZ);
+ attr_str,
+ sizeof(attr_str));
zlog_debug(
"%u: prefix %pRN with attr %s - DENIED due to martian or self nexthop",
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 7692a200ee..701b9f446f 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1214,7 +1214,6 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
* "Bad BGP Identifier".
*/
if (remote_id.s_addr == INADDR_ANY
- || IPV4_CLASS_DE(ntohl(remote_id.s_addr))
|| (peer->sort == BGP_PEER_IBGP
&& ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr))) {
if (bgp_debug_neighbor_events(peer))
@@ -1574,7 +1573,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW
|| BGP_DEBUG(update, UPDATE_IN)
|| BGP_DEBUG(update, UPDATE_PREFIX)) {
- ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, BUFSIZ);
+ ret = bgp_dump_attr(&attr, peer->rcvd_attr_str,
+ sizeof(peer->rcvd_attr_str));
peer->stat_upd_7606++;
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 5df9e3f23f..f706b834fe 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -837,7 +837,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
memset(send_attr_str, 0, BUFSIZ);
send_attr_printed = 0;
bgp_dump_attr(adv->baa->attr, send_attr_str,
- BUFSIZ);
+ sizeof(send_attr_str));
}
}
@@ -1147,7 +1147,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
attrstr[0] = '\0';
- bgp_dump_attr(attr, attrstr, BUFSIZ);
+ bgp_dump_attr(attr, attrstr, sizeof(attrstr));
if (addpath_encode)
snprintf(tx_id_buf, sizeof(tx_id_buf),
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b2a795b97d..af02e13340 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -12746,11 +12746,13 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
use_json, json);
}
json_object_free(json);
+ json = NULL;
}
if (use_json) {
vty_out(vty, "}\n");
- json_object_free(json);
+ if (json)
+ json_object_free(json);
}
else if (!nbr_output)
vty_out(vty, "%% BGP instance not found\n");
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 66f7fa1d00..12817a0837 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3975,9 +3975,6 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag)
peer->host);
}
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop(peer);
-
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
char *msg = peer->tx_shutdown_message;
size_t msglen;
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 47792317ad..86b0c28002 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -171,6 +171,33 @@ BFD peers and profiles share the same BFD session configuration commands.
'administrative down' message is sent to the remote peer.
+.. index:: [no] passive-mode
+.. clicmd:: [no] passive-mode
+
+ Mark session as passive: a passive session will not attempt to start
+ the connection and will wait for control packets from peer before it
+ begins replying.
+
+ This feature is useful when you have a router that acts as the
+ central node of a star network and you want to avoid sending BFD
+ control packets you don't need to.
+
+ The default is active-mode (or ``no passive-mode``).
+
+.. index:: [no] minimum-ttl (1-254)
+.. clicmd:: [no] minimum-ttl (1-254)
+
+ For multi hop sessions only: configure the minimum expected TTL for
+ an incoming BFD control packet.
+
+ This feature serves the purpose of thightening the packet validation
+ requirements to avoid receiving BFD control packets from other
+ sessions.
+
+ The default value is 254 (which means we only expect one hop between
+ this system and the peer).
+
+
BFD Peer Specific Commands
--------------------------
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 16eaf3be2a..9aae89daee 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -310,6 +310,17 @@ To start OSPF process you have to specify the OSPF router.
In some cases it may be more convenient to enable OSPF on a per
interface/subnet basis (:clicmd:`ip ospf area AREA [ADDR]`).
+.. index:: proactive-arp
+.. clicmd:: proactive-arp
+
+.. index:: no proactive-arp
+.. clicmd:: no proactive-arp
+
+ This command enables or disables sending ARP requests to update neighbor
+ table entries. It speeds up convergence for /32 networks on a P2P
+ connection.
+
+ This feature is enabled by default.
.. _ospf-area:
diff --git a/grpc/frr-northbound.proto b/grpc/frr-northbound.proto
index d070d715e8..32544ba694 100644
--- a/grpc/frr-northbound.proto
+++ b/grpc/frr-northbound.proto
@@ -1,20 +1,27 @@
//
-// Copyright (C) 2019 NetDEF, Inc.
-// Renato Westphal
+// Copyright 2019 FRRouting
//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 2 of the License, or (at your option)
-// any later version.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
//
-// You should have received a copy of the GNU General Public License along
-// with this program; see the file COPYING; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
//
syntax = "proto3";
@@ -280,6 +287,9 @@ message CommitResponse {
// ID of the created configuration transaction (when the phase is APPLY
// or ALL).
uint32 transaction_id = 1;
+
+ // Human-readable error or warning message(s).
+ string error_message = 2;
}
//
diff --git a/isisd/fabricd.c b/isisd/fabricd.c
index e9dfd46010..ebaf14461e 100644
--- a/isisd/fabricd.c
+++ b/isisd/fabricd.c
@@ -475,7 +475,7 @@ void fabricd_run_spf(struct isis_area *area)
if (!f)
return;
- isis_run_hopcount_spf(area, isis->sysid, f->spftree);
+ isis_run_hopcount_spf(area, area->isis->sysid, f->spftree);
neighbors_neighbors_update(f);
fabricd_bump_tier_calculation_timer(f);
}
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 425627485a..af5258846a 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -50,8 +50,6 @@
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
-extern struct isis *isis;
-
static struct isis_adjacency *adj_alloc(const uint8_t *id)
{
struct isis_adjacency *adj;
@@ -94,6 +92,7 @@ struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
}
}
adj->adj_sids = list_new();
+ listnode_add(circuit->area->adjacency_list, adj);
return adj;
}
@@ -123,42 +122,21 @@ struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
return NULL;
}
-bool isis_adj_exists(const struct isis_area *area, int level,
- const uint8_t *sysid)
+struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
+ const uint8_t *sysid)
{
- struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
struct listnode *node;
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- struct isis_adjacency *adj;
- struct listnode *anode;
- struct list *adjdb;
-
- switch (circuit->circ_type) {
- case CIRCUIT_T_BROADCAST:
- adjdb = circuit->u.bc.adjdb[level - 1];
- if (!adjdb)
- continue;
+ for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
+ if (!(adj->level & level))
+ continue;
- for (ALL_LIST_ELEMENTS_RO(adjdb, anode, adj)) {
- if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
- return true;
- }
- break;
- case CIRCUIT_T_P2P:
- adj = circuit->u.p2p.neighbor;
- if (!adj)
- break;
-
- if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
- return true;
- break;
- default:
- break;
- }
+ if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ return adj;
}
- return false;
+ return NULL;
}
DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
@@ -186,6 +164,7 @@ void isis_delete_adj(void *arg)
adj_mt_finish(adj);
list_delete(&adj->adj_sids);
+ listnode_delete(adj->circuit->area->adjacency_list, adj);
XFREE(MTYPE_ISIS_ADJACENCY, adj);
return;
}
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index d61fbbd751..3c3a211a52 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -113,8 +113,8 @@ struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid,
struct list *adjdb);
struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
struct list *adjdb);
-bool isis_adj_exists(const struct isis_area *area, int level,
- const uint8_t *sysid);
+struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
+ const uint8_t *sysid);
struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
int level, struct isis_circuit *circuit);
void isis_delete_adj(void *adj);
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index 5729994baa..f81dd6cf51 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -195,6 +195,14 @@ static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
struct listnode *anode;
struct isis_area *area;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(vrf_id);
+
+ if (isis == NULL) {
+ zlog_warn(" %s : ISIS routing instance not found", __func__);
+ return -1;
+ }
if (IS_DEBUG_BFD)
zlog_debug("ISIS-BFD: Got neighbor replay request, resending neighbors.");
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 253ba22667..985e07820f 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -224,10 +224,17 @@ struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
struct isis_area *area;
struct listnode *node;
struct isis_circuit *circuit;
+ struct isis *isis = NULL;
if (ifp->info)
return (struct isis_circuit *)ifp->info;
+ isis = isis_lookup_by_vrfid(ifp->vrf_id);
+ if (isis == NULL) {
+ zlog_warn(" %s : ISIS routing instance not found", __func__);
+ return NULL;
+ }
+
if (isis->area_list) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
circuit =
@@ -618,7 +625,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- circuit->circuit_id = isis_circuit_id_gen(isis, circuit->interface);
+ circuit->circuit_id = isis_circuit_id_gen(circuit->area->isis,
+ circuit->interface);
if (!circuit->circuit_id) {
flog_err(
EC_ISIS_CONFIG,
@@ -802,7 +810,8 @@ void isis_circuit_down(struct isis_circuit *circuit)
circuit->lsp_regenerate_pending[0] = 0;
circuit->lsp_regenerate_pending[1] = 0;
- _ISIS_CLEAR_FLAG(isis->circuit_ids_used, circuit->circuit_id);
+ _ISIS_CLEAR_FLAG(circuit->area->isis->circuit_ids_used,
+ circuit->circuit_id);
circuit->circuit_id = 0;
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
isis_delete_adj(circuit->u.p2p.neighbor);
@@ -1011,6 +1020,14 @@ static int isis_interface_config_write(struct vty *vty)
struct isis_area *area;
struct isis_circuit *circuit;
int i;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(vrf->vrf_id);
+
+ if (isis == NULL) {
+ vty_out(vty, "ISIS routing instance not found");
+ return 0;
+ }
FOR_ALL_INTERFACES (vrf, ifp) {
/* IF name */
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 7c380fb0d9..da358f411b 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -50,16 +50,18 @@ struct metric {
};
struct isis_bcast_info {
- uint8_t snpa[ETH_ALEN]; /* SNPA of this circuit */
- char run_dr_elect[2]; /* Should we run dr election ? */
- struct thread *t_run_dr[2]; /* DR election thread */
- struct thread *t_send_lan_hello[2]; /* send LAN IIHs in this thread */
- struct list *adjdb[2]; /* adjacency dbs */
- struct list *lan_neighs[2]; /* list of lx neigh snpa */
- char is_dr[2]; /* Are we level x DR ? */
+ uint8_t snpa[ETH_ALEN]; /* SNPA of this circuit */
+ char run_dr_elect[ISIS_LEVELS]; /* Should we run dr election ? */
+ struct thread *t_run_dr[ISIS_LEVELS]; /* DR election thread */
+ struct thread *t_send_lan_hello[ISIS_LEVELS]; /* send LAN IIHs in this
+ thread */
+ struct list *adjdb[ISIS_LEVELS]; /* adjacency dbs */
+ struct list *lan_neighs[ISIS_LEVELS]; /* list of lx neigh snpa */
+ char is_dr[ISIS_LEVELS]; /* Are we level x DR ? */
uint8_t l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */
uint8_t l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */
- struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */
+ struct thread *t_refresh_pseudo_lsp[ISIS_LEVELS]; /* refresh pseudo-node
+ LSPs */
};
struct isis_p2p_info {
@@ -86,10 +88,11 @@ struct isis_circuit {
* Threads
*/
struct thread *t_read;
- struct thread *t_send_csnp[2];
- struct thread *t_send_psnp[2];
+ struct thread *t_send_csnp[ISIS_LEVELS];
+ struct thread *t_send_psnp[ISIS_LEVELS];
struct isis_tx_queue *tx_queue;
- struct isis_circuit_arg level_arg[2]; /* used as argument for threads */
+ struct isis_circuit_arg
+ level_arg[ISIS_LEVELS]; /* used as argument for threads */
/* there is no real point in two streams, just for programming kicker */
int (*rx)(struct isis_circuit *circuit, uint8_t *ssnpa);
@@ -107,7 +110,7 @@ struct isis_circuit {
struct isis_bcast_info bc;
struct isis_p2p_info p2p;
} u;
- uint8_t priority[2]; /* l1/2 IS configured priority */
+ uint8_t priority[ISIS_LEVELS]; /* l1/2 IS configured priority */
int pad_hellos; /* add padding to Hello PDUs ? */
char ext_domain; /* externalDomain (boolean) */
int lsp_regenerate_pending[ISIS_LEVELS];
@@ -117,12 +120,12 @@ struct isis_circuit {
struct isis_passwd passwd; /* Circuit rx/tx password */
int is_type; /* circuit is type == level of circuit
* differentiated from circuit type (media) */
- uint32_t hello_interval[2]; /* hello-interval in seconds */
- uint16_t hello_multiplier[2]; /* hello-multiplier */
- uint16_t csnp_interval[2]; /* csnp-interval in seconds */
- uint16_t psnp_interval[2]; /* psnp-interval in seconds */
- uint8_t metric[2];
- uint32_t te_metric[2];
+ uint32_t hello_interval[ISIS_LEVELS]; /* hello-interval in seconds */
+ uint16_t hello_multiplier[ISIS_LEVELS]; /* hello-multiplier */
+ uint16_t csnp_interval[ISIS_LEVELS]; /* csnp-interval in seconds */
+ uint16_t psnp_interval[ISIS_LEVELS]; /* psnp-interval in seconds */
+ uint8_t metric[ISIS_LEVELS];
+ uint32_t te_metric[ISIS_LEVELS];
struct isis_ext_subtlvs *ext; /* Extended parameters (TE + Adj SID */
int ip_router; /* Route IP ? */
int is_passive; /* Is Passive ? */
@@ -131,7 +134,7 @@ struct isis_circuit {
int ipv6_router; /* Route IPv6 ? */
struct list *ipv6_link; /* our link local IPv6 addresses */
struct list *ipv6_non_link; /* our non-link local IPv6 addresses */
- uint16_t upadjcount[2];
+ uint16_t upadjcount[ISIS_LEVELS];
#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01
uint8_t flags;
bool disable_threeway_adj;
@@ -143,8 +146,8 @@ struct isis_circuit {
uint32_t init_failures; /* intialisationFailures */
uint32_t ctrl_pdus_rxed; /* controlPDUsReceived */
uint32_t ctrl_pdus_txed; /* controlPDUsSent */
- uint32_t
- desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */
+ uint32_t desig_changes[ISIS_LEVELS]; /* lanLxDesignatedIntermediateSystemChanges
+ */
uint32_t rej_adjacencies; /* rejectedAdjacencies */
/*
* Counters as in ietf-isis@2019-09-09.yang
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index cd75116c50..4d02758003 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -62,7 +62,12 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
* need to make sure to set it in the yang model so that it
* is consistent with what FRR sees.
*/
- if (listcount(isis->area_list) == 0)
+
+ if (!im) {
+ return CMD_SUCCESS;
+ }
+
+ if (listcount(im->isis) == 0)
nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY,
"level-1-2");
ret = nb_cli_apply_changes(vty, base_xpath);
@@ -90,7 +95,7 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
}
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
- area = isis_area_lookup(tag);
+ area = isis_area_lookup(tag, VRF_DEFAULT);
if (area && area->circuit_list && listcount(area->circuit_list)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) {
@@ -134,13 +139,20 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
- struct isis_area *area;
+ struct isis_area *area = NULL;
struct interface *ifp;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
*/
- area = isis_area_lookup(tag);
+
+ if (!im) {
+ return CMD_SUCCESS;
+ }
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp)
+ area = isis_area_lookup(tag, ifp->vrf_id);
+
if (!area) {
snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']", tag);
@@ -148,9 +160,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']/is-type",
tag);
- nb_cli_enqueue_change(
- vty, temp_xpath, NB_OP_MODIFY,
- listcount(isis->area_list) == 0 ? "level-1-2" : NULL);
+ nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
+ listcount(im->isis) == 0 ? "level-1-2"
+ : NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
@@ -159,8 +171,7 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY,
- listcount(isis->area_list) == 0 ? "level-1-2"
- : "level-1");
+ listcount(im->isis) == 0 ? "level-1-2" : "level-1");
} else {
/* area exists, circuit type defaults to its area's is_type */
switch (area->is_type) {
@@ -188,7 +199,6 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
}
/* check if the interface is a loopback and if so set it as passive */
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp && if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
@@ -204,13 +214,20 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
- struct isis_area *area;
+ struct isis_area *area = NULL;
struct interface *ifp;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
*/
- area = isis_area_lookup(tag);
+
+ if (!im)
+ return CMD_SUCCESS;
+
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (ifp)
+ area = isis_area_lookup(tag, ifp->vrf_id);
+
if (!area) {
snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']", tag);
@@ -218,9 +235,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
snprintf(temp_xpath, XPATH_MAXLEN,
"/frr-isisd:isis/instance[area-tag='%s']/is-type",
tag);
- nb_cli_enqueue_change(
- vty, temp_xpath, NB_OP_MODIFY,
- listcount(isis->area_list) == 0 ? "level-1-2" : NULL);
+ nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
+ listcount(im->isis) == 0 ? "level-1-2"
+ : NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
@@ -229,8 +246,7 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY,
- listcount(isis->area_list) == 0 ? "level-1-2"
- : "level-1");
+ listcount(im->isis) == 0 ? "level-1-2" : "level-1");
} else {
/* area exists, circuit type defaults to its area's is_type */
switch (area->is_type) {
@@ -258,7 +274,6 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
}
/* check if the interface is a loopback and if so set it as passive */
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp && if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
@@ -1154,7 +1169,7 @@ DEFPY_YANG(isis_default_originate, isis_default_originate_cmd,
"Distribute default route into level-2\n"
"Always advertise default route\n"
"Metric for default route\n"
- "ISIS default metric\n"
+ "IS-IS default metric\n"
"Route map reference\n"
"Pointer to route-map entries\n")
{
@@ -1228,7 +1243,7 @@ DEFPY_YANG(isis_redistribute, isis_redistribute_cmd,
"Redistribute into level-1\n"
"Redistribute into level-2\n"
"Metric for redistributed routes\n"
- "ISIS default metric\n"
+ "IS-IS default metric\n"
"Route map reference\n"
"Pointer to route-map entries\n")
{
diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c
index 7aae326a4f..929b4c26e8 100644
--- a/isisd/isis_csm.c
+++ b/isisd/isis_csm.c
@@ -48,8 +48,6 @@
#include "isisd/isis_events.h"
#include "isisd/isis_errors.h"
-extern struct isis *isis;
-
static const char *const csm_statestr[] = {"C_STATE_NA", "C_STATE_INIT",
"C_STATE_CONF", "C_STATE_UP"};
@@ -66,6 +64,7 @@ struct isis_circuit *
isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
{
int old_state;
+ struct isis *isis = NULL;
old_state = circuit ? circuit->state : C_STATE_NA;
if (IS_DEBUG_EVENTS)
@@ -86,6 +85,13 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
case IF_UP_FROM_Z:
circuit = isis_circuit_new();
isis_circuit_if_add(circuit, (struct interface *)arg);
+ isis = isis_lookup_by_vrfid(circuit->interface->vrf_id);
+ if (isis == NULL) {
+ zlog_warn(
+ " %s : ISIS routing instance not found",
+ __func__);
+ break;
+ }
listnode_add(isis->init_circ_list, circuit);
circuit->state = C_STATE_INIT;
break;
@@ -111,7 +117,8 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
circuit->state = C_STATE_UP;
isis_event_circuit_state_change(circuit, circuit->area,
1);
- listnode_delete(isis->init_circ_list, circuit);
+ listnode_delete(circuit->area->isis->init_circ_list,
+ circuit);
break;
case IF_UP_FROM_Z:
assert(circuit);
@@ -122,6 +129,14 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
break;
case IF_DOWN_FROM_Z:
isis_circuit_if_del(circuit, (struct interface *)arg);
+ isis = isis_lookup_by_vrfid(circuit->interface->vrf_id);
+ if (isis == NULL) {
+ zlog_warn(
+ "%s : ISIS routing instance not found",
+ __func__);
+ break;
+ }
+
listnode_delete(isis->init_circ_list, circuit);
isis_circuit_del(circuit);
circuit = NULL;
@@ -174,6 +189,15 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
circuit->state = C_STATE_INIT;
isis_event_circuit_state_change(
circuit, (struct isis_area *)arg, 0);
+
+ isis = isis_lookup_by_vrfid(circuit->interface->vrf_id);
+ if (isis == NULL) {
+ zlog_warn(
+ "%s : ISIS routing instance not found",
+ __func__);
+ break;
+ }
+
listnode_add(isis->init_circ_list, circuit);
break;
case IF_DOWN_FROM_Z:
diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c
index 8df1304866..318fb9fab8 100644
--- a/isisd/isis_dr.c
+++ b/isisd/isis_dr.c
@@ -225,7 +225,7 @@ int isis_dr_resign(struct isis_circuit *circuit, int level)
THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
circuit->lsp_regenerate_pending[level - 1] = 0;
- memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(id) = circuit->circuit_id;
LSP_FRAGMENT(id) = 0;
lsp_purge_pseudo(id, circuit, level);
@@ -278,7 +278,8 @@ int isis_dr_commence(struct isis_circuit *circuit, int level)
/* there was a dr elected, purge its LSPs from the db */
lsp_purge_pseudo(old_dr, circuit, level);
}
- memcpy(circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(circuit->u.bc.l1_desig_is, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
*(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) =
circuit->circuit_id;
@@ -299,7 +300,8 @@ int isis_dr_commence(struct isis_circuit *circuit, int level)
/* there was a dr elected, purge its LSPs from the db */
lsp_purge_pseudo(old_dr, circuit, level);
}
- memcpy(circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(circuit->u.bc.l2_desig_is, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
*(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) =
circuit->circuit_id;
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
index 921e23d33a..e34c59be11 100644
--- a/isisd/isis_dynhn.c
+++ b/isisd/isis_dynhn.c
@@ -45,11 +45,11 @@ extern struct host host;
struct list *dyn_cache = NULL;
static int dyn_cache_cleanup(struct thread *);
-void dyn_cache_init(void)
+void dyn_cache_init(struct isis *isis)
{
if (dyn_cache == NULL)
dyn_cache = list_new();
- thread_add_timer(master, dyn_cache_cleanup, NULL, 120,
+ thread_add_timer(master, dyn_cache_cleanup, isis, 120,
&isis->t_dync_clean);
return;
}
@@ -59,19 +59,22 @@ static int dyn_cache_cleanup(struct thread *thread)
struct listnode *node, *nnode;
struct isis_dynhn *dyn;
time_t now = time(NULL);
+ struct isis *isis = NULL;
+
+ isis = THREAD_ARG(thread);
isis->t_dync_clean = NULL;
for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
continue;
-
list_delete_node(dyn_cache, node);
XFREE(MTYPE_ISIS_DYNHN, dyn);
}
- thread_add_timer(master, dyn_cache_cleanup, NULL, 120,
- &isis->t_dync_clean);
+ thread_add_timer(master, dyn_cache_cleanup, isis, 120,
+ &isis->t_dync_clean);
+
return ISIS_OK;
}
@@ -132,11 +135,14 @@ void isis_dynhn_remove(const uint8_t *id)
* 2 0000.0000.0002 bar-gw
* * 0000.0000.0004 this-gw
*/
-void dynhn_print_all(struct vty *vty)
+void dynhn_print_all(struct vty *vty, struct isis *isis)
{
struct listnode *node;
struct isis_dynhn *dyn;
+ vty_out(vty, "vrf : %s\n", isis->name);
+ if (!isis->sysid_set)
+ return;
vty_out(vty, "Level System ID Dynamic Hostname\n");
for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
vty_out(vty, "%-7d", dyn->level);
diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h
index 27133bd3fd..2cfc43fc17 100644
--- a/isisd/isis_dynhn.h
+++ b/isisd/isis_dynhn.h
@@ -30,11 +30,11 @@ struct isis_dynhn {
int level;
};
-void dyn_cache_init(void);
+void dyn_cache_init(struct isis *isis);
void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level);
void isis_dynhn_remove(const uint8_t *id);
struct isis_dynhn *dynhn_find_by_id(const uint8_t *id);
struct isis_dynhn *dynhn_find_by_name(const char *hostname);
-void dynhn_print_all(struct vty *vty);
+void dynhn_print_all(struct vty *vty, struct isis *isis);
#endif /* _ZEBRA_ISIS_DYNHN_H */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index bf15163cbf..90c7c0efb5 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -338,13 +338,17 @@ void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
static void lsp_purge_add_poi(struct isis_lsp *lsp,
const uint8_t *sender)
{
+ if (lsp->area == NULL)
+ return;
+
if (!lsp->area->purge_originator)
return;
/* add purge originator identification */
if (!lsp->tlvs)
lsp->tlvs = isis_alloc_tlvs();
- isis_tlvs_set_purge_originator(lsp->tlvs, isis->sysid, sender);
+ isis_tlvs_set_purge_originator(lsp->tlvs, lsp->area->isis->sysid,
+ sender);
isis_tlvs_set_dynamic_hostname(lsp->tlvs, cmd_hostname_get());
}
@@ -591,7 +595,8 @@ static void lsp_set_time(struct isis_lsp *lsp)
stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime);
}
-void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag)
+void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag,
+ struct isis *isis)
{
struct isis_dynhn *dyn = NULL;
char id[SYSID_STRLEN];
@@ -607,6 +612,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag)
snprintf(id, sizeof(id), "%.14s", cmd_hostname_get());
else
memcpy(id, sysid_print(lsp_id), 15);
+
if (frag)
sprintf(dest, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id),
LSP_FRAGMENT(lsp_id));
@@ -638,13 +644,14 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
}
/* this function prints the lsp on show isis database */
-void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
+void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+ struct isis *isis)
{
char LSPid[255];
char age_out[8];
char b[200];
- lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1);
+ lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1, isis);
vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
vty_out(vty, "%5hu ", lsp->hdr.pdu_len);
vty_out(vty, "0x%08x ", lsp->hdr.seqno);
@@ -658,9 +665,10 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
}
-void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
+void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+ struct isis *isis)
{
- lsp_print(lsp, vty, dynhost);
+ lsp_print(lsp, vty, dynhost, isis);
if (lsp->tlvs)
vty_multiline(vty, " ", "%s", isis_format_tlvs(lsp->tlvs));
vty_out(vty, "\n");
@@ -668,19 +676,19 @@ void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
/* print all the lsps info in the local lspdb */
int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail,
- char dynhost)
+ char dynhost, struct isis *isis)
{
struct isis_lsp *lsp;
int lsp_count = 0;
if (detail == ISIS_UI_LEVEL_BRIEF) {
frr_each (lspdb, head, lsp) {
- lsp_print(lsp, vty, dynhost);
+ lsp_print(lsp, vty, dynhost, isis);
lsp_count++;
}
} else if (detail == ISIS_UI_LEVEL_DETAIL) {
frr_each (lspdb, head, lsp) {
- lsp_print_detail(lsp, vty, dynhost);
+ lsp_print_detail(lsp, vty, dynhost, isis);
lsp_count++;
}
}
@@ -913,10 +921,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
}
/* Add Router Capability TLV. */
- if (isis->router_id != 0) {
+ if (area->isis->router_id != 0) {
struct isis_router_cap cap = {};
- cap.router_id.s_addr = isis->router_id;
+ cap.router_id.s_addr = area->isis->router_id;
/* Add SR Sub-TLVs if SR is enabled. */
if (area->srdb.enabled) {
@@ -954,8 +962,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
* into LSP. TE router ID will be the same if MPLS-TE
* is not activate or MPLS-TE router-id not specified
*/
- if (isis->router_id != 0) {
- struct in_addr id = {.s_addr = isis->router_id};
+ if (area->isis->router_id != 0) {
+ struct in_addr id = {.s_addr = area->isis->router_id};
inet_ntop(AF_INET, &id, buf, sizeof(buf));
lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
area->area_tag, buf);
@@ -1210,7 +1218,8 @@ int lsp_generate(struct isis_area *area, int level)
return ISIS_ERROR;
memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
- memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
+
+ memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
/* only builds the lsp if the area shares the level */
oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
@@ -1281,9 +1290,8 @@ static int lsp_regenerate(struct isis_area *area, int level)
return ISIS_ERROR;
head = &area->lspdb[level - 1];
-
memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
- memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
lsp = lsp_search(head, lspid);
@@ -1404,7 +1412,7 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
all_pseudo ? "" : "not ",
func, file, line);
- memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(id, area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
now = time(NULL);
@@ -1525,7 +1533,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
*/
uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
- memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(ne_id, area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(ne_id) = 0;
if (circuit->area->oldmetric) {
@@ -1537,7 +1545,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
}
if (circuit->area->newmetric) {
isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
- ne_id, 0, circuit->ext);
+ ne_id, 0, NULL);
lsp_debug(
"ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
area->area_tag, sysid_print(ne_id),
@@ -1579,7 +1587,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
if (circuit->area->newmetric) {
isis_tlvs_add_extended_reach(lsp->tlvs,
ISIS_MT_IPV4_UNICAST,
- ne_id, 0, circuit->ext);
+ ne_id, 0, NULL);
lsp_debug(
"ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
area->area_tag, sysid_print(ne_id),
@@ -1603,7 +1611,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
|| (circuit->u.bc.is_dr[level - 1] == 0))
return ISIS_ERROR;
- memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_FRAGMENT(lsp_id) = 0;
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
@@ -1663,7 +1671,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
|| (circuit->u.bc.is_dr[level - 1] == 0))
return ISIS_ERROR;
- memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
LSP_FRAGMENT(lsp_id) = 0;
@@ -1720,7 +1728,7 @@ static int lsp_l1_refresh_pseudo(struct thread *thread)
if ((circuit->u.bc.is_dr[0] == 0)
|| (circuit->is_type & IS_LEVEL_1) == 0) {
- memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(id) = circuit->circuit_id;
LSP_FRAGMENT(id) = 0;
lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
@@ -1742,7 +1750,7 @@ static int lsp_l2_refresh_pseudo(struct thread *thread)
if ((circuit->u.bc.is_dr[1] == 0)
|| (circuit->is_type & IS_LEVEL_2) == 0) {
- memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(id) = circuit->circuit_id;
LSP_FRAGMENT(id) = 0;
lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
@@ -1770,7 +1778,7 @@ int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
area->area_tag, circuit_t2string(level),
circuit->interface->name);
- memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ memcpy(lsp_id, area->isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
LSP_FRAGMENT(lsp_id) = 0;
now = time(NULL);
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index 4cbca5d517..6cbea47496 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -29,6 +29,7 @@
PREDECL_RBTREE_UNIQ(lspdb)
+struct isis;
/* Structure for isis_lsp, this structure will only support the fixed
* System ID (Currently 6) (atleast for now). In order to support more
* We will have to split the header into two parts, and for readability
@@ -115,11 +116,14 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
struct isis_tlvs *tlvs, struct stream *stream,
struct isis_area *area, int level, bool confusion);
void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno);
-void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag);
-void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost);
-void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost);
+void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag,
+ struct isis *isis);
+void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+ struct isis *isis);
+void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+ struct isis *isis);
int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail,
- char dynhost);
+ char dynhost, struct isis *isis);
/* sets SRMflags for all active circuits of an lsp */
void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set);
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 2317b166c6..ed4b206851 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -101,6 +101,7 @@ void sigusr1(void);
static __attribute__((__noreturn__)) void terminate(int i)
{
+ isis_terminate();
isis_sr_term();
isis_zebra_stop();
exit(i);
@@ -233,7 +234,8 @@ int main(int argc, char **argv, char **envp)
}
/* thread master */
- master = frr_init();
+ isis_master_init(frr_init());
+ master = im->master;
/*
* initializations
@@ -259,7 +261,7 @@ int main(int argc, char **argv, char **envp)
mt_init();
/* create the global 'isis' instance */
- isis_new(1, VRF_DEFAULT);
+ isis_global_instance_create();
isis_zebra_init(master, instance);
isis_bfd_init();
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
index 86725173c4..3aedd8ba1f 100644
--- a/isisd/isis_misc.c
+++ b/isisd/isis_misc.c
@@ -437,15 +437,18 @@ struct in_addr newprefix2inaddr(uint8_t *prefix_start, uint8_t prefix_masklen)
* Returns the dynamic hostname associated with the passed system ID.
* If no dynamic hostname found then returns formatted system ID.
*/
-const char *print_sys_hostname(const uint8_t *sysid)
+const char *print_sys_hostname(uint8_t *sysid)
{
struct isis_dynhn *dyn;
+ struct isis *isis = NULL;
if (!sysid)
return "nullsysid";
/* For our system ID return our host name */
- if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
+ isis = isis_lookup_by_sysid(sysid);
+
+ if (isis != NULL)
return cmd_hostname_get();
dyn = dynhn_find_by_id(sysid);
diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h
index 5cdbbfb058..c6a5832f33 100644
--- a/isisd/isis_misc.h
+++ b/isisd/isis_misc.h
@@ -49,7 +49,7 @@ const char *time2string(uint32_t);
const char *nlpid2str(uint8_t nlpid);
/* typedef struct nlpids nlpids; */
char *nlpid2string(struct nlpids *);
-const char *print_sys_hostname(const uint8_t *sysid);
+const char *print_sys_hostname(uint8_t *sysid);
void zlog_dump_data(void *data, int len);
/*
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 6873c652f2..ffc3d5b2e0 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -58,11 +58,11 @@ int isis_instance_create(struct nb_cb_create_args *args)
return NB_OK;
area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
- area = isis_area_lookup(area_tag);
+ area = isis_area_lookup(area_tag, VRF_DEFAULT);
if (area)
return NB_ERR_INCONSISTENCY;
- area = isis_area_create(area_tag);
+ area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
/* save area in dnode to avoid looking it up all the time */
nb_running_set_entry(args->dnode, area);
@@ -77,7 +77,7 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
area = nb_running_unset_entry(args->dnode);
- isis_area_destroy(area->area_tag);
+ isis_area_destroy(area);
return NB_OK;
}
@@ -113,6 +113,10 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
switch (args->event) {
case NB_EV_VALIDATE:
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ if (area == NULL)
+ return NB_ERR_VALIDATION;
+
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len);
if (addr.area_addr[addr.addr_len - 1] != 0) {
@@ -121,9 +125,9 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
"nsel byte (last byte) in area address must be 0");
return NB_ERR_VALIDATION;
}
- if (isis->sysid_set) {
+ if (area->isis->sysid_set) {
/* Check that the SystemID portions match */
- if (memcmp(isis->sysid, GETSYSID((&addr)),
+ if (memcmp(area->isis->sysid, GETSYSID((&addr)),
ISIS_SYS_ID_LEN)) {
snprintf(
args->errmsg, args->errmsg_len,
@@ -145,12 +149,13 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
addrr = args->resource->ptr;
- if (isis->sysid_set == 0) {
+ if (area->isis->sysid_set == 0) {
/*
* First area address - get the SystemID for this router
*/
- memcpy(isis->sysid, GETSYSID(addrr), ISIS_SYS_ID_LEN);
- isis->sysid_set = 1;
+ memcpy(area->isis->sysid, GETSYSID(addrr),
+ ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 1;
} else {
/* check that we don't already have this address */
for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node,
@@ -200,6 +205,7 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, (int)addr.addr_len);
area = nb_running_get_entry(args->dnode, NULL, true);
+
for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, addrp)) {
if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len
&& !memcmp(addrp->area_addr, addr.area_addr, addr.addr_len))
@@ -214,8 +220,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args)
* Last area address - reset the SystemID for this router
*/
if (listcount(area->area_addrs) == 0) {
- memset(isis->sysid, 0, ISIS_SYS_ID_LEN);
- isis->sysid_set = 0;
+ memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 0;
if (IS_DEBUG_EVENTS)
zlog_debug("Router has no SystemID");
}
@@ -1822,7 +1828,7 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_mo
*/
int lib_interface_isis_create(struct nb_cb_create_args *args)
{
- struct isis_area *area;
+ struct isis_area *area = NULL;
struct interface *ifp;
struct isis_circuit *circuit;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
@@ -1842,7 +1848,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
break;
actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
- area = isis_area_lookup(area_tag);
+ area = isis_area_lookup(area_tag, ifp->vrf_id);
if (area)
min_mtu = area->lsp_mtu;
else
@@ -1860,7 +1866,9 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
}
break;
case NB_EV_APPLY:
- area = isis_area_lookup(area_tag);
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ if (ifp)
+ area = isis_area_lookup(area_tag, ifp->vrf_id);
/* The area should have already be created. We are
* setting the priority of the global isis area creation
* slightly lower, so it should be executed first, but I
@@ -1874,7 +1882,6 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
abort();
}
- ifp = nb_running_get_entry(args->dnode, NULL, true);
circuit = isis_circuit_create(area, ifp);
assert(circuit
&& (circuit->state == C_STATE_CONF
@@ -1915,6 +1922,7 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
struct interface *ifp;
struct vrf *vrf;
const char *area_tag, *ifname, *vrfname;
+ struct isis *isis = NULL;
if (args->event == NB_EV_VALIDATE) {
/* libyang doesn't like relative paths across module boundaries
@@ -1926,8 +1934,14 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
vrf = vrf_lookup_by_name(vrfname);
assert(vrf);
ifp = if_lookup_by_name(ifname, vrf->vrf_id);
+
if (!ifp)
return NB_OK;
+
+ isis = isis_lookup_by_vrfid(ifp->vrf_id);
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+
circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
area_tag = yang_dnode_get_string(args->dnode, NULL);
if (circuit && circuit->area && circuit->area->area_tag
@@ -1952,6 +1966,7 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
struct interface *ifp;
struct vrf *vrf;
const char *ifname, *vrfname;
+ struct isis *isis = NULL;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1966,6 +1981,11 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
ifp = if_lookup_by_name(ifname, vrf->vrf_id);
if (!ifp)
break;
+
+ isis = isis_lookup_by_vrfid(ifp->vrf_id);
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+
circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
if (circuit && circuit->state == C_STATE_UP
&& circuit->area->is_type != IS_LEVEL_1_AND_2
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 72548e0425..43b9f6685e 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -74,8 +74,10 @@ static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
fill_fixed_hdr(pdu_type, circuit->snd_stream);
lenp = stream_get_endp(circuit->snd_stream);
+
stream_putw(circuit->snd_stream, 0); /* PDU length */
- stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ stream_put(circuit->snd_stream, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
stream_putc(circuit->snd_stream, circuit->idx);
stream_putc(circuit->snd_stream, 9); /* code */
stream_putc(circuit->snd_stream, 16); /* len */
@@ -128,6 +130,7 @@ struct iih_info {
static int process_p2p_hello(struct iih_info *iih)
{
struct isis_threeway_adj *tw_adj = iih->tlvs->threeway_adj;
+
if (tw_adj) {
if (tw_adj->state > ISIS_THREEWAY_DOWN) {
if (IS_DEBUG_ADJ_PACKETS) {
@@ -140,8 +143,10 @@ static int process_p2p_hello(struct iih_info *iih)
}
if (tw_adj->neighbor_set
- && (memcmp(tw_adj->neighbor_id, isis->sysid, ISIS_SYS_ID_LEN)
- || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
+ && (memcmp(tw_adj->neighbor_id,
+ iih->circuit->area->isis->sysid, ISIS_SYS_ID_LEN)
+ || tw_adj->neighbor_circuit_id
+ != (uint32_t)iih->circuit->idx)) {
if (IS_DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.",
@@ -561,7 +566,6 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
? "P2P IIH"
: (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH";
-
stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
pdu_end - pdu_start);
if (IS_DEBUG_ADJ_PACKETS) {
@@ -724,7 +728,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
goto out;
}
- if (!memcmp(iih.sys_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+ if (!memcmp(iih.sys_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN)) {
zlog_warn(
"ISIS-Adj (%s): Received IIH with own sysid - discard",
circuit->area->area_tag);
@@ -1040,7 +1044,8 @@ dontcheckadj:
ack_lsp(&hdr, circuit, level);
goto out; /* FIXME: do we need a purge? */
} else {
- if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+ if (memcmp(hdr.lsp_id, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN)) {
/* LSP by some other system -> do 7.3.16.4 b) */
/* 7.3.16.4 b) 1) */
if (comp == LSP_NEWER) {
@@ -1134,7 +1139,8 @@ dontcheckadj:
}
/* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
* purge */
- if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
+ if (memcmp(hdr.lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN)
+ == 0) {
if (!lsp) {
/* 7.3.16.4: initiate a purge */
lsp_purge_non_exist(level, &hdr, circuit->area);
@@ -1370,6 +1376,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
struct isis_passwd *passwd = (level == IS_LEVEL_1)
? &circuit->area->area_passwd
: &circuit->area->domain_passwd;
+
if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) {
int auth_code = isis_tlvs_auth_is_valid(
tlvs, passwd, circuit->rcv_stream, false);
@@ -1420,7 +1427,8 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
entry = entry->next) {
struct isis_lsp *lsp =
lsp_search(&circuit->area->lspdb[level - 1], entry->id);
- bool own_lsp = !memcmp(entry->id, isis->sysid, ISIS_SYS_ID_LEN);
+ bool own_lsp = !memcmp(entry->id, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
if (lsp) {
/* 7.3.15.2 b) 1) is this LSP newer */
int cmp = lsp_compare(circuit->area->area_tag, lsp,
@@ -1459,8 +1467,9 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
* are not 0,
* insert it and set SSN on it */
if (entry->rem_lifetime && entry->checksum
- && entry->seqno && memcmp(entry->id, isis->sysid,
- ISIS_SYS_ID_LEN)) {
+ && entry->seqno
+ && memcmp(entry->id, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN)) {
struct isis_lsp *lsp0 = NULL;
if (LSP_FRAGMENT(entry->id)) {
@@ -1667,13 +1676,14 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
}
/* either 3 or 0 */
- if (pdu_type != FS_LINK_STATE /* FS PDU doesn't contain max area addr field */
+ if (pdu_type != FS_LINK_STATE /* FS PDU doesn't contain max area addr
+ field */
&& max_area_addrs != 0
- && max_area_addrs != isis->max_area_addrs) {
+ && max_area_addrs != circuit->area->isis->max_area_addrs) {
flog_err(
EC_ISIS_PACKET,
"maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %hhu while the parameter for this IS is %u",
- max_area_addrs, isis->max_area_addrs);
+ max_area_addrs, circuit->area->isis->max_area_addrs);
circuit->max_area_addr_mismatches++;
#ifndef FABRICD
/* send northbound notification */
@@ -2052,8 +2062,10 @@ int send_csnp(struct isis_circuit *circuit, int level)
fill_fixed_hdr(pdu_type, circuit->snd_stream);
size_t len_pointer = stream_get_endp(circuit->snd_stream);
+
stream_putw(circuit->snd_stream, 0);
- stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ stream_put(circuit->snd_stream, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
/* with zero circuit id - ref 9.10, 9.11 */
stream_putc(circuit->snd_stream, 0);
@@ -2230,7 +2242,8 @@ static int send_psnp(int level, struct isis_circuit *circuit)
size_t len_pointer = stream_get_endp(circuit->snd_stream);
stream_putw(circuit->snd_stream, 0); /* length is filled in later */
- stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+ stream_put(circuit->snd_stream, circuit->area->isis->sysid,
+ ISIS_SYS_ID_LEN);
stream_putc(circuit->snd_stream, circuit->idx);
struct isis_passwd *passwd = (level == ISIS_LEVEL1)
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index 45e79b46da..44422ff664 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -218,8 +218,9 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
}
/* Handle notification about route being added */
-void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
- uint8_t distance, uint32_t metric)
+void isis_redist_add(struct isis *isis, int type, struct prefix *p,
+ struct prefix_ipv6 *src_p, uint8_t distance,
+ uint32_t metric)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -270,7 +271,8 @@ void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
}
}
-void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
+void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
+ struct prefix_ipv6 *src_p)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -292,8 +294,8 @@ void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p)
* by "default-information originate always". Areas without the
* "always" setting will ignore routes with origin
* DEFAULT_ROUTE. */
- isis_redist_add(DEFAULT_ROUTE, p, NULL,
- 254, MAX_WIDE_PATH_METRIC);
+ isis_redist_add(isis, DEFAULT_ROUTE, p, NULL, 254,
+ MAX_WIDE_PATH_METRIC);
return;
}
diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h
index 9c37c310ea..0d2dc6a803 100644
--- a/isisd/isis_redist.h
+++ b/isisd/isis_redist.h
@@ -40,6 +40,7 @@ struct isis_redist {
struct route_map *map;
};
+struct isis;
struct isis_area;
struct prefix;
struct prefix_ipv6;
@@ -47,9 +48,11 @@ struct vty;
struct route_table *get_ext_reach(struct isis_area *area, int family,
int level);
-void isis_redist_add(int type, struct prefix *p, struct prefix_ipv6 *src_p,
- uint8_t distance, uint32_t metric);
-void isis_redist_delete(int type, struct prefix *p, struct prefix_ipv6 *src_p);
+void isis_redist_add(struct isis *isis, int type, struct prefix *p,
+ struct prefix_ipv6 *src_p, uint8_t distance,
+ uint32_t metric);
+void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
+ struct prefix_ipv6 *src_p);
int isis_redist_config_write(struct vty *vty, struct isis_area *area,
int family);
void isis_redist_init(void);
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index c092721ab4..ebce86bed9 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -35,6 +35,7 @@
#include "table.h"
#include "spf_backoff.h"
#include "srcdest_table.h"
+#include "vrf.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -1083,7 +1084,8 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2,
AF_INET, SPFTREE_IPV4, true);
- if (!memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN)) {
+
+ if (!memcmp(sysid, area->isis->sysid, ISIS_SYS_ID_LEN)) {
/* If we are running locally, initialize with information from adjacencies */
struct isis_vertex *root = isis_spf_add_root(spftree, sysid);
isis_spf_preload_tent(spftree, sysid, root);
@@ -1099,19 +1101,17 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
}
static int isis_run_spf(struct isis_area *area, int level,
- enum spf_tree_id tree_id,
- uint8_t *sysid, struct timeval *nowtv)
+ enum spf_tree_id tree_id, uint8_t *sysid)
{
int retval = ISIS_OK;
struct isis_vertex *root_vertex;
struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
- struct timeval time_now;
- unsigned long long start_time, end_time;
+ struct timeval time_start;
+ struct timeval time_end;
uint16_t mtid = 0;
/* Get time that can't roll backwards. */
- start_time = nowtv->tv_sec;
- start_time = (start_time * 1000000) + nowtv->tv_usec;
+ monotime(&time_start);
int family = -1;
switch (tree_id) {
@@ -1162,10 +1162,10 @@ static int isis_run_spf(struct isis_area *area, int level,
out:
spftree->runcount++;
spftree->last_run_timestamp = time(NULL);
- spftree->last_run_monotime = monotime(&time_now);
- end_time = time_now.tv_sec;
- end_time = (end_time * 1000000) + time_now.tv_usec;
- spftree->last_run_duration = end_time - start_time;
+ spftree->last_run_monotime = monotime(&time_end);
+ spftree->last_run_duration =
+ ((time_end.tv_sec - time_start.tv_sec) * 1000000)
+ + (time_end.tv_usec - time_start.tv_usec);
return retval;
}
@@ -1211,15 +1211,14 @@ static int isis_run_spf_cb(struct thread *thread)
area->area_tag, level);
if (area->ip_circuits)
- retval = isis_run_spf(area, level, SPFTREE_IPV4, isis->sysid,
- &thread->real);
+ retval = isis_run_spf(area, level, SPFTREE_IPV4,
+ area->isis->sysid);
if (area->ipv6_circuits)
- retval = isis_run_spf(area, level, SPFTREE_IPV6, isis->sysid,
- &thread->real);
- if (area->ipv6_circuits
- && isis_area_ipv6_dstsrc_enabled(area))
- retval = isis_run_spf(area, level, SPFTREE_DSTSRC, isis->sysid,
- &thread->real);
+ retval = isis_run_spf(area, level, SPFTREE_IPV6,
+ area->isis->sysid);
+ if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
+ retval = isis_run_spf(area, level, SPFTREE_DSTSRC,
+ area->isis->sysid);
isis_area_verify_routes(area);
@@ -1411,38 +1410,19 @@ static void isis_print_spftree(struct vty *vty, int level,
vty_out(vty, "IS-IS paths to level-%d routers %s\n",
level, tree_id_text);
isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths,
- isis->sysid);
+ area->isis->sysid);
+
vty_out(vty, "\n");
}
-DEFUN (show_isis_topology,
- show_isis_topology_cmd,
- "show " PROTO_NAME " topology"
-#ifndef FABRICD
- " [<level-1|level-2>]"
-#endif
- , SHOW_STR
- PROTO_HELP
- "IS-IS paths to Intermediate Systems\n"
-#ifndef FABRICD
- "Paths to all level-1 routers in the area\n"
- "Paths to all level-2 routers in the domain\n"
-#endif
- )
+static void show_isis_topology_common(struct vty *vty, int levels,
+ struct isis *isis)
{
- int levels;
struct listnode *node;
struct isis_area *area;
- if (argc < 4)
- levels = ISIS_LEVEL1 | ISIS_LEVEL2;
- else if (strmatch(argv[3]->text, "level-1"))
- levels = ISIS_LEVEL1;
- else
- levels = ISIS_LEVEL2;
-
if (!isis->area_list || isis->area_list->count == 0)
- return CMD_SUCCESS;
+ return;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
vty_out(vty, "Area %s:\n",
@@ -1475,6 +1455,58 @@ DEFUN (show_isis_topology,
vty_out(vty, "\n");
}
+}
+
+DEFUN(show_isis_topology, show_isis_topology_cmd,
+ "show " PROTO_NAME
+ " [vrf <NAME|all>] topology"
+#ifndef FABRICD
+ " [<level-1|level-2>]"
+#endif
+ ,
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "IS-IS paths to Intermediate Systems\n"
+#ifndef FABRICD
+ "Paths to all level-1 routers in the area\n"
+ "Paths to all level-2 routers in the domain\n"
+#endif
+)
+{
+ int levels = ISIS_LEVELS;
+ struct listnode *inode, *nnode;
+ struct isis *isis = NULL;
+ int idx = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ if (argv_find(argv, argc, "topology", &idx)) {
+ if (argc < idx + 2)
+ levels = ISIS_LEVEL1 | ISIS_LEVEL2;
+ else if (strmatch(argv[idx + 1]->arg, "level-1"))
+ levels = ISIS_LEVEL1;
+ else
+ levels = ISIS_LEVEL2;
+ }
+
+ if (!im) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ show_isis_topology_common(vty, levels, isis);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ show_isis_topology_common(vty, levels, isis);
+ }
return CMD_SUCCESS;
}
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index 59f00a73f5..bdbdc30b4a 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -1055,7 +1055,7 @@ static void parse_prefix_sid_subtlvs(struct sr_node *srn,
|| srp->sid.value != psid->value) {
srp->sid = *psid;
srp->state = SRDB_STATE_MODIFIED;
- } else
+ } else if (srp->state == SRDB_STATE_VALIDATED)
srp->state = SRDB_STATE_UNCHANGED;
sr_debug(" |- Found %s Prefix-SID %pFX",
srp->state == SRDB_STATE_MODIFIED
@@ -1223,7 +1223,7 @@ static void process_node_changes(struct isis_area *area, int level,
* If an neighbor router's SRGB was changed or created, then reinstall
* all Prefix-SIDs from all nodes that use this neighbor as nexthop.
*/
- adjacent = isis_adj_exists(area, level, sysid);
+ adjacent = !!isis_adj_find(area, level, sysid);
switch (srn->state) {
case SRDB_STATE_NEW:
case SRDB_STATE_MODIFIED:
@@ -1980,20 +1980,48 @@ static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
* Declaration of new show commands.
*/
DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
- "show isis segment-routing prefix-sids",
- SHOW_STR PROTO_HELP
+ "show isis [vrf <NAME|all>] segment-routing prefix-sids",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
"Segment-Routing\n"
"Segment-Routing Prefix-SIDs\n")
{
- struct listnode *node;
+ struct listnode *node, *inode, *nnode;
struct isis_area *area;
-
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- vty_out(vty, "Area %s:\n",
- area->area_tag ? area->area_tag : "null");
-
- for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
- show_prefix_sids(vty, area, level);
+ struct isis *isis = NULL;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag
+ : "null");
+ for (int level = ISIS_LEVEL1;
+ level <= ISIS_LEVELS; level++)
+ show_prefix_sids(vty, area,
+ level);
+ }
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag
+ : "null");
+ for (int level = ISIS_LEVEL1;
+ level <= ISIS_LEVELS; level++)
+ show_prefix_sids(vty, area, level);
+ }
+ }
}
return CMD_SUCCESS;
@@ -2056,15 +2084,19 @@ DEFUN(show_sr_node, show_sr_node_cmd,
"Segment-Routing\n"
"Segment-Routing node\n")
{
- struct listnode *node;
+ struct listnode *node, *inode, *nnode;
struct isis_area *area;
+ struct isis *isis = NULL;
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- vty_out(vty, "Area %s:\n",
- area->area_tag ? area->area_tag : "null");
+ for (ALL_LIST_ELEMENTS(im->isis, inode, nnode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
- for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
- show_node(vty, area, level);
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+ level++)
+ show_node(vty, area, level);
+ }
}
return CMD_SUCCESS;
@@ -2103,7 +2135,7 @@ static int sr_start_label_manager(struct thread *start)
int isis_sr_start(struct isis_area *area)
{
struct isis_sr_db *srdb = &area->srdb;
- struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
struct listnode *node;
/* First start Label Manager if not ready */
@@ -2140,34 +2172,11 @@ int isis_sr_start(struct isis_area *area)
area->area_tag);
/* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- struct isis_adjacency *adj;
- struct listnode *anode;
-
- switch (circuit->circ_type) {
- case CIRCUIT_T_BROADCAST:
- for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
- level++) {
- for (ALL_LIST_ELEMENTS_RO(
- circuit->u.bc.adjdb[level - 1],
- anode, adj)) {
- if (adj->ipv4_address_count > 0)
- sr_adj_sid_add(adj, AF_INET);
- if (adj->ipv6_address_count > 0)
- sr_adj_sid_add(adj, AF_INET6);
- }
- }
- break;
- case CIRCUIT_T_P2P:
- adj = circuit->u.p2p.neighbor;
- if (adj && adj->ipv4_address_count > 0)
- sr_adj_sid_add(adj, AF_INET);
- if (adj && adj->ipv6_address_count > 0)
- sr_adj_sid_add(adj, AF_INET6);
- break;
- default:
- break;
- }
+ for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
+ if (adj->ipv4_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET);
+ if (adj->ipv6_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET6);
}
area->srdb.enabled = true;
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index a599909eb8..016f811a72 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -302,34 +302,68 @@ int isis_mpls_te_update(struct interface *ifp)
/* Followings are vty command functions */
#ifndef FABRICD
-DEFUN (show_isis_mpls_te_router,
- show_isis_mpls_te_router_cmd,
- "show " PROTO_NAME " mpls-te router",
- SHOW_STR
- PROTO_HELP
- MPLS_TE_STR
- "Router information\n")
+DEFUN(show_isis_mpls_te_router,
+ show_isis_mpls_te_router_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] mpls-te router",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR "All VRFs\n"
+ MPLS_TE_STR "Router information\n")
{
- struct listnode *anode;
+ struct listnode *anode, *nnode, *inode;
struct isis_area *area;
+ struct isis *isis = NULL;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
- if (!isis) {
+ if (!im) {
vty_out(vty, "IS-IS Routing Process not enabled\n");
return CMD_SUCCESS;
}
-
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
-
- if (!IS_MPLS_TE(area->mta))
- continue;
-
- vty_out(vty, "Area %s:\n", area->area_tag);
- if (ntohs(area->mta->router_id.s_addr) != 0)
- vty_out(vty, " MPLS-TE Router-Address: %s\n",
- inet_ntoa(area->mta->router_id));
- else
- vty_out(vty, " N/A\n");
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list,
+ anode, area)) {
+ if (!IS_MPLS_TE(area->mta))
+ continue;
+
+ vty_out(vty, "Area %s:\n",
+ area->area_tag);
+ if (ntohs(area->mta->router_id.s_addr)
+ != 0)
+ vty_out(vty,
+ " MPLS-TE Router-Address: %s\n",
+ inet_ntoa(
+ area->mta
+ ->router_id));
+ else
+ vty_out(vty, " N/A\n");
+ }
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
+ area)) {
+
+ if (!IS_MPLS_TE(area->mta))
+ continue;
+
+ vty_out(vty, "Area %s:\n", area->area_tag);
+ if (ntohs(area->mta->router_id.s_addr) != 0)
+ vty_out(vty,
+ " MPLS-TE Router-Address: %s\n",
+ inet_ntoa(
+ area->mta->router_id));
+ else
+ vty_out(vty, " N/A\n");
+ }
+ }
}
return CMD_SUCCESS;
@@ -449,30 +483,35 @@ DEFUN (show_isis_mpls_te_interface,
"Interface information\n"
"Interface name\n")
{
- struct listnode *anode, *cnode;
+ struct listnode *anode, *cnode, *nnode, *inode;
struct isis_area *area;
struct isis_circuit *circuit;
struct interface *ifp;
int idx_interface = 4;
+ struct isis *isis = NULL;
- if (!isis) {
+ if (!im) {
vty_out(vty, "IS-IS Routing Process not enabled\n");
return CMD_SUCCESS;
}
if (argc == idx_interface) {
/* Show All Interfaces. */
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
+ area)) {
- if (!IS_MPLS_TE(area->mta))
- continue;
+ if (!IS_MPLS_TE(area->mta))
+ continue;
- vty_out(vty, "Area %s:\n", area->area_tag);
+ vty_out(vty, "Area %s:\n", area->area_tag);
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode,
- circuit))
- show_ext_sub(vty, circuit->interface->name,
- circuit->ext);
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
+ cnode, circuit))
+ show_ext_sub(vty,
+ circuit->interface->name,
+ circuit->ext);
+ }
}
} else {
/* Interface name is specified. */
diff --git a/isisd/isis_vty_fabricd.c b/isisd/isis_vty_fabricd.c
index a574c5bd3f..d0a411a8db 100644
--- a/isisd/isis_vty_fabricd.c
+++ b/isisd/isis_vty_fabricd.c
@@ -112,12 +112,13 @@ DEFUN (no_triggered_csnp,
return CMD_SUCCESS;
}
-static void lsp_print_flooding(struct vty *vty, struct isis_lsp *lsp)
+static void lsp_print_flooding(struct vty *vty, struct isis_lsp *lsp,
+ struct isis *isis)
{
char lspid[255];
char buf[MONOTIME_STRLEN];
- lspid_print(lsp->hdr.lsp_id, lspid, true, true);
+ lspid_print(lsp->hdr.lsp_id, lspid, true, true, isis);
vty_out(vty, "Flooding information for %s\n", lspid);
if (!lsp->flooding_neighbors[TX_LSP_NORMAL]) {
@@ -170,25 +171,29 @@ DEFUN (show_lsp_flooding,
struct listnode *node;
struct isis_area *area;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
struct lspdb_head *head = &area->lspdb[ISIS_LEVEL2 - 1];
struct isis_lsp *lsp;
- vty_out(vty, "Area %s:\n", area->area_tag ?
- area->area_tag : "null");
-
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
if (lspid) {
- lsp = lsp_for_arg(head, lspid);
-
+ lsp = lsp_for_arg(head, lspid, isis);
if (lsp)
- lsp_print_flooding(vty, lsp);
-
+ lsp_print_flooding(vty, lsp, isis);
continue;
}
-
frr_each (lspdb, head, lsp) {
- lsp_print_flooding(vty, lsp);
+ lsp_print_flooding(vty, lsp, isis);
vty_out(vty, "\n");
}
}
@@ -222,9 +227,9 @@ DEFUN (ip_router_isis,
}
}
- area = isis_area_lookup(area_tag);
+ area = isis_area_lookup(area_tag, VRF_DEFAULT);
if (!area)
- area = isis_area_create(area_tag);
+ area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
if (!circuit || !circuit->area) {
circuit = isis_circuit_create(area, ifp);
@@ -276,7 +281,7 @@ DEFUN (no_ip_router_isis,
const char *af = argv[idx_afi]->arg;
const char *area_tag = argv[idx_word]->arg;
- area = isis_area_lookup(area_tag);
+ area = isis_area_lookup(area_tag, VRF_DEFAULT);
if (!area) {
vty_out(vty, "Can't find ISIS instance %s\n",
area_tag);
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index a80a18d887..3aa21a9aed 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -62,6 +62,13 @@ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
struct isis_area *area;
struct listnode *node;
struct prefix router_id;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(vrf_id);
+
+ if (isis == NULL) {
+ return -1;
+ }
zebra_router_id_update_read(zclient->ibuf, &router_id);
if (isis->router_id == router_id.u.prefix4.s_addr)
@@ -407,6 +414,12 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
{
struct zapi_route api;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(vrf_id);
+
+ if (isis == NULL)
+ return -1;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
@@ -428,10 +441,11 @@ static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
}
if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
- isis_redist_add(api.type, &api.prefix, &api.src_prefix,
+ isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
api.distance, api.metric);
else
- isis_redist_delete(api.type, &api.prefix, &api.src_prefix);
+ isis_redist_delete(isis, api.type, &api.prefix,
+ &api.src_prefix);
return 0;
}
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 6f126b7faf..0d39aba20b 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -35,6 +35,7 @@
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "vrf.h"
#include "spf_backoff.h"
#include "lib/northbound_cli.h"
@@ -75,44 +76,142 @@ unsigned long debug_bfd;
unsigned long debug_tx_queue;
unsigned long debug_sr;
-struct isis *isis = NULL;
-
-DEFINE_QOBJ_TYPE(isis)
DEFINE_QOBJ_TYPE(isis_area)
+/* ISIS process wide configuration. */
+static struct isis_master isis_master;
+
+/* ISIS process wide configuration pointer to export. */
+struct isis_master *im;
+
/*
* Prototypes.
*/
int isis_area_get(struct vty *, const char *);
int area_net_title(struct vty *, const char *);
int area_clear_net_title(struct vty *, const char *);
-int show_isis_interface_common(struct vty *, const char *ifname, char);
-int show_isis_neighbor_common(struct vty *, const char *id, char);
-int clear_isis_neighbor_common(struct vty *, const char *id);
+int show_isis_interface_common(struct vty *, const char *ifname, char,
+ const char *vrf_name, bool all_vrf);
+int show_isis_neighbor_common(struct vty *, const char *id, char,
+ const char *vrf_name, bool all_vrf);
+int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name,
+ bool all_vrf);
+
+static void isis_add(struct isis *isis)
+{
+ listnode_add(im->isis, isis);
+}
+
+static void isis_delete(struct isis *isis)
+{
+ listnode_delete(im->isis, isis);
+}
+
+/* Link ISIS instance to VRF. */
+void isis_vrf_link(struct isis *isis, struct vrf *vrf)
+{
+ isis->vrf_id = vrf->vrf_id;
+ if (vrf->info != (void *)isis)
+ vrf->info = (void *)isis;
+}
+
+/* Unlink ISIS instance to VRF. */
+void isis_vrf_unlink(struct isis *isis, struct vrf *vrf)
+{
+ if (vrf->info == (void *)isis)
+ vrf->info = NULL;
+ isis->vrf_id = VRF_UNKNOWN;
+}
+
+struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id)
+{
+ struct isis *isis = NULL;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis))
+ if (isis->vrf_id == vrf_id)
+ return isis;
+ return NULL;
+}
+
+struct isis *isis_lookup_by_vrfname(const char *vrfname)
+{
+ struct isis *isis = NULL;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis))
+ if (isis->name && vrfname && strcmp(isis->name, vrfname) == 0)
+ return isis;
+ return NULL;
+}
+
+struct isis *isis_lookup_by_sysid(uint8_t *sysid)
+{
+ struct isis *isis = NULL;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis))
+ if (!memcmp(isis->sysid, sysid, ISIS_SYS_ID_LEN))
+ return isis;
+ return NULL;
+}
+
+void isis_master_init(struct thread_master *master)
+{
+ memset(&isis_master, 0, sizeof(struct isis_master));
+ im = &isis_master;
+ im->isis = list_new();
+ im->master = master;
+}
+
+void isis_global_instance_create()
+{
+ struct isis *isis = NULL;
+ isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ if (isis == NULL) {
+ isis = isis_new(VRF_DEFAULT);
+ isis_add(isis);
+ }
+}
-void isis_new(unsigned long process_id, vrf_id_t vrf_id)
+struct isis *isis_new(vrf_id_t vrf_id)
{
+ struct vrf *vrf = NULL;
+ struct isis *isis = NULL;
+
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
+ isis->vrf_id = vrf_id;
+ vrf = vrf_lookup_by_id(vrf_id);
+
+ if (vrf) {
+ isis_vrf_link(isis, vrf);
+ isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+ }
+
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "%s: Create new isis instance with vrf_name %s vrf_id %u",
+ __func__, isis->name, isis->vrf_id);
+
/*
* Default values
*/
- isis->vrf_id = vrf_id;
isis->max_area_addrs = 3;
- isis->process_id = process_id;
+ isis->process_id = getpid();
isis->router_id = 0;
isis->area_list = list_new();
isis->init_circ_list = list_new();
isis->uptime = time(NULL);
- dyn_cache_init();
+ dyn_cache_init(isis);
- QOBJ_REG(isis, isis);
+ return isis;
}
-struct isis_area *isis_area_create(const char *area_tag)
+struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
{
struct isis_area *area;
-
+ struct isis *isis = NULL;
+ struct vrf *vrf = NULL;
area = XCALLOC(MTYPE_ISIS_AREA, sizeof(struct isis_area));
/*
@@ -136,6 +235,7 @@ struct isis_area *isis_area_create(const char *area_tag)
spftree_area_init(area);
area->circuit_list = list_new();
+ area->adjacency_list = list_new();
area->area_addrs = list_new();
thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
flags_initialize(&area->flags);
@@ -192,6 +292,25 @@ struct isis_area *isis_area_create(const char *area_tag)
area_mt_init(area);
area->area_tag = strdup(area_tag);
+
+ if (vrf_name) {
+ vrf = vrf_lookup_by_name(vrf_name);
+ if (vrf) {
+ isis = isis_lookup_by_vrfid(vrf->vrf_id);
+ if (isis == NULL) {
+ isis = isis_new(vrf->vrf_id);
+ isis_add(isis);
+ }
+ } else
+ return NULL;
+ } else {
+ isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ if (isis == NULL) {
+ isis = isis_new(VRF_DEFAULT);
+ isis_add(isis);
+ }
+ }
+
listnode_add(isis->area_list, area);
area->isis = isis;
@@ -212,10 +331,15 @@ struct isis_area *isis_area_create(const char *area_tag)
return area;
}
-struct isis_area *isis_area_lookup(const char *area_tag)
+struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id)
{
struct isis_area *area;
struct listnode *node;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfid(vrf_id);
+ if (isis == NULL)
+ return NULL;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
if ((area->area_tag == NULL && area_tag == NULL)
@@ -230,14 +354,14 @@ int isis_area_get(struct vty *vty, const char *area_tag)
{
struct isis_area *area;
- area = isis_area_lookup(area_tag);
+ area = isis_area_lookup(area_tag, VRF_DEFAULT);
if (area) {
VTY_PUSH_CONTEXT(ROUTER_NODE, area);
return CMD_SUCCESS;
}
- area = isis_area_create(area_tag);
+ area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
if (IS_DEBUG_EVENTS)
zlog_debug("New IS-IS area instance %s", area->area_tag);
@@ -247,21 +371,12 @@ int isis_area_get(struct vty *vty, const char *area_tag)
return CMD_SUCCESS;
}
-int isis_area_destroy(const char *area_tag)
+void isis_area_destroy(struct isis_area *area)
{
- struct isis_area *area;
struct listnode *node, *nnode;
struct isis_circuit *circuit;
struct area_addr *addr;
- area = isis_area_lookup(area_tag);
-
- if (area == NULL) {
- zlog_warn("%s: could not find area with area-tag %s",
- __func__, area_tag);
- return CMD_ERR_NO_MATCH;
- }
-
QOBJ_UNREG(area);
if (fabricd)
@@ -280,6 +395,7 @@ int isis_area_destroy(const char *area_tag)
}
list_delete(&area->circuit_list);
}
+ list_delete(&area->adjacency_list);
lsp_db_fini(&area->lspdb[0]);
lsp_db_fini(&area->lspdb[1]);
@@ -312,20 +428,50 @@ int isis_area_destroy(const char *area_tag)
thread_cancel_event(master, area);
- listnode_delete(isis->area_list, area);
+ listnode_delete(area->isis->area_list, area);
free(area->area_tag);
area_mt_finish(area);
+ if (listcount(area->isis->area_list) == 0) {
+ memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 0;
+ }
+
XFREE(MTYPE_ISIS_AREA, area);
- if (listcount(isis->area_list) == 0) {
- memset(isis->sysid, 0, ISIS_SYS_ID_LEN);
- isis->sysid_set = 0;
+}
+
+void isis_finish(struct isis *isis)
+{
+ struct vrf *vrf = NULL;
+
+ isis_delete(isis);
+ if (isis->name) {
+ vrf = vrf_lookup_by_name(isis->name);
+ if (vrf)
+ isis_vrf_unlink(isis, vrf);
+ XFREE(MTYPE_ISIS, isis->name);
+ } else {
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ if (vrf)
+ isis_vrf_unlink(isis, vrf);
}
- return CMD_SUCCESS;
+ XFREE(MTYPE_ISIS, isis);
+}
+
+void isis_terminate()
+{
+ struct isis *isis = NULL;
+ struct listnode *node, *nnode;
+
+ if (listcount(im->isis) == 0)
+ return;
+
+ for (ALL_LIST_ELEMENTS(im->isis, node, nnode, isis))
+ isis_finish(isis);
}
#ifdef FABRICD
@@ -366,10 +512,10 @@ int area_net_title(struct vty *vty, const char *net_title)
uint8_t buff[255];
/* We check that we are not over the maximal number of addresses */
- if (listcount(area->area_addrs) >= isis->max_area_addrs) {
+ if (listcount(area->area_addrs) >= area->isis->max_area_addrs) {
vty_out(vty,
"Maximum of area addresses (%d) already reached \n",
- isis->max_area_addrs);
+ area->isis->max_area_addrs);
return CMD_ERR_NOTHING_TODO;
}
@@ -395,20 +541,21 @@ int area_net_title(struct vty *vty, const char *net_title)
return CMD_WARNING_CONFIG_FAILED;
}
- if (isis->sysid_set == 0) {
+ if (area->isis->sysid_set == 0) {
/*
* First area address - get the SystemID for this router
*/
- memcpy(isis->sysid, GETSYSID(addr), ISIS_SYS_ID_LEN);
- isis->sysid_set = 1;
+ memcpy(area->isis->sysid, GETSYSID(addr), ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 1;
if (IS_DEBUG_EVENTS)
zlog_debug("Router has SystemID %s",
- sysid_print(isis->sysid));
+ sysid_print(area->isis->sysid));
} else {
/*
* Check that the SystemID portions match
*/
- if (memcmp(isis->sysid, GETSYSID(addr), ISIS_SYS_ID_LEN)) {
+ if (memcmp(area->isis->sysid, GETSYSID(addr),
+ ISIS_SYS_ID_LEN)) {
vty_out(vty,
"System ID must not change when defining additional area addresses\n");
XFREE(MTYPE_ISIS_AREA_ADDR, addr);
@@ -480,8 +627,8 @@ int area_clear_net_title(struct vty *vty, const char *net_title)
* Last area address - reset the SystemID for this router
*/
if (listcount(area->area_addrs) == 0) {
- memset(isis->sysid, 0, ISIS_SYS_ID_LEN);
- isis->sysid_set = 0;
+ memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN);
+ area->isis->sysid_set = 0;
if (IS_DEBUG_EVENTS)
zlog_debug("Router has no SystemID");
}
@@ -493,100 +640,144 @@ int area_clear_net_title(struct vty *vty, const char *net_title)
* 'show isis interface' command
*/
-int show_isis_interface_common(struct vty *vty, const char *ifname, char detail)
+int show_isis_interface_common(struct vty *vty, const char *ifname, char detail,
+ const char *vrf_name, bool all_vrf)
{
- struct listnode *anode, *cnode;
+ struct listnode *anode, *cnode, *mnode, *inode;
struct isis_area *area;
struct isis_circuit *circuit;
+ struct isis *isis = NULL;
- if (!isis) {
+ if (!im) {
vty_out(vty, "IS-IS Routing Process not enabled\n");
return CMD_SUCCESS;
}
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, mnode, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list,
+ anode, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag);
+
+ if (detail == ISIS_UI_LEVEL_BRIEF)
+ vty_out(vty,
+ " Interface CircId State Type Level\n");
+
+ for (ALL_LIST_ELEMENTS_RO(
+ area->circuit_list, cnode,
+ circuit))
+ if (!ifname)
+ isis_circuit_print_vty(
+ circuit, vty,
+ detail);
+ else if (strcmp(circuit->interface->name, ifname) == 0)
+ isis_circuit_print_vty(
+ circuit, vty,
+ detail);
+ }
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
+ area)) {
+ vty_out(vty, "Area %s:\n", area->area_tag);
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
- vty_out(vty, "Area %s:\n", area->area_tag);
-
- if (detail == ISIS_UI_LEVEL_BRIEF)
- vty_out(vty,
- " Interface CircId State Type Level\n");
-
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
- if (!ifname)
- isis_circuit_print_vty(circuit, vty, detail);
- else if (strcmp(circuit->interface->name, ifname) == 0)
- isis_circuit_print_vty(circuit, vty, detail);
+ if (detail == ISIS_UI_LEVEL_BRIEF)
+ vty_out(vty,
+ " Interface CircId State Type Level\n");
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
+ cnode, circuit))
+ if (!ifname)
+ isis_circuit_print_vty(
+ circuit, vty, detail);
+ else if (
+ strcmp(circuit->interface->name,
+ ifname)
+ == 0)
+ isis_circuit_print_vty(
+ circuit, vty, detail);
+ }
+ }
}
return CMD_SUCCESS;
}
-DEFUN (show_isis_interface,
- show_isis_interface_cmd,
- "show " PROTO_NAME " interface",
- SHOW_STR
- PROTO_HELP
- "ISIS interface\n")
+DEFUN(show_isis_interface,
+ show_isis_interface_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] interface",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "IS-IS interface\n")
{
- return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF);
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF,
+ vrf_name, all_vrf);
}
-DEFUN (show_isis_interface_detail,
- show_isis_interface_detail_cmd,
- "show " PROTO_NAME " interface detail",
- SHOW_STR
- PROTO_HELP
- "ISIS interface\n"
- "show detailed information\n")
+DEFUN(show_isis_interface_detail,
+ show_isis_interface_detail_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] interface detail",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "IS-IS interface\n"
+ "show detailed information\n")
{
- return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_DETAIL);
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
}
-DEFUN (show_isis_interface_arg,
- show_isis_interface_arg_cmd,
- "show " PROTO_NAME " interface WORD",
- SHOW_STR
- PROTO_HELP
- "ISIS interface\n"
- "ISIS interface name\n")
+DEFUN(show_isis_interface_arg,
+ show_isis_interface_arg_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] interface WORD",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "IS-IS interface\n"
+ "IS-IS interface name\n")
{
- int idx_word = 3;
- return show_isis_interface_common(vty, argv[idx_word]->arg,
- ISIS_UI_LEVEL_DETAIL);
-}
+ int idx_word = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
-/*
- * 'show isis neighbor' command
- */
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
-int show_isis_neighbor_common(struct vty *vty, const char *id, char detail)
+ char *ifname = argv_find(argv, argc, "WORD", &idx_word)
+ ? argv[idx_word]->arg
+ : NULL;
+ return show_isis_interface_common(vty, ifname, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+}
+
+static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
+ struct isis *isis, uint8_t *sysid)
{
struct listnode *anode, *cnode, *node;
struct isis_area *area;
struct isis_circuit *circuit;
struct list *adjdb;
struct isis_adjacency *adj;
- struct isis_dynhn *dynhn;
- uint8_t sysid[ISIS_SYS_ID_LEN];
int i;
- if (!isis) {
- vty_out(vty, "IS-IS Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- memset(sysid, 0, ISIS_SYS_ID_LEN);
- if (id) {
- if (sysid2buff(sysid, id) == 0) {
- dynhn = dynhn_find_by_name(id);
- if (dynhn == NULL) {
- vty_out(vty, "Invalid system id %s\n", id);
- return CMD_SUCCESS;
- }
- memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
- }
- }
-
for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
vty_out(vty, "Area %s:\n", area->area_tag);
@@ -602,9 +793,10 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail)
for (ALL_LIST_ELEMENTS_RO(
adjdb, node, adj))
if (!id
- || !memcmp(adj->sysid,
- sysid,
- ISIS_SYS_ID_LEN))
+ || !memcmp(
+ adj->sysid,
+ sysid,
+ ISIS_SYS_ID_LEN))
isis_adj_print_vty(
adj,
vty,
@@ -622,24 +814,20 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail)
}
}
- return CMD_SUCCESS;
}
-
/*
- * 'clear isis neighbor' command
+ * 'show isis neighbor' command
*/
-int clear_isis_neighbor_common(struct vty *vty, const char *id)
+
+int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
+ const char *vrf_name, bool all_vrf)
{
- struct listnode *anode, *cnode, *cnextnode, *node, *nnode;
- struct isis_area *area;
- struct isis_circuit *circuit;
- struct list *adjdb;
- struct isis_adjacency *adj;
+ struct listnode *nnode, *inode;
struct isis_dynhn *dynhn;
uint8_t sysid[ISIS_SYS_ID_LEN];
- int i;
+ struct isis *isis = NULL;
- if (!isis) {
+ if (!im) {
vty_out(vty, "IS-IS Routing Process not enabled\n");
return CMD_SUCCESS;
}
@@ -656,6 +844,32 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id)
}
}
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ isis_neighbor_common(vty, id, detail, isis,
+ sysid);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ isis_neighbor_common(vty, id, detail, isis, sysid);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static void isis_neighbor_common_clear(struct vty *vty, const char *id,
+ uint8_t *sysid, struct isis *isis)
+{
+ struct listnode *anode, *cnode, *cnextnode, *node, *nnode;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct list *adjdb;
+ struct isis_adjacency *adj;
+ int i;
+
for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, cnode, cnextnode,
circuit)) {
@@ -667,9 +881,10 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id)
adjdb, node, nnode,
adj))
if (!id
- || !memcmp(adj->sysid,
- sysid,
- ISIS_SYS_ID_LEN))
+ || !memcmp(
+ adj->sysid,
+ sysid,
+ ISIS_SYS_ID_LEN))
isis_adj_state_change(
&adj,
ISIS_ADJ_DOWN,
@@ -688,64 +903,149 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id)
}
}
}
-
- return CMD_SUCCESS;
}
-
-DEFUN (show_isis_neighbor,
- show_isis_neighbor_cmd,
- "show " PROTO_NAME " neighbor",
- SHOW_STR
- PROTO_HELP
- "ISIS neighbor adjacencies\n")
+/*
+ * 'clear isis neighbor' command
+ */
+int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_name,
+ bool all_vrf)
{
- return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF);
-}
+ struct listnode *nnode, *inode;
+ struct isis_dynhn *dynhn;
+ uint8_t sysid[ISIS_SYS_ID_LEN];
+ struct isis *isis = NULL;
-DEFUN (show_isis_neighbor_detail,
- show_isis_neighbor_detail_cmd,
- "show " PROTO_NAME " neighbor detail",
- SHOW_STR
- PROTO_HELP
- "ISIS neighbor adjacencies\n"
- "show detailed information\n")
-{
- return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL);
-}
+ if (!im) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
-DEFUN (show_isis_neighbor_arg,
- show_isis_neighbor_arg_cmd,
- "show " PROTO_NAME " neighbor WORD",
- SHOW_STR
- PROTO_HELP
- "ISIS neighbor adjacencies\n"
- "System id\n")
-{
- int idx_word = 3;
- return show_isis_neighbor_common(vty, argv[idx_word]->arg,
- ISIS_UI_LEVEL_DETAIL);
-}
+ memset(sysid, 0, ISIS_SYS_ID_LEN);
+ if (id) {
+ if (sysid2buff(sysid, id) == 0) {
+ dynhn = dynhn_find_by_name(id);
+ if (dynhn == NULL) {
+ vty_out(vty, "Invalid system id %s\n", id);
+ return CMD_SUCCESS;
+ }
+ memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
+ }
+ }
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ isis_neighbor_common_clear(vty, id, sysid,
+ isis);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ isis_neighbor_common_clear(vty, id, sysid, isis);
+ }
-DEFUN (clear_isis_neighbor,
- clear_isis_neighbor_cmd,
- "clear " PROTO_NAME " neighbor",
- CLEAR_STR
- PROTO_HELP
- "ISIS neighbor adjacencies\n")
-{
- return clear_isis_neighbor_common(vty, NULL);
+ return CMD_SUCCESS;
}
-DEFUN (clear_isis_neighbor_arg,
- clear_isis_neighbor_arg_cmd,
- "clear " PROTO_NAME " neighbor WORD",
- CLEAR_STR
- PROTO_HELP
- "ISIS neighbor adjacencies\n"
- "System id\n")
-{
- int idx_word = 3;
- return clear_isis_neighbor_common(vty, argv[idx_word]->arg);
+DEFUN(show_isis_neighbor,
+ show_isis_neighbor_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All vrfs\n"
+ "IS-IS neighbor adjacencies\n")
+{
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF,
+ vrf_name, all_vrf);
+}
+
+DEFUN(show_isis_neighbor_detail,
+ show_isis_neighbor_detail_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "all vrfs\n"
+ "IS-IS neighbor adjacencies\n"
+ "show detailed information\n")
+{
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+}
+
+DEFUN(show_isis_neighbor_arg,
+ show_isis_neighbor_arg_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD",
+ SHOW_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All vrfs\n"
+ "IS-IS neighbor adjacencies\n"
+ "System id\n")
+{
+ int idx_word = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ char *id = argv_find(argv, argc, "WORD", &idx_word)
+ ? argv[idx_word]->arg
+ : NULL;
+
+ return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+}
+
+DEFUN(clear_isis_neighbor,
+ clear_isis_neighbor_cmd,
+ "clear " PROTO_NAME " [vrf <NAME|all>] neighbor",
+ CLEAR_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All vrfs\n"
+ "IS-IS neighbor adjacencies\n")
+{
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return clear_isis_neighbor_common(vty, NULL, vrf_name, all_vrf);
+}
+
+DEFUN(clear_isis_neighbor_arg,
+ clear_isis_neighbor_arg_cmd,
+ "clear " PROTO_NAME " [vrf <NAME|all>] neighbor WORD",
+ CLEAR_STR
+ PROTO_HELP
+ VRF_CMD_HELP_STR
+ "All vrfs\n"
+ "IS-IS neighbor adjacencies\n"
+ "System id\n")
+{
+ int idx_word = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ char *id = argv_find(argv, argc, "WORD", &idx_word)
+ ? argv[idx_word]->arg
+ : NULL;
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return clear_isis_neighbor_common(vty, id, vrf_name, all_vrf);
}
/*
@@ -1248,34 +1548,41 @@ DEFUN (no_debug_isis_bfd,
return CMD_SUCCESS;
}
-DEFUN (show_hostname,
- show_hostname_cmd,
- "show " PROTO_NAME " hostname",
- SHOW_STR
- PROTO_HELP
- "IS-IS Dynamic hostname mapping\n")
+DEFUN(show_hostname, show_hostname_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] hostname",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "IS-IS Dynamic hostname mapping\n")
{
- dynhn_print_all(vty);
+ struct listnode *nnode, *inode;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ struct isis *isis = NULL;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ dynhn_print_all(vty, isis);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ dynhn_print_all(vty, isis);
+ }
return CMD_SUCCESS;
}
-DEFUN (show_isis_spf_ietf,
- show_isis_spf_ietf_cmd,
- "show " PROTO_NAME " spf-delay-ietf",
- SHOW_STR
- PROTO_HELP
- "SPF delay IETF information\n")
+static void isis_spf_ietf_common(struct vty *vty, struct isis *isis)
{
- if (!isis) {
- vty_out(vty, "ISIS is not running\n");
- return CMD_SUCCESS;
- }
-
struct listnode *node;
struct isis_area *area;
-
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+
+ vty_out(vty, "vrf : %s\n", isis->name);
vty_out(vty, "Area %s:\n",
area->area_tag ? area->area_tag : "null");
@@ -1306,23 +1613,49 @@ DEFUN (show_isis_spf_ietf,
}
}
}
+}
+
+DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] spf-delay-ietf",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "SPF delay IETF information\n")
+{
+ struct listnode *nnode, *inode;
+ struct isis *isis = NULL;
+ int idx_vrf = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf)
+
+ if (!im) {
+ vty_out(vty, "ISIS is not running\n");
+ return CMD_SUCCESS;
+ }
+
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ isis_spf_ietf_common(vty, isis);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ isis_spf_ietf_common(vty, isis);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_isis_summary,
- show_isis_summary_cmd,
- "show " PROTO_NAME " summary",
- SHOW_STR PROTO_HELP "summary\n")
+static void common_isis_summary(struct vty *vty, struct isis *isis)
{
struct listnode *node, *node2;
struct isis_area *area;
int level;
- if (isis == NULL) {
- vty_out(vty, PROTO_NAME " is not running\n");
- return CMD_SUCCESS;
- }
-
+ vty_out(vty, "vrf : %s\n", isis->name);
vty_out(vty, "Process Id : %ld\n", isis->process_id);
if (isis->sysid_set)
vty_out(vty, "System Id : %s\n",
@@ -1390,25 +1723,68 @@ DEFUN (show_isis_summary,
" (not used, IETF SPF delay activated)");
vty_out(vty, "\n");
- vty_out(vty, " IPv4 route computation:\n");
- isis_spf_print(area->spftree[SPFTREE_IPV4][level - 1],
- vty);
+ if (area->ip_circuits) {
+ vty_out(vty, " IPv4 route computation:\n");
+ isis_spf_print(
+ area->spftree[SPFTREE_IPV4][level - 1],
+ vty);
+ }
+
+ if (area->ipv6_circuits) {
+ vty_out(vty, " IPv6 route computation:\n");
+ isis_spf_print(
+ area->spftree[SPFTREE_IPV6][level - 1],
+ vty);
+ }
+
+ if (area->ipv6_circuits
+ && isis_area_ipv6_dstsrc_enabled(area)) {
+ vty_out(vty,
+ " IPv6 dst-src route computation:\n");
+ isis_spf_print(area->spftree[SPFTREE_DSTSRC]
+ [level - 1],
+ vty);
+ }
+ }
+ }
+}
- vty_out(vty, " IPv6 route computation:\n");
- isis_spf_print(area->spftree[SPFTREE_IPV6][level - 1],
- vty);
+DEFUN(show_isis_summary, show_isis_summary_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] summary",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "summary\n")
+{
+ struct listnode *inode, *nnode;
+ int idx_vrf = 0;
+ struct isis *isis = NULL;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
- vty_out(vty, " IPv6 dst-src route computation:\n");
- isis_spf_print(area->spftree[SPFTREE_DSTSRC][level-1],
- vty);
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf)
+ if (!im) {
+ vty_out(vty, PROTO_NAME " is not running\n");
+ return CMD_SUCCESS;
+ }
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ common_isis_summary(vty, isis);
+ }
+ return 0;
}
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ common_isis_summary(vty, isis);
}
+
vty_out(vty, "\n");
return CMD_SUCCESS;
}
-struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv)
+struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
+ struct isis *isis)
{
char sysid[255] = {0};
uint8_t number[3];
@@ -1468,23 +1844,8 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv)
return lsp;
}
-/*
- * This function supports following display options:
- * [ show isis database [detail] ]
- * [ show isis database <sysid> [detail] ]
- * [ show isis database <hostname> [detail] ]
- * [ show isis database <sysid>.<pseudo-id> [detail] ]
- * [ show isis database <hostname>.<pseudo-id> [detail] ]
- * [ show isis database <sysid>.<pseudo-id>-<fragment-number> [detail] ]
- * [ show isis database <hostname>.<pseudo-id>-<fragment-number> [detail] ]
- * [ show isis database detail <sysid> ]
- * [ show isis database detail <hostname> ]
- * [ show isis database detail <sysid>.<pseudo-id> ]
- * [ show isis database detail <hostname>.<pseudo-id> ]
- * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
- * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
- */
-static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
+static int show_isis_database_common(struct vty *vty, const char *argv,
+ int ui_level, struct isis *isis)
{
struct listnode *node;
struct isis_area *area;
@@ -1500,7 +1861,9 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
for (level = 0; level < ISIS_LEVELS; level++) {
if (lspdb_count(&area->lspdb[level]) > 0) {
- lsp = lsp_for_arg(&area->lspdb[level], argv);
+ lsp = NULL;
+ lsp = lsp_for_arg(&area->lspdb[level], argv,
+ isis);
if (lsp != NULL || argv == NULL) {
vty_out(vty,
@@ -1516,14 +1879,17 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
if (ui_level == ISIS_UI_LEVEL_DETAIL)
lsp_print_detail(
lsp, vty,
- area->dynhostname);
+ area->dynhostname,
+ isis);
else
lsp_print(lsp, vty,
- area->dynhostname);
+ area->dynhostname,
+ isis);
} else if (argv == NULL) {
lsp_count = lsp_print_all(
vty, &area->lspdb[level],
- ui_level, area->dynhostname);
+ ui_level, area->dynhostname,
+ isis);
vty_out(vty, " %u LSPs\n\n",
lsp_count);
@@ -1531,25 +1897,64 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
}
}
}
+ return CMD_SUCCESS;
+}
+/*
+ * This function supports following display options:
+ * [ show isis database [detail] ]
+ * [ show isis database <sysid> [detail] ]
+ * [ show isis database <hostname> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database detail <sysid> ]
+ * [ show isis database detail <hostname> ]
+ * [ show isis database detail <sysid>.<pseudo-id> ]
+ * [ show isis database detail <hostname>.<pseudo-id> ]
+ * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
+ * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
+ */
+static int show_isis_database(struct vty *vty, const char *argv, int ui_level,
+ const char *vrf_name, bool all_vrf)
+{
+ struct listnode *inode, *nnode;
+ struct isis *isis = NULL;
+
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ show_isis_database_common(vty, argv, ui_level,
+ isis);
+ }
+ return 0;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ show_isis_database_common(vty, argv, ui_level, isis);
+ }
return CMD_SUCCESS;
}
-DEFUN (show_database,
- show_database_cmd,
- "show " PROTO_NAME " database [detail] [WORD]",
- SHOW_STR
- PROTO_HELP
- "Link state database\n"
- "Detailed information\n"
- "LSP ID\n")
+DEFUN(show_database, show_database_cmd,
+ "show " PROTO_NAME " [vrf <NAME|all>] database [detail] [WORD]",
+ SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Link state database\n"
+ "Detailed information\n"
+ "LSP ID\n")
{
int idx = 0;
+ int idx_vrf = 0;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
int uilevel = argv_find(argv, argc, "detail", &idx)
? ISIS_UI_LEVEL_DETAIL
: ISIS_UI_LEVEL_BRIEF;
char *id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
- return show_isis_database(vty, id, uilevel);
+ ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ return show_isis_database(vty, id, uilevel, vrf_name, all_vrf);
}
#ifdef FABRICD
@@ -1578,8 +1983,20 @@ DEFUN (no_router_openfabric,
PROTO_HELP
"ISO Routing area tag\n")
{
+ struct isis_area *area;
+ const char *area_tag;
int idx_word = 3;
- return isis_area_destroy(argv[idx_word]->arg);
+
+ area_tag = argv[idx_word]->arg;
+ area = isis_area_lookup(area_tag, VRF_DEFAULT);
+ if (area == NULL) {
+ zlog_warn("%s: could not find area with area-tag %s",
+ __func__, area_tag);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ isis_area_destroy(area);
+ return CMD_SUCCESS;
}
#endif /* ifdef FABRICD */
#ifdef FABRICD
@@ -1934,10 +2351,16 @@ DEFUN (no_log_adj_changes,
static int isis_config_write(struct vty *vty)
{
int write = 0;
+ struct isis_area *area;
+ struct listnode *node, *node2, *inode, *nnode;
+ struct isis *isis = NULL;
+
+ if (!im) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
- if (isis != NULL) {
- struct isis_area *area;
- struct listnode *node, *node2;
+ for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
/* ISIS - Area name */
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 57d9691cc7..41b69df2bf 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -55,6 +55,12 @@ static const bool fabricd = false;
extern void isis_cli_init(void);
#endif
+#define ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf) \
+ if (argv_find(argv, argc, "vrf", &idx_vrf)) { \
+ vrf_name = argv[idx_vrf + 1]->arg; \
+ all_vrf = strmatch(vrf_name, "all"); \
+ }
+
extern struct zebra_privs_t isisd_privs;
/* uncomment if you are a developer in bug hunt */
@@ -62,8 +68,18 @@ extern struct zebra_privs_t isisd_privs;
struct fabricd;
+struct isis_master {
+ /* ISIS instance. */
+ struct list *isis;
+ /* ISIS thread master. */
+ struct thread_master *master;
+ /* Various OSPF global configuration. */
+ uint8_t options;
+};
+
struct isis {
vrf_id_t vrf_id;
+ char *name;
unsigned long process_id;
int sysid_set;
uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */
@@ -77,12 +93,9 @@ struct isis {
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
-
- QOBJ_FIELDS
};
-extern struct isis *isis;
-DECLARE_QOBJ_TYPE(isis_area)
+extern struct isis_master *im;
enum spf_tree_id {
SPFTREE_IPV4 = 0,
@@ -110,6 +123,7 @@ struct isis_area {
#define DEFAULT_LSP_MTU 1497
unsigned int lsp_mtu; /* Size of LSPs to generate */
struct list *circuit_list; /* IS-IS circuits */
+ struct list *adjacency_list; /* IS-IS adjacencies */
struct flags flags;
struct thread *t_tick; /* LSP walker */
struct thread *t_lsp_refresh[ISIS_LEVELS];
@@ -193,14 +207,25 @@ struct isis_area {
};
DECLARE_QOBJ_TYPE(isis_area)
+void isis_terminate(void);
+void isis_finish(struct isis *isis);
+void isis_master_init(struct thread_master *master);
+void isis_vrf_link(struct isis *isis, struct vrf *vrf);
+void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
+void isis_global_instance_create(void);
+struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);
+struct isis *isis_lookup_by_vrfname(const char *vrfname);
+struct isis *isis_lookup_by_sysid(uint8_t *sysid);
+
void isis_init(void);
-void isis_new(unsigned long process_id, vrf_id_t vrf_id);
-struct isis_area *isis_area_create(const char *);
-struct isis_area *isis_area_lookup(const char *);
+struct isis *isis_new(vrf_id_t vrf_id);
+struct isis_area *isis_area_create(const char *, const char *);
+struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id);
int isis_area_get(struct vty *vty, const char *area_tag);
-int isis_area_destroy(const char *area_tag);
+void isis_area_destroy(struct isis_area *area);
void print_debug(struct vty *, int, int);
-struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv);
+struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
+ struct isis *isis);
void isis_area_invalidate_routes(struct isis_area *area, int levels);
void isis_area_verify_routes(struct isis_area *area);
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index 41bf3cf7f4..91691d2f1d 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -24,6 +24,7 @@
#include "lib/northbound.h"
#include "lib/prefix.h"
+#include "lib/printfrr.h"
#include "lib/filter.h"
#include "lib/plist.h"
@@ -39,20 +40,19 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen)
return hostaddr & mask.s_addr;
}
-static enum nb_error
-prefix_list_length_validate(const struct lyd_node *dnode)
+static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
{
- int type = yang_dnode_get_enum(dnode, "../../type");
+ int type = yang_dnode_get_enum(args->dnode, "../../type");
const char *xpath_le = NULL, *xpath_ge = NULL;
struct prefix p;
uint8_t le, ge;
if (type == YPLT_IPV4) {
- yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix");
+ yang_dnode_get_prefix(&p, args->dnode, "../ipv4-prefix");
xpath_le = "../ipv4-prefix-length-lesser-or-equal";
xpath_ge = "../ipv4-prefix-length-greater-or-equal";
} else {
- yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix");
+ yang_dnode_get_prefix(&p, args->dnode, "../ipv6-prefix");
xpath_le = "../ipv6-prefix-length-lesser-or-equal";
xpath_ge = "../ipv6-prefix-length-greater-or-equal";
}
@@ -61,19 +61,18 @@ prefix_list_length_validate(const struct lyd_node *dnode)
* Check rule:
* prefix length <= le.
*/
- if (yang_dnode_exists(dnode, xpath_le)) {
- le = yang_dnode_get_uint8(dnode, xpath_le);
+ if (yang_dnode_exists(args->dnode, xpath_le)) {
+ le = yang_dnode_get_uint8(args->dnode, xpath_le);
if (p.prefixlen > le)
goto log_and_fail;
-
}
/*
* Check rule:
* prefix length < ge.
*/
- if (yang_dnode_exists(dnode, xpath_ge)) {
- ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (yang_dnode_exists(args->dnode, xpath_ge)) {
+ ge = yang_dnode_get_uint8(args->dnode, xpath_ge);
if (p.prefixlen >= ge)
goto log_and_fail;
}
@@ -82,18 +81,21 @@ prefix_list_length_validate(const struct lyd_node *dnode)
* Check rule:
* ge <= le.
*/
- if (yang_dnode_exists(dnode, xpath_le) &&
- yang_dnode_exists(dnode, xpath_ge)) {
- le = yang_dnode_get_uint8(dnode, xpath_le);
- ge = yang_dnode_get_uint8(dnode, xpath_ge);
+ if (yang_dnode_exists(args->dnode, xpath_le)
+ && yang_dnode_exists(args->dnode, xpath_ge)) {
+ le = yang_dnode_get_uint8(args->dnode, xpath_le);
+ ge = yang_dnode_get_uint8(args->dnode, xpath_ge);
if (ge > le)
goto log_and_fail;
}
return NB_OK;
- log_and_fail:
- zlog_info("prefix-list: invalid prefix range for %pFX: Make sure that mask length < ge <= le", &p);
+log_and_fail:
+ snprintfrr(
+ args->errmsg, args->errmsg_len,
+ "Invalid prefix range for %pFX: Make sure that mask length < ge <= le",
+ &p);
return NB_ERR_VALIDATION;
}
@@ -829,7 +831,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args->dnode) != NB_OK)
+ prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
@@ -878,7 +880,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
struct prefix_list_entry *ple;
if (args->event == NB_EV_VALIDATE &&
- prefix_list_length_validate(args->dnode) != NB_OK)
+ prefix_list_length_validate(args) != NB_OK)
return NB_ERR_VALIDATION;
if (args->event != NB_EV_APPLY)
diff --git a/lib/linklist.c b/lib/linklist.c
index 2936c5b502..84dc6e1419 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -150,6 +150,23 @@ bool listnode_add_sort_nodup(struct list *list, void *val)
return true;
}
+struct list *list_dup(struct list *list)
+{
+ struct list *dup;
+ struct listnode *node;
+ void *data;
+
+ assert(list);
+
+ dup = list_new();
+ dup->cmp = list->cmp;
+ dup->del = list->del;
+ for (ALL_LIST_ELEMENTS_RO(list, node, data))
+ listnode_add(dup, data);
+
+ return dup;
+}
+
void listnode_add_sort(struct list *list, void *val)
{
struct listnode *n;
diff --git a/lib/linklist.h b/lib/linklist.h
index 94a1a1604a..d8820c924d 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -327,6 +327,19 @@ extern void list_filter_out_nodes(struct list *list, bool (*cond)(void *data));
*/
extern bool listnode_add_sort_nodup(struct list *list, void *val);
+
+/*
+ * Duplicate the specified list, creating a shallow copy of each of its
+ * elements.
+ *
+ * list
+ * list to duplicate
+ *
+ * Returns:
+ * the duplicated list
+ */
+extern struct list *list_dup(struct list *list);
+
/* List iteration macro.
* Usage: for (ALL_LIST_ELEMENTS (...) { ... }
* It is safe to delete the listnode using this macro.
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 97815ceeb9..8ae001e42a 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -986,7 +986,7 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
if (nh->vrf_id != VRF_DEFAULT) {
vrf = vrf_lookup_by_id(nh->vrf_id);
- vty_out(vty, " nexthop-vrf %s", vrf->name);
+ vty_out(vty, " nexthop-vrf %s", VRF_LOGNAME(vrf));
}
if (nh->nh_label && nh->nh_label->num_labels > 0) {
diff --git a/lib/northbound.c b/lib/northbound.c
index 11007e4309..29e843a84e 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -680,8 +680,12 @@ int nb_candidate_commit_prepare(struct nb_context *context,
RB_INIT(nb_config_cbs, &changes);
nb_config_diff(running_config, candidate, &changes);
- if (RB_EMPTY(nb_config_cbs, &changes))
+ if (RB_EMPTY(nb_config_cbs, &changes)) {
+ snprintf(
+ errmsg, errmsg_len,
+ "No changes to apply were found during preparation phase");
return NB_ERR_NO_CHANGES;
+ }
if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
errmsg_len)
@@ -707,23 +711,21 @@ int nb_candidate_commit_prepare(struct nb_context *context,
errmsg_len);
}
-void nb_candidate_commit_abort(struct nb_transaction *transaction)
+void nb_candidate_commit_abort(struct nb_transaction *transaction, char *errmsg,
+ size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_ABORT, transaction, errmsg,
- sizeof(errmsg));
+ errmsg_len);
nb_transaction_free(transaction);
}
void nb_candidate_commit_apply(struct nb_transaction *transaction,
- bool save_transaction, uint32_t *transaction_id)
+ bool save_transaction, uint32_t *transaction_id,
+ char *errmsg, size_t errmsg_len)
{
- char errmsg[BUFSIZ] = {0};
-
(void)nb_transaction_process(NB_EV_APPLY, transaction, errmsg,
- sizeof(errmsg));
- nb_transaction_apply_finish(transaction, errmsg, sizeof(errmsg));
+ errmsg_len);
+ nb_transaction_apply_finish(transaction, errmsg, errmsg_len);
/* Replace running by candidate. */
transaction->config->version++;
@@ -754,9 +756,9 @@ int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
*/
if (ret == NB_OK)
nb_candidate_commit_apply(transaction, save_transaction,
- transaction_id);
+ transaction_id, errmsg, errmsg_len);
else if (transaction != NULL)
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, errmsg_len);
return ret;
}
diff --git a/lib/northbound.h b/lib/northbound.h
index d5028ea7d2..fa5ac5616c 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -910,8 +910,15 @@ extern int nb_candidate_commit_prepare(struct nb_context *context,
*
* transaction
* Candidate configuration to abort. It's consumed by this function.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
-extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
+extern void nb_candidate_commit_abort(struct nb_transaction *transaction,
+ char *errmsg, size_t errmsg_len);
/*
* Commit a previously created configuration transaction.
@@ -925,10 +932,17 @@ extern void nb_candidate_commit_abort(struct nb_transaction *transaction);
*
* transaction_id
* Optional output parameter providing the ID of the committed transaction.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
*/
extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
bool save_transaction,
- uint32_t *transaction_id);
+ uint32_t *transaction_id, char *errmsg,
+ size_t errmsg_len);
/*
* Create a new transaction to commit a candidate configuration. This is a
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 534b5128ee..2f6aef5398 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -74,7 +74,9 @@ static int nb_cli_classic_commit(struct vty *vty)
/* Regenerate candidate for consistency. */
nb_config_replace(vty->candidate_config, running_config, true);
return CMD_WARNING_CONFIG_FAILED;
- }
+ } else if (strlen(errmsg) > 0)
+ /* Successful commit. Print warnings (if any). */
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
}
@@ -318,11 +320,14 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
&context, vty->confirmed_commit_rollback, true,
"Rollback to previous configuration - confirmed commit has timed out",
&transaction_id, errmsg, sizeof(errmsg));
- if (ret == NB_OK)
+ if (ret == NB_OK) {
vty_out(vty,
"Rollback performed successfully (Transaction ID #%u).\n",
transaction_id);
- else {
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
+ } else {
vty_out(vty,
"Failed to rollback to previous configuration.\n\n");
vty_show_nb_errors(vty, ret, errmsg);
@@ -407,6 +412,9 @@ static int nb_cli_commit(struct vty *vty, bool force,
vty_out(vty,
"%% Configuration committed successfully (Transaction ID #%u).\n\n",
transaction_id);
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty, "%% No configuration changes to commit.\n\n");
@@ -1666,6 +1674,9 @@ static int nb_cli_rollback_configuration(struct vty *vty,
case NB_OK:
vty_out(vty,
"%% Configuration was successfully rolled back.\n\n");
+ /* Print warnings (if any). */
+ if (strlen(errmsg) > 0)
+ vty_out(vty, "%s\n", errmsg);
return CMD_SUCCESS;
case NB_ERR_NO_CHANGES:
vty_out(vty,
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index a3aaf02f08..1f480f3d02 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -375,8 +375,10 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen)
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -400,8 +402,9 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen)
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 83d7e0ce95..f35b4bb31b 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -677,11 +677,13 @@ class NorthboundImpl
switch (phase) {
case frr::CommitRequest::VALIDATE:
+ zlog_debug("`-> Performing VALIDATE");
ret = nb_candidate_validate(
&context, candidate->config, errmsg,
sizeof(errmsg));
break;
case frr::CommitRequest::PREPARE:
+ zlog_debug("`-> Performing PREPARE");
ret = nb_candidate_commit_prepare(
&context, candidate->config,
comment.c_str(),
@@ -689,15 +691,20 @@ class NorthboundImpl
sizeof(errmsg));
break;
case frr::CommitRequest::ABORT:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_abort(
- candidate->transaction);
+ candidate->transaction, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::APPLY:
+ zlog_debug("`-> Performing ABORT");
nb_candidate_commit_apply(
candidate->transaction, true,
- &transaction_id);
+ &transaction_id, errmsg,
+ sizeof(errmsg));
break;
case frr::CommitRequest::ALL:
+ zlog_debug("`-> Performing ALL");
ret = nb_candidate_commit(
&context, candidate->config, true,
comment.c_str(), &transaction_id,
@@ -735,12 +742,20 @@ class NorthboundImpl
grpc::StatusCode::INTERNAL, errmsg);
break;
}
+
+ if (nb_dbg_client_grpc)
+ zlog_debug("`-> Result: %s (message: '%s')",
+ nb_err_name((enum nb_error)ret),
+ errmsg);
+
if (ret == NB_OK) {
// Response: uint32 transaction_id = 1;
if (transaction_id)
tag->response.set_transaction_id(
transaction_id);
}
+ if (strlen(errmsg) > 0)
+ tag->response.set_error_message(errmsg);
tag->responder.Finish(tag->response, status, tag);
tag->state = FINISH;
@@ -1281,10 +1296,13 @@ class NorthboundImpl
void delete_candidate(struct candidate *candidate)
{
+ char errmsg[BUFSIZ] = {0};
+
_candidates.erase(candidate->id);
nb_config_free(candidate->config);
if (candidate->transaction)
- nb_candidate_commit_abort(candidate->transaction);
+ nb_candidate_commit_abort(candidate->transaction,
+ errmsg, sizeof(errmsg));
}
struct candidate *get_candidate(uint32_t candidate_id)
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 500203173c..3dec685927 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -37,13 +37,11 @@ DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module")
static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
static struct thread_master *master;
-static struct list *sysrepo_threads;
static sr_session_ctx_t *session;
static sr_conn_ctx_t *connection;
static struct nb_transaction *transaction;
static int frr_sr_read_cb(struct thread *thread);
-static int frr_sr_write_cb(struct thread *thread);
static int frr_sr_finish(void);
/* Convert FRR YANG data value to sysrepo YANG data value. */
@@ -236,25 +234,23 @@ static int frr_sr_process_change(struct nb_config *candidate,
return NB_OK;
}
-static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
- const char *module_name,
- bool startup_config)
+static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session,
+ const char *module_name,
+ bool startup_config)
{
sr_change_iter_t *it;
int ret;
sr_change_oper_t sr_op;
sr_val_t *sr_old_val, *sr_new_val;
- char xpath[XPATH_MAXLEN];
struct nb_context context = {};
struct nb_config *candidate;
char errmsg[BUFSIZ] = {0};
- snprintf(xpath, sizeof(xpath), "/%s:*", module_name);
- ret = sr_get_changes_iter(session, xpath, &it);
+ ret = sr_get_changes_iter(session, "//*", &it);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO,
- "%s: sr_get_changes_iter() failed for xpath %s",
- __func__, xpath);
+ "%s: sr_get_changes_iter() failed for \"%s\"",
+ __func__, module_name);
return ret;
}
@@ -307,12 +303,14 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
__func__, nb_err_name(ret), errmsg);
}
+ if (!transaction)
+ nb_config_free(candidate);
+
/* Map northbound return code to sysrepo return code. */
switch (ret) {
case NB_OK:
return SR_ERR_OK;
case NB_ERR_NO_CHANGES:
- nb_config_free(candidate);
return SR_ERR_OK;
case NB_ERR_LOCKED:
return SR_ERR_LOCKED;
@@ -329,8 +327,10 @@ static int frr_sr_config_change_cb_apply(sr_session_ctx_t *session,
/* Apply the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_apply(transaction, true, NULL);
+ nb_candidate_commit_apply(transaction, true, NULL, errmsg,
+ sizeof(errmsg));
nb_config_free(candidate);
}
@@ -343,8 +343,9 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session,
/* Abort the transaction. */
if (transaction) {
struct nb_config *candidate = transaction->config;
+ char errmsg[BUFSIZ] = {0};
- nb_candidate_commit_abort(transaction);
+ nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg));
nb_config_free(candidate);
}
@@ -353,22 +354,23 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session,
/* Callback for changes in the running configuration. */
static int frr_sr_config_change_cb(sr_session_ctx_t *session,
- const char *module_name,
- sr_notif_event_t sr_ev, void *private_ctx)
+ const char *module_name, const char *xpath,
+ sr_event_t sr_ev, uint32_t request_id,
+ void *private_data)
{
switch (sr_ev) {
case SR_EV_ENABLED:
- return frr_sr_config_change_cb_verify(session, module_name,
- true);
- case SR_EV_VERIFY:
- return frr_sr_config_change_cb_verify(session, module_name,
- false);
- case SR_EV_APPLY:
+ return frr_sr_config_change_cb_prepare(session, module_name,
+ true);
+ case SR_EV_CHANGE:
+ return frr_sr_config_change_cb_prepare(session, module_name,
+ false);
+ case SR_EV_DONE:
return frr_sr_config_change_cb_apply(session, module_name);
case SR_EV_ABORT:
return frr_sr_config_change_cb_abort(session, module_name);
default:
- flog_err(EC_LIB_LIBSYSREPO, "%s: unknown sysrepo event: %u",
+ flog_err(EC_LIB_LIBSYSREPO, "%s: unexpected sysrepo event: %u",
__func__, sr_ev);
return SR_ERR_INTERNAL;
}
@@ -378,70 +380,49 @@ static int frr_sr_state_data_iter_cb(const struct lys_node *snode,
struct yang_translator *translator,
struct yang_data *data, void *arg)
{
- struct list *elements = arg;
-
- listnode_add(elements, data);
+ struct lyd_node *dnode = arg;
+
+ ly_errno = 0;
+ dnode = lyd_new_path(dnode, ly_native_ctx, data->xpath, data->value, 0,
+ LYD_PATH_OPT_UPDATE);
+ if (!dnode && ly_errno) {
+ flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed",
+ __func__);
+ yang_data_free(data);
+ return NB_ERR;
+ }
+ yang_data_free(data);
return NB_OK;
}
/* Callback for state retrieval. */
-static int frr_sr_state_cb(const char *xpath, sr_val_t **values,
- size_t *values_cnt, uint64_t request_id,
- const char *original_xpath, void *private_ctx)
+static int frr_sr_state_cb(sr_session_ctx_t *session, const char *module_name,
+ const char *xpath, const char *request_xpath,
+ uint32_t request_id, struct lyd_node **parent,
+ void *private_ctx)
{
- struct list *elements;
- struct yang_data *data;
- struct listnode *node;
- sr_val_t *v;
- int ret, count, i = 0;
+ struct lyd_node *dnode;
- elements = yang_data_list_new();
- if (nb_oper_data_iterate(xpath, NULL, NB_OPER_DATA_ITER_NORECURSE,
- frr_sr_state_data_iter_cb, elements)
+ dnode = *parent;
+ if (nb_oper_data_iterate(request_xpath, NULL, 0,
+ frr_sr_state_data_iter_cb, dnode)
!= NB_OK) {
flog_warn(EC_LIB_NB_OPERATIONAL_DATA,
"%s: failed to obtain operational data [xpath %s]",
__func__, xpath);
- goto exit;
- }
-
- if (list_isempty(elements))
- goto exit;
-
- count = listcount(elements);
- ret = sr_new_values(count, &v);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_LIBSYSREPO, "%s: sr_new_values(): %s", __func__,
- sr_strerror(ret));
- goto exit;
- }
-
- for (ALL_LIST_ELEMENTS_RO(elements, node, data)) {
- if (yang_data_frr2sr(data, &v[i++]) != 0) {
- flog_err(EC_LIB_SYSREPO_DATA_CONVERT,
- "%s: failed to convert data to sysrepo format",
- __func__);
- }
+ return SR_ERR_INTERNAL;
}
- *values = v;
- *values_cnt = count;
-
- list_delete(&elements);
-
- return SR_ERR_OK;
-
-exit:
- list_delete(&elements);
- *values = NULL;
- *values_cnt = 0;
+ *parent = dnode;
return SR_ERR_OK;
}
-static int frr_sr_config_rpc_cb(const char *xpath, const sr_val_t *sr_input,
- const size_t input_cnt, sr_val_t **sr_output,
+static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, const char *xpath,
+ const sr_val_t *sr_input,
+ const size_t input_cnt, sr_event_t sr_ev,
+ uint32_t request_id, sr_val_t **sr_output,
size_t *sr_output_cnt, void *private_ctx)
{
struct nb_node *nb_node;
@@ -548,8 +529,7 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
}
}
- ret = sr_event_notif_send(session, xpath, values, values_cnt,
- SR_EV_NOTIF_DEFAULT);
+ ret = sr_event_notif_send(session, xpath, values, values_cnt);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO,
"%s: sr_event_notif_send() failed for xpath %s",
@@ -560,102 +540,13 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
return NB_OK;
}
-/* Code to integrate the sysrepo client into FRR main event loop. */
-struct sysrepo_thread {
- struct thread *thread;
- sr_fd_event_t event;
- int fd;
-};
-
-static struct sysrepo_thread *frr_sr_fd_lookup(sr_fd_event_t event, int fd)
-{
- struct sysrepo_thread *sr_thread;
- struct listnode *node;
-
- for (ALL_LIST_ELEMENTS_RO(sysrepo_threads, node, sr_thread)) {
- if (sr_thread->event == event && sr_thread->fd == fd)
- return sr_thread;
- }
-
- return NULL;
-}
-
-static void frr_sr_fd_add(int event, int fd)
-{
- struct sysrepo_thread *sr_thread;
-
- if (frr_sr_fd_lookup(event, fd) != NULL)
- return;
-
- sr_thread = XCALLOC(MTYPE_SYSREPO, sizeof(*sr_thread));
- sr_thread->event = event;
- sr_thread->fd = fd;
- listnode_add(sysrepo_threads, sr_thread);
-
- switch (event) {
- case SR_FD_INPUT_READY:
- thread_add_read(master, frr_sr_read_cb, NULL, fd,
- &sr_thread->thread);
- break;
- case SR_FD_OUTPUT_READY:
- thread_add_write(master, frr_sr_write_cb, NULL, fd,
- &sr_thread->thread);
- break;
- default:
- return;
- }
-}
-
-static void frr_sr_fd_free(struct sysrepo_thread *sr_thread)
-{
- THREAD_OFF(sr_thread->thread);
- XFREE(MTYPE_SYSREPO, sr_thread);
-}
-
-static void frr_sr_fd_del(int event, int fd)
-{
- struct sysrepo_thread *sr_thread;
-
- sr_thread = frr_sr_fd_lookup(event, fd);
- if (!sr_thread)
- return;
-
- listnode_delete(sysrepo_threads, sr_thread);
- frr_sr_fd_free(sr_thread);
-}
-
-static void frr_sr_fd_update(sr_fd_change_t *fd_change_set,
- size_t fd_change_set_cnt)
-{
- for (size_t i = 0; i < fd_change_set_cnt; i++) {
- int fd = fd_change_set[i].fd;
- int event = fd_change_set[i].events;
-
- if (event != SR_FD_INPUT_READY && event != SR_FD_OUTPUT_READY)
- continue;
-
- switch (fd_change_set[i].action) {
- case SR_FD_START_WATCHING:
- frr_sr_fd_add(event, fd);
- break;
- case SR_FD_STOP_WATCHING:
- frr_sr_fd_del(event, fd);
- break;
- default:
- break;
- }
- }
-}
-
static int frr_sr_read_cb(struct thread *thread)
{
+ sr_subscription_ctx_t *sr_subscription = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
- sr_fd_change_t *fd_change_set = NULL;
- size_t fd_change_set_cnt = 0;
int ret;
- ret = sr_fd_event_process(fd, SR_FD_INPUT_READY, &fd_change_set,
- &fd_change_set_cnt);
+ ret = sr_process_events(sr_subscription, session, NULL);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
__func__, sr_strerror(ret));
@@ -663,31 +554,7 @@ static int frr_sr_read_cb(struct thread *thread)
}
thread = NULL;
- thread_add_read(master, frr_sr_read_cb, NULL, fd, &thread);
-
- frr_sr_fd_update(fd_change_set, fd_change_set_cnt);
- free(fd_change_set);
-
- return 0;
-}
-
-static int frr_sr_write_cb(struct thread *thread)
-{
- int fd = THREAD_FD(thread);
- sr_fd_change_t *fd_change_set = NULL;
- size_t fd_change_set_cnt = 0;
- int ret;
-
- ret = sr_fd_event_process(fd, SR_FD_OUTPUT_READY, &fd_change_set,
- &fd_change_set_cnt);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
- __func__, sr_strerror(ret));
- return -1;
- }
-
- frr_sr_fd_update(fd_change_set, fd_change_set_cnt);
- free(fd_change_set);
+ thread_add_read(master, frr_sr_read_cb, sr_subscription, fd, &thread);
return 0;
}
@@ -697,8 +564,8 @@ static void frr_sr_subscribe_config(struct yang_module *module)
int ret;
ret = sr_module_change_subscribe(
- session, module->name, frr_sr_config_change_cb, NULL, 0,
- SR_SUBSCR_DEFAULT | SR_SUBSCR_EV_ENABLED,
+ session, module->name, NULL, frr_sr_config_change_cb, NULL, 0,
+ SR_SUBSCR_DEFAULT | SR_SUBSCR_ENABLED | SR_SUBSCR_NO_THREAD,
&module->sr_subscription);
if (ret != SR_ERR_OK)
flog_err(EC_LIB_LIBSYSREPO, "sr_module_change_subscribe(): %s",
@@ -722,11 +589,11 @@ static int frr_sr_subscribe_state(const struct lys_node *snode, void *arg)
DEBUGD(&nb_dbg_client_sysrepo, "%s: providing data to '%s'", __func__,
nb_node->xpath);
- ret = sr_dp_get_items_subscribe(
- session, nb_node->xpath, frr_sr_state_cb, NULL,
- SR_SUBSCR_CTX_REUSE, &module->sr_subscription);
+ ret = sr_oper_get_items_subscribe(
+ session, snode->module->name, nb_node->xpath, frr_sr_state_cb,
+ NULL, SR_SUBSCR_CTX_REUSE, &module->sr_subscription);
if (ret != SR_ERR_OK)
- flog_err(EC_LIB_LIBSYSREPO, "sr_dp_get_items_subscribe(): %s",
+ flog_err(EC_LIB_LIBSYSREPO, "sr_oper_get_items_subscribe(): %s",
sr_strerror(ret));
return YANG_ITER_CONTINUE;
@@ -747,7 +614,7 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg)
nb_node->xpath);
ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
- NULL, SR_SUBSCR_CTX_REUSE,
+ NULL, 0, SR_SUBSCR_CTX_REUSE,
&module->sr_subscription);
if (ret != SR_ERR_OK)
flog_err(EC_LIB_LIBSYSREPO, "sr_rpc_subscribe(): %s",
@@ -756,30 +623,6 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg)
return YANG_ITER_CONTINUE;
}
-static int frr_sr_subscribe_action(const struct lys_node *snode, void *arg)
-{
- struct yang_module *module = arg;
- struct nb_node *nb_node;
- int ret;
-
- if (snode->nodetype != LYS_ACTION)
- return YANG_ITER_CONTINUE;
-
- nb_node = snode->priv;
-
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing action to '%s'", __func__,
- nb_node->xpath);
-
- ret = sr_action_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
- NULL, SR_SUBSCR_CTX_REUSE,
- &module->sr_subscription);
- if (ret != SR_ERR_OK)
- flog_err(EC_LIB_LIBSYSREPO, "sr_action_subscribe(): %s",
- sr_strerror(ret));
-
- return YANG_ITER_CONTINUE;
-}
-
/* CLI commands. */
DEFUN (debug_nb_sr,
debug_nb_sr_cmd,
@@ -827,22 +670,13 @@ static void frr_sr_cli_init(void)
}
/* FRR's Sysrepo initialization. */
-static int frr_sr_init(const char *program_name)
+static int frr_sr_init(void)
{
struct yang_module *module;
- int sysrepo_fd, ret;
-
- sysrepo_threads = list_new();
-
- ret = sr_fd_watcher_init(&sysrepo_fd, NULL);
- if (ret != SR_ERR_OK) {
- flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_fd_watcher_init(): %s",
- __func__, sr_strerror(ret));
- goto cleanup;
- }
+ int ret;
/* Connect to Sysrepo. */
- ret = sr_connect(program_name, SR_CONN_DEFAULT, &connection);
+ ret = sr_connect(SR_CONN_DEFAULT, &connection);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_connect(): %s", __func__,
sr_strerror(ret));
@@ -850,8 +684,7 @@ static int frr_sr_init(const char *program_name)
}
/* Start session. */
- ret = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT,
- &session);
+ ret = sr_session_start(connection, SR_DS_RUNNING, &session);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_SYSREPO_INIT, "%s: sr_session_start(): %s",
__func__, sr_strerror(ret));
@@ -860,19 +693,28 @@ static int frr_sr_init(const char *program_name)
/* Perform subscriptions. */
RB_FOREACH (module, yang_modules, &yang_modules) {
+ int event_pipe;
+
frr_sr_subscribe_config(module);
yang_snodes_iterate_module(module->info, frr_sr_subscribe_state,
0, module);
yang_snodes_iterate_module(module->info, frr_sr_subscribe_rpc,
0, module);
- yang_snodes_iterate_module(module->info,
- frr_sr_subscribe_action, 0, module);
+
+ /* Watch subscriptions. */
+ ret = sr_get_event_pipe(module->sr_subscription, &event_pipe);
+ if (ret != SR_ERR_OK) {
+ flog_err(EC_LIB_SYSREPO_INIT,
+ "%s: sr_get_event_pipe(): %s", __func__,
+ sr_strerror(ret));
+ goto cleanup;
+ }
+ thread_add_read(master, frr_sr_read_cb, module->sr_subscription,
+ event_pipe, &module->sr_thread);
}
hook_register(nb_notification_send, frr_sr_notification_send);
- frr_sr_fd_add(SR_FD_INPUT_READY, sysrepo_fd);
-
return 0;
cleanup:
@@ -888,7 +730,8 @@ static int frr_sr_finish(void)
RB_FOREACH (module, yang_modules, &yang_modules) {
if (!module->sr_subscription)
continue;
- sr_unsubscribe(session, module->sr_subscription);
+ sr_unsubscribe(module->sr_subscription);
+ THREAD_OFF(module->sr_thread);
}
if (session)
@@ -896,10 +739,6 @@ static int frr_sr_finish(void)
if (connection)
sr_disconnect(connection);
- sysrepo_threads->del = (void (*)(void *))frr_sr_fd_free;
- list_delete(&sysrepo_threads);
- sr_fd_watcher_cleanup();
-
return 0;
}
@@ -907,7 +746,7 @@ static int frr_sr_module_late_init(struct thread_master *tm)
{
master = tm;
- if (frr_sr_init(frr_get_progname()) < 0) {
+ if (frr_sr_init() < 0) {
flog_err(EC_LIB_SYSREPO_INIT,
"failed to initialize the Sysrepo module");
return -1;
diff --git a/lib/stream.c b/lib/stream.c
index 768114e69b..6e62e11380 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -256,6 +256,18 @@ void stream_forward_getp(struct stream *s, size_t size)
s->getp += size;
}
+bool stream_forward_getp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!GETP_VALID(s, s->getp + size))
+ return false;
+
+ s->getp += size;
+
+ return true;
+}
+
void stream_forward_endp(struct stream *s, size_t size)
{
STREAM_VERIFY_SANE(s);
@@ -268,6 +280,18 @@ void stream_forward_endp(struct stream *s, size_t size)
s->endp += size;
}
+bool stream_forward_endp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!ENDP_VALID(s, s->endp + size))
+ return false;
+
+ s->endp += size;
+
+ return true;
+}
+
/* Copy from stream to destination. */
bool stream_get2(void *dst, struct stream *s, size_t size)
{
diff --git a/lib/stream.h b/lib/stream.h
index 1250b6944d..f2c16b3486 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -173,7 +173,9 @@ extern struct stream *stream_dupcat(const struct stream *s1,
extern void stream_set_getp(struct stream *, size_t);
extern void stream_set_endp(struct stream *, size_t);
extern void stream_forward_getp(struct stream *, size_t);
+extern bool stream_forward_getp2(struct stream *, size_t);
extern void stream_forward_endp(struct stream *, size_t);
+extern bool stream_forward_endp2(struct stream *, size_t);
/* steam_put: NULL source zeroes out size_t bytes of stream */
extern void stream_put(struct stream *, const void *, size_t);
@@ -453,6 +455,18 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
goto stream_failure; \
} while (0)
+#define STREAM_FORWARD_GETP(STR, SIZE) \
+ do { \
+ if (!stream_forward_getp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
+#define STREAM_FORWARD_ENDP(STR, SIZE) \
+ do { \
+ if (!stream_forward_endp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/yang.h b/lib/yang.h
index cc048c44e8..94bbed233d 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -63,6 +63,7 @@ struct yang_module {
#endif
#ifdef HAVE_SYSREPO
sr_subscription_ctx_t *sr_subscription;
+ struct thread *sr_thread;
#endif
};
RB_HEAD(yang_modules, yang_module);
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 49cd42d030..61aae695b3 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -4322,7 +4322,7 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi)
*/
void ospf_proactively_arp(struct ospf_neighbor *nbr)
{
- if (!nbr)
+ if (!nbr || !nbr->oi->ospf->proactive_arp)
return;
ospf_zebra_send_arp(nbr->oi->ifp, &nbr->address);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index e8cc50c8d0..8be7748c87 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -8925,6 +8925,31 @@ DEFUN (no_ospf_max_metric_router_lsa_shutdown,
return CMD_SUCCESS;
}
+DEFUN (ospf_proactive_arp,
+ ospf_proactive_arp_cmd,
+ "proactive-arp",
+ "Allow sending ARP requests proactively\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+ ospf->proactive_arp = true;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_proactive_arp,
+ no_ospf_proactive_arp_cmd,
+ "no proactive-arp",
+ NO_STR
+ "Disallow sending ARP requests proactively\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+ ospf->proactive_arp = false;
+
+ return CMD_SUCCESS;
+}
+
static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
{
struct listnode *ln;
@@ -10415,6 +10440,14 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
if (ospf->passive_interface_default == OSPF_IF_PASSIVE)
vty_out(vty, " passive-interface default\n");
+ /* proactive-arp print. */
+ if (ospf->proactive_arp != OSPF_PROACTIVE_ARP_DEFAULT) {
+ if (ospf->proactive_arp)
+ vty_out(vty, " proactive-arp\n");
+ else
+ vty_out(vty, " no proactive-arp\n");
+ }
+
FOR_ALL_INTERFACES (vrf, ifp)
if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp),
passive_interface)
@@ -10871,6 +10904,10 @@ void ospf_vty_init(void)
install_element(OSPF_NODE, &no_ospf_write_multiplier_cmd);
install_element(OSPF_NODE, &no_write_multiplier_cmd);
+ /* "proactive-arp" commands. */
+ install_element(OSPF_NODE, &ospf_proactive_arp_cmd);
+ install_element(OSPF_NODE, &no_ospf_proactive_arp_cmd);
+
/* Init interface related vty commands. */
ospf_vty_if_init();
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index f9cc474d5c..31d8417eb6 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -305,6 +305,8 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
new->oi_write_q = list_new();
new->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT;
+ new->proactive_arp = OSPF_PROACTIVE_ARP_DEFAULT;
+
QOBJ_REG(new, ospf);
new->fd = -1;
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 45d121a4f0..8a1469469f 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -312,6 +312,10 @@ struct ospf {
* update to neighbors immediatly */
uint8_t inst_shutdown;
+ /* Enable or disable sending proactive ARP requests. */
+ bool proactive_arp;
+#define OSPF_PROACTIVE_ARP_DEFAULT true
+
/* Redistributed external information. */
struct list *external[ZEBRA_ROUTE_MAX + 1];
#define EXTERNAL_INFO(E) (E->external_info)
diff --git a/python/makevars.py b/python/makevars.py
index 1a85fbd6f5..63bf8c5eeb 100644
--- a/python/makevars.py
+++ b/python/makevars.py
@@ -70,7 +70,7 @@ class MakeReVars(MakeVarsBase):
repl_re = re.compile(r'\$(?:([A-Za-z])|\(([^\)]+)\))')
def __init__(self, maketext):
- super().__init__()
+ super(MakeReVars, self).__init__()
self._vars = dict(self.var_re.findall(maketext.replace('\\\n', '')))
def replacevar(self, match):
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index ba1a8f9a25..4763406934 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -257,8 +257,9 @@ static int static_route_leak(struct vty *vty, const char *svrf,
strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
sizeof(ab_xpath));
- nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY,
- color_str);
+ if (color_str)
+ nb_cli_enqueue_change(vty, ab_xpath,
+ NB_OP_MODIFY, color_str);
}
if (label_str) {
/* copy of label string (start) */
diff --git a/tests/isisd/test_isis_lspdb.c b/tests/isisd/test_isis_lspdb.c
index f0baa482c7..6a571eaa84 100644
--- a/tests/isisd/test_isis_lspdb.c
+++ b/tests/isisd/test_isis_lspdb.c
@@ -82,6 +82,7 @@ static void test_lsp_build_list_nonzero_ht(void)
int main(int argc, char **argv)
{
+ struct isis *isis = NULL;
isis = calloc(sizeof(*isis), 1);
test_lsp_build_list_nonzero_ht();
return 0;
diff --git a/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf
index 4793155939..57f9cd9e3d 100644
--- a/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf
+++ b/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf
@@ -8,10 +8,12 @@ bfd
detect-multiplier 3
receive-interval 300
transmit-interval 300
+ no shutdown
!
peer 10.0.2.2 interface eth-rt3
detect-multiplier 3
receive-interval 300
transmit-interval 300
+ no shutdown
!
!
diff --git a/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf
index a49cd4fa6b..6b34e337d3 100644
--- a/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf
+++ b/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf
@@ -8,5 +8,6 @@ bfd
detect-multiplier 3
receive-interval 300
transmit-interval 300
+ no shutdown
!
!
diff --git a/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf
index 600054a0bc..22937fe46f 100644
--- a/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf
+++ b/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf
@@ -8,5 +8,6 @@ bfd
detect-multiplier 3
receive-interval 300
transmit-interval 300
+ no shutdown
!
!
diff --git a/tests/topotests/bfd-topo3/__init__.py b/tests/topotests/bfd-topo3/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bfd-topo3/__init__.py
diff --git a/tests/topotests/bfd-topo3/r1/bfd-peers.json b/tests/topotests/bfd-topo3/r1/bfd-peers.json
new file mode 100644
index 0000000000..56205d538b
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r1/bfd-peers.json
@@ -0,0 +1,68 @@
+[
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "local": "2001:db8:1::1",
+ "minimum-ttl": 253,
+ "multihop": true,
+ "passive-mode": true,
+ "peer": "2001:db8:3::1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r1-eth0",
+ "local": "2001:db8:1::1",
+ "multihop": false,
+ "passive-mode": true,
+ "peer": "2001:db8:1::2",
+ "receive-interval": 600,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 600,
+ "remote-transmit-interval": 600,
+ "status": "up",
+ "transmit-interval": 600,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "local": "192.168.1.1",
+ "minimum-ttl": 254,
+ "multihop": true,
+ "passive-mode": true,
+ "peer": "192.168.2.1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ }
+]
diff --git a/tests/topotests/bfd-topo3/r1/bfdd.conf b/tests/topotests/bfd-topo3/r1/bfdd.conf
new file mode 100644
index 0000000000..8e40b76d41
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r1/bfdd.conf
@@ -0,0 +1,17 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ profile fast-tx
+ receive-interval 600
+ transmit-interval 600
+ passive-mode
+ !
+ profile slow-tx
+ receive-interval 2000
+ transmit-interval 2000
+ passive-mode
+ !
+!
diff --git a/tests/topotests/bfd-topo3/r1/bgpd.conf b/tests/topotests/bfd-topo3/r1/bgpd.conf
new file mode 100644
index 0000000000..a0281d50c6
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r1/bgpd.conf
@@ -0,0 +1,20 @@
+router bgp 100
+ no bgp ebgp-requires-policy
+ neighbor 2001:db8:1::2 remote-as internal
+ neighbor 2001:db8:1::2 bfd profile fast-tx
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 ebgp-multihop 2
+ neighbor 192.168.2.1 bfd profile slow-tx
+ neighbor 2001:db8:3::1 remote-as external
+ neighbor 2001:db8:3::1 ebgp-multihop 3
+ neighbor 2001:db8:3::1 bfd profile slow-tx
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor 2001:db8:1::2 activate
+ neighbor 192.168.2.1 activate
+ neighbor 2001:db8:3::1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo3/r1/zebra.conf b/tests/topotests/bfd-topo3/r1/zebra.conf
new file mode 100644
index 0000000000..64aee48436
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r1/zebra.conf
@@ -0,0 +1,10 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+ ipv6 address 2001:db8:1::1/64
+!
diff --git a/tests/topotests/bfd-topo3/r2/bfd-peers.json b/tests/topotests/bfd-topo3/r2/bfd-peers.json
new file mode 100644
index 0000000000..cb8985b13e
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r2/bfd-peers.json
@@ -0,0 +1,46 @@
+[
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r2-eth0",
+ "local": "2001:db8:1::2",
+ "multihop": false,
+ "passive-mode": false,
+ "peer": "2001:db8:1::1",
+ "receive-interval": 600,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 600,
+ "remote-transmit-interval": 600,
+ "status": "up",
+ "transmit-interval": 600,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r2-eth1",
+ "local": "2001:db8:2::2",
+ "multihop": false,
+ "passive-mode": false,
+ "peer": "2001:db8:2::1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ }
+]
diff --git a/tests/topotests/bfd-topo3/r2/bfdd.conf b/tests/topotests/bfd-topo3/r2/bfdd.conf
new file mode 100644
index 0000000000..2a92e463e0
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r2/bfdd.conf
@@ -0,0 +1,15 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ profile fast-tx
+ receive-interval 600
+ transmit-interval 600
+ !
+ profile slow-tx
+ receive-interval 2000
+ transmit-interval 2000
+ !
+!
diff --git a/tests/topotests/bfd-topo3/r2/bgpd.conf b/tests/topotests/bfd-topo3/r2/bgpd.conf
new file mode 100644
index 0000000000..0e96033023
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r2/bgpd.conf
@@ -0,0 +1,15 @@
+router bgp 100
+ no bgp ebgp-requires-policy
+ neighbor 2001:db8:1::1 remote-as internal
+ neighbor 2001:db8:1::1 bfd profile fast-tx
+ neighbor 2001:db8:2::1 remote-as external
+ neighbor 2001:db8:2::1 bfd profile slow-tx
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor 2001:db8:1::1 activate
+ neighbor 2001:db8:2::1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo3/r2/zebra.conf b/tests/topotests/bfd-topo3/r2/zebra.conf
new file mode 100644
index 0000000000..c7e22d4804
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r2/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+ ipv6 address 2001:db8:1::2/64
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+ ipv6 address 2001:db8:2::2/64
+!
diff --git a/tests/topotests/bfd-topo3/r3/bfd-peers.json b/tests/topotests/bfd-topo3/r3/bfd-peers.json
new file mode 100644
index 0000000000..8be35fd084
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r3/bfd-peers.json
@@ -0,0 +1,68 @@
+[
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r3-eth1",
+ "local": "2001:db8:3::2",
+ "multihop": false,
+ "passive-mode": false,
+ "peer": "2001:db8:3::1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r3-eth0",
+ "local": "2001:db8:2::1",
+ "multihop": false,
+ "passive-mode": false,
+ "peer": "2001:db8:2::2",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "local": "192.168.2.1",
+ "minimum-ttl": 254,
+ "multihop": true,
+ "passive-mode": false,
+ "peer": "192.168.1.1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ }
+]
diff --git a/tests/topotests/bfd-topo3/r3/bfdd.conf b/tests/topotests/bfd-topo3/r3/bfdd.conf
new file mode 100644
index 0000000000..f7972c6ce5
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r3/bfdd.conf
@@ -0,0 +1,11 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ profile slow-tx
+ receive-interval 2000
+ transmit-interval 2000
+ !
+!
diff --git a/tests/topotests/bfd-topo3/r3/bgpd.conf b/tests/topotests/bfd-topo3/r3/bgpd.conf
new file mode 100644
index 0000000000..e14d2011a0
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r3/bgpd.conf
@@ -0,0 +1,19 @@
+router bgp 300
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 ebgp-multihop 2
+ neighbor 192.168.1.1 bfd profile slow-tx
+ neighbor 2001:db8:2::2 remote-as external
+ neighbor 2001:db8:2::2 bfd profile slow-tx
+ neighbor 2001:db8:3::1 remote-as external
+ neighbor 2001:db8:3::1 bfd profile slow-tx
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor 192.168.1.1 activate
+ neighbor 2001:db8:2::2 activate
+ neighbor 2001:db8:3::1 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo3/r3/zebra.conf b/tests/topotests/bfd-topo3/r3/zebra.conf
new file mode 100644
index 0000000000..14248fb6f7
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r3/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.1/24
+ ipv6 address 2001:db8:2::1/64
+!
+interface r3-eth1
+ ip address 192.168.3.2/24
+ ipv6 address 2001:db8:3::2/64
+!
diff --git a/tests/topotests/bfd-topo3/r4/bfd-peers.json b/tests/topotests/bfd-topo3/r4/bfd-peers.json
new file mode 100644
index 0000000000..e2e6722ef4
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r4/bfd-peers.json
@@ -0,0 +1,46 @@
+[
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "local": "2001:db8:3::1",
+ "minimum-ttl": 253,
+ "multihop": true,
+ "passive-mode": false,
+ "peer": "2001:db8:1::1",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ },
+ {
+ "detect-multiplier": 3,
+ "diagnostic": "ok",
+ "echo-interval": 0,
+ "id": "*",
+ "interface": "r4-eth0",
+ "local": "2001:db8:3::1",
+ "multihop": false,
+ "passive-mode": false,
+ "peer": "2001:db8:3::2",
+ "receive-interval": 2000,
+ "remote-detect-multiplier": 3,
+ "remote-diagnostic": "ok",
+ "remote-echo-interval": 50,
+ "remote-id": "*",
+ "remote-receive-interval": 2000,
+ "remote-transmit-interval": 2000,
+ "status": "up",
+ "transmit-interval": 2000,
+ "uptime": "*",
+ "vrf": "default"
+ }
+]
diff --git a/tests/topotests/bfd-topo3/r4/bfdd.conf b/tests/topotests/bfd-topo3/r4/bfdd.conf
new file mode 100644
index 0000000000..f44abc0b8a
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r4/bfdd.conf
@@ -0,0 +1,16 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ profile slow-tx
+ receive-interval 2000
+ transmit-interval 2000
+ !
+ profile slow-tx-mh
+ receive-interval 2000
+ transmit-interval 2000
+ minimum-ttl 250
+ !
+!
diff --git a/tests/topotests/bfd-topo3/r4/bgpd.conf b/tests/topotests/bfd-topo3/r4/bgpd.conf
new file mode 100644
index 0000000000..3e81008d5d
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r4/bgpd.conf
@@ -0,0 +1,16 @@
+router bgp 400
+ no bgp ebgp-requires-policy
+ neighbor 2001:db8:3::2 remote-as external
+ neighbor 2001:db8:3::2 bfd profile slow-tx
+ neighbor 2001:db8:1::1 remote-as external
+ neighbor 2001:db8:1::1 ebgp-multihop 3
+ neighbor 2001:db8:1::1 bfd profile slow-tx-mh
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor 2001:db8:1::1 activate
+ neighbor 2001:db8:3::2 activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo3/r4/zebra.conf b/tests/topotests/bfd-topo3/r4/zebra.conf
new file mode 100644
index 0000000000..bf0cfcf42c
--- /dev/null
+++ b/tests/topotests/bfd-topo3/r4/zebra.conf
@@ -0,0 +1,10 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.4/32
+!
+interface r4-eth0
+ ip address 192.168.3.1/24
+ ipv6 address 2001:db8:3::1/64
+!
diff --git a/tests/topotests/bfd-topo3/test_bfd_topo3.dot b/tests/topotests/bfd-topo3/test_bfd_topo3.dot
new file mode 100644
index 0000000000..502cea11f2
--- /dev/null
+++ b/tests/topotests/bfd-topo3/test_bfd_topo3.dot
@@ -0,0 +1,73 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo3";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n192.168.1.0/24\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.2.0/24\n2001:db8:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n192.168.3.0/24\n2001:db8:3::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0\n.1"];
+ r2 -- sw1 [label="eth0\n.2"];
+
+ r3 -- sw2 [label="eth0\n.1"];
+ r2 -- sw2 [label="eth1\n.2"];
+
+ r4 -- sw3 [label="eth0\n.1"];
+ r3 -- sw3 [label="eth2\n.2"];
+}
diff --git a/tests/topotests/bfd-topo3/test_bfd_topo3.jpg b/tests/topotests/bfd-topo3/test_bfd_topo3.jpg
new file mode 100644
index 0000000000..6b532560bf
--- /dev/null
+++ b/tests/topotests/bfd-topo3/test_bfd_topo3.jpg
Binary files differ
diff --git a/tests/topotests/bfd-topo3/test_bfd_topo3.py b/tests/topotests/bfd-topo3/test_bfd_topo3.py
new file mode 100644
index 0000000000..bcee338a92
--- /dev/null
+++ b/tests/topotests/bfd-topo3/test_bfd_topo3.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_topo3.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bfd_topo3.py: Test the FRR BFD daemon multi hop.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class BFDTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BFDTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BFD, daemon_file)
+
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BGP, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def test_wait_bgp_convergence():
+ "Wait for BGP to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_loopback_route(router, iptype, route, proto):
+ "Wait until route is present on RIB for protocol."
+ logger.info('waiting route {} in {}'.format(route, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ 'show {} route json'.format(iptype),
+ { route: [{ 'protocol': proto }] }
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" OSPF convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ # Wait for R1 <-> R2 convergence.
+ expect_loopback_route('r1', 'ip', '10.254.254.2/32', 'bgp')
+ # Wait for R1 <-> R3 convergence.
+ expect_loopback_route('r1', 'ip', '10.254.254.3/32', 'bgp')
+ # Wait for R1 <-> R4 convergence.
+ expect_loopback_route('r1', 'ip', '10.254.254.4/32', 'bgp')
+
+ # Wait for R2 <-> R1 convergence.
+ expect_loopback_route('r2', 'ip', '10.254.254.1/32', 'bgp')
+ # Wait for R2 <-> R3 convergence.
+ expect_loopback_route('r2', 'ip', '10.254.254.3/32', 'bgp')
+ # Wait for R2 <-> R4 convergence.
+ expect_loopback_route('r2', 'ip', '10.254.254.4/32', 'bgp')
+
+ # Wait for R3 <-> R1 convergence.
+ expect_loopback_route('r3', 'ip', '10.254.254.1/32', 'bgp')
+ # Wait for R3 <-> R2 convergence.
+ expect_loopback_route('r3', 'ip', '10.254.254.2/32', 'bgp')
+ # Wait for R3 <-> R4 convergence.
+ expect_loopback_route('r3', 'ip', '10.254.254.4/32', 'bgp')
+
+ # Wait for R4 <-> R1 convergence.
+ expect_loopback_route('r4', 'ip', '10.254.254.1/32', 'bgp')
+ # Wait for R4 <-> R2 convergence.
+ expect_loopback_route('r4', 'ip', '10.254.254.2/32', 'bgp')
+ # Wait for R4 <-> R3 convergence.
+ expect_loopback_route('r4', 'ip', '10.254.254.3/32', 'bgp')
+
+
+def test_wait_bfd_convergence():
+ "Wait for BFD to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("test BFD configurations")
+
+ def expect_bfd_configuration(router):
+ "Load JSON file and compare with 'show bfd peer json'"
+ logger.info('waiting BFD configuration on router {}'.format(router))
+ bfd_config = json.loads(open('{}/{}/bfd-peers.json'.format(CWD, router)).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ 'show bfd peers json',
+ bfd_config
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" BFD configuration failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_bfd_configuration('r1')
+ expect_bfd_configuration('r2')
+ expect_bfd_configuration('r3')
+ expect_bfd_configuration('r4')
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/evpn.vni.json b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/evpn.vni.json
index d9f2182aa0..2937504244 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/evpn.vni.json
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/evpn.vni.json
@@ -3,12 +3,11 @@
"type":"L2",
"vrf":"default",
"vxlanInterface":"vxlan101",
- "ifindex":5,
"vtepIp":"10.10.10.10",
"mcastGroup":"0.0.0.0",
"advertiseGatewayMacip":"No",
"numMacs":5,
- "numArpNd":2,
+ "numArpNd":3,
"numRemoteVteps":[
"10.30.30.30"
]
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/zebra.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/zebra.conf
index 938ec7bca9..e2699475c9 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/zebra.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/zebra.conf
@@ -3,8 +3,6 @@ log file zebra.log
!
interface lo
ip address 10.10.10.10/32
-interface PE1-eth0
- ip address 10.10.1.1/24
interface PE1-eth1
ip address 10.20.1.1/24
!
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/evpn.vni.json b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/evpn.vni.json
index 13255ab4f2..0853147a00 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/evpn.vni.json
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/evpn.vni.json
@@ -3,12 +3,11 @@
"type":"L2",
"vrf":"default",
"vxlanInterface":"vxlan101",
- "ifindex":5,
"vtepIp":"10.30.30.30",
"mcastGroup":"0.0.0.0",
"advertiseGatewayMacip":"No",
"numMacs":5,
- "numArpNd":2,
+ "numArpNd":3,
"numRemoteVteps":[
"10.10.10.10"
]
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/zebra.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/zebra.conf
index 07b83f6395..9738916ab0 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/zebra.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/zebra.conf
@@ -3,6 +3,4 @@ interface lo
ip address 10.30.30.30/32
interface PE2-eth0
ip address 10.20.2.3/24
-interface PE2-eth1
- ip address 10.10.1.3/24
!
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
index ad72540185..90144f5c66 100755
--- a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
@@ -29,6 +29,7 @@ import os
import sys
import json
from functools import partial
+from time import sleep
import pytest
# Save the Current Working Directory to find configuration files.
@@ -97,6 +98,7 @@ def setup_module(mod):
# set up PE bridges with the EVPN member interfaces facing the CE hosts
pe1.run("ip link add name br101 type bridge stp_state 0")
+ pe1.run("ip addr add 10.10.1.1/24 dev br101")
pe1.run("ip link set dev br101 up")
pe1.run(
"ip link add vxlan101 type vxlan id 101 dstport 4789 local 10.10.10.10 nolearning"
@@ -106,6 +108,7 @@ def setup_module(mod):
pe1.run("ip link set dev PE1-eth0 master br101")
pe2.run("ip link add name br101 type bridge stp_state 0")
+ pe2.run("ip addr add 10.10.1.3/24 dev br101")
pe2.run("ip link set dev br101 up")
pe2.run(
"ip link add vxlan101 type vxlan id 101 dstport 4789 local 10.30.30.30 nolearning"
@@ -142,6 +145,15 @@ def teardown_module(mod):
tgen.stop_topology()
+def show_vni_json_elide_ifindex(pe, vni, expected):
+ output_json = pe.vtysh_cmd("show evpn vni {} json".format(vni), isjson=True)
+
+ if "ifindex" in output_json:
+ output_json.pop("ifindex")
+
+ return topotest.json_cmp(output_json, expected)
+
+
def test_pe1_converge_evpn():
"Wait for protocol convergence"
@@ -154,9 +166,7 @@ def test_pe1_converge_evpn():
json_file = "{}/{}/evpn.vni.json".format(CWD, pe1.name)
expected = json.loads(open(json_file).read())
- test_func = partial(
- topotest.router_json_cmp, pe1, "show evpn vni 101 json", expected
- )
+ test_func = partial(show_vni_json_elide_ifindex, pe1, 101, expected)
_, result = topotest.run_and_expect(test_func, None, count=125, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(pe1.name)
assert result is None, assertmsg
@@ -175,9 +185,7 @@ def test_pe2_converge_evpn():
json_file = "{}/{}/evpn.vni.json".format(CWD, pe2.name)
expected = json.loads(open(json_file).read())
- test_func = partial(
- topotest.router_json_cmp, pe2, "show evpn vni 101 json", expected
- )
+ test_func = partial(show_vni_json_elide_ifindex, pe2, 101, expected)
_, result = topotest.run_and_expect(test_func, None, count=125, wait=1)
assertmsg = '"{}" JSON output mismatches'.format(pe2.name)
assert result is None, assertmsg
@@ -194,7 +202,7 @@ def mac_learn_test(host, local):
mac_output = local.vtysh_cmd("show evpn mac vni 101 mac {} json".format(mac))
mac_output_json = json.loads(mac_output)
assertmsg = "Local MAC output does not match interface mac {}".format(mac)
- assert mac_output_json[mac]["type"] == "local"
+ assert mac_output_json[mac]["type"] == "local", assertmsg
def mac_test_local_remote(local, remote):
@@ -275,6 +283,103 @@ def test_local_remote_mac_pe2():
# Memory leak test template
+def ip_learn_test(tgen, host, local, remote, ip_addr):
+ "check the host IP gets learned by the VNI"
+ host_output = host.vtysh_cmd("show interface {}-eth0".format(host.name))
+ int_lines = host_output.splitlines()
+ mac_line = int_lines[7].split(": ")
+ mac = mac_line[1]
+ print(host_output)
+
+ # check we have a local association between the MAC and IP
+ local_output = local.vtysh_cmd("show evpn mac vni 101 mac {} json".format(mac))
+ print(local_output)
+ local_output_json = json.loads(local_output)
+ mac_type = local_output_json[mac]["type"]
+ assertmsg = "Failed to learn local IP address on host {}".format(host.name)
+ assert local_output_json[mac]["neighbors"] != "none", assertmsg
+ learned_ip = local_output_json[mac]["neighbors"]["active"][0]
+
+ assertmsg = "local learned mac wrong type: {} ".format(mac_type)
+ assert mac_type == "local", assertmsg
+
+ assertmsg = "learned address mismatch with configured address host: {} learned: {}".format(
+ ip_addr, learned_ip
+ )
+ assert ip_addr == learned_ip, assertmsg
+
+ # now lets check the remote
+ count = 0
+ converged = False
+ while count < 30:
+ remote_output = remote.vtysh_cmd(
+ "show evpn mac vni 101 mac {} json".format(mac)
+ )
+ print(remote_output)
+ remote_output_json = json.loads(remote_output)
+ type = remote_output_json[mac]["type"]
+ if not remote_output_json[mac]["neighbors"] == "none":
+ # due to a kernel quirk, learned IPs can be inactive
+ if (
+ remote_output_json[mac]["neighbors"]["active"]
+ or remote_output_json[mac]["neighbors"]["inactive"]
+ ):
+ converged = True
+ break
+ count += 1
+ sleep(1)
+
+ print("tries: {}".format(count))
+ assertmsg = "{} remote learned mac no address: {} ".format(host.name, mac)
+ # some debug for this failure
+ if not converged == True:
+ log_output = remote.run("cat zebra.log")
+ print(log_output)
+
+ assert converged == True, assertmsg
+ if remote_output_json[mac]["neighbors"]["active"]:
+ learned_ip = remote_output_json[mac]["neighbors"]["active"][0]
+ else:
+ learned_ip = remote_output_json[mac]["neighbors"]["inactive"][0]
+ assertmsg = "remote learned mac wrong type: {} ".format(type)
+ assert type == "remote", assertmsg
+
+ assertmsg = "remote learned address mismatch with configured address host: {} learned: {}".format(
+ ip_addr, learned_ip
+ )
+ assert ip_addr == learned_ip, assertmsg
+
+
+def test_ip_pe1_learn():
+ "run the IP learn test for PE1"
+
+ tgen = get_topogen()
+ host1 = tgen.gears["host1"]
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ pe2.vtysh_cmd("debug zebra vxlan")
+ pe2.vtysh_cmd("debug zebra kernel")
+ # lets populate that arp cache
+ host1.run("ping -c1 10.10.1.1")
+ ip_learn_test(tgen, host1, pe1, pe2, "10.10.1.55")
+ # tgen.mininet_cli()
+
+
+def test_ip_pe2_learn():
+ "run the IP learn test for PE2"
+
+ tgen = get_topogen()
+ host2 = tgen.gears["host2"]
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ pe1.vtysh_cmd("debug zebra vxlan")
+ pe1.vtysh_cmd("debug zebra kernel")
+ # lets populate that arp cache
+ host2.run("ping -c1 10.10.1.3")
+ ip_learn_test(tgen, host2, pe2, pe1, "10.10.1.56")
+ # tgen.mininet_cli()
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/tests/topotests/isis-sr-topo1/rt1/isisd.conf b/tests/topotests/isis-sr-topo1/rt1/isisd.conf
index 70ae1b07f5..26ec4eb261 100644
--- a/tests/topotests/isis-sr-topo1/rt1/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt1/isisd.conf
@@ -21,6 +21,7 @@ interface eth-sw1
router isis 1
net 49.0000.0000.0000.0001.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
diff --git a/tests/topotests/isis-sr-topo1/rt2/isisd.conf b/tests/topotests/isis-sr-topo1/rt2/isisd.conf
index 733f26bc62..8704a28b6c 100644
--- a/tests/topotests/isis-sr-topo1/rt2/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt2/isisd.conf
@@ -32,6 +32,7 @@ interface eth-rt4-2
router isis 1
net 49.0000.0000.0000.0002.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
diff --git a/tests/topotests/isis-sr-topo1/rt3/isisd.conf b/tests/topotests/isis-sr-topo1/rt3/isisd.conf
index ceb982ca32..5a0add22a9 100644
--- a/tests/topotests/isis-sr-topo1/rt3/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt3/isisd.conf
@@ -32,6 +32,7 @@ interface eth-rt5-2
router isis 1
net 49.0000.0000.0000.0003.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 17000 24999
diff --git a/tests/topotests/isis-sr-topo1/rt4/isisd.conf b/tests/topotests/isis-sr-topo1/rt4/isisd.conf
index 07a7867cbb..39003b9d7b 100644
--- a/tests/topotests/isis-sr-topo1/rt4/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt4/isisd.conf
@@ -39,6 +39,7 @@ interface eth-rt6
router isis 1
net 49.0000.0000.0000.0004.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
diff --git a/tests/topotests/isis-sr-topo1/rt5/isisd.conf b/tests/topotests/isis-sr-topo1/rt5/isisd.conf
index b0fcdede07..e693ca156c 100644
--- a/tests/topotests/isis-sr-topo1/rt5/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt5/isisd.conf
@@ -39,6 +39,7 @@ interface eth-rt6
router isis 1
net 49.0000.0000.0000.0005.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
diff --git a/tests/topotests/isis-sr-topo1/rt6/isisd.conf b/tests/topotests/isis-sr-topo1/rt6/isisd.conf
index 16c34dfae6..3b85dbae4e 100644
--- a/tests/topotests/isis-sr-topo1/rt6/isisd.conf
+++ b/tests/topotests/isis-sr-topo1/rt6/isisd.conf
@@ -27,6 +27,7 @@ interface eth-rt5
router isis 1
net 49.0000.0000.0000.0006.00
is-type level-1
+ lsp-gen-interval 2
topology ipv6-unicast
segment-routing on
segment-routing global-block 16000 23999
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 05410e3c25..a72e5c2772 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -116,7 +116,6 @@ class Vtysh(object):
output = self('configure')
if 'VTY configuration is locked by other VTY' in output:
- print(output)
log.error("vtysh 'configure' returned\n%s\n" % (output))
return False
@@ -1203,7 +1202,11 @@ if __name__ == '__main__':
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--reload', action='store_true', help='Apply the deltas', default=False)
group.add_argument('--test', action='store_true', help='Show the deltas', default=False)
- parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False)
+ level_group = parser.add_mutually_exclusive_group()
+ level_group.add_argument('--debug', action='store_true',
+ help='Enable debugs (synonym for --log-level=debug)', default=False)
+ level_group.add_argument('--log-level', help='Log level', default="info",
+ choices=("critical", "error", "warning", "info", "debug"))
parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False)
parser.add_argument('--pathspace', '-N', metavar='NAME', help='Reload specified path/namespace', default=None)
parser.add_argument('filename', help='Location of new frr config file')
@@ -1220,8 +1223,7 @@ if __name__ == '__main__':
# For --test log to stdout
# For --reload log to /var/log/frr/frr-reload.log
if args.test or args.stdout:
- logging.basicConfig(level=logging.INFO,
- format='%(asctime)s %(levelname)5s: %(message)s')
+ logging.basicConfig(format='%(asctime)s %(levelname)5s: %(message)s')
# Color the errors and warnings in red
logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR))
@@ -1232,7 +1234,6 @@ if __name__ == '__main__':
os.makedirs('/var/log/frr/')
logging.basicConfig(filename='/var/log/frr/frr-reload.log',
- level=logging.INFO,
format='%(asctime)s %(levelname)5s: %(message)s')
# argparse should prevent this from happening but just to be safe...
@@ -1240,45 +1241,49 @@ if __name__ == '__main__':
raise Exception('Must specify --reload or --test')
log = logging.getLogger(__name__)
+ if args.debug:
+ log.setLevel(logging.DEBUG)
+ else:
+ log.setLevel(args.log_level.upper())
+
+ if args.reload and not args.stdout:
+ # Additionally send errors and above to STDOUT, with no metadata,
+ # when we are logging to a file. This specifically does not follow
+ # args.log_level, and is analagous to behaviour in earlier versions
+ # which additionally logged most errors using print().
+
+ stdout_hdlr = logging.StreamHandler(sys.stdout)
+ stdout_hdlr.setLevel(logging.ERROR)
+ stdout_hdlr.setFormatter(logging.Formatter())
+ log.addHandler(stdout_hdlr)
+
# Verify the new config file is valid
if not os.path.isfile(args.filename):
- msg = "Filename %s does not exist" % args.filename
- print(msg)
- log.error(msg)
+ log.error("Filename %s does not exist" % args.filename)
sys.exit(1)
if not os.path.getsize(args.filename):
- msg = "Filename %s is an empty file" % args.filename
- print(msg)
- log.error(msg)
+ log.error("Filename %s is an empty file" % args.filename)
sys.exit(1)
# Verify that confdir is correct
if not os.path.isdir(args.confdir):
- msg = "Confdir %s is not a valid path" % args.confdir
- print(msg)
- log.error(msg)
+ log.error("Confdir %s is not a valid path" % args.confdir)
sys.exit(1)
# Verify that bindir is correct
if not os.path.isdir(args.bindir) or not os.path.isfile(args.bindir + '/vtysh'):
- msg = "Bindir %s is not a valid path to vtysh" % args.bindir
- print(msg)
- log.error(msg)
+ log.error("Bindir %s is not a valid path to vtysh" % args.bindir)
sys.exit(1)
# verify that the vty_socket, if specified, is valid
if args.vty_socket and not os.path.isdir(args.vty_socket):
- msg = 'vty_socket %s is not a valid path' % args.vty_socket
- print(msg)
- log.error(msg)
+ log.error('vty_socket %s is not a valid path' % args.vty_socket)
sys.exit(1)
# verify that the daemon, if specified, is valid
if args.daemon and args.daemon not in ['zebra', 'bgpd', 'fabricd', 'isisd', 'ospf6d', 'ospfd', 'pbrd', 'pimd', 'ripd', 'ripngd', 'sharpd', 'staticd', 'vrrpd', 'ldpd']:
- msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon
- print(msg)
- log.error(msg)
+ log.error("Daemon %s is not a valid option for 'show running-config'" % args.daemon)
sys.exit(1)
vtysh = Vtysh(args.bindir, args.confdir, args.vty_socket, args.pathspace)
@@ -1300,14 +1305,9 @@ if __name__ == '__main__':
break
if not service_integrated_vtysh_config and not args.daemon:
- msg = "'service integrated-vtysh-config' is not configured, this is required for 'service frr reload'"
- print(msg)
- log.error(msg)
+ log.error("'service integrated-vtysh-config' is not configured, this is required for 'service frr reload'")
sys.exit(1)
- if args.debug:
- log.setLevel(logging.DEBUG)
-
log.info('Called via "%s"', str(args))
# Create a Config object from the config generated by newconf
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index 13bad27b19..4b7785e690 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -185,6 +185,13 @@ module frr-bfdd {
default true;
description "Disables or enables the session administratively";
}
+
+ leaf passive-mode {
+ type boolean;
+ default false;
+ description
+ "Don't attempt to start session establishment.";
+ }
}
grouping session-echo {
@@ -204,6 +211,18 @@ module frr-bfdd {
}
}
+ grouping session-multi-hop {
+ description "BFD session multi hop settings.";
+
+ leaf minimum-ttl {
+ type uint8 {
+ range 1..254;
+ }
+ description
+ "Minimum expected TTL on received packets.";
+ }
+ }
+
grouping session-states {
/*
* Local settings.
@@ -363,6 +382,7 @@ module frr-bfdd {
uses session-common;
uses session-echo;
+ uses session-multi-hop;
}
container sessions {
@@ -438,6 +458,7 @@ module frr-bfdd {
}
uses session-common;
+ uses session-multi-hop;
container stats {
uses session-states;
diff --git a/yang/frr-bgp-bmp.yang b/yang/frr-bgp-bmp.yang
new file mode 100644
index 0000000000..344448f104
--- /dev/null
+++ b/yang/frr-bgp-bmp.yang
@@ -0,0 +1,203 @@
+submodule frr-bgp-bmp {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import frr-bgp-types {
+ prefix frr-bt;
+ }
+
+ include frr-bgp-common-multiprotocol;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This submodule defines a model for managing FRR BGP BMP.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping bmp-incoming-session {
+ container incoming-session {
+ list session-list {
+ key "address tcp-port";
+ leaf address {
+ type inet:ip-address;
+ description
+ "IPv4 address to listen on.";
+ }
+
+ leaf tcp-port {
+ type uint32;
+ }
+ }
+ }
+ }
+
+ grouping bmp-outgoing-session {
+ container outgoing-session {
+ list session-list {
+ key "hostname tcp-port";
+ leaf hostname {
+ type string;
+ }
+
+ leaf tcp-port {
+ type uint32;
+ }
+
+ leaf min-retry-time {
+ type uint32 {
+ range "100..86400000";
+ }
+ units "miliseconds";
+ default "30000";
+ description
+ "Minimum connection retry interval.";
+ }
+
+ leaf max-retry-time {
+ type uint32 {
+ range "100..86400000";
+ }
+ units "miliseconds";
+ default "720000";
+ description
+ "Maximum connection retry interval.";
+ }
+ }
+ }
+ }
+
+ grouping bmp-afi-safis {
+ container afi-safis {
+ description
+ "List of address-families associated with the BGP
+ instance.";
+ list afi-safi {
+ key "afi-safi-name";
+ description
+ "AFI, SAFI configuration available for the
+ neighbour or group.";
+ uses mp-afi-safi-config;
+
+ uses mp-all-afi-safi-list-contents;
+ }
+ }
+ }
+
+ grouping bmp-afi-safi-common-config {
+ container common-config {
+ leaf pre-policy {
+ type boolean;
+ default "false";
+ description
+ "Send state before policy and filter processing.";
+ }
+
+ leaf post-policy {
+ type boolean;
+ default "false";
+ description
+ "Send state after policy and filter processing.";
+ }
+ }
+ }
+
+ grouping global-bmp-config {
+ description
+ "Structural grouping used to include filter
+ configuration for BMP.";
+ container bmp-config {
+ description
+ "BMP related parameters.";
+ list target-list {
+ key "target-name";
+ leaf target-name {
+ type string;
+ description
+ "Targets group name.";
+ }
+
+ uses bmp-incoming-session;
+
+ uses bmp-outgoing-session;
+
+ leaf mirror {
+ type boolean;
+ default "false";
+ description
+ "When set to 'TRUE' it send BMP route mirroring messages.";
+ }
+
+ leaf stats-time {
+ type uint32 {
+ range "100..86400000";
+ }
+ units "miliseconds";
+ description
+ "Interval to send BMP Stats.";
+ }
+
+ leaf ipv4-access-list {
+ type frr-bt:access-list-ref;
+ description
+ "Access list to restrict BMP sessions.";
+ }
+
+ leaf ipv6-access-list {
+ type frr-bt:access-list-ref;
+ description
+ "Access list to restrict BMP sessions.";
+ }
+
+ uses bmp-afi-safis;
+ }
+
+ leaf mirror-buffer-limit {
+ type uint32 {
+ range "0..4294967294";
+ }
+ units "bytes";
+ description
+ "Maximum memory used for buffered mirroring messages.";
+ }
+ }
+ }
+}
diff --git a/yang/frr-bgp-common-multiprotocol.yang b/yang/frr-bgp-common-multiprotocol.yang
new file mode 100644
index 0000000000..aefdf02ba6
--- /dev/null
+++ b/yang/frr-bgp-common-multiprotocol.yang
@@ -0,0 +1,209 @@
+submodule frr-bgp-common-multiprotocol {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ import frr-routing {
+ prefix frr-rt;
+ }
+
+ include frr-bgp-common;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module contains general data definitions for use in BGP
+ Multiprotocol.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping mp-afi-safi-config {
+ description
+ "Configuration parameters used for all BGP AFI-SAFIs.";
+ leaf afi-safi-name {
+ type identityref {
+ base frr-rt:afi-safi-type;
+ }
+ description
+ "AFI, SAFI.";
+ }
+ }
+
+ grouping mp-all-afi-safi-list-contents {
+ description
+ "A common grouping used for contents of the list that is used
+ for AFI-SAFI entries.";
+ container ipv4-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv4-unicast')" {
+ description
+ "Include this container for IPv4 Unicast specific
+ configuration.";
+ }
+ description
+ "IPv4 unicast configuration options.";
+ }
+
+ container ipv6-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv6-unicast')" {
+ description
+ "Include this container for IPv6 Unicast specific
+ configuration.";
+ }
+ description
+ "IPv6 unicast configuration options.";
+ }
+
+ container ipv4-labeled-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv4-labeled-unicast')" {
+ description
+ "Include this container for IPv4 Labeled Unicast specific
+ configuration.";
+ }
+ description
+ "IPv4 Labeled Unicast configuration options.";
+ }
+
+ container ipv6-labeled-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv6-labeled-unicast')" {
+ description
+ "Include this container for IPv6 Labeled Unicast specific
+ configuration.";
+ }
+ description
+ "IPv6 Labeled Unicast configuration options.";
+ }
+
+ container l3vpn-ipv4-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'l3vpn-ipv4-unicast')" {
+ description
+ "Include this container for IPv4 Unicast L3VPN specific
+ configuration.";
+ }
+ description
+ "Unicast IPv4 L3VPN configuration options.";
+ }
+
+ container l3vpn-ipv6-unicast {
+ when "derived-from-or-self(../afi-safi-name, 'l3vpn-ipv6-unicast')" {
+ description
+ "Include this container for unicast IPv6 L3VPN specific
+ configuration.";
+ }
+ description
+ "Unicast IPv6 L3VPN configuration options.";
+ }
+
+ container l3vpn-ipv4-multicast {
+ when "derived-from-or-self(../afi-safi-name, 'l3vpn-ipv4-multicast')" {
+ description
+ "Include this container for multicast IPv4 L3VPN specific
+ configuration.";
+ }
+ description
+ "Multicast IPv4 L3VPN configuration options.";
+ }
+
+ container l3vpn-ipv6-multicast {
+ when "derived-from-or-self(../afi-safi-name, 'l3vpn-ipv6-multicast')" {
+ description
+ "Include this container for multicast IPv6 L3VPN specific
+ configuration.";
+ }
+ description
+ "Multicast IPv6 L3VPN configuration options.";
+ }
+
+ container l2vpn-vpls {
+ when "derived-from-or-self(../afi-safi-name, 'l2vpn-vpls')" {
+ description
+ "Include this container for BGP-signalled VPLS specific
+ configuration.";
+ }
+ description
+ "BGP-signalled VPLS configuration options.";
+ }
+
+ container l2vpn-evpn {
+ when "derived-from-or-self(../afi-safi-name, 'l2vpn-evpn')" {
+ description
+ "Include this container for BGP EVPN specific
+ configuration.";
+ }
+ description
+ "BGP EVPN configuration options.";
+ }
+
+ container ipv4-multicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv4-multicast')" {
+ description
+ "Include this container for IPv4 multicast specific
+ configuration.";
+ }
+ description
+ "IPv4 multicast configuration options.";
+ }
+
+ container ipv6-multicast {
+ when "derived-from-or-self(../afi-safi-name, 'ipv6-multicast')" {
+ description
+ "Include this container for IPv6 multicast specific
+ configuration.";
+ }
+ description
+ "IPv6 multicast configuration options.";
+ }
+
+ container ipv4-flowspec {
+ when "derived-from-or-self(../afi-safi-name, 'ipv4-flowspec')" {
+ description
+ "Include this container for IPv4 flowspec specific
+ configuration.";
+ }
+ description
+ "IPv4 flowspec configuration options.";
+ }
+
+ container ipv6-flowspec {
+ when "derived-from-or-self(../afi-safi-name, 'ipv6-flowspec')" {
+ description
+ "Include this container for IPv6 flowspec specific
+ configuration.";
+ }
+ description
+ "IPv6 flowspec configuration options.";
+ }
+ }
+}
diff --git a/yang/frr-bgp-common-structure.yang b/yang/frr-bgp-common-structure.yang
new file mode 100644
index 0000000000..8162527e90
--- /dev/null
+++ b/yang/frr-bgp-common-structure.yang
@@ -0,0 +1,807 @@
+submodule frr-bgp-common-structure {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ import ietf-bgp-types {
+ prefix bt;
+ }
+
+ import frr-bgp-types {
+ prefix frr-bt;
+ }
+
+ include frr-bgp-common;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This submodule contains general data definitions for use in BGP.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping structure-neighbor-group-ebgp-multihop {
+ description
+ "Structural grouping used to include EBGP multi-hop
+ configuration for both BGP neighbors and peer groups.";
+ container ebgp-multihop {
+ description
+ "EBGP multi-hop parameters for the BGP group.";
+ choice hop-count-choice {
+ case default-hop-count {
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "When enabled the referenced group or neighbors are
+ permitted to be indirectly connected - including cases
+ where the TTL can be decremented between the BGP peers.";
+ }
+ }
+
+ case max-hop-count {
+ leaf multihop-ttl {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Time-to-live value to use when packets are sent to the
+ referenced group or neighbors and ebgp-multihop is
+ enabled.";
+ }
+ }
+ }
+
+ leaf disable-connected-check {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it enforces EBGP neighbors perform multihop.";
+ }
+ }
+ }
+
+ grouping neighbor-local-as-options {
+ container local-as {
+ leaf local-as {
+ type inet:as-number;
+ mandatory true;
+ description
+ "The local autonomous system number that is to be used when
+ establishing sessions with the remote peer or peer group, if
+ this differs from the global BGP router autonomous system
+ number.";
+ }
+
+ leaf no-prepend {
+ when "../local-as != 0";
+ type boolean;
+ default "false";
+ description
+ "Do not prepend local-as to updates from EBGP peers. When
+ set to 'true' it will not prepend local-as to updates. When
+ set to 'false' it will prepend local-as to updates.";
+ }
+
+ leaf no-replace-as {
+ type boolean;
+ default "false";
+ description
+ "Do not prepend local-as to updates from IBGP peers.";
+ }
+ }
+ }
+
+ grouping neighbor-bfd-options {
+ container bfd-options {
+ leaf enable {
+ type boolean;
+ default "false";
+ description
+ "BFD support.";
+ }
+
+ leaf detect-multiplier {
+ when "../enable = 'true'";
+ type uint8 {
+ range "2..255";
+ }
+ default "3";
+ description
+ "Detect multiplier.";
+ }
+
+ leaf required-min-rx {
+ when "../enable = 'true'";
+ type uint16 {
+ range "50..60000";
+ }
+ units "miliseconds";
+ default "300";
+ description
+ "Required min receive interval.";
+ }
+
+ leaf desired-min-tx {
+ when "../enable = 'true'";
+ type uint16 {
+ range "50..60000";
+ }
+ units "miliseconds";
+ default "300";
+ description
+ "Desired min transmit interval.";
+ }
+
+ leaf session-type {
+ when "../enable = 'true'";
+ type frr-bt:bfd-session-type;
+ default "not-configured";
+ description
+ "BFD session type.";
+ }
+
+ leaf check-cp-failure {
+ when "../enable = 'true'";
+ type boolean;
+ default "false";
+ description
+ "Link dataplane status with BGP control plane.";
+ }
+ }
+ }
+
+ grouping neighbor-remote-as {
+ container neighbor-remote-as {
+ leaf remote-as-type {
+ type frr-bt:as-type;
+ mandatory true;
+ description
+ "Remote AS type.";
+ }
+
+ leaf remote-as {
+ when "../remote-as-type = 'as-specified'";
+ type inet:as-number;
+ description
+ "The remote autonomous system number received in
+ the BGP OPEN message.";
+ reference
+ "RFC 4271";
+ }
+ }
+ }
+
+ grouping neighbor-update-source {
+ description
+ "Source of routing updates.";
+ container update-source {
+ description
+ "Source of routing updates config.";
+ choice source {
+ case ip-based {
+ leaf ip {
+ type inet:ip-address;
+ description
+ "IPv4 address/IPv6 address.";
+ }
+ }
+
+ case interface-based {
+ leaf interface {
+ type frr-interface:interface-ref {
+ require-instance false;
+ }
+ description
+ "The local interface.";
+ }
+ }
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-add-paths {
+ description
+ "Structural grouping used to include ADD-PATHs configuration
+ and state for both BGP neighbors and peer groups.";
+ container add-paths {
+ description
+ "Parameters relating to the advertisement and receipt of
+ multiple paths for a single NLRI (add-paths).";
+ reference
+ "RFC 7911: ADD-PATH.";
+ leaf path-type {
+ type frr-bt:add-path-type;
+ default "none";
+ description
+ "Enable ability to receive multiple path advertisements for
+ an NLRI from the neighbor or group.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-as-path-options {
+ description
+ "Structural grouping used to include AS_PATH manipulation
+ configuration both BGP neighbors and peer groups.";
+ container as-path-options {
+ description
+ "AS_PATH manipulation parameters for the BGP neighbor or
+ group.";
+ choice allowas-in {
+ case occurence-based {
+ leaf allow-own-as {
+ type uint8 {
+ range "1..10";
+ }
+ description
+ "Specify the number of occurrences of the local BGP
+ speaker's AS that can occur within the AS_PATH before it
+ is rejected.";
+ }
+ }
+
+ case origin-based {
+ leaf allow-own-origin-as {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' only accept my AS in the as-path
+ if the route was originated in my AS.";
+ }
+ }
+ }
+
+ leaf replace-peer-as {
+ type boolean;
+ default "false";
+ description
+ "Replace occurrences of the peer's AS in the AS_PATH with
+ the local autonomous system number. This is same as override
+ ASN CLI.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-capability-options {
+ description
+ "Structural grouping used to include capability
+ configuration for both BGP neighbors and peer groups.";
+ container capability-options {
+ description
+ "Capability manipulation parameters for the BGP neighbor or
+ group.";
+ leaf dynamic-capability {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' dynamic capability is advertise to this peer.";
+ }
+
+ leaf strict-capability {
+ type boolean;
+ default "false";
+ description
+ "Strict capability negotiation match. When set to 'true'
+ remote and local capabilities are strictly compared
+ if capabilities are different, send Unsupported Capability
+ error then reset connection.";
+ }
+
+ leaf extended-nexthop-capability {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' extended next-hop capability is advertise
+ to this peer.";
+ }
+
+ leaf capability-negotiate {
+ type boolean;
+ default "true";
+ description
+ "When set to 'true' sending Capability Negotiation in the open
+ message is supressed to this peer.";
+ }
+
+ leaf override-capability {
+ type boolean;
+ default "false";
+ description
+ "Overrides the result of Capability Negotiation, ignoring remote
+ peer's capability value, when set to 'true'.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-default-originate-options {
+ description
+ "Structural grouping used to include default-originate
+ configuration for both BGP neighbors and peer groups.";
+ container default-originate-options {
+ description
+ "default originate parameters for the BGP neighbor or
+ group.";
+ leaf send-default-route {
+ type boolean;
+ default "false";
+ description
+ "If set to 'true', send the default-route to the neighbour(s).";
+ }
+
+ leaf rmap-policy-export {
+ type frr-bt:rmap-ref;
+ description
+ "Route-map to specify criteria to originate default.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-prefix-limit {
+ container prefix-limit {
+ description
+ "Parameters relating to the prefix limit for the AFI-SAFI.";
+ list direction-list {
+ key "direction";
+ leaf direction {
+ type frr-bt:direction;
+ description
+ "Prefix limit applied on Tx route-updates or Rx route-updates.";
+ }
+
+ leaf max-prefixes {
+ type uint32;
+ mandatory true;
+ description
+ "Maximum number of prefixes that will be accepted from the
+ neighbour.";
+ }
+
+ container prefix-limit-options {
+ when "../direction = 'in'";
+ choice options {
+ case warning {
+ leaf warning-only {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' only give warning message when limit
+ is exceeded.";
+ }
+ }
+
+ case restart {
+ leaf restart-timer {
+ type uint16;
+ units "minutes";
+ description
+ "Time interval in seconds after which the BGP session is
+ re-established after being torn down due to exceeding the
+ max-prefix limit.";
+ }
+ }
+
+ case threshold {
+ leaf shutdown-threshold-pct {
+ type bt:percentage;
+ description
+ "Threshold on number of prefixes that can be received from
+ a neighbour before generation of warning messages or log
+ entries. Expressed as a percentage of max-prefixes.";
+ }
+ }
+
+ case threshold-restart {
+ leaf tr-shutdown-threshold-pct {
+ type bt:percentage;
+ description
+ "Threshold on number of prefixes that can be received from
+ a neighbour before generation of warning messages or log
+ entries. Expressed as a percentage of max-prefixes.";
+ }
+
+ leaf tr-restart-timer {
+ type uint32;
+ units "minutes";
+ description
+ "Time interval in seconds after which the BGP session is
+ re-established after being torn down due to exceeding the
+ max-prefix limit.";
+ }
+ }
+
+ case threshold-warning {
+ leaf tw-shutdown-threshold-pct {
+ type bt:percentage;
+ description
+ "Threshold on number of prefixes that can be received from
+ a neighbour before generation of warning messages or log
+ entries. Expressed as a percentage of max-prefixes.";
+ }
+
+ leaf tw-warning-only {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' only give warning message when limit
+ is exceeded.";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ grouping structure-neighbor-nexthop-self {
+ container nexthop-self {
+ description
+ "Parameters relating to the nexthop-self for the AFI-SAFI.";
+ leaf next-hop-self {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', EBGP learned routes are announced with the
+ local speaker's nexthop.";
+ }
+
+ leaf next-hop-self-force {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', EBGP learned routes are announced with the
+ local speaker's nexthop.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-private-as {
+ container private-as {
+ description
+ "Parameters relating to the private-as for the AFI-SAFI.";
+ leaf remove-private-as-all {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', private ASNs are removed from outbound updates;
+ applies to all AS numbers.";
+ }
+
+ leaf remove-private-as-all-replace {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', private ASNs are replaced by the local
+ speaker's ASN in all outbound updates; applies to all AS numbers.";
+ }
+
+ leaf remove-private-as {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', removes private ASNs in outbound updates;
+ applies to all AS numbers.";
+ }
+
+ leaf remove-private-as-replace {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', private ASNs are replaced with the local
+ speaker's ASN in all outbound updates; applies to all AS numbers.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-weight {
+ container weight {
+ description
+ "Parameters relating to the weight for the AFI-SAFI.";
+ leaf weight-attribute {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "Set default weight for routes from this neighbor.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-route-reflector {
+ container route-reflector {
+ description
+ "Parameters relating to the route-reflector for the AFI-SAFI.";
+ leaf route-reflector-client {
+ type boolean;
+ default "false";
+ description
+ "Configure a neighbor as route reflector client.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-route-server {
+ container route-server {
+ description
+ "Parameters relating to the route-server for the AFI-SAFI.";
+ leaf route-server-client {
+ type boolean;
+ default "false";
+ description
+ "Configure a neighbor as route server client.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-send-community {
+ container send-community {
+ description
+ "Parameters relating to the send-community for the AFI-SAFI.";
+ leaf send-community {
+ type boolean;
+ default "true";
+ description
+ "Send standard community attribute to this neighbor.";
+ }
+
+ leaf send-ext-community {
+ type boolean;
+ default "true";
+ description
+ "Send extended community attribute to this neighbor.";
+ }
+
+ leaf send-large-community {
+ type boolean;
+ default "false";
+ description
+ "Send large community attribute to this neighbor.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-admin-shutdown {
+ description
+ "Structural grouping used to include admin-shutdown
+ configuration for both BGP neighbors and peer groups.";
+ container admin-shutdown {
+ description
+ "BGP Administrative Shutdown Communication.";
+ leaf enable {
+ type boolean;
+ mandatory true;
+ description
+ "When set to 'true', BGP shutdown communication is enabled.";
+ }
+
+ leaf message {
+ type string;
+ description
+ "Shutdown message.";
+ reference
+ "draft-ietf-idr-shutdown-06";
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-graceful-restart {
+ description
+ "Structural grouping used to include graceful-restart
+ configuration for both BGP neighbors and peer groups.";
+ container graceful-restart {
+ description
+ "BGP Graceful restart feature.";
+ choice mode {
+ case graceful-restart-mode {
+ leaf enable {
+ type boolean;
+ default "false";
+ description
+ "Enable or disable the graceful-restart capability.
+ Setting this value to 'true' enables the graceful-restart
+ and helper both at peer level. Setting this value to 'false'
+ disables graceful restart and helper mode. The peer will inherit
+ global configuration.";
+ }
+ }
+
+ case graceful-restart-helper-mode {
+ leaf graceful-restart-helper {
+ type boolean;
+ default "false";
+ description
+ "Setting this value to 'true' enables helper mode for the peer
+ Setting this value to 'false' disables the helper mode. The
+ peer will inherit global configuration.";
+ }
+ }
+
+ case graceful-restart-disable-mode {
+ leaf graceful-restart-disable {
+ type boolean;
+ default "false";
+ description
+ "Setting this value to 'true' disables the graceful-restart
+ and helper Mode. Setting this value to 'false' causes the peer
+ to inherit global configuration.";
+ }
+ }
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-soft-reconfiguration {
+ description
+ "Structural grouping used to include soft-reconfiguration
+ configuration for both BGP neighbors and peer groups.";
+ leaf soft-reconfiguration {
+ type boolean;
+ default "false";
+ description
+ "Allow inbound soft reconfiguration for this neighbor.";
+ }
+ }
+
+ grouping structure-neighbor-group-attr-unchanged {
+ description
+ "Structural grouping used to include BGP route propagation
+ rules configuration for both BGP neighbors and peer groups.";
+ container attr-unchanged {
+ description
+ "BGP route propagation rules configuration.";
+ leaf as-path-unchanged {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' as-path attribute is propagated unchanged.";
+ }
+
+ leaf next-hop-unchanged {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' next-hop attribute is propagated unchanged.";
+ }
+
+ leaf med-unchanged {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' med attribute is propagated unchanged.";
+ }
+ }
+ }
+
+ grouping structure-neighbor-group-orf-capability {
+ description
+ "Structural grouping used to include orf
+ configuration for both BGP neighbors and peer groups.";
+ container orf-capability {
+ choice orf-update {
+ case send {
+ leaf orf-send {
+ type boolean;
+ default "false";
+ description
+ "Setting to 'true' advertises the ORF capability.";
+ }
+ }
+
+ case receive {
+ leaf orf-receive {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it receives the orf capability.";
+ }
+ }
+
+ case both {
+ leaf orf-both {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it advertises/receives the orf capability.";
+ }
+ }
+ }
+ }
+ }
+
+ grouping structure-neighbor-config-timers {
+ description
+ "Structural grouping used to include per neighbor timers
+ configuration for both BGP neighbors and peer groups.";
+ container timers {
+ leaf advertise-interval {
+ type uint16 {
+ range "0..600";
+ }
+ units "seconds";
+ description
+ "Minimum interval between sending BGP routing updates.";
+ }
+
+ leaf connect-time {
+ type uint16 {
+ range "1..65535";
+ }
+ units "seconds";
+ description
+ "BGP connect timer.";
+ }
+
+ uses neighbor-timers;
+ }
+ }
+
+ grouping structure-neighbor-group-filter-config {
+ description
+ "Structural grouping used to include filter
+ configuration for both BGP neighbors and peer groups.";
+ container filter-config {
+ description
+ "BGP Policy configuration for both BGP neighbors and groups.";
+ uses rmap-policy-import;
+
+ uses rmap-policy-export;
+
+ uses plist-policy-import;
+
+ uses plist-policy-export;
+
+ uses access-list-policy-import;
+
+ uses access-list-policy-export;
+
+ uses as-path-filter-list-policy-import;
+
+ uses as-path-filter-list-policy-export;
+
+ uses unsupress-map-policy-import;
+
+ uses unsupress-map-policy-export;
+ }
+ }
+}
diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang
new file mode 100644
index 0000000000..188cf856db
--- /dev/null
+++ b/yang/frr-bgp-common.yang
@@ -0,0 +1,1108 @@
+submodule frr-bgp-common {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ import ietf-bgp-types {
+ prefix bt;
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import frr-bgp-types {
+ prefix frr-bt;
+ }
+
+ import frr-route-types {
+ prefix frr-rt-type;
+ }
+
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+
+ import ietf-routing-types {
+ prefix rt-types;
+ }
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This submodule contains general data definitions for use in BGP.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping rmap-policy-import {
+ leaf rmap-import {
+ type frr-bt:rmap-ref;
+ }
+ }
+
+ grouping rmap-policy-export {
+ leaf rmap-export {
+ type frr-bt:rmap-ref;
+ }
+ }
+
+ grouping unsupress-map-policy-import {
+ leaf unsupress-map-import {
+ type frr-bt:rmap-ref;
+ }
+ }
+
+ grouping unsupress-map-policy-export {
+ leaf unsupress-map-export {
+ type frr-bt:rmap-ref;
+ }
+ }
+
+ grouping plist-policy-import {
+ leaf plist-import {
+ type frr-bt:plist-ref;
+ }
+ }
+
+ grouping plist-policy-export {
+ leaf plist-export {
+ type frr-bt:plist-ref;
+ }
+ }
+
+ grouping access-list-policy-import {
+ leaf access-list-import {
+ type frr-bt:access-list-ref;
+ }
+ }
+
+ grouping access-list-policy-export {
+ leaf access-list-export {
+ type frr-bt:access-list-ref;
+ }
+ }
+
+ grouping as-path-filter-list-policy-import {
+ leaf as-path-filter-list-import {
+ type frr-bt:as-path-filter-ref;
+ }
+ }
+
+ grouping as-path-filter-list-policy-export {
+ leaf as-path-filter-list-export {
+ type frr-bt:as-path-filter-ref;
+ }
+ }
+
+ grouping route-selection-options {
+ description
+ "Configuration relating to route selection options.";
+ container route-selection-options {
+ description
+ "Parameters relating to options for route selection.";
+ leaf always-compare-med {
+ type boolean;
+ default "false";
+ description
+ "Compare multi-exit discriminator (MED) value from
+ different ASes when selecting the best route. The
+ default behaviour is to only compare MEDs for paths
+ received from the same AS.";
+ }
+
+ leaf deterministic-med {
+ type boolean;
+ default "false";
+ description
+ "Compare multi-exit discriminator (MED) value from
+ Same ASes when selecting the best route.";
+ }
+
+ leaf confed-med {
+ type boolean;
+ default "false";
+ description
+ "Compare multi-exit discriminator (MED) value from
+ different Sub ASes when selecting the best route.";
+ }
+
+ leaf missing-as-worst-med {
+ type boolean;
+ default "false";
+ description
+ "Missing multi-exit discriminator (MED) value is
+ considered as value of infinity, making the path
+ least desirable when selecting the best route.";
+ }
+
+ leaf aspath-confed {
+ type boolean;
+ default "false";
+ description
+ "Compare path lengths including confederation sets
+ and sequences in selecting a route.";
+ }
+
+ leaf ignore-as-path-length {
+ type boolean;
+ default "false";
+ description
+ "Ignore the AS path length when selecting the best path.
+ The default is to use the AS path length and prefer paths
+ with shorter length.";
+ }
+
+ leaf external-compare-router-id {
+ type boolean;
+ default "true";
+ description
+ "When comparing similar routes received from external BGP
+ peers, use the router-id as a criterion to select the
+ active path.";
+ }
+
+ leaf allow-multiple-as {
+ type boolean;
+ default "false";
+ description
+ "Allow multi-path to use paths from different neighbouring
+ ASes. The default is to only consider multiple paths
+ from the same neighbouring AS.";
+ }
+
+ leaf multi-path-as-set {
+ when "../allow-multiple-as = 'true'";
+ type boolean;
+ default "false";
+ description
+ "Multi-path with AS-SET, When set to 'true' it adds AS set
+ information for aggregate routes, When set to 'false' it
+ prevents AS set generation.";
+ }
+ }
+ }
+
+ grouping med-config {
+ description
+ "Configuration relating to MED.";
+ container med-config {
+ leaf enable-med-admin {
+ type boolean;
+ default "false";
+ description
+ "Flag to enable receiving of MED metric attribute
+ in routing updates.";
+ }
+ leaf max-med-admin {
+ type uint32 {
+ range "0..4294967295";
+ }
+ default "4294967294";
+ description
+ "Tells the router to announce routes with this MED value
+ This MED value is applicable for indefinite time.";
+ }
+
+ leaf max-med-onstart-up-time {
+ type uint32 {
+ range "5..86400";
+ }
+ units "seconds";
+ description
+ "Tells the router to announce routes with MED value,
+ This MED value is applicable for this duration during
+ start-up.";
+ }
+
+ leaf max-med-onstart-up-value {
+ type uint32 {
+ range "0..4294967295";
+ }
+ default "4294967294";
+ description
+ "Tells the router to announce routes with this MED value
+ This MED value is applicable for start-up time.";
+ }
+ }
+ }
+
+ grouping route-reflector-config {
+ description
+ "Grouping used to include route reflector
+ configuration for BGP global.";
+ container route-reflector {
+ description
+ "Route reflector parameters for the BGP global.";
+ leaf route-reflector-cluster-id {
+ type bt:rr-cluster-id-type;
+ description
+ "Route Reflector cluster ID to use when local router is
+ configured as a route reflector. Commonly set at the
+ group level, but allows a different cluster ID to be set
+ for each neighbor.";
+ reference
+ "RFC 4456: BGP Route Reflection: An Alternative to
+ Full Mesh.";
+ }
+
+ leaf no-client-reflect {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', this disables route redistribution
+ by the Route Reflector. It is set 'true' when the client is
+ fully meshed to prevent sending of redundant route
+ advertisements.";
+ reference
+ "TODO: Add reference when IETF writes a draft describing
+ this.";
+ }
+
+ leaf allow-outbound-policy {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true', this allow RR to modify the attributes of the
+ reflected IBGP routes as per the out route-map. It is set 'false'
+ RR will not modify the attributes of the reflected IBGP routes as
+ per the out route-map rules.";
+ }
+ }
+ }
+
+ grouping global-bgp-config {
+ leaf instance-type-view {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' BGP instance type is view.
+ When set to 'false' BGP instance type is regular.";
+ }
+
+ leaf ebgp-multihop-connected-route-check {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it will disable checking if nexthop is connected
+ on EBGP sessions. When set to 'false' it will enable checking if
+ nexthop is connected on EBGP sessions.";
+ }
+
+ leaf fast-external-failover {
+ type boolean;
+ default "true";
+ description
+ "It's an interface tracking mechanism. When set to 'true' don't
+ immediately reset session if a link to a directly connected
+ external peer goes down. When set to 'false' it will immediately
+ reset session if a link to a directly connected external peer goes down.";
+ }
+
+ leaf local-pref {
+ type uint32;
+ default "100";
+ description
+ "BGP local preference attribute sent to internal peers to
+ indicate the degree of preference for externally learned
+ routes. The route with the highest local preference
+ value is preferred.";
+ reference
+ "RFC 4271.";
+ }
+
+ leaf default-shutdown {
+ type boolean;
+ default "false";
+ description
+ "Apply administrative shutdown to newly configured peers.";
+ }
+
+ leaf ebgp-requires-policy {
+ type boolean;
+ default "true";
+ description
+ "When set to 'true' BGP speaker requires in and out policy
+ for EBGP peers (RFC8212).";
+ }
+
+ leaf show-hostname {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' BGP show hostname in certain command outputs.";
+ }
+
+ leaf show-nexthop-hostname {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' BGP show hostname for nexthop in certain
+ command outputs.";
+ }
+ }
+
+ grouping global-neighbor-config {
+ container global-neighbor-config {
+ leaf dynamic-neighbors-limit {
+ type uint32 {
+ range "1..5000";
+ }
+ description
+ "Maximum number of BGP Dynamic Neighbors that can be created.";
+ }
+
+ leaf log-neighbor-changes {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' BGP will start logging neighbor up/down and reset reason.
+ When set to 'false' BGP will stop logging neighbor up/down and reset reason.";
+ }
+
+ container packet-quanta-config {
+ leaf wpkt-quanta {
+ type uint32 {
+ range "1..64";
+ }
+ default "64";
+ description
+ "How many packets to write to peer socket per run.";
+ }
+
+ leaf rpkt-quanta {
+ type uint32 {
+ range "1..10";
+ }
+ default "10";
+ description
+ "How many packets to read from peer socket per I/O cycle.";
+ }
+ }
+ }
+ }
+
+ grouping global-update-group-config {
+ container global-update-group-config {
+ leaf subgroup-pkt-queue-size {
+ type uint32 {
+ range "20..100";
+ }
+ default "40";
+ description
+ "Subgroup packet queue size.";
+ }
+
+ leaf coalesce-time {
+ type uint32 {
+ range "0..4294967295";
+ }
+ units "miliseconds";
+ default "1000";
+ description
+ "Configures the Subgroup coalesce timer.";
+ }
+ }
+ }
+
+ grouping global-network-config {
+ leaf import-check {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' bgp creates entries for network statements
+ if a matching prefix exists in the rib. When set to 'false' bgp
+ creates entries for networks that the router cannot reach.";
+ }
+ }
+
+ grouping neighbor-timers {
+ leaf hold-time {
+ type uint16 {
+ range "0 | 3..65535";
+ }
+ units "seconds";
+ default "180";
+ description
+ "Time interval (in seconds) for the HoldTimer established
+ with the peer. When read as operational data (ro), the
+ value of this object is calculated by this BGP speaker,
+ using the smaller of the values in hold-time that was
+ configured (rw) in the running datastore and the Hold Time
+ received in the OPEN message.
+
+ This value must be at least three seconds
+ if it is not zero (0).
+
+ If the Hold Timer has not been established
+ with the peer this object MUST have a value
+ of zero (0).
+
+ If the configured value of hold-time object was
+ a value of (0), then when read this object MUST have a
+ value of (0) also.";
+ reference
+ "RFC 4271";
+ }
+
+ leaf keepalive {
+ type uint16 {
+ range "0..65535";
+ }
+ units "seconds";
+ default "60";
+ description
+ "When used as a configuration (rw) value, this Time interval
+ (in seconds) for the KeepAlive timer configured for this BGP
+ speaker with this peer. The value of this object will only
+ determine the KEEPALIVE messages' frequency relative to
+ the value specified in configured value for hold-time.
+
+ If the value of this object is zero (0), no periodical
+ KEEPALIVE messages are sent to the peer after the BGP
+ connection has been established. The suggested value for
+ this timer is 30 seconds.;
+
+ The actual time interval for the KEEPALIVE messages is
+ indicated by operational value of keepalive. That value
+ of this object is calculated by this BGP speaker such that,
+ when compared with hold-time, it has the same proportion
+ that keepalive has, compared with hold-time. A
+ reasonable maximum value for this timer would be one third
+ of that of hold-time.";
+ reference
+ "RFC 4271";
+ }
+ }
+
+ grouping global-config-timers {
+ container global-config-timers {
+ leaf rmap-delay-time {
+ type uint16 {
+ range "0..600";
+ }
+ units "seconds";
+ default "5";
+ description
+ "Time to wait before processing route-map changes.";
+ }
+
+ leaf update-delay-time {
+ type uint16 {
+ range "0..3600";
+ }
+ units "seconds";
+ description
+ "Time to force initial delay for best-path and updates.";
+ }
+
+ leaf establish-wait-time {
+ type uint16 {
+ range "1..3600";
+ }
+ units "seconds";
+ description
+ "Time to force initial delay for updates.";
+ }
+
+ leaf connect-retry-interval {
+ type uint16 {
+ range "1..max";
+ }
+ units "seconds";
+ default "120";
+ description
+ "Time interval (in seconds) for the ConnectRetryTimer. The
+ suggested value for this timer is 120 seconds.";
+ reference
+ "RFC 4271, This is the value used
+ to initialize the 'ConnectRetryTimer'.";
+ }
+
+ uses neighbor-timers;
+ }
+ }
+
+ grouping graceful-restart-config {
+ description
+ "Configuration parameters relating to BGP graceful restart.";
+ choice mode {
+ case graceful-restart-mode {
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "Enable or disable the graceful-restart capability. When set to 'true'
+ it will enable graceful restart and helper both globally. When set
+ to 'false' it will enable the default behaviour global helper mode.";
+ }
+ }
+
+ case graceful-restart-disable-mode {
+ leaf graceful-restart-disable {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it will disable graceful restart and helper both
+ globally. when set to 'false' it will enable the default behaviour
+ global helper mode.";
+ }
+ }
+ }
+
+ leaf preserve-fw-entry {
+ type boolean;
+ default "false";
+ description
+ "Sets F-bit indication that fib is preserved while doing Graceful Restart.
+ When set to 'true' Zebra would preserve the FIB entry on the restarting
+ node.";
+ }
+
+ leaf restart-time {
+ type uint16 {
+ range "1..3600";
+ }
+ units "seconds";
+ default "120";
+ description
+ "Estimated time (in seconds) for the local BGP speaker to
+ restart a session. This value is advertise in the graceful
+ restart BGP capability. This is a 12-bit value, referred to
+ as Restart Time in RFC4724. Per RFC4724, the suggested
+ default value is <= the hold-time value. This timer is
+ applicable for helper node.";
+ reference
+ "RFC 4724: Graceful Restart Mechanism for BGP.";
+ }
+
+ leaf stale-routes-time {
+ type uint16 {
+ range "1..3600";
+ }
+ units "seconds";
+ default "360";
+ description
+ "An upper-bound on the time that stale routes will be
+ retained by a router after a session is restarted. If an
+ End-of-RIB (EOR) marker is received prior to this timer
+ expiring stale-routes will be flushed upon its receipt - if
+ no EOR is received, then when this timer expires stale paths
+ will be purged. This timer is applicable for restarting node.";
+ reference
+ "RFC 4724: Graceful Restart Mechanism for BGP.";
+ }
+
+ leaf selection-deferral-time {
+ type uint16 {
+ range "0..3600";
+ }
+ units "seconds";
+ default "360";
+ description
+ "An upper-bound on the time that restarting router defers
+ the route selection process after restart.";
+ reference
+ "RFC 4724: Graceful Restart Mechanism for BGP.";
+ }
+
+ leaf rib-stale-time {
+ type uint16 {
+ range "1..3600";
+ }
+ units "seconds";
+ default "500";
+ description
+ "An upper-bound on the time that helper router holds the
+ stale routes in Zebra, When this timer gets expired Zebra
+ removes the stale routes.";
+ }
+ }
+
+ grouping global-group-use-multiple-paths {
+ description
+ "Common grouping used for both global and groups which provides
+ configuration parameters relating to use of multiple paths.";
+ container use-multiple-paths {
+ description
+ "Parameters related to the use of multiple paths for the
+ same NLRI.";
+ container ebgp {
+ description
+ "Multi-Path parameters for EBGP.";
+ leaf maximum-paths {
+ type uint16;
+ default "64";
+ description
+ "Maximum number of parallel paths to consider when using
+ BGP multi-path. The default is use a single path.";
+ }
+ }
+
+ container ibgp {
+ description
+ "Multi-Path parameters for IBGP.";
+ leaf maximum-paths {
+ type uint16;
+ default "64";
+ description
+ "Maximum number of parallel paths to consider when using
+ IBGP multi-path. The default is to use a single path.";
+ }
+
+ leaf cluster-length-list {
+ when "../maximum-paths != 0";
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' route with the shortest cluster-list
+ length is used. The cluster-list reflects the IBGP
+ reflection path the route has taken. It's the part
+ of route selection algo.";
+ }
+ }
+ }
+ }
+
+ grouping global-redistribute {
+ description
+ "List of route redistribution per AFI.";
+ list redistribution-list {
+ key "route-type route-instance";
+ leaf route-type {
+ type frr-rt-type:frr-route-types;
+ description
+ "Protocol route type.";
+ }
+
+ leaf route-instance {
+ type uint16 {
+ range "0..65535";
+ }
+ description
+ "Protocol Instance.";
+ }
+
+ leaf metric {
+ type uint32 {
+ range "0..4294967295";
+ }
+ description
+ "Metric for redistributed routes.";
+ }
+
+ leaf rmap-policy-import {
+ type frr-bt:rmap-ref;
+ description
+ "Route-map to be applied for redistributed routes into the bgp.";
+ }
+ }
+ }
+
+ grouping mp-afi-safi-network-config {
+ leaf label-index {
+ type rt-types:mpls-label;
+ description
+ "Label index to associate with the prefix.";
+ }
+
+ leaf rmap-policy-export {
+ type frr-bt:rmap-ref;
+ description
+ "Route-map to modify the attributes for Routes going out
+ via BGP updates.";
+ }
+ }
+
+ grouping mp-afi-safi-agg-route-config {
+ leaf as-set {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' AS set path information is generated
+ for aggregate address. When set to 'false' AS set path
+ information is not generated.";
+ }
+
+ leaf summary-only {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it advertise only the aggregate route
+ and suppress the advertisement of all the component routes.
+ When set to 'false' all more-specific routes summarized
+ by the aggregate route are advertised.";
+ }
+
+ leaf rmap-policy-export {
+ type frr-bt:rmap-ref;
+ description
+ "Apply route map to aggregate network.";
+ }
+ }
+
+ grouping admin-distance {
+ container admin-distance {
+ description
+ "Administrative distance (or preference) assigned to
+ routes received from different sources
+ (external, internal, and local).";
+ leaf external {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Administrative distance for routes learned from
+ external BGP (EBGP).";
+ }
+
+ leaf internal {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Administrative distance for routes learned from
+ internal BGP (IBGP).";
+ }
+
+ leaf local {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Administrative distance for routes learned from
+ local.";
+ }
+ }
+ }
+
+ grouping distance-per-route-config {
+ leaf distance {
+ type uint8 {
+ range "1..255";
+ }
+ mandatory true;
+ description
+ "Administrative distance for route.";
+ }
+
+ leaf access-list-policy-export {
+ type frr-bt:access-list-ref;
+ description
+ "Access-list policy applied on routes going from BGP to Zebra.";
+ }
+ }
+
+ grouping route-flap-dampening {
+ container route-flap-dampening {
+ description
+ "Dampening feature";
+ leaf enable {
+ type boolean;
+ default "false";
+ description
+ "Enable route flap dampening.";
+ }
+
+ leaf reach-decay {
+ when "../enable = 'true'";
+ type uint8 {
+ range "1..45";
+ }
+ units "seconds";
+ default "15";
+ description
+ "This value specifies the time desired for the instability
+ metric value to reach one-half of its current value when
+ the route is reachable. This half-life value determines
+ the rate at which the metric value is decayed. A smaller
+ half-life value makes a suppressed route reusable sooner
+ than a larger value. The accumulated penalty will be reduced
+ to half after this duration.";
+ }
+
+ leaf reuse-above {
+ when "../enable = 'true'";
+ type uint16 {
+ range "1..20000";
+ }
+ default "750";
+ description
+ "This is the value of the instability metric at which a
+ suppressed route becomes unsuppressed if it is reachable
+ but currently suppressed. The value assigned to
+ reuse-below must be less than suppress-above.";
+ }
+
+ leaf suppress-above {
+ when "../enable = 'true'";
+ type uint16 {
+ range "1..20000";
+ }
+ default "2000";
+ description
+ "This is the value of the instability metric at which
+ route suppression takes place. A route is not installed
+ in the forwarding information base (FIB), or announced
+ even if it is reachable during the period that it is
+ suppressed.";
+ }
+
+ leaf unreach-decay {
+ when "../enable = 'true'";
+ type uint8 {
+ range "1..255";
+ }
+ units "seconds";
+ default "60";
+ description
+ "This value acts the same as reach-decay except that it
+ specifies the rate at which the instability metric is
+ decayed when a route is unreachable. It should have a
+ value greater than or equal to reach-decay.";
+ }
+ }
+ }
+
+ grouping flow-spec-config {
+ container flow-spec-config {
+ description
+ "Flow spec feature.";
+ leaf interface {
+ type frr-interface:interface-ref {
+ require-instance false;
+ }
+ description
+ "The local interface.";
+ }
+ }
+ }
+
+ grouping global-graceful-shutdown {
+ description
+ "Structural grouping used to include graceful-shutdown
+ configuration for both BGP neighbors and peer groups.";
+ container graceful-shutdown {
+ description
+ "BGP Graceful shutdown feature.";
+ leaf enable {
+ type boolean;
+ default "false";
+ description
+ "Enable graceful-shutdown feature.";
+ }
+ }
+ }
+
+ grouping global-filter-config {
+ description
+ "Structural grouping used to include filter
+ configuration for BGP RIB table.";
+ container filter-config {
+ description
+ "BGP table to RIB route download filter.";
+ uses rmap-policy-export;
+ }
+ }
+
+ grouping route-distinguisher-params {
+ description
+ "Route distinguisher value as per RFC4364.";
+ leaf rd {
+ type rt-types:route-distinguisher;
+ description
+ "Route distinguisher value as per RFC4364.";
+ }
+ }
+
+ grouping vpn-label-params {
+ description
+ "Label value for VRF.";
+ choice label-allocation-mode {
+ case manual {
+ leaf label {
+ type rt-types:mpls-label;
+ description
+ "Label index to associate with the prefix.";
+ }
+ }
+
+ case auto {
+ leaf label-auto {
+ type boolean;
+ default "false";
+ description
+ "Automatically assign a label.";
+ }
+ }
+ }
+ }
+
+ grouping vpn-nexthop-params {
+ description
+ "Specify next hop to use for VRF advertised prefixes.";
+ leaf nexthop {
+ type inet:ip-address;
+ description
+ "Nexthop IP address.";
+ }
+ }
+
+ grouping rt-list {
+ description
+ "Route Target list";
+ leaf-list import-rt-list {
+ type rt-types:route-target;
+ description
+ "For routes leaked from vpn to current address-family: match any.";
+ }
+
+ leaf-list export-rt-list {
+ type rt-types:route-target;
+ description
+ "For routes leaked from current address-family to vpn: set.";
+ }
+ }
+
+ grouping vpn-route-target-params {
+ description
+ "Route Target value.";
+ leaf redirect-rt {
+ type rt-types:route-target;
+ description
+ "Flow-spec redirect type route target.";
+ }
+
+ choice rt-direction {
+ case import-export {
+ uses rt-list;
+ }
+ case both {
+ leaf-list rt-list {
+ type rt-types:route-target;
+ description
+ "Both import: match any and export: set.";
+ }
+ }
+ }
+ }
+
+ grouping vpn-import-params {
+ description
+ "VPN route leaking parameters.";
+ leaf import-vpn {
+ type boolean;
+ default "false";
+ description
+ "Import routes from default instance VPN RIB.";
+ }
+
+ leaf export-vpn {
+ type boolean;
+ default "false";
+ description
+ "Export routes to default instance VPN RIB.";
+ }
+
+ list import-vrf-list {
+ key "vrf";
+ description
+ "List of VRFs to import routes from.";
+ leaf vrf {
+ type frr-vrf:vrf-ref {
+ require-instance false;
+ }
+ description
+ "Routing instance.";
+ }
+ }
+
+ uses rmap-policy-import;
+
+ uses rmap-policy-export;
+ }
+
+ grouping global-afi-safi-vpn-config {
+ container vpn-config {
+ uses route-distinguisher-params;
+
+ uses vpn-label-params;
+
+ uses vpn-nexthop-params;
+
+ uses vpn-import-params;
+
+ uses vpn-route-target-params;
+ }
+ }
+
+ grouping global-afi-safi-vpn-network-config {
+ list network-config {
+ key "rd";
+ description
+ "A list of rd.";
+ uses route-distinguisher-params;
+
+ list prefix-list {
+ key "prefix";
+ description
+ "A list of prefix.";
+ leaf prefix {
+ type inet:ip-prefix;
+ description
+ "IP destination prefix.";
+ }
+
+ leaf label-index {
+ type uint32;
+ mandatory true;
+ description
+ "Label index to associate with the prefix.";
+ }
+
+ leaf rmap-policy-export {
+ type frr-bt:rmap-ref;
+ description
+ "Route-map to modify the attributes for Routes going out
+ via BGP updates.";
+ }
+ }
+ }
+ }
+}
diff --git a/yang/frr-bgp-neighbor.yang b/yang/frr-bgp-neighbor.yang
new file mode 100644
index 0000000000..3b8d63c447
--- /dev/null
+++ b/yang/frr-bgp-neighbor.yang
@@ -0,0 +1,137 @@
+submodule frr-bgp-neighbor {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ include frr-bgp-common-structure;
+ include frr-bgp-common-multiprotocol;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This submodule contains general data definitions for use in BGP neighbor.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping neighbor-parameters {
+ leaf password {
+ type string {
+ length "1..254";
+ }
+ description
+ "Actual password.";
+ }
+
+ leaf ttl-security {
+ type uint8;
+ description
+ "BGP Time To Live (TTL) security check.";
+ reference
+ "RFC 5082: The Generalized TTL Security Mechanism
+ (GTSM),
+ RFC 7454: BGP Operations and Security.";
+ }
+
+ leaf solo {
+ type boolean;
+ default "false";
+ description
+ "Solo peer - part of its own update group.";
+ }
+
+ leaf enforce-first-as {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it will enforce the first AS for EBGP routes.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "An optional textual description (intended primarily for use
+ with a peer or group.";
+ }
+
+ leaf passive-mode {
+ type boolean;
+ default "false";
+ description
+ "Don't send open messages to this neighbor.";
+ }
+
+ uses structure-neighbor-group-capability-options;
+
+ uses neighbor-update-source;
+
+ uses neighbor-remote-as;
+
+ uses structure-neighbor-group-ebgp-multihop;
+
+ uses neighbor-local-as-options;
+
+ uses neighbor-bfd-options;
+
+ uses structure-neighbor-group-admin-shutdown;
+
+ uses structure-neighbor-group-graceful-restart;
+
+ uses structure-neighbor-config-timers;
+
+ container afi-safis {
+ description
+ "List of address-families associated with the BGP
+ instance.";
+ list afi-safi {
+ key "afi-safi-name";
+ description
+ "AFI, SAFI configuration available for the
+ neighbour or group.";
+ uses mp-afi-safi-config;
+
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "This leaf indicates whether the IPv4 Unicast AFI, SAFI is
+ enabled for the neighbour or group.";
+ }
+
+ uses mp-all-afi-safi-list-contents;
+ }
+ }
+ }
+}
diff --git a/yang/frr-bgp-peer-group.yang b/yang/frr-bgp-peer-group.yang
new file mode 100644
index 0000000000..3ce628d2b7
--- /dev/null
+++ b/yang/frr-bgp-peer-group.yang
@@ -0,0 +1,89 @@
+submodule frr-bgp-peer-group {
+ yang-version 1.1;
+
+ belongs-to frr-bgp {
+ prefix "bgp";
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ include frr-bgp-common-structure;
+ include frr-bgp-neighbor;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This submodule contains general data definitions for use in BGP
+ peer group.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ grouping bgp-peer-group-base {
+ description
+ "Parameters related to a BGP group.";
+ leaf peer-group-name {
+ type string;
+ description
+ "Name of the BGP peer-group.";
+ }
+
+ leaf-list ipv4-listen-range {
+ type inet:ipv4-address;
+ description
+ "Configure BGP dynamic neighbors listen range.";
+ }
+
+ leaf-list ipv6-listen-range {
+ type inet:ipv6-address;
+ description
+ "Configure BGP dynamic neighbors listen range.";
+ }
+
+ uses neighbor-parameters;
+ }
+
+ grouping bgp-peer-group-list {
+ description
+ "The list of BGP peer groups.";
+ list peer-group {
+ key "peer-group-name";
+ description
+ "List of BGP peer-groups configured on the local system -
+ uniquely identified by peer-group name.";
+ uses bgp-peer-group-base;
+ }
+ }
+}
diff --git a/yang/frr-bgp-rpki.yang b/yang/frr-bgp-rpki.yang
new file mode 100644
index 0000000000..e9b6752f26
--- /dev/null
+++ b/yang/frr-bgp-rpki.yang
@@ -0,0 +1,209 @@
+module frr-bgp-rpki {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/frr-bgp-rpki";
+ prefix frr-bgp-rpki;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines a model for managing FRR BGP RPKI.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ typedef transport-type {
+ type enumeration {
+ enum "TCP" {
+ value 1;
+ description
+ "Connection to server is TCP based.";
+ }
+ enum "SSH" {
+ value 2;
+ description
+ "Connection to server is SSH based.";
+ }
+ }
+ }
+
+ grouping bgp-rpki-timers {
+ container rpki-timers {
+ description
+ "RPKI timers config.";
+ leaf polling-time {
+ type uint32 {
+ range "1..86400";
+ }
+ units "seconds";
+ default "3600";
+ description
+ "Set the number of seconds the router waits until the
+ router asks the cache again for updated data.";
+ }
+
+ leaf expire-time {
+ type uint32 {
+ range "600..172800";
+ }
+ units "seconds";
+ default "7200";
+ description
+ "Set the expire interval.";
+ }
+
+ leaf retry-time {
+ type uint16 {
+ range "1..7200";
+ }
+ units "seconds";
+ default "600";
+ description
+ "Set the retry interval.";
+ }
+ }
+ }
+
+ grouping bgp-rpki-cache-server {
+ container rpki-cache-server {
+ description
+ "Add a cache server to the socket.";
+ list cache-list {
+ key "preference";
+ leaf preference {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Preference of the cache server.";
+ }
+
+ leaf cache-type {
+ type transport-type;
+ mandatory true;
+ description
+ "Specifies a transport method for the RPKI cache.";
+ }
+
+ choice server {
+ case ip-address {
+ leaf ip-address {
+ type inet:ip-address;
+ mandatory true;
+ }
+ }
+
+ case host-name {
+ leaf ip-host-address {
+ type inet:host;
+ mandatory true;
+ }
+ }
+ }
+
+ container transport {
+ container tcp {
+ when "../../cache-type = 'TCP'";
+ description
+ "TCP server details.";
+ leaf tcp-port {
+ type uint32;
+ }
+ }
+
+ container ssh {
+ when "../../cache-type = 'SSH'";
+ description
+ "SSH login details";
+ leaf ssh-port {
+ type uint32 {
+ range "1..65535";
+ }
+ description
+ "SSH port on which session gets opened.";
+ }
+
+ leaf user-name {
+ type string;
+ description
+ "SSH username to establish an SSH connection to the
+ cache server.";
+ }
+
+ leaf private-key {
+ type string;
+ description
+ "Local path that includes the private key file of the router.";
+ }
+
+ leaf public-key {
+ type string;
+ description
+ "Local path that includes the public key file of the router.";
+ }
+
+ leaf server-public-ley {
+ type string;
+ description
+ "Server public key.";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ augment "/frr-vrf:lib/frr-vrf:vrf" {
+ container bgp-rpki {
+ description
+ "RPKI configuration parameters.";
+ leaf enable {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it enables the RPKI.";
+ }
+
+ uses bgp-rpki-timers;
+
+ uses bgp-rpki-cache-server;
+ }
+ }
+}
diff --git a/yang/frr-bgp-types.yang b/yang/frr-bgp-types.yang
new file mode 100644
index 0000000000..0afdea1ba6
--- /dev/null
+++ b/yang/frr-bgp-types.yang
@@ -0,0 +1,154 @@
+module frr-bgp-types {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/bgp-types";
+ prefix frr-bt;
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module contains general data definitions for use in BGP.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ typedef rmap-ref {
+ type string;
+ }
+
+ typedef plist-ref {
+ type string;
+ }
+
+ typedef access-list-ref {
+ type string;
+ }
+
+ typedef as-path-filter-ref {
+ type string;
+ }
+
+ typedef bgp-instance-type {
+ type enumeration {
+ enum "default" {
+ value 1;
+ description
+ "BGP instance default.";
+ }
+ enum "vrf" {
+ value 2;
+ description
+ "BGP instance vrf.";
+ }
+ enum "view" {
+ value 3;
+ description
+ "BGP instance view.";
+ }
+ }
+ }
+
+ typedef as-type {
+ type enumeration {
+ enum "as-specified" {
+ value 1;
+ description
+ "AS has explicitly specified value.";
+ }
+ enum "internal" {
+ value 2;
+ description
+ "Internal BGP peer.";
+ }
+ enum "external" {
+ value 3;
+ description
+ "External BGP peer.";
+ }
+ }
+ }
+
+ typedef add-path-type {
+ type enumeration {
+ enum "all" {
+ value 1;
+ description
+ "To advertise all paths to a neighbor.";
+ }
+ enum "per-as" {
+ value 2;
+ description
+ "To advertise the best path per each neighboring AS.";
+ }
+ enum "none" {
+ value 3;
+ description
+ "Add path feature is disabled.";
+ }
+ }
+ }
+
+ typedef bfd-session-type {
+ type enumeration {
+ enum "single-hop" {
+ value 1;
+ description
+ "Single hop session.";
+ }
+ enum "multi-hop" {
+ value 2;
+ description
+ "Multiple hop session.";
+ }
+ enum "not-configured" {
+ value 3;
+ description
+ "Not Configured.";
+ }
+ }
+ }
+
+ typedef direction {
+ type enumeration {
+ enum "in" {
+ value 1;
+ description
+ "IN, ingress, Rx.";
+ }
+ enum "out" {
+ value 2;
+ description
+ "OUT, egress, Tx.";
+ }
+ }
+ }
+}
diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang
new file mode 100644
index 0000000000..3e5b1da7d3
--- /dev/null
+++ b/yang/frr-bgp.yang
@@ -0,0 +1,1239 @@
+module frr-bgp {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/bgp";
+ prefix frr-bgp;
+
+ import frr-routing {
+ prefix frr-rt;
+ }
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import ietf-routing-types {
+ prefix rt-types;
+ }
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ include "frr-bgp-common-structure";
+
+ include "frr-bgp-common";
+
+ include "frr-bgp-common-multiprotocol";
+
+ include "frr-bgp-neighbor";
+
+ include "frr-bgp-peer-group";
+
+ include "frr-bgp-bmp";
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines a model for managing FRR bgpd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ identity bgp {
+ base frr-rt:routing-protocol;
+ description
+ "BGP protocol.";
+ }
+
+ grouping mp-afi-unicast-common {
+ uses global-group-use-multiple-paths;
+
+ uses global-redistribute;
+
+ uses admin-distance;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol" {
+ container bgp {
+ when "../frr-rt:type = 'frr-bgp:bgp'" {
+ description
+ "BGP protocol augmentation of ietf-routing module
+ control-plane-protocol.";
+ }
+ description
+ "Top-level configuration for the BGP router.";
+ container global {
+ presence "Enables global configuration of BGP";
+ description
+ "Global configuration for the BGP router.";
+ leaf local-as {
+ type inet:as-number;
+ mandatory true;
+ description
+ "Local autonomous system number of the router. Uses
+ the 32-bit as-number type from the model in RFC 6991.";
+ }
+
+ uses frr-rt:router-id;
+
+ container confederation {
+ description
+ "Configuration options specifying parameters when the
+ local router is within an autonomous system which is
+ part of a BGP confederation.";
+ leaf identifier {
+ type inet:as-number;
+ description
+ "Confederation identifier for the autonomous system.";
+ }
+
+ leaf-list member-as {
+ type inet:as-number;
+ description
+ "Remote autonomous systems that are to be treated
+ as part of the local confederation.";
+ }
+ }
+
+ uses med-config;
+
+ uses route-reflector-config;
+
+ uses route-selection-options;
+
+ uses global-neighbor-config;
+
+ container graceful-restart {
+ description
+ "Parameters relating the graceful restart mechanism for
+ BGP.";
+ uses graceful-restart-config;
+ }
+
+ uses global-update-group-config;
+
+ uses global-config-timers;
+
+ uses global-bgp-config;
+
+ uses global-network-config;
+
+ uses global-graceful-shutdown;
+
+ uses global-bmp-config;
+
+ container afi-safis {
+ description
+ "List of address-families associated with the BGP
+ instance.";
+ list afi-safi {
+ key "afi-safi-name";
+ description
+ "AFI, SAFI configuration available for the
+ neighbour or group.";
+ uses mp-afi-safi-config;
+
+ uses mp-all-afi-safi-list-contents;
+ }
+ }
+ }
+
+ container neighbors {
+ description
+ "Configuration for BGP neighbors.";
+ list neighbor {
+ key "remote-address";
+ description
+ "List of BGP neighbors configured on the local system,
+ uniquely identified by remote IPv[46] address.";
+ leaf remote-address {
+ type inet:ip-address;
+ description
+ "The remote IP address of this entry's BGP peer.";
+ }
+
+ leaf local-interface {
+ type frr-interface:interface-ref {
+ require-instance false;
+ }
+ description
+ "Neighbor's interface name.";
+ }
+
+ leaf local-port {
+ type inet:port-number {
+ range "0..65535";
+ }
+ description
+ "Neighbor's BGP TCP port number.";
+ }
+
+ leaf peer-group {
+ type leafref {
+ path "../../../peer-groups/peer-group/peer-group-name";
+ }
+ description
+ "The peer-group with which this neighbor is associated.";
+ }
+
+ uses neighbor-parameters;
+ }
+
+ list unnumbered-neighbor {
+ key "interface";
+ description
+ "List of BGP neighbors configured on the local system,
+ uniquely identified by interfaces.";
+ leaf interface {
+ type frr-interface:interface-ref {
+ require-instance false;
+ }
+ description
+ "The local interface of this entry's BGP peer.";
+ }
+
+ leaf v6only {
+ type boolean;
+ default "false";
+ description
+ "When set to 'true' it will create a neighbor with v6
+ link local only.";
+ }
+
+ leaf peer-group {
+ type leafref {
+ path "../../../peer-groups/peer-group/peer-group-name";
+ }
+ description
+ "The peer-group with which this neighbor is associated.";
+ }
+
+ uses neighbor-parameters;
+ }
+ }
+
+ container peer-groups {
+ description
+ "Configuration for BGP peer-groups.";
+ uses bgp-peer-group-list;
+ }
+ }
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv4-unicast" {
+ list network-config {
+ key "prefix";
+ description
+ "A list of network routes.";
+ leaf prefix {
+ type inet:ipv4-prefix;
+ description
+ "IPv4 destination prefix.";
+ }
+
+ leaf backdoor {
+ type boolean;
+ default "false";
+ description
+ "Specify a BGP backdoor route.";
+ }
+
+ uses mp-afi-safi-network-config;
+ }
+
+ list aggregate-route {
+ key "prefix";
+ description
+ "A list of aggregated routes.";
+ leaf prefix {
+ type inet:ipv4-prefix;
+ description
+ "IPv4 destination prefix.";
+ }
+
+ uses mp-afi-safi-agg-route-config;
+ }
+
+ list admin-distance-route {
+ key "prefix";
+ description
+ "A list of routes with a particular admin distance.";
+ leaf prefix {
+ type inet:ipv4-prefix;
+ description
+ "IPv4 destination prefix.";
+ }
+
+ uses distance-per-route-config;
+ }
+
+ uses route-flap-dampening;
+
+ uses mp-afi-unicast-common;
+
+ uses global-filter-config;
+
+ uses global-afi-safi-vpn-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv6-unicast" {
+ list network-config {
+ key "prefix";
+ description
+ "A list of network routes.";
+ leaf prefix {
+ type inet:ipv6-prefix;
+ description
+ "IPv6 destination prefix.";
+ }
+
+ leaf backdoor {
+ type boolean;
+ default "false";
+ description
+ "Specify a BGP backdoor route.";
+ }
+
+ uses mp-afi-safi-network-config;
+ }
+
+ list aggregate-route {
+ key "prefix";
+ description
+ "A list of aggregated routes.";
+ leaf prefix {
+ type inet:ipv6-prefix;
+ description
+ "IPv6 destination prefix.";
+ }
+
+ uses mp-afi-safi-agg-route-config;
+ }
+
+ list admin-distance-route {
+ key "prefix";
+ description
+ "A list of routes with a particular admin distance.";
+ leaf prefix {
+ type inet:ipv6-prefix;
+ description
+ "IPv6 destination prefix.";
+ }
+
+ uses distance-per-route-config;
+ }
+
+ uses mp-afi-unicast-common;
+
+ uses global-filter-config;
+
+ uses global-afi-safi-vpn-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv4-labeled-unicast" {
+ uses global-group-use-multiple-paths;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv6-labeled-unicast" {
+ uses global-group-use-multiple-paths;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv4-multicast" {
+ list network-config {
+ key "prefix";
+ description
+ "A list of network routes.";
+ leaf prefix {
+ type rt-types:ipv4-multicast-group-address;
+ description
+ "IPv4 multicast destination prefix.";
+ }
+
+ leaf backdoor {
+ type boolean;
+ default "false";
+ description
+ "Specify a BGP backdoor route.";
+ }
+
+ uses mp-afi-safi-network-config;
+ }
+
+ list aggregate-route {
+ key "prefix";
+ description
+ "A list of aggregated routes.";
+ leaf prefix {
+ type rt-types:ipv4-multicast-group-address;
+ description
+ "IPv4 multicast destination prefix.";
+ }
+
+ uses mp-afi-safi-agg-route-config;
+ }
+
+ list admin-distance-route {
+ key "prefix";
+ description
+ "A list of routes with a particular admin distance.";
+ leaf prefix {
+ type rt-types:ipv4-multicast-group-address;
+ description
+ "IPv4 multicast destination prefix.";
+ }
+ }
+
+ uses admin-distance;
+
+ uses route-flap-dampening;
+
+ uses global-filter-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv6-multicast" {
+ list network-config {
+ key "prefix";
+ description
+ "A list of network routes.";
+ leaf prefix {
+ type rt-types:ipv6-multicast-group-address;
+ description
+ "IPv6 multicast destination prefix.";
+ }
+
+ leaf backdoor {
+ type boolean;
+ default "false";
+ description
+ "Specify a BGP backdoor route.";
+ }
+
+ uses mp-afi-safi-network-config;
+ }
+
+ list aggregate-route {
+ key "prefix";
+ description
+ "A list of aggregated routes.";
+ leaf prefix {
+ type rt-types:ipv6-multicast-group-address;
+ description
+ "IPv6 multicast destination prefix.";
+ }
+
+ uses mp-afi-safi-agg-route-config;
+ }
+
+ list admin-distance-route {
+ key "prefix";
+ description
+ "A list of routes with a particular admin distance.";
+ leaf prefix {
+ type rt-types:ipv6-multicast-group-address;
+ description
+ "IPv6 multicast destination prefix.";
+ }
+ }
+
+ uses admin-distance;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/ipv4-flowspec" {
+ uses flow-spec-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
+ uses global-afi-safi-vpn-network-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
+ uses global-afi-safi-vpn-network-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/bmp-config/target-list/afi-safis/afi-safi/ipv4-unicast" {
+ uses bmp-afi-safi-common-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/bmp-config/target-list/afi-safis/afi-safi/ipv4-multicast" {
+ uses bmp-afi-safi-common-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/bmp-config/target-list/afi-safis/afi-safi/ipv6-unicast" {
+ uses bmp-afi-safi-common-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/global/bmp-config/target-list/afi-safis/afi-safi/ipv6-multicast" {
+ uses bmp-afi-safi-common-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-default-originate-options;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-weight;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-group-filter-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-unicast" {
+ leaf nexthop-local-unchanged {
+ type boolean;
+ default "false";
+ description
+ "Configure treatment of outgoing link-local nexthop attribute.
+ When set to 'true' it leaves link-local nexthop unchanged
+ for this peer.";
+ }
+
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/l2vpn-evpn" {
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv6-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-default-originate-options;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-weight;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-group-filter-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-unicast" {
+ leaf nexthop-local-unchanged {
+ type boolean;
+ default "false";
+ description
+ "Configure treatment of outgoing link-local nexthop attribute.
+ When set to 'true' it leaves link-local nexthop unchanged
+ for this peer.";
+ }
+
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn" {
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv6-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-default-originate-options;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-weight;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-group-filter-config;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-unicast" {
+ leaf nexthop-local-unchanged {
+ type boolean;
+ default "false";
+ description
+ "Configure treatment of outgoing link-local nexthop attribute.
+ When set to 'true' it leaves link-local nexthop unchanged
+ for this peer.";
+ }
+
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-multicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-labeled-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-group-orf-capability;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv4-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l3vpn-ipv6-unicast" {
+ uses structure-neighbor-group-add-paths;
+
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-prefix-limit;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-private-as;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-send-community;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+
+ uses structure-neighbor-weight;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn" {
+ uses structure-neighbor-group-as-path-options;
+
+ uses structure-neighbor-group-attr-unchanged;
+
+ uses structure-neighbor-nexthop-self;
+
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+
+ augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv6-flowspec" {
+ uses structure-neighbor-route-reflector;
+
+ uses structure-neighbor-route-server;
+
+ uses structure-neighbor-group-soft-reconfiguration;
+ }
+}
diff --git a/yang/frr-deviations-bgp-datacenter.yang b/yang/frr-deviations-bgp-datacenter.yang
new file mode 100644
index 0000000000..9d2725b253
--- /dev/null
+++ b/yang/frr-deviations-bgp-datacenter.yang
@@ -0,0 +1,106 @@
+module frr-deviations-bgp-datacenter {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/frr-deviations-bgp-datacenter";
+ prefix frr-deviations-bgp-dc;
+
+ import frr-routing {
+ prefix frr-rt;
+ }
+
+ import frr-bgp {
+ prefix frr-bgp;
+ }
+
+ organization
+ "FRRouting";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
+ List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines deviations for the frr-bgp module with
+ datacenter profile.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
+ revision 2019-12-03 {
+ description
+ "Initial revision.";
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:global-config-timers/frr-bgp:connect-retry-interval" {
+ deviate replace {
+ default "10";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:global-config-timers/frr-bgp:hold-time" {
+ deviate replace {
+ default "9";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:global-config-timers/frr-bgp:keepalive" {
+ deviate replace {
+ default "3";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:route-selection-options/frr-bgp:deterministic-med" {
+ deviate replace {
+ default "false";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:import-check" {
+ deviate replace {
+ default "true";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:show-hostname" {
+ deviate replace {
+ default "true";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:show-nexthop-hostname" {
+ deviate replace {
+ default "true";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:ebgp-requires-policy" {
+ deviate replace {
+ default "false";
+ }
+ }
+
+ deviation "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/frr-bgp:bgp/frr-bgp:global/frr-bgp:global-neighbor-config/frr-bgp:log-neighbor-changes" {
+ deviate replace {
+ default "true";
+ }
+ }
+}
diff --git a/yang/frr-ospfd.yang b/yang/frr-ospfd.yang
index 324b66dd98..466dd42ce4 100644
--- a/yang/frr-ospfd.yang
+++ b/yang/frr-ospfd.yang
@@ -346,6 +346,13 @@ module frr-ospfd {
"The reference bandwidth in terms of Mbits per second.";
}
+ leaf use-arp {
+ type boolean;
+ default "true";
+ description
+ "ARP for neighbor table entry.";
+ }
+
leaf capability-opaque {
type boolean;
default "false";
diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang
index d22e12074f..52607f9ad0 100644
--- a/yang/frr-routing.yang
+++ b/yang/frr-routing.yang
@@ -101,6 +101,76 @@ module frr-routing {
"This identity represents the IPv6 multicast address family.";
}
+ identity ipv4-labeled-unicast {
+ base afi-safi-type;
+ description
+ "This identity represents the IPv4 labeled unicast address family.";
+ }
+
+
+ identity ipv6-labeled-unicast {
+ base afi-safi-type;
+ description
+ "This identity represents the IPv6 labeled unicast address family.";
+ }
+
+
+ identity l3vpn-ipv4-unicast {
+ base afi-safi-type;
+ description
+ "This identity represents the L3vpn IPv4 unicast address family.";
+ }
+
+
+ identity l3vpn-ipv6-unicast {
+ base afi-safi-type;
+ description
+ "This identity represents the L3vpn IPv6 unicast address family.";
+ }
+
+
+ identity l3vpn-ipv4-multicast {
+ base afi-safi-type;
+ description
+ "This identity represents the L3vpn IPv4 multicast address family.";
+ }
+
+
+ identity l3vpn-ipv6-multicast {
+ base afi-safi-type;
+ description
+ "This identity represents the L3vpn IPv6 multicast address family.";
+ }
+
+
+ identity l2vpn-vpls {
+ base afi-safi-type;
+ description
+ "This identity represents the L2vpn VPLS address family.";
+ }
+
+
+ identity l2vpn-evpn {
+ base afi-safi-type;
+ description
+ "This identity represents the L2vpn EVPN address family.";
+ }
+
+
+ identity ipv4-flowspec {
+ base afi-safi-type;
+ description
+ "This identity represents the IPv4 flowspec address family.";
+ }
+
+
+ identity ipv6-flowspec {
+ base afi-safi-type;
+ description
+ "This identity represents the IPv6 flowspec address family.";
+ }
+
+
identity control-plane-protocol {
description
"Base identity from which control-plane protocol identities are
diff --git a/yang/ietf/ietf-bgp-types.yang b/yang/ietf/ietf-bgp-types.yang
new file mode 100644
index 0000000000..9c7a6af76c
--- /dev/null
+++ b/yang/ietf/ietf-bgp-types.yang
@@ -0,0 +1,525 @@
+module ietf-bgp-types {
+ yang-version "1.1";
+ namespace "urn:ietf:params:xml:ns:yang:ietf-bgp-types";
+
+ prefix "bt";
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ // meta
+ organization
+ "IETF IDR Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/idr>
+ WG List: <idr@ietf.org>
+
+ Authors: Mahesh Jethanandani (mjethanandani at gmail.com),
+ Keyur Patel (keyur at arrcus.com),
+ Susan Hares (shares at ndzh.com),
+ Jeffrey Haas (jhaas at pfrc.org).";
+ description
+ "This module contains general data definitions for use in BGP
+ policy. It can be imported by modules that make use of BGP
+ attributes";
+
+ revision 2019-10-03 {
+ description
+ "Initial Version";
+ reference
+ "RFC XXX, BGP Model for Service Provider Network.";
+ }
+
+ identity bgp-capability {
+ description "Base identity for a BGP capability";
+ }
+
+ identity mp-bgp {
+ base bgp-capability;
+ description
+ "Multi-protocol extensions to BGP";
+ reference
+ "RFC 4760";
+ }
+
+ identity route-refresh {
+ base bgp-capability;
+ description
+ "The BGP route-refresh functionality";
+ reference
+ "RFC2918";
+ }
+
+ identity asn32 {
+ base bgp-capability;
+ description
+ "4-byte (32-bit) AS number functionality";
+ reference
+ "RFC6793";
+ }
+
+ identity graceful-restart {
+ base bgp-capability;
+ description
+ "Graceful restart functionality";
+ reference
+ "RFC4724";
+ }
+
+ identity add-paths {
+ base bgp-capability;
+ description
+ "BGP add-paths";
+ reference
+ "RFC 7911.";
+ }
+
+ identity afi-safi-type {
+ description
+ "Base identity type for AFI,SAFI tuples for BGP-4";
+ reference
+ "RFC4760 - multi-protocol extensions for BGP-4";
+ }
+
+ identity ipv4-unicast {
+ base afi-safi-type;
+ description
+ "IPv4 unicast (AFI,SAFI = 1,1)";
+ reference
+ "RFC4760";
+ }
+
+ identity ipv6-unicast {
+ base afi-safi-type;
+ description
+ "IPv6 unicast (AFI,SAFI = 2,1)";
+ reference
+ "RFC4760";
+ }
+
+ identity ipv4-labeled-unicast {
+ base afi-safi-type;
+ description
+ "Labeled IPv4 unicast (AFI,SAFI = 1,4)";
+ reference
+ "RFC3107";
+ }
+
+ identity ipv6-labeled-unicast {
+ base afi-safi-type;
+ description
+ "Labeled IPv6 unicast (AFI,SAFI = 2,4)";
+ reference
+ "RFC3107";
+ }
+
+ identity l3vpn-ipv4-unicast {
+ base afi-safi-type;
+ description
+ "Unicast IPv4 MPLS L3VPN (AFI,SAFI = 1,128)";
+ reference
+ "RFC4364";
+ }
+
+ identity l3vpn-ipv6-unicast {
+ base afi-safi-type;
+ description
+ "Unicast IPv6 MPLS L3VPN (AFI,SAFI = 2,128)";
+ reference
+ "RFC4659";
+ }
+
+ identity l3vpn-ipv4-multicast {
+ base afi-safi-type;
+ description
+ "Multicast IPv4 MPLS L3VPN (AFI,SAFI = 1,129)";
+ reference
+ "RFC6514";
+ }
+
+ identity l3vpn-ipv6-multicast {
+ base afi-safi-type;
+ description
+ "Multicast IPv6 MPLS L3VPN (AFI,SAFI = 2,129)";
+ reference
+ "RFC6514";
+ }
+
+ identity l2vpn-vpls {
+ base afi-safi-type;
+ description
+ "BGP-signalled VPLS (AFI,SAFI = 25,65)";
+ reference
+ "RFC4761";
+ }
+
+ identity l2vpn-evpn {
+ base afi-safi-type;
+ description
+ "BGP MPLS Based Ethernet VPN (AFI,SAFI = 25,70)";
+ }
+
+ identity bgp-well-known-std-community {
+ description
+ "Base identity for reserved communities within the standard
+ community space defined by RFC1997. These communities must
+ fall within the range 0xFFFF0000 to 0xFFFFFFFF";
+ reference
+ "RFC 1997: BGP Communities Attribute.";
+ }
+
+ identity no-export {
+ base bgp-well-known-std-community;
+ description
+ "Do not export NLRI received carrying this community outside
+ the bounds of this autonomous system, or this confederation if
+ the local autonomous system is a confederation member AS. This
+ community has a value of 0xFFFFFF01.";
+ reference
+ "RFC 1997: BGP Communities Attribute.";
+ }
+
+ identity no-advertise {
+ base bgp-well-known-std-community;
+ description
+ "All NLRI received carrying this community must not be
+ advertised to other BGP peers. This community has a value of
+ 0xFFFFFF02.";
+ reference
+ "RFC 1997: BGP Communities Attribute.";
+ }
+
+ identity no-export-subconfed {
+ base bgp-well-known-std-community;
+ description
+ "All NLRI received carrying this community must not be
+ advertised to external BGP peers - including over confederation
+ sub-AS boundaries. This community has a value of 0xFFFFFF03.";
+ reference
+ "RFC 1997: BGP Communities Attribute.";
+ }
+
+ identity no-peer {
+ base bgp-well-known-std-community;
+ description
+ "An autonomous system receiving NLRI tagged with this community
+ is advised not to re-advertise the NLRI to external bi-lateral
+ peer autonomous systems. An AS may also filter received NLRI
+ from bilateral peer sessions when they are tagged with this
+ community value";
+ reference
+ "RFC 3765: NOPEER Community for BGP.";
+ }
+ identity as-path-segment-type {
+ description
+ "Base AS Path Segment Type. In [BGP-4], the path segment type
+ is a 1-octet field with the following values defined.";
+ reference
+ "RFC 4271: A Border Gateway Protocol 4 (BGP-4), Section 4.3.";
+ }
+
+ identity as-set {
+ base as-path-segment-type;
+ description
+ "Unordered set of autonomous systems that a route in the UPDATE
+ message has traversed.";
+ reference
+ "RFC 4271: A Border Gateway Protocol 4 (BGP-4), Section 4.3.";
+ }
+
+ identity as-sequence {
+ base as-path-segment-type;
+ description
+ "Ordered set of autonomous systems that a route in the UPDATE
+ message has traversed.";
+ reference
+ "RFC 4271: A Border Gateway Protocol 4 (BGP-4), Section 4.3.";
+ }
+
+ identity as-confed-sequence {
+ base as-path-segment-type;
+ description
+ "Ordered set of Member Autonomous Systems in the local
+ confederation that the UPDATE message has traversed.";
+ reference
+ "RFC 5065, Autonomous System Configuration for BGP.";
+ }
+
+ identity as-confed-set {
+ base as-path-segment-type;
+ description
+ "Unordered set of Member Autonomous Systems in the local
+ confederation that the UPDATE message has traversed.";
+ reference
+ "RFC 5065, Autonomous System Configuration for BGP.";
+ }
+
+ /*
+ * Features.
+ */
+ feature send-communities {
+ description
+ "Enable the propogation of communities.";
+ }
+
+ feature ttl-security {
+ description
+ "BGP Time To Live (TTL) security check support.";
+ reference
+ "RFC 5082, The Generalized TTL Security Mechanism (GTSM)";
+ }
+
+ feature bfd {
+ description
+ "Support for BFD detection of BGP neighbor reachability.";
+ reference
+ "RFC 5880, Bidirectional Forward Detection (BFD),
+ RFC 5881, Bidirectional Forward Detection for IPv4 and IPv6
+ (Single Hop).
+ RFC 5883, Bidirectional Forwarding Detection (BFD) for Multihop
+ Paths";
+ }
+
+ typedef bgp-session-direction {
+ type enumeration {
+ enum INBOUND {
+ description
+ "Refers to all NLRI received from the BGP peer";
+ }
+ enum OUTBOUND {
+ description
+ "Refers to all NLRI advertised to the BGP peer";
+ }
+ }
+ description
+ "Type to describe the direction of NLRI transmission";
+ }
+
+ typedef bgp-well-known-community-type {
+ type identityref {
+ base bgp-well-known-std-community;
+ }
+ description
+ "Type definition for well-known IETF community attribute
+ values";
+ reference
+ "IANA Border Gateway Protocol (BGP) Well Known Communities";
+ }
+
+ typedef bgp-std-community-type {
+ // TODO: further refine restrictions and allowed patterns
+ // 4-octet value:
+ // <as number> 2 octets
+ // <community value> 2 octets
+ type union {
+ type uint32 {
+ // per RFC 1997, 0x00000000 - 0x0000FFFF and 0xFFFF0000 -
+ // 0xFFFFFFFF are reserved
+ range "65536..4294901759"; // 0x00010000..0xFFFEFFFF
+ }
+ type string {
+ pattern '([0-9]+:[0-9]+)';
+ }
+ }
+ description
+ "Type definition for standard community attributes";
+ reference
+ "RFC 1997 - BGP Communities Attribute";
+ }
+
+ typedef bgp-ext-community-type {
+ // TODO: needs more work to make this more precise given the
+ // variability of extended community attribute specifications
+ // 8-octet value:
+ // <type> 2 octects
+ // <value> 6 octets
+
+ type union {
+ type string {
+ // Type 1: 2-octet global and 4-octet local
+ // (AS number) (Integer)
+ pattern '(6[0-5][0-5][0-3][0-5]|[1-5][0-9]{4}|' +
+ '[1-9][0-9]{1,4}|[0-9]):' +
+ '(4[0-2][0-9][0-4][0-9][0-6][0-7][0-2][0-9][0-6]|' +
+ '[1-3][0-9]{9}|[1-9]([0-9]{1,7})?[0-9]|[1-9])';
+ }
+ type string {
+ // Type 2: 4-octet global and 2-octet local
+ // (ipv4-address) (integer)
+ pattern '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|' +
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|' +
+ '2[0-4][0-9]|25[0-5]):' +
+ '(6[0-5][0-5][0-3][0-5]|[1-5][0-9]{4}|' +
+ '[1-9][0-9]{1,4}|[0-9])';
+ }
+ type string {
+ // route-target with Type 1
+ // route-target:(ASN):(local-part)
+ pattern 'route\-target:(6[0-5][0-5][0-3][0-5]|' +
+ '[1-5][0-9]{4}|[1-9][0-9]{1,4}|[0-9]):' +
+ '(4[0-2][0-9][0-4][0-9][0-6][0-7][0-2][0-9][0-6]|' +
+ '[1-3][0-9]{9}|[1-9]([0-9]{1,7})?[0-9]|[1-9])';
+ }
+ type string {
+ // route-target with Type 2
+ // route-target:(IPv4):(local-part)
+ pattern 'route\-target:' +
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|' +
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|' +
+ '2[0-4][0-9]|25[0-5]):' +
+ '(6[0-5][0-5][0-3][0-5]|[1-5][0-9]{4}|' +
+ '[1-9][0-9]{1,4}|[0-9])';
+ }
+ type string {
+ // route-origin with Type 1
+ pattern 'route\-origin:(6[0-5][0-5][0-3][0-5]|' +
+ '[1-5][0-9]{4}|[1-9][0-9]{1,4}|[0-9]):' +
+ '(4[0-2][0-9][0-4][0-9][0-6][0-7][0-2][0-9][0-6]|' +
+ '[1-3][0-9]{9}|[1-9]([0-9]{1,7})?[0-9]|[1-9])';
+ }
+ type string {
+ // route-origin with Type 2
+ pattern 'route\-origin:' +
+ '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|' +
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|' +
+ '2[0-4][0-9]|25[0-5]):' +
+ '(6[0-5][0-5][0-3][0-5]|[1-5][0-9]{4}|' +
+ '[1-9][0-9]{1,4}|[0-9])';
+ }
+ }
+ description
+ "Type definition for extended community attributes";
+ reference
+ "RFC 4360 - BGP Extended Communities Attribute";
+ }
+
+ typedef bgp-community-regexp-type {
+ // TODO: needs more work to decide what format these regexps can
+ // take.
+ type string;
+ description
+ "Type definition for communities specified as regular
+ expression patterns";
+ }
+
+ typedef bgp-origin-attr-type {
+ type enumeration {
+ enum igp {
+ description "Origin of the NLRI is internal";
+ }
+ enum egp {
+ description "Origin of the NLRI is EGP";
+ }
+ enum incomplete {
+ description "Origin of the NLRI is neither IGP or EGP";
+ }
+ }
+ description
+ "Type definition for standard BGP origin attribute";
+ reference
+ "RFC 4271 - A Border Gateway Protocol 4 (BGP-4), Sec 4.3";
+ }
+
+ typedef peer-type {
+ type enumeration {
+ enum internal {
+ description
+ "internal (iBGP) peer";
+ }
+ enum external {
+ description
+ "external (eBGP) peer";
+ }
+ enum confederation {
+ description
+ "Confederation as peer";
+ }
+ }
+ description
+ "Labels a peer or peer group as explicitly internal,
+ external or confederation.";
+ }
+
+ identity REMOVE_PRIVATE_AS_OPTION {
+ description
+ "Base identity for options for removing private autonomous
+ system numbers from the AS_PATH attribute";
+ }
+
+ identity PRIVATE_AS_REMOVE_ALL {
+ base REMOVE_PRIVATE_AS_OPTION;
+ description
+ "Strip all private autonomous system numbers from the AS_PATH.
+ This action is performed regardless of the other content of the
+ AS_PATH attribute, and for all instances of private AS numbers
+ within that attribute.";
+ }
+
+ identity PRIVATE_AS_REPLACE_ALL {
+ base REMOVE_PRIVATE_AS_OPTION;
+ description
+ "Replace all instances of private autonomous system numbers in
+ the AS_PATH with the local BGP speaker's autonomous system
+ number. This action is performed regardless of the other
+ content of the AS_PATH attribute, and for all instances of
+ private AS number within that attribute.";
+ }
+
+ typedef remove-private-as-option {
+ type identityref {
+ base REMOVE_PRIVATE_AS_OPTION;
+ }
+ description
+ "Set of options for configuring how private AS path numbers
+ are removed from advertisements";
+ }
+
+ typedef percentage {
+ type uint8 {
+ range "0..100";
+ }
+ description
+ "Integer indicating a percentage value";
+ }
+
+ typedef rr-cluster-id-type {
+ type union {
+ type uint32;
+ type inet:ipv4-address;
+ }
+ description
+ "Union type for route reflector cluster ids:
+ option 1: 4-byte number
+ option 2: IP address";
+ }
+
+ typedef community-type {
+ type bits {
+ bit standard {
+ position 0;
+ description
+ "Send only standard communities.";
+ reference
+ "RFC 1997: BGP Communities Attribute.";
+ }
+ bit extended {
+ description
+ "Send only extended communities.";
+ reference
+ "RFC 4360: BGP Extended Communities Attribute.";
+ }
+ bit large {
+ description
+ "Send only large communities.";
+ reference
+ "RFC 8092: BGP Large Communities Attribute.";
+ }
+ }
+ description
+ "Type describing variations of community attributes.
+ The community types can be combined and a value of 0
+ implies 'none'";
+ }
+}
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 4165fa1b3a..5bf47580a8 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -44,6 +44,8 @@
#include "zebra/interface.h"
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_router.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
#include "zebra/zebra_vxlan_private.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 4d6346151a..0b97562424 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -200,8 +200,8 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
- "%u:%s: Redist update re %p (%s), old %p (%s)",
- re->vrf_id, prefix2str(p, buf, sizeof(buf)),
+ "(%u:%u):%s: Redist update re %p (%s), old %p (%s)",
+ re->vrf_id, re->table, prefix2str(p, buf, sizeof(buf)),
re, zebra_route_string(re->type), prev_re,
prev_re ? zebra_route_string(prev_re->type) : "None");
}
@@ -224,12 +224,12 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
if (zebra_redistribute_check(re, client, p, afi)) {
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
- "%s: client %s %s(%u), type=%d, distance=%d, metric=%d",
- __func__,
- zebra_route_string(client->proto),
- prefix2str(p, buf, sizeof(buf)),
- re->vrf_id, re->type,
- re->distance, re->metric);
+ "%s: client %s %s(%u:%u), type=%d, distance=%d, metric=%d",
+ __func__,
+ zebra_route_string(client->proto),
+ prefix2str(p, buf, sizeof(buf)),
+ re->vrf_id, re->table, re->type,
+ re->distance, re->metric);
}
zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
client, p, src_p, re);
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 1cea1a9f40..a6ef1537c0 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -80,6 +80,9 @@ zebra_zebra_SOURCES = \
zebra/zebra_errors.c \
zebra/zebra_gr.c \
zebra/zebra_l2.c \
+ zebra/zebra_evpn.c \
+ zebra/zebra_evpn_mac.c \
+ zebra/zebra_evpn_neigh.c \
zebra/zebra_mlag.c \
zebra/zebra_mlag_vty.c \
zebra/zebra_memory.c \
@@ -147,6 +150,10 @@ noinst_HEADERS += \
zebra/zapi_msg.h \
zebra/zebra_dplane.h \
zebra/zebra_errors.h \
+ zebra/zebra_evpn.h \
+ zebra/zebra_evpn_mac.h \
+ zebra/zebra_evpn_neigh.h \
+ zebra/zebra_evpn_vxlan.h \
zebra/zebra_fpm_private.h \
zebra/zebra_l2.h \
zebra/zebra_memory.h \
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index fbed99dc59..2bcb3502d5 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1588,16 +1588,17 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
return;
}
+ vrf_id = zvrf_id(zvrf);
+
if (IS_ZEBRA_DEBUG_RECV) {
char buf_prefix[PREFIX_STRLEN];
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x",
- __func__, buf_prefix, (int)api.message, api.flags);
+ zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x",
+ __func__, vrf_id, api.tableid, buf_prefix, (int)api.message, api.flags);
}
/* Allocate new route. */
- vrf_id = zvrf_id(zvrf);
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
re->type = api.type;
re->instance = api.instance;
@@ -1878,6 +1879,15 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
else
table_id = zvrf->table_id;
+ if (IS_ZEBRA_DEBUG_RECV) {
+ char buf_prefix[PREFIX_STRLEN];
+
+ prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x",
+ __func__, zvrf_id(zvrf), table_id, buf_prefix,
+ (int)api.message, api.flags);
+ }
+
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);
@@ -3152,7 +3162,8 @@ void zserv_handle_commands(struct zserv *client, struct stream_fifo *fifo)
zapi_parse_header(msg, &hdr);
- if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+ if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV
+ && IS_ZEBRA_DEBUG_DETAIL)
zserv_log_message(NULL, msg, &hdr);
#if defined(HANDLE_ZAPI_FUZZING)
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 8ab7a7f5bc..6e8d35aa77 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -3144,25 +3144,6 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
}
/*
- * Enqueue evpn neighbor update for the dataplane.
- */
-enum zebra_dplane_result dplane_rem_neigh_update(const struct interface *ifp,
- const struct ipaddr *ip,
- const struct ethaddr *mac)
-{
- enum zebra_dplane_result result;
- uint32_t update_flags = 0;
-
- update_flags |= DPLANE_NEIGH_REMOTE;
-
- result = neigh_update_internal(DPLANE_OP_NEIGH_UPDATE,
- ifp, mac, ip, 0, DPLANE_NUD_PROBE,
- update_flags);
-
- return result;
-}
-
-/*
* Enqueue evpn neighbor delete for the dataplane.
*/
enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index c68a617f38..5dd789a851 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -561,9 +561,6 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
const struct ethaddr *mac,
bool set_router, bool set_static,
bool set_inactive);
-enum zebra_dplane_result dplane_rem_neigh_update(const struct interface *ifp,
- const struct ipaddr *ip,
- const struct ethaddr *mac);
enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
const struct ipaddr *ip);
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
new file mode 100644
index 0000000000..73df93258e
--- /dev/null
+++ b/zebra/zebra_evpn.c
@@ -0,0 +1,1448 @@
+/*
+ * Zebra EVPN for VxLAN code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+#include "vlan.h"
+#include "vxlan.h"
+#ifdef GNU_LINUX
+#include <linux/neighbour.h>
+#endif
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
+#include "zebra/zebra_evpn_neigh.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_vxlan.h"
+#include "zebra/zebra_router.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, ZEVPN, "VNI hash");
+DEFINE_MTYPE_STATIC(ZEBRA, ZEVPN_VTEP, "VNI remote VTEP");
+
+/* PMSI strings. */
+#define VXLAN_FLOOD_STR_NO_INFO "-"
+#define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO
+static const struct message zvtep_flood_str[] = {
+ {VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO},
+ {VXLAN_FLOOD_PIM_SM, "PIM-SM"},
+ {VXLAN_FLOOD_HEAD_END_REPL, "HER"},
+ {0}
+};
+
+int advertise_gw_macip_enabled(zebra_evpn_t *zevpn)
+{
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+ if (zvrf && zvrf->advertise_gw_macip)
+ return 1;
+
+ if (zevpn && zevpn->advertise_gw_macip)
+ return 1;
+
+ return 0;
+}
+
+int advertise_svi_macip_enabled(zebra_evpn_t *zevpn)
+{
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+ if (zvrf && zvrf->advertise_svi_macip)
+ return 1;
+
+ if (zevpn && zevpn->advertise_svi_macip)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Print a specific EVPN entry.
+ */
+void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
+{
+ struct vty *vty;
+ zebra_vtep_t *zvtep;
+ uint32_t num_macs;
+ uint32_t num_neigh;
+ json_object *json = NULL;
+ json_object *json_vtep_list = NULL;
+ json_object *json_ip_str = NULL;
+
+ vty = ctxt[0];
+ json = ctxt[1];
+
+ if (json == NULL) {
+ vty_out(vty, "VNI: %u\n", zevpn->vni);
+ vty_out(vty, " Type: %s\n", "L2");
+ vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zevpn->vrf_id));
+ } else {
+ json_object_int_add(json, "vni", zevpn->vni);
+ json_object_string_add(json, "type", "L2");
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(zevpn->vrf_id));
+ }
+
+ if (!zevpn->vxlan_if) { // unexpected
+ if (json == NULL)
+ vty_out(vty, " VxLAN interface: unknown\n");
+ return;
+ }
+ num_macs = num_valid_macs(zevpn);
+ num_neigh = hashcount(zevpn->neigh_table);
+ if (json == NULL) {
+ vty_out(vty, " VxLAN interface: %s\n", zevpn->vxlan_if->name);
+ vty_out(vty, " VxLAN ifIndex: %u\n", zevpn->vxlan_if->ifindex);
+ vty_out(vty, " Local VTEP IP: %s\n",
+ inet_ntoa(zevpn->local_vtep_ip));
+ vty_out(vty, " Mcast group: %s\n",
+ inet_ntoa(zevpn->mcast_grp));
+ } else {
+ json_object_string_add(json, "vxlanInterface",
+ zevpn->vxlan_if->name);
+ json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex);
+ json_object_string_add(json, "vtepIp",
+ inet_ntoa(zevpn->local_vtep_ip));
+ json_object_string_add(json, "mcastGroup",
+ inet_ntoa(zevpn->mcast_grp));
+ json_object_string_add(json, "advertiseGatewayMacip",
+ zevpn->advertise_gw_macip ? "Yes" : "No");
+ json_object_int_add(json, "numMacs", num_macs);
+ json_object_int_add(json, "numArpNd", num_neigh);
+ }
+ if (!zevpn->vteps) {
+ if (json == NULL)
+ vty_out(vty, " No remote VTEPs known for this VNI\n");
+ } else {
+ if (json == NULL)
+ vty_out(vty, " Remote VTEPs for this VNI:\n");
+ else
+ json_vtep_list = json_object_new_array();
+ for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
+ const char *flood_str = lookup_msg(zvtep_flood_str,
+ zvtep->flood_control,
+ VXLAN_FLOOD_STR_DEFAULT);
+
+ if (json == NULL) {
+ vty_out(vty, " %s flood: %s\n",
+ inet_ntoa(zvtep->vtep_ip),
+ flood_str);
+ } else {
+ json_ip_str = json_object_new_string(
+ inet_ntoa(zvtep->vtep_ip));
+ json_object_array_add(json_vtep_list,
+ json_ip_str);
+ }
+ }
+ if (json)
+ json_object_object_add(json, "numRemoteVteps",
+ json_vtep_list);
+ }
+ if (json == NULL) {
+ vty_out(vty,
+ " Number of MACs (local and remote) known for this VNI: %u\n",
+ num_macs);
+ vty_out(vty,
+ " Number of ARPs (IPv4 and IPv6, local and remote) "
+ "known for this VNI: %u\n",
+ num_neigh);
+ vty_out(vty, " Advertise-gw-macip: %s\n",
+ zevpn->advertise_gw_macip ? "Yes" : "No");
+ }
+}
+
+/*
+ * Print an EVPN hash entry - called for display of all VNIs.
+ */
+void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[])
+{
+ struct vty *vty;
+ zebra_evpn_t *zevpn;
+ zebra_vtep_t *zvtep;
+ uint32_t num_vteps = 0;
+ uint32_t num_macs = 0;
+ uint32_t num_neigh = 0;
+ json_object *json = NULL;
+ json_object *json_evpn = NULL;
+ json_object *json_ip_str = NULL;
+ json_object *json_vtep_list = NULL;
+
+ vty = ctxt[0];
+ json = ctxt[1];
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+
+ zvtep = zevpn->vteps;
+ while (zvtep) {
+ num_vteps++;
+ zvtep = zvtep->next;
+ }
+
+ num_macs = num_valid_macs(zevpn);
+ num_neigh = hashcount(zevpn->neigh_table);
+ if (json == NULL)
+ vty_out(vty, "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
+ zevpn->vni, "L2",
+ zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown",
+ num_macs, num_neigh, num_vteps,
+ vrf_id_to_name(zevpn->vrf_id));
+ else {
+ char vni_str[VNI_STR_LEN];
+ snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
+ json_evpn = json_object_new_object();
+ json_object_int_add(json_evpn, "vni", zevpn->vni);
+ json_object_string_add(json_evpn, "type", "L2");
+ json_object_string_add(json_evpn, "vxlanIf",
+ zevpn->vxlan_if ? zevpn->vxlan_if->name
+ : "unknown");
+ json_object_int_add(json_evpn, "numMacs", num_macs);
+ json_object_int_add(json_evpn, "numArpNd", num_neigh);
+ json_object_int_add(json_evpn, "numRemoteVteps", num_vteps);
+ json_object_string_add(json_evpn, "tenantVrf",
+ vrf_id_to_name(zevpn->vrf_id));
+ if (num_vteps) {
+ json_vtep_list = json_object_new_array();
+ for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
+ json_ip_str = json_object_new_string(
+ inet_ntoa(zvtep->vtep_ip));
+ json_object_array_add(json_vtep_list,
+ json_ip_str);
+ }
+ json_object_object_add(json_evpn, "remoteVteps",
+ json_vtep_list);
+ }
+ json_object_object_add(json, vni_str, json_evpn);
+ }
+}
+
+/*
+ * Print an EVPN hash entry in detail - called for display of all EVPNs.
+ */
+void zebra_evpn_print_hash_detail(struct hash_bucket *bucket, void *data)
+{
+ struct vty *vty;
+ zebra_evpn_t *zevpn;
+ json_object *json_array = NULL;
+ bool use_json = false;
+ struct zebra_evpn_show *zes = data;
+
+ vty = zes->vty;
+ json_array = zes->json;
+ use_json = zes->use_json;
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+
+ zebra_vxlan_print_vni(vty, zes->zvrf, zevpn->vni, use_json, json_array);
+
+ if (!use_json)
+ vty_out(vty, "\n");
+}
+
+int zebra_evpn_del_macip_for_intf(struct interface *ifp, zebra_evpn_t *zevpn)
+{
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct ipaddr ip;
+
+ memset(&ip, 0, sizeof(struct ipaddr));
+ if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+ continue;
+
+ if (c->address->family == AF_INET) {
+ ip.ipa_type = IPADDR_V4;
+ memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (c->address->family == AF_INET6) {
+ ip.ipa_type = IPADDR_V6;
+ memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+ sizeof(struct in6_addr));
+ } else {
+ continue;
+ }
+
+ zebra_evpn_gw_macip_del(ifp, zevpn, &ip);
+ }
+
+ return 0;
+}
+
+int zebra_evpn_add_macip_for_intf(struct interface *ifp, zebra_evpn_t *zevpn)
+{
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct ipaddr ip;
+
+ memset(&ip, 0, sizeof(struct ipaddr));
+ if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
+ continue;
+
+ if (c->address->family == AF_INET) {
+ ip.ipa_type = IPADDR_V4;
+ memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
+ sizeof(struct in_addr));
+ } else if (c->address->family == AF_INET6) {
+ ip.ipa_type = IPADDR_V6;
+ memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
+ sizeof(struct in6_addr));
+ } else {
+ continue;
+ }
+
+ zebra_evpn_gw_macip_add(ifp, zevpn, &macaddr, &ip);
+ }
+ return 0;
+}
+
+static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
+ uint16_t cmd)
+{
+ struct zserv *client = NULL;
+ struct stream *s = NULL;
+ char buf[PREFIX_STRLEN];
+
+ client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, cmd, vrf_id);
+ stream_put(s, p, sizeof(struct prefix));
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Send ip prefix %s %s on vrf %s",
+ prefix2str(p, buf, sizeof(buf)),
+ (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+ vrf_id_to_name(vrf_id));
+
+ if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
+ client->prefixadd_cnt++;
+ else
+ client->prefixdel_cnt++;
+
+ return zserv_send_message(client, s);
+}
+
+int zebra_evpn_advertise_subnet(zebra_evpn_t *zevpn, struct interface *ifp,
+ int advertise)
+{
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct prefix p;
+
+ memcpy(&p, c->address, sizeof(struct prefix));
+
+ /* skip link local address */
+ if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
+ continue;
+
+ apply_mask(&p);
+ if (advertise)
+ ip_prefix_send_to_client(ifp->vrf_id, &p,
+ ZEBRA_IP_PREFIX_ROUTE_ADD);
+ else
+ ip_prefix_send_to_client(ifp->vrf_id, &p,
+ ZEBRA_IP_PREFIX_ROUTE_DEL);
+ }
+ return 0;
+}
+
+/*
+ * zebra_evpn_gw_macip_add_to_client
+ */
+int zebra_evpn_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ethaddr *macaddr, struct ipaddr *ip)
+{
+ zebra_mac_t *mac = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
+
+ zif = zevpn->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ if (zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr,
+ vxl->access_vlan)
+ != 0)
+ return -1;
+
+ return zebra_evpn_neigh_gw_macip_add(ifp, zevpn, ip, mac);
+}
+
+/*
+ * zebra_evpn_gw_macip_del_from_client
+ */
+int zebra_evpn_gw_macip_del(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ipaddr *ip)
+{
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *mac = NULL;
+
+ /* If the neigh entry is not present nothing to do*/
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
+ if (!n)
+ return 0;
+
+ /* mac entry should be present */
+ mac = zebra_evpn_mac_lookup(zevpn, &n->emac);
+ if (!mac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u",
+ prefix_mac2str(&n->emac,
+ buf1, sizeof(buf1)),
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ zevpn->vni);
+ return -1;
+ }
+
+ /* If the entry is not local nothing to do*/
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+ return -1;
+
+ /* only need to delete the entry from bgp if we sent it before */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+ ifp->vrf_id, ifp->name, ifp->ifindex, zevpn->vni,
+ prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
+ ipaddr2str(ip, buf2, sizeof(buf2)));
+
+ /* Remove neighbor from BGP. */
+ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac,
+ n->flags, ZEBRA_NEIGH_ACTIVE,
+ false /*force*/);
+
+ /* Delete this neighbor entry. */
+ zebra_evpn_neigh_del(zevpn, n);
+
+ /* see if the mac needs to be deleted as well*/
+ if (mac)
+ zebra_evpn_deref_ip2mac(zevpn, mac);
+
+ return 0;
+}
+
+void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ zebra_evpn_t *zevpn = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *vrr_if = NULL;
+ struct interface *ifp;
+
+ /* Add primary SVI MAC*/
+ zevpn = (zebra_evpn_t *)bucket->data;
+
+ /* Global (Zvrf) advertise-default-gw is disabled,
+ * but zevpn advertise-default-gw is enabled
+ */
+ if (zevpn->advertise_gw_macip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip",
+ zevpn->vni);
+ return;
+ }
+
+ ifp = zevpn->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if =
+ zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ /* Del primary MAC-IP */
+ zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
+
+ /* Del VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zebra_evpn_del_macip_for_intf(vrr_if, zevpn);
+
+ return;
+}
+
+void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ zebra_evpn_t *zevpn = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *vrr_if = NULL;
+ struct interface *ifp = NULL;
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+
+ ifp = zevpn->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if =
+ zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ /* Add primary SVI MAC-IP */
+ zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
+
+ if (advertise_gw_macip_enabled(zevpn)) {
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
+ }
+
+ return;
+}
+
+void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ zebra_evpn_t *zevpn = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *ifp;
+
+ /* Add primary SVI MAC*/
+ zevpn = (zebra_evpn_t *)bucket->data;
+ if (!zevpn)
+ return;
+
+ /* Global(vrf) advertise-svi-ip disabled, but zevpn advertise-svi-ip
+ * enabled
+ */
+ if (zevpn->advertise_svi_macip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip",
+ zevpn->vni);
+ return;
+ }
+
+ ifp = zevpn->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if =
+ zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ /* Del primary MAC-IP */
+ zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
+
+ return;
+}
+
+/*
+ * Map port or (port, VLAN) to an EVPN. This is invoked upon getting MAC
+ * notifications, to see if they are of interest.
+ */
+zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
+ struct interface *br_if, vlanid_t vid)
+{
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_bridge *br;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ uint8_t bridge_vlan_aware;
+ zebra_evpn_t *zevpn;
+ int found = 0;
+
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
+ assert(zif);
+ br = &zif->l2info.br;
+ bridge_vlan_aware = br->vlan_aware;
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ zevpn = zebra_evpn_lookup(vxl->vni);
+ return zevpn;
+}
+
+/*
+ * Map SVI and associated bridge to an EVPN. This is invoked upon getting
+ * neighbor notifications, to see if they are of interest.
+ */
+zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
+ struct interface *br_if)
+{
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_bridge *br;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ uint8_t bridge_vlan_aware;
+ vlanid_t vid = 0;
+ zebra_evpn_t *zevpn;
+ int found = 0;
+
+ if (!br_if)
+ return NULL;
+
+ /* Make sure the linked interface is a bridge. */
+ if (!IS_ZEBRA_IF_BRIDGE(br_if))
+ return NULL;
+
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
+ assert(zif);
+ br = &zif->l2info.br;
+ bridge_vlan_aware = br->vlan_aware;
+ if (bridge_vlan_aware) {
+ struct zebra_l2info_vlan *vl;
+
+ if (!IS_ZEBRA_IF_VLAN(ifp))
+ return NULL;
+
+ zif = ifp->info;
+ assert(zif);
+ vl = &zif->l2info.vl;
+ vid = vl->vid;
+ }
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* TODO: Optimize with a hash. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ zevpn = zebra_evpn_lookup(vxl->vni);
+ return zevpn;
+}
+
+/* Map to MAC-VLAN interface corresponding to specified SVI interface.
+ */
+struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
+ struct interface *svi_if)
+{
+ struct zebra_ns *zns;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ int found = 0;
+
+ /* Defensive check, caller expected to invoke only with valid bridge. */
+ if (!br_if)
+ return NULL;
+
+ if (!svi_if) {
+ zlog_debug("svi_if is not passed.");
+ return NULL;
+ }
+
+ /* Determine if bridge is VLAN-aware or not */
+ zif = br_if->info;
+ assert(zif);
+
+ /* Identify corresponding VLAN interface. */
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
+ continue;
+ zif = tmp_if->info;
+
+ if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
+ continue;
+
+ if (zif->link == svi_if) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? tmp_if : NULL;
+}
+
+/*
+ * Install MAC hash entry - called upon access VLAN change.
+ */
+void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_mac_t *mac;
+ struct mac_walk_ctx *wctx = ctxt;
+
+ mac = (zebra_mac_t *)bucket->data;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
+ zebra_evpn_rem_mac_install(wctx->zevpn, mac, false);
+}
+
+/*
+ * Read and populate local MACs and neighbors corresponding to this EVPN.
+ */
+void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
+{
+ struct zebra_ns *zns;
+ struct zebra_if *zif;
+ struct interface *vlan_if;
+ struct zebra_l2info_vxlan *vxl;
+ struct interface *vrr_if;
+
+ zif = ifp->info;
+ vxl = &zif->l2info.vxl;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u",
+ ifp->name, ifp->ifindex, zevpn->vni,
+ zif->brslave_info.bridge_ifindex);
+
+ macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ if (vlan_if) {
+
+ /* Add SVI MAC-IP */
+ zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
+
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
+
+ neigh_read_for_vlan(zns, vlan_if);
+ }
+}
+
+/*
+ * Hash function for EVPN.
+ */
+unsigned int zebra_evpn_hash_keymake(const void *p)
+{
+ const zebra_evpn_t *zevpn = p;
+
+ return (jhash_1word(zevpn->vni, 0));
+}
+
+/*
+ * Compare 2 evpn hash entries.
+ */
+bool zebra_evpn_hash_cmp(const void *p1, const void *p2)
+{
+ const zebra_evpn_t *zevpn1 = p1;
+ const zebra_evpn_t *zevpn2 = p2;
+
+ return (zevpn1->vni == zevpn2->vni);
+}
+
+int zebra_evpn_list_cmp(void *p1, void *p2)
+{
+ const zebra_evpn_t *zevpn1 = p1;
+ const zebra_evpn_t *zevpn2 = p2;
+
+ if (zevpn1->vni == zevpn2->vni)
+ return 0;
+ return (zevpn1->vni < zevpn2->vni) ? -1 : 1;
+}
+
+/*
+ * Callback to allocate VNI hash entry.
+ */
+void *zebra_evpn_alloc(void *p)
+{
+ const zebra_evpn_t *tmp_vni = p;
+ zebra_evpn_t *zevpn;
+
+ zevpn = XCALLOC(MTYPE_ZEVPN, sizeof(zebra_evpn_t));
+ zevpn->vni = tmp_vni->vni;
+ return ((void *)zevpn);
+}
+
+/*
+ * Look up EVPN hash entry.
+ */
+zebra_evpn_t *zebra_evpn_lookup(vni_t vni)
+{
+ struct zebra_vrf *zvrf;
+ zebra_evpn_t tmp_vni;
+ zebra_evpn_t *zevpn = NULL;
+
+ zvrf = zebra_vrf_get_evpn();
+ assert(zvrf);
+ memset(&tmp_vni, 0, sizeof(zebra_evpn_t));
+ tmp_vni.vni = vni;
+ zevpn = hash_lookup(zvrf->evpn_table, &tmp_vni);
+
+ return zevpn;
+}
+
+/*
+ * Add EVPN hash entry.
+ */
+zebra_evpn_t *zebra_evpn_add(vni_t vni)
+{
+ struct zebra_vrf *zvrf;
+ zebra_evpn_t tmp_zevpn;
+ zebra_evpn_t *zevpn = NULL;
+
+ zvrf = zebra_vrf_get_evpn();
+ assert(zvrf);
+ memset(&tmp_zevpn, 0, sizeof(zebra_evpn_t));
+ tmp_zevpn.vni = vni;
+ zevpn = hash_get(zvrf->evpn_table, &tmp_zevpn, zebra_evpn_alloc);
+ assert(zevpn);
+
+ zebra_evpn_evpn_es_init(zevpn);
+
+ /* Create hash table for MAC */
+ zevpn->mac_table = zebra_mac_db_create("Zebra EVPN MAC Table");
+
+ /* Create hash table for neighbors */
+ zevpn->neigh_table = zebra_neigh_db_create("Zebra EVPN Neighbor Table");
+
+ return zevpn;
+}
+
+/*
+ * Delete EVPN hash entry.
+ */
+int zebra_evpn_del(zebra_evpn_t *zevpn)
+{
+ struct zebra_vrf *zvrf;
+ zebra_evpn_t *tmp_zevpn;
+
+ zvrf = zebra_vrf_get_evpn();
+ assert(zvrf);
+
+ /* Free the neighbor hash table. */
+ hash_free(zevpn->neigh_table);
+ zevpn->neigh_table = NULL;
+
+ /* Free the MAC hash table. */
+ hash_free(zevpn->mac_table);
+ zevpn->mac_table = NULL;
+
+ zebra_evpn_evpn_es_cleanup(zevpn);
+
+ /* Free the EVPN hash entry and allocated memory. */
+ tmp_zevpn = hash_release(zvrf->evpn_table, zevpn);
+ XFREE(MTYPE_ZEVPN, tmp_zevpn);
+
+ return 0;
+}
+
+/*
+ * Inform BGP about local EVPN addition.
+ */
+int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
+{
+ struct zserv *client;
+ struct stream *s;
+ int rc;
+
+ client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
+ stream_putl(s, zevpn->vni);
+ stream_put_in_addr(s, &zevpn->local_vtep_ip);
+ stream_put(s, &zevpn->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
+ stream_put_in_addr(s, &zevpn->mcast_grp);
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Send EVPN_ADD %u %s tenant vrf %s to %s", zevpn->vni,
+ inet_ntoa(zevpn->local_vtep_ip),
+ vrf_id_to_name(zevpn->vrf_id),
+ zebra_route_string(client->proto));
+
+ client->vniadd_cnt++;
+ rc = zserv_send_message(client, s);
+
+ if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) {
+ zevpn->flags |= ZEVPN_READY_FOR_BGP;
+ /* once the EVPN is sent the ES-EVIs can also be replayed
+ * to BGP
+ */
+ zebra_evpn_update_all_es(zevpn);
+ }
+ return rc;
+}
+
+/*
+ * Inform BGP about local EVPN deletion.
+ */
+int zebra_evpn_send_del_to_client(zebra_evpn_t *zevpn)
+{
+ struct zserv *client;
+ struct stream *s;
+
+ client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ if (zevpn->flags & ZEVPN_READY_FOR_BGP) {
+ zevpn->flags &= ~ZEVPN_READY_FOR_BGP;
+ /* the ES-EVIs must be removed from BGP before the EVPN is */
+ zebra_evpn_update_all_es(zevpn);
+ }
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id());
+ stream_putl(s, zevpn->vni);
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Send EVPN_DEL %u to %s", zevpn->vni,
+ zebra_route_string(client->proto));
+
+ client->vnidel_cnt++;
+ return zserv_send_message(client, s);
+}
+
+/*
+ * See if remote VTEP matches with prefix.
+ */
+static int zebra_evpn_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep)
+{
+ return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip));
+}
+
+/*
+ * Locate remote VTEP in EVPN hash table.
+ */
+zebra_vtep_t *zebra_evpn_vtep_find(zebra_evpn_t *zevpn, struct in_addr *vtep_ip)
+{
+ zebra_vtep_t *zvtep;
+
+ if (!zevpn)
+ return NULL;
+
+ for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
+ if (zebra_evpn_vtep_match(vtep_ip, zvtep))
+ break;
+ }
+
+ return zvtep;
+}
+
+/*
+ * Add remote VTEP to EVPN hash table.
+ */
+zebra_vtep_t *zebra_evpn_vtep_add(zebra_evpn_t *zevpn, struct in_addr *vtep_ip,
+ int flood_control)
+
+{
+ zebra_vtep_t *zvtep;
+
+ zvtep = XCALLOC(MTYPE_ZEVPN_VTEP, sizeof(zebra_vtep_t));
+
+ zvtep->vtep_ip = *vtep_ip;
+ zvtep->flood_control = flood_control;
+
+ if (zevpn->vteps)
+ zevpn->vteps->prev = zvtep;
+ zvtep->next = zevpn->vteps;
+ zevpn->vteps = zvtep;
+
+ return zvtep;
+}
+
+/*
+ * Remove remote VTEP from EVPN hash table.
+ */
+int zebra_evpn_vtep_del(zebra_evpn_t *zevpn, zebra_vtep_t *zvtep)
+{
+ if (zvtep->next)
+ zvtep->next->prev = zvtep->prev;
+ if (zvtep->prev)
+ zvtep->prev->next = zvtep->next;
+ else
+ zevpn->vteps = zvtep->next;
+
+ zvtep->prev = zvtep->next = NULL;
+ XFREE(MTYPE_ZEVPN_VTEP, zvtep);
+
+ return 0;
+}
+
+/*
+ * Delete all remote VTEPs for this EVPN (upon VNI delete). Also
+ * uninstall from kernel if asked to.
+ */
+int zebra_evpn_vtep_del_all(zebra_evpn_t *zevpn, int uninstall)
+{
+ zebra_vtep_t *zvtep, *zvtep_next;
+
+ if (!zevpn)
+ return -1;
+
+ for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep_next) {
+ zvtep_next = zvtep->next;
+ if (uninstall)
+ zebra_evpn_vtep_uninstall(zevpn, &zvtep->vtep_ip);
+ zebra_evpn_vtep_del(zevpn, zvtep);
+ }
+
+ return 0;
+}
+
+/*
+ * Install remote VTEP into the kernel if the remote VTEP has asked
+ * for head-end-replication.
+ */
+int zebra_evpn_vtep_install(zebra_evpn_t *zevpn, zebra_vtep_t *zvtep)
+{
+ if (is_vxlan_flooding_head_end() &&
+ (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) {
+ if (ZEBRA_DPLANE_REQUEST_FAILURE ==
+ dplane_vtep_add(zevpn->vxlan_if,
+ &zvtep->vtep_ip, zevpn->vni))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Uninstall remote VTEP from the kernel.
+ */
+int zebra_evpn_vtep_uninstall(zebra_evpn_t *zevpn, struct in_addr *vtep_ip)
+{
+ if (!zevpn->vxlan_if) {
+ zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
+ zevpn->vni, zevpn);
+ return -1;
+ }
+
+ if (ZEBRA_DPLANE_REQUEST_FAILURE ==
+ dplane_vtep_delete(zevpn->vxlan_if, vtep_ip, zevpn->vni))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Install or uninstall flood entries in the kernel corresponding to
+ * remote VTEPs. This is invoked upon change to BUM handling.
+ */
+void zebra_evpn_handle_flooding_remote_vteps(struct hash_bucket *bucket,
+ void *zvrf)
+{
+ zebra_evpn_t *zevpn;
+ zebra_vtep_t *zvtep;
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+ if (!zevpn)
+ return;
+
+ for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
+ if (is_vxlan_flooding_head_end())
+ zebra_evpn_vtep_install(zevpn, zvtep);
+ else
+ zebra_evpn_vtep_uninstall(zevpn, &zvtep->vtep_ip);
+ }
+}
+
+/*
+ * Cleanup EVPN/VTEP and update kernel
+ */
+void zebra_evpn_cleanup_all(struct hash_bucket *bucket, void *arg)
+{
+ zebra_evpn_t *zevpn = NULL;
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+
+ /* Free up all neighbors and MACs, if any. */
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zebra_evpn_vtep_del_all(zevpn, 1);
+
+ /* Delete the hash entry. */
+ zebra_evpn_del(zevpn);
+}
+
+static void
+zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq, esi_t *esi)
+{
+ struct sync_mac_ip_ctx ctx;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool sticky;
+ bool remote_gw;
+ zebra_neigh_t *n = NULL;
+
+ sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ /* if sticky or remote-gw ignore updates from the peer */
+ if (sticky || remote_gw) {
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
+ || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "Ignore sync-macip vni %u mac %s%s%s%s%s",
+ zevpn->vni,
+ prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf))
+ : "",
+ sticky ? " sticky" : "",
+ remote_gw ? " remote_gw" : "");
+ return;
+ }
+
+ if (ipa_len) {
+ n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
+ if (n
+ && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq))
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.mac = zebra_evpn_proc_sync_mac_update(
+ zevpn, macaddr, ipa_len, ipaddr, flags, seq, esi, &ctx);
+ if (ctx.ignore_macip || !ctx.mac || !ipa_len)
+ return;
+
+ zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, flags, seq,
+ esi, &ctx);
+}
+
+/************************** remote mac-ip handling **************************/
+/* Process a remote MACIP add from BGP. */
+void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ struct in_addr vtep_ip, esi_t *esi)
+{
+ zebra_evpn_t *zevpn;
+ zebra_vtep_t *zvtep;
+ zebra_mac_t *mac = NULL;
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_vrf *zvrf;
+
+ /* Locate EVPN hash entry - expected to exist. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
+ return;
+ }
+
+ ifp = zevpn->vxlan_if;
+ if (ifp)
+ zif = ifp->info;
+ if (!ifp || !if_is_operative(ifp) || !zif || !zif->brslave_info.br_if) {
+ zlog_warn(
+ "Ignoring remote MACIP ADD VNI %u, invalid interface state or info",
+ vni);
+ return;
+ }
+
+ /* Type-2 routes from another PE can be interpreted as remote or
+ * SYNC based on the destination ES -
+ * SYNC - if ES is local
+ * REMOTE - if ES is not local
+ */
+ if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) {
+ zebra_evpn_process_sync_macip_add(zevpn, macaddr, ipa_len,
+ ipaddr, flags, seq, esi);
+ return;
+ }
+
+ /* The remote VTEP specified should normally exist, but it is
+ * possible that when peering comes up, peer may advertise MACIP
+ * routes before advertising type-3 routes.
+ */
+ if (vtep_ip.s_addr) {
+ zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
+ if (!zvtep) {
+ zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip,
+ VXLAN_FLOOD_DISABLED);
+ if (!zvtep) {
+ flog_err(
+ EC_ZEBRA_VTEP_ADD_FAILED,
+ "Failed to add remote VTEP, VNI %u zevpn %p upon remote MACIP ADD",
+ vni, zevpn);
+ return;
+ }
+
+ zebra_evpn_vtep_install(zevpn, zvtep);
+ }
+ }
+
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+ if (!zvrf)
+ return;
+
+
+ if (process_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len, ipaddr,
+ &mac, vtep_ip, flags, seq, esi)
+ != 0)
+ return;
+
+ process_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip, flags,
+ seq);
+}
+
+/* Process a remote MACIP delete from BGP. */
+void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ struct in_addr vtep_ip)
+{
+ zebra_evpn_t *zevpn;
+ zebra_mac_t *mac = NULL;
+ zebra_neigh_t *n = NULL;
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_ns *zns;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_vrf *zvrf;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+
+ /* Locate EVPN hash entry - expected to exist. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni);
+ return;
+ }
+
+ ifp = zevpn->vxlan_if;
+ if (ifp)
+ zif = ifp->info;
+ if (!ifp || !if_is_operative(ifp) || !zif || !zif->brslave_info.br_if) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Ignoring remote MACIP DEL VNI %u, invalid interface state or info",
+ vni);
+ return;
+ }
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ vxl = &zif->l2info.vxl;
+
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (ipa_len)
+ n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
+
+ if (n && !mac) {
+ zlog_warn(
+ "Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni);
+ return;
+ }
+
+ /* If the remote mac or neighbor doesn't exist there is nothing
+ * more to do. Otherwise, uninstall the entry and then remove it.
+ */
+ if (!mac && !n)
+ return;
+
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+
+ /* Ignore the delete if this mac is a gateway mac-ip */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
+ && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
+ zlog_warn(
+ "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
+ vni, prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
+ return;
+ }
+
+ /* Uninstall remote neighbor or MAC. */
+ if (n)
+ zebra_evpn_neigh_remote_uninstall(zevpn, zvrf, n, mac, ipaddr);
+ else {
+ /* DAD: when MAC is freeze state as remote learn event,
+ * remote mac-ip delete event is received will result in freeze
+ * entry removal, first fetch kernel for the same entry present
+ * as LOCAL and reachable, avoid deleting this entry instead
+ * use kerenel local entry to update during unfreeze time.
+ */
+ if (zvrf->dad_freeze
+ && CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)
+ && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry",
+ __func__,
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ mac->flags);
+ macfdb_read_specific_mac(zns, zif->brslave_info.br_if,
+ macaddr, vxl->access_vlan);
+ }
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ if (!ipa_len)
+ zebra_evpn_sync_mac_del(mac);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_evpn_rem_mac_del(zevpn, mac);
+ }
+ }
+}
+
+/************************** EVPN BGP config management ************************/
+void zebra_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_evpn_t *zevpn = NULL;
+
+ zevpn = (zebra_evpn_t *)bucket->data;
+ zevpn->advertise_gw_macip = 0;
+ zevpn->advertise_svi_macip = 0;
+ zevpn->advertise_subnet = 0;
+
+ zebra_evpn_neigh_del_all(zevpn, 1, 0,
+ DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP);
+ zebra_evpn_mac_del_all(zevpn, 1, 0,
+ DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP);
+ zebra_evpn_vtep_del_all(zevpn, 1);
+}
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
new file mode 100644
index 0000000000..3b6a5b21e8
--- /dev/null
+++ b/zebra/zebra_evpn.h
@@ -0,0 +1,208 @@
+/*
+ * Zebra EVPN Data structures and definitions
+ * These are "internal" to this function.
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ * Copyright (C) 2020 Volta Networks.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EVPN_H
+#define _ZEBRA_EVPN_H
+
+#include <zebra.h>
+
+#include "if.h"
+#include "linklist.h"
+#include "bitfield.h"
+
+#include "zebra/zebra_l2.h"
+#include "zebra/interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zebra_evpn_t_ zebra_evpn_t;
+typedef struct zebra_vtep_t_ zebra_vtep_t;
+
+RB_HEAD(zebra_es_evi_rb_head, zebra_evpn_es_evi);
+RB_PROTOTYPE(zebra_es_evi_rb_head, zebra_evpn_es_evi, rb_node,
+ zebra_es_evi_rb_cmp);
+
+/* Private Structure to pass callback data for hash iterator */
+struct zebra_evpn_show {
+ struct vty *vty;
+ json_object *json;
+ struct zebra_vrf *zvrf;
+ bool use_json;
+};
+
+/*
+ * VTEP info
+ *
+ * Right now, this just has each remote VTEP's IP address.
+ */
+struct zebra_vtep_t_ {
+ /* Remote IP. */
+ /* NOTE: Can only be IPv4 right now. */
+ struct in_addr vtep_ip;
+ /* Flood mode (one of enum vxlan_flood_control) based on the PMSI
+ * tunnel type advertised by the remote VTEP
+ */
+ int flood_control;
+
+ /* Links. */
+ struct zebra_vtep_t_ *next;
+ struct zebra_vtep_t_ *prev;
+};
+
+/*
+ * VNI hash table
+ *
+ * Contains information pertaining to a VNI:
+ * - the list of remote VTEPs (with this VNI)
+ */
+struct zebra_evpn_t_ {
+ /* VNI - key */
+ vni_t vni;
+
+ /* ES flags */
+ uint32_t flags;
+#define ZEVPN_READY_FOR_BGP (1 << 0) /* ready to be sent to BGP */
+
+ /* Flag for advertising gw macip */
+ uint8_t advertise_gw_macip;
+
+ /* Flag for advertising svi macip */
+ uint8_t advertise_svi_macip;
+
+ /* Flag for advertising gw macip */
+ uint8_t advertise_subnet;
+
+ /* Corresponding VxLAN interface. */
+ struct interface *vxlan_if;
+
+ /* List of remote VTEPs */
+ zebra_vtep_t *vteps;
+
+ /* Local IP */
+ struct in_addr local_vtep_ip;
+
+ /* PIM-SM MDT group for BUM flooding */
+ struct in_addr mcast_grp;
+
+ /* tenant VRF, if any */
+ vrf_id_t vrf_id;
+
+ /* List of local or remote MAC */
+ struct hash *mac_table;
+
+ /* List of local or remote neighbors (MAC+IP) */
+ struct hash *neigh_table;
+
+ /* RB tree of ES-EVIs */
+ struct zebra_es_evi_rb_head es_evi_rb_tree;
+
+ /* List of local ESs */
+ struct list *local_es_evi_list;
+};
+
+struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
+
+static inline struct interface *zevpn_map_to_svi(zebra_evpn_t *zevpn)
+{
+ struct interface *ifp;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+
+ ifp = zevpn->vxlan_if;
+ if (!ifp)
+ return NULL;
+ zif = ifp->info;
+ if (!zif)
+ return NULL;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return NULL;
+ zl2_info = zif->l2info.vxl;
+ return zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+}
+
+int advertise_gw_macip_enabled(zebra_evpn_t *zevpn);
+int advertise_svi_macip_enabled(zebra_evpn_t *zevpn);
+void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt);
+void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]);
+void zebra_evpn_print_hash_detail(struct hash_bucket *bucket, void *data);
+int zebra_evpn_add_macip_for_intf(struct interface *ifp, zebra_evpn_t *zevpn);
+int zebra_evpn_del_macip_for_intf(struct interface *ifp, zebra_evpn_t *zevpn);
+int zebra_evpn_advertise_subnet(zebra_evpn_t *zevpn, struct interface *ifp,
+ int advertise);
+int zebra_evpn_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ethaddr *macaddr, struct ipaddr *ip);
+int zebra_evpn_gw_macip_del(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ipaddr *ip);
+void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt);
+void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt);
+void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
+ void *ctxt);
+zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
+ struct interface *br_if, vlanid_t vid);
+zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
+ struct interface *br_if);
+struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
+ struct interface *svi_if);
+void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp);
+unsigned int zebra_evpn_hash_keymake(const void *p);
+bool zebra_evpn_hash_cmp(const void *p1, const void *p2);
+int zebra_evpn_list_cmp(void *p1, void *p2);
+void *zebra_evpn_alloc(void *p);
+zebra_evpn_t *zebra_evpn_lookup(vni_t vni);
+zebra_evpn_t *zebra_evpn_add(vni_t vni);
+int zebra_evpn_del(zebra_evpn_t *zevpn);
+int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn);
+int zebra_evpn_send_del_to_client(zebra_evpn_t *zevpn);
+zebra_vtep_t *zebra_evpn_vtep_find(zebra_evpn_t *zevpn,
+ struct in_addr *vtep_ip);
+zebra_vtep_t *zebra_evpn_vtep_add(zebra_evpn_t *zevpn, struct in_addr *vtep_ip,
+ int flood_control);
+int zebra_evpn_vtep_del(zebra_evpn_t *zevpn, zebra_vtep_t *zvtep);
+int zebra_evpn_vtep_del_all(zebra_evpn_t *zevpn, int uninstall);
+int zebra_evpn_vtep_install(zebra_evpn_t *zevpn, zebra_vtep_t *zvtep);
+int zebra_evpn_vtep_uninstall(zebra_evpn_t *zevpn, struct in_addr *vtep_ip);
+void zebra_evpn_handle_flooding_remote_vteps(struct hash_bucket *bucket,
+ void *zvrf);
+void zebra_evpn_cleanup_all(struct hash_bucket *bucket, void *arg);
+void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ struct in_addr vtep_ip, esi_t *esi);
+void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ struct in_addr vtep_ip);
+void zebra_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_ZEBRA_EVPN_H */
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
new file mode 100644
index 0000000000..b9cc02a276
--- /dev/null
+++ b/zebra/zebra_evpn_mac.c
@@ -0,0 +1,2231 @@
+/*
+ * Zebra EVPN for VxLAN code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "interface.h"
+#include "jhash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "vlan.h"
+#include "json.h"
+
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_mac.h"
+#include "zebra/zebra_evpn_neigh.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, MAC, "EVPN MAC");
+
+/*
+ * Return number of valid MACs in an EVPN's MAC hash table - all
+ * remote MACs and non-internal (auto) local MACs count.
+ */
+uint32_t num_valid_macs(zebra_evpn_t *zevpn)
+{
+ unsigned int i;
+ uint32_t num_macs = 0;
+ struct hash *hash;
+ struct hash_bucket *hb;
+ zebra_mac_t *mac;
+
+ hash = zevpn->mac_table;
+ if (!hash)
+ return num_macs;
+ for (i = 0; i < hash->size; i++) {
+ for (hb = hash->index[i]; hb; hb = hb->next) {
+ mac = (zebra_mac_t *)hb->data;
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+ || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
+ || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
+ num_macs++;
+ }
+ }
+
+ return num_macs;
+}
+
+uint32_t num_dup_detected_macs(zebra_evpn_t *zevpn)
+{
+ unsigned int i;
+ uint32_t num_macs = 0;
+ struct hash *hash;
+ struct hash_bucket *hb;
+ zebra_mac_t *mac;
+
+ hash = zevpn->mac_table;
+ if (!hash)
+ return num_macs;
+ for (i = 0; i < hash->size; i++) {
+ for (hb = hash->index[i]; hb; hb = hb->next) {
+ mac = (zebra_mac_t *)hb->data;
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ num_macs++;
+ }
+ }
+
+ return num_macs;
+}
+
+/*
+ * Install remote MAC into the forwarding plane.
+ */
+int zebra_evpn_rem_mac_install(zebra_evpn_t *zevpn, zebra_mac_t *mac,
+ bool was_static)
+{
+ const struct zebra_if *zif, *br_zif;
+ const struct zebra_l2info_vxlan *vxl;
+ bool sticky;
+ enum zebra_dplane_result res;
+ const struct interface *br_ifp;
+ vlanid_t vid;
+ uint32_t nhg_id;
+ struct in_addr vtep_ip;
+
+ if (!(mac->flags & ZEBRA_MAC_REMOTE))
+ return 0;
+
+ zif = zevpn->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ br_ifp = zif->brslave_info.br_if;
+ if (br_ifp == NULL)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ sticky = !!CHECK_FLAG(mac->flags,
+ (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
+
+ /* If nexthop group for the FDB entry is inactive (not programmed in
+ * the dataplane) the MAC entry cannot be installed
+ */
+ if (mac->es) {
+ if (!(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
+ return -1;
+ nhg_id = mac->es->nhg_id;
+ vtep_ip.s_addr = 0;
+ } else {
+ nhg_id = 0;
+ vtep_ip = mac->fwd_info.r_vtep_ip;
+ }
+
+ br_zif = (const struct zebra_if *)(br_ifp->info);
+
+ if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
+ vid = vxl->access_vlan;
+ else
+ vid = 0;
+
+ res = dplane_rem_mac_add(zevpn->vxlan_if, br_ifp, vid, &mac->macaddr,
+ vtep_ip, sticky, nhg_id, was_static);
+ if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * Uninstall remote MAC from the forwarding plane.
+ */
+int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+{
+ const struct zebra_if *zif, *br_zif;
+ const struct zebra_l2info_vxlan *vxl;
+ struct in_addr vtep_ip;
+ const struct interface *ifp, *br_ifp;
+ vlanid_t vid;
+ enum zebra_dplane_result res;
+
+ if (!(mac->flags & ZEBRA_MAC_REMOTE))
+ return 0;
+
+ if (!zevpn->vxlan_if) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "VNI %u hash %p couldn't be uninstalled - no intf",
+ zevpn->vni, zevpn);
+ return -1;
+ }
+
+ zif = zevpn->vxlan_if->info;
+ if (!zif)
+ return -1;
+
+ br_ifp = zif->brslave_info.br_if;
+ if (br_ifp == NULL)
+ return -1;
+
+ vxl = &zif->l2info.vxl;
+
+ br_zif = (const struct zebra_if *)br_ifp->info;
+
+ if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
+ vid = vxl->access_vlan;
+ else
+ vid = 0;
+
+ ifp = zevpn->vxlan_if;
+ vtep_ip = mac->fwd_info.r_vtep_ip;
+
+ res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
+ if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * Decrement neighbor refcount of MAC; uninstall and free it if
+ * appropriate.
+ */
+void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+{
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
+ return;
+
+ /* If all remote neighbors referencing a remote MAC go away,
+ * we need to uninstall the MAC.
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+ && remote_neigh_count(mac) == 0) {
+ zebra_evpn_rem_mac_uninstall(zevpn, mac);
+ zebra_evpn_es_mac_deref_entry(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ }
+
+ /* If no neighbors, delete the MAC. */
+ if (list_isempty(mac->neigh_list))
+ zebra_evpn_mac_del(zevpn, mac);
+}
+
+static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
+ struct interface **ifpP,
+ vlanid_t *vid)
+{
+ /* if the mac is associated with an ES we must get the access
+ * info from the ES
+ */
+ if (mac->es) {
+ struct zebra_if *zif;
+
+ /* get the access port from the es */
+ *ifpP = mac->es->zif ? mac->es->zif->ifp : NULL;
+ /* get the vlan from the EVPN */
+ if (mac->zevpn->vxlan_if) {
+ zif = mac->zevpn->vxlan_if->info;
+ *vid = zif->l2info.vxl.access_vlan;
+ } else {
+ *vid = 0;
+ }
+ } else {
+ struct zebra_ns *zns;
+
+ *vid = mac->fwd_info.local.vid;
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ *ifpP = if_lookup_by_index_per_ns(zns,
+ mac->fwd_info.local.ifindex);
+ }
+}
+
+static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
+{
+ struct zebra_vrf *zvrf = NULL;
+ zebra_mac_t *mac = NULL;
+ zebra_evpn_t *zevpn = NULL;
+ struct listnode *node = NULL;
+ zebra_neigh_t *nbr = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+
+ mac = THREAD_ARG(t);
+
+ /* since this is asynchronous we need sanity checks*/
+ zvrf = vrf_info_lookup(mac->zevpn->vrf_id);
+ if (!zvrf)
+ return 0;
+
+ zevpn = zebra_evpn_lookup(mac->zevpn->vni);
+ if (!zevpn)
+ return 0;
+
+ mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr);
+ if (!mac)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr mac %s flags 0x%x learn 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));
+
+ /* Remove all IPs as duplicate associcated with this MAC */
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
+ ZEBRA_NEIGH_SET_INACTIVE(nbr);
+ else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
+ zebra_evpn_rem_neigh_install(
+ zevpn, nbr, false /*was_static*/);
+ }
+
+ UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+ nbr->dad_count = 0;
+ nbr->detect_start_time.tv_sec = 0;
+ nbr->dad_dup_detect_time = 0;
+ }
+
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
+ mac->dad_count = 0;
+ mac->detect_start_time.tv_sec = 0;
+ mac->detect_start_time.tv_usec = 0;
+ mac->dad_dup_detect_time = 0;
+ mac->dad_mac_auto_recovery_timer = NULL;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ /* Inform to BGP */
+ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
+ mac->flags, mac->loc_seq,
+ mac->es))
+ return -1;
+
+ /* Process all neighbors associated with this MAC. */
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
+ 0 /*es_change*/);
+
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
+
+ /* Install the entry. */
+ zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
+ }
+
+ return 0;
+}
+
+static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
+ zebra_mac_t *mac,
+ struct in_addr vtep_ip,
+ bool do_dad, bool *is_dup_detect,
+ bool is_local)
+{
+ zebra_neigh_t *nbr;
+ struct listnode *node = NULL;
+ struct timeval elapsed = {0, 0};
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+ bool reset_params = false;
+
+ if (!(zvrf->dup_addr_detect && do_dad))
+ return;
+
+ /* MAC is detected as duplicate,
+ * Local MAC event -> hold on advertising to BGP.
+ * Remote MAC event -> hold on installing it.
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s flags 0x%x skip 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);
+
+ /* For duplicate MAC do not update
+ * client but update neigh due to
+ * this MAC update.
+ */
+ if (zvrf->dad_freeze)
+ *is_dup_detect = true;
+
+ return;
+ }
+
+ /* Check if detection time (M-secs) expired.
+ * Reset learn count and detection start time.
+ */
+ monotime_since(&mac->detect_start_time, &elapsed);
+ reset_params = (elapsed.tv_sec > zvrf->dad_time);
+ if (is_local && !reset_params) {
+ /* RFC-7432: A PE/VTEP that detects a MAC mobility
+ * event via LOCAL learning starts an M-second timer.
+ *
+ * NOTE: This is the START of the probe with count is
+ * 0 during LOCAL learn event.
+ * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
+ */
+ reset_params = !mac->dad_count;
+ }
+
+ if (reset_params) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
+ __func__,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ mac->flags, mac->dad_count);
+
+ mac->dad_count = 0;
+ /* Start dup. addr detection (DAD) start time,
+ * ONLY during LOCAL learn.
+ */
+ if (is_local)
+ monotime(&mac->detect_start_time);
+
+ } else if (!is_local) {
+ /* For REMOTE MAC, increment detection count
+ * ONLY while in probe window, once window passed,
+ * next local learn event should trigger DAD.
+ */
+ mac->dad_count++;
+ }
+
+ /* For LOCAL MAC learn event, once count is reset above via either
+ * initial/start detection time or passed the probe time, the count
+ * needs to be incremented.
+ */
+ if (is_local)
+ mac->dad_count++;
+
+ if (mac->dad_count >= zvrf->dad_max_moves) {
+ flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
+ "VNI %u: MAC %s detected as duplicate during %s VTEP %s",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ is_local ? "local update, last" :
+ "remote update, from", inet_ntoa(vtep_ip));
+
+ SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
+
+ /* Capture Duplicate detection time */
+ mac->dad_dup_detect_time = monotime(NULL);
+
+ /* Mark all IPs/Neighs as duplicate
+ * associcated with this MAC
+ */
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
+
+ /* Ony Mark IPs which are Local */
+ if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
+ continue;
+
+ SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+
+ nbr->dad_dup_detect_time = monotime(NULL);
+
+ flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
+ "VNI %u: MAC %s IP %s detected as duplicate during %s update, inherit duplicate from MAC",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr,
+ buf, sizeof(buf)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+ is_local ? "local" : "remote");
+ }
+
+ /* 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)
+ zlog_debug(
+ "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
+ __func__,
+ prefix_mac2str(&mac->macaddr, buf,
+ sizeof(buf)),
+ mac->flags, zvrf->dad_freeze_time);
+
+ thread_add_timer(zrouter.master,
+ zebra_evpn_dad_mac_auto_recovery_exp,
+ mac, zvrf->dad_freeze_time,
+ &mac->dad_mac_auto_recovery_timer);
+ }
+
+ /* In case of local update, do not inform to client (BGPd),
+ * upd_neigh for neigh sequence change.
+ */
+ if (zvrf->dad_freeze)
+ *is_dup_detect = true;
+ }
+}
+
+/*
+ * Print a specific MAC entry.
+ */
+void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
+{
+ struct vty *vty;
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ struct zebra_vrf *zvrf;
+ struct timeval detect_start_time = {0, 0};
+ char timebuf[MONOTIME_STRLEN];
+ char thread_buf[THREAD_TIMER_STRLEN];
+
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return;
+
+ vty = (struct vty *)ctxt;
+ prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
+
+ if (json) {
+ json_object *json_mac = json_object_new_object();
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct interface *ifp;
+ vlanid_t vid;
+
+ zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
+ json_object_string_add(json_mac, "type", "local");
+ if (ifp) {
+ json_object_string_add(json_mac, "intf",
+ ifp->name);
+ json_object_int_add(json_mac, "ifindex",
+ ifp->ifindex);
+ }
+ if (vid)
+ json_object_int_add(json_mac, "vlan", vid);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ json_object_string_add(json_mac, "type", "remote");
+ json_object_string_add(
+ json_mac, "remoteVtep",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
+ json_object_string_add(json_mac, "type", "auto");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ json_object_boolean_true_add(json_mac, "stickyMac");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+ json_object_boolean_true_add(json_mac,
+ "defaultGateway");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
+ json_object_boolean_true_add(json_mac,
+ "remoteGatewayMac");
+
+ json_object_int_add(json_mac, "localSequence", mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
+
+ json_object_int_add(json_mac, "detectionCount", mac->dad_count);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ json_object_boolean_true_add(json_mac, "isDuplicate");
+ else
+ json_object_boolean_false_add(json_mac, "isDuplicate");
+
+ json_object_int_add(json_mac, "syncNeighCount",
+ mac->sync_neigh_cnt);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
+ json_object_boolean_true_add(json_mac, "localInactive");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
+ json_object_boolean_true_add(json_mac, "peerProxy");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ json_object_boolean_true_add(json_mac, "peerActive");
+ if (mac->hold_timer)
+ json_object_string_add(
+ json_mac, "peerActiveHold",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
+ if (mac->es)
+ json_object_string_add(json_mac, "esi",
+ mac->es->esi_str);
+ /* print all the associated neigh */
+ if (!listcount(mac->neigh_list))
+ json_object_string_add(json_mac, "neighbors", "none");
+ else {
+ json_object *json_active_nbrs = json_object_new_array();
+ json_object *json_inactive_nbrs =
+ json_object_new_array();
+ json_object *json_nbrs = json_object_new_object();
+
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ json_object_array_add(
+ json_active_nbrs,
+ json_object_new_string(
+ ipaddr2str(
+ &n->ip, buf2,
+ sizeof(buf2))));
+ else
+ json_object_array_add(
+ json_inactive_nbrs,
+ json_object_new_string(
+ ipaddr2str(
+ &n->ip, buf2,
+ sizeof(buf2))));
+ }
+
+ json_object_object_add(json_nbrs, "active",
+ json_active_nbrs);
+ json_object_object_add(json_nbrs, "inactive",
+ json_inactive_nbrs);
+ json_object_object_add(json_mac, "neighbors",
+ json_nbrs);
+ }
+
+ json_object_object_add(json, buf1, json_mac);
+ } else {
+ vty_out(vty, "MAC: %s\n", buf1);
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct interface *ifp;
+ vlanid_t vid;
+
+ zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
+
+ if (mac->es)
+ vty_out(vty, " ESI: %s\n", mac->es->esi_str);
+
+ if (ifp)
+ vty_out(vty, " Intf: %s(%u)", ifp->name,
+ ifp->ifindex);
+ else
+ vty_out(vty, " Intf: -");
+ vty_out(vty, " VLAN: %u", vid);
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ if (mac->es)
+ vty_out(vty, " Remote ES: %s",
+ mac->es->esi_str);
+ else
+ vty_out(vty, " Remote VTEP: %s",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+ vty_out(vty, " Auto Mac ");
+ }
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ vty_out(vty, " Sticky Mac ");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+ vty_out(vty, " Default-gateway Mac ");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
+ vty_out(vty, " Remote-gateway Mac ");
+
+ vty_out(vty, "\n");
+ vty_out(vty, " Sync-info: neigh#: %u", mac->sync_neigh_cnt);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
+ vty_out(vty, " local-inactive");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
+ vty_out(vty, " peer-proxy");
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ vty_out(vty, " peer-active");
+ if (mac->hold_timer)
+ vty_out(vty, " (ht: %s)",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ mac->hold_timer));
+ vty_out(vty, "\n");
+ vty_out(vty, " Local Seq: %u Remote Seq: %u", mac->loc_seq,
+ mac->rem_seq);
+ vty_out(vty, "\n");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
+ vty_out(vty, " Duplicate, detected at %s",
+ time_to_string(mac->dad_dup_detect_time,
+ timebuf));
+ } else if (mac->dad_count) {
+ monotime_since(&mac->detect_start_time,
+ &detect_start_time);
+ if (detect_start_time.tv_sec <= zvrf->dad_time) {
+ time_to_string(mac->detect_start_time.tv_sec,
+ timebuf);
+ vty_out(vty,
+ " Duplicate detection started at %s, detection count %u\n",
+ timebuf, mac->dad_count);
+ }
+ }
+
+ /* print all the associated neigh */
+ vty_out(vty, " Neighbors:\n");
+ if (!listcount(mac->neigh_list))
+ vty_out(vty, " No Neighbors\n");
+ else {
+ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
+ vty_out(vty, " %s %s\n",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ (IS_ZEBRA_NEIGH_ACTIVE(n)
+ ? "Active"
+ : "Inactive"));
+ }
+ }
+
+ vty_out(vty, "\n");
+ }
+}
+
+static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
+ uint32_t flags_buf_sz)
+{
+ snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
+ mac->sync_neigh_cnt ?
+ "N" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ?
+ "P" : "",
+ (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ?
+ "X" : "",
+ (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ?
+ "I" : "");
+
+ return flags_buf;
+}
+
+/*
+ * Print MAC hash entry - called for display of all MACs.
+ */
+void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ struct vty *vty;
+ json_object *json_mac_hdr = NULL, *json_mac = NULL;
+ zebra_mac_t *mac;
+ char buf1[ETHER_ADDR_STRLEN];
+ struct mac_walk_ctx *wctx = ctxt;
+ char flags_buf[6];
+
+ vty = wctx->vty;
+ json_mac_hdr = wctx->json;
+ mac = (zebra_mac_t *)bucket->data;
+
+ prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
+
+ if (json_mac_hdr)
+ json_mac = json_object_new_object();
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct interface *ifp;
+ vlanid_t vid;
+
+ if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
+ return;
+
+ zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
+ if (json_mac_hdr == NULL) {
+ vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
+ zebra_evpn_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
+ ifp ? ifp->name : "-");
+ } else {
+ json_object_string_add(json_mac, "type", "local");
+ if (ifp)
+ json_object_string_add(json_mac, "intf",
+ ifp->name);
+ }
+ if (vid) {
+ if (json_mac_hdr == NULL)
+ vty_out(vty, " %-5u", vid);
+ else
+ json_object_int_add(json_mac, "vlan", vid);
+ } else /* No vid? fill out the space */
+ if (json_mac_hdr == NULL)
+ vty_out(vty, " %-5s", "");
+ if (json_mac_hdr == NULL) {
+ vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
+ vty_out(vty, "\n");
+ } else {
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
+ json_object_int_add(json_mac, "detectionCount",
+ mac->dad_count);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ json_object_boolean_true_add(json_mac,
+ "isDuplicate");
+ else
+ json_object_boolean_false_add(json_mac,
+ "isDuplicate");
+ json_object_object_add(json_mac_hdr, buf1, json_mac);
+ }
+
+ wctx->count++;
+
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+
+ if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
+ && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
+ &wctx->r_vtep_ip))
+ return;
+
+ if (json_mac_hdr == NULL) {
+ if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
+ && (wctx->count == 0)) {
+ vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni);
+ vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
+ "MAC", "Type", "Flags",
+ "Intf/Remote ES/VTEP", "VLAN",
+ "Seq #'s");
+ }
+ vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
+ "remote",
+ zebra_evpn_print_mac_flags(mac, flags_buf,
+ sizeof(flags_buf)),
+ mac->es ? mac->es->esi_str
+ : inet_ntoa(mac->fwd_info.r_vtep_ip),
+ "", mac->loc_seq, mac->rem_seq);
+ } else {
+ json_object_string_add(json_mac, "type", "remote");
+ json_object_string_add(
+ json_mac, "remoteVtep",
+ inet_ntoa(mac->fwd_info.r_vtep_ip));
+ json_object_object_add(json_mac_hdr, buf1, json_mac);
+ json_object_int_add(json_mac, "localSequence",
+ mac->loc_seq);
+ json_object_int_add(json_mac, "remoteSequence",
+ mac->rem_seq);
+ json_object_int_add(json_mac, "detectionCount",
+ mac->dad_count);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ json_object_boolean_true_add(json_mac,
+ "isDuplicate");
+ else
+ json_object_boolean_false_add(json_mac,
+ "isDuplicate");
+ }
+
+ wctx->count++;
+ }
+}
+
+/*
+ * Print MAC hash entry in detail - called for display of all MACs.
+ */
+void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
+{
+ struct vty *vty;
+ json_object *json_mac_hdr = NULL;
+ zebra_mac_t *mac;
+ struct mac_walk_ctx *wctx = ctxt;
+ char buf1[ETHER_ADDR_STRLEN];
+
+ vty = wctx->vty;
+ json_mac_hdr = wctx->json;
+ mac = (zebra_mac_t *)bucket->data;
+ if (!mac)
+ return;
+
+ wctx->count++;
+ prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
+
+ zebra_evpn_print_mac(mac, vty, json_mac_hdr);
+}
+
+/*
+ * Inform BGP about local MACIP.
+ */
+int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
+ struct ipaddr *ip, uint8_t flags,
+ uint32_t seq, int state,
+ struct zebra_evpn_es *es, uint16_t cmd)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ int ipa_len;
+ struct zserv *client = NULL;
+ struct stream *s = NULL;
+ esi_t *esi = es ? &es->esi : zero_esi;
+
+ client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
+ stream_putl(s, vni);
+ stream_put(s, macaddr->octet, ETH_ALEN);
+ if (ip) {
+ ipa_len = 0;
+ if (IS_IPADDR_V4(ip))
+ ipa_len = IPV4_MAX_BYTELEN;
+ else if (IS_IPADDR_V6(ip))
+ ipa_len = IPV6_MAX_BYTELEN;
+
+ stream_putl(s, ipa_len); /* IP address length */
+ if (ipa_len)
+ stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
+ } else
+ stream_putl(s, 0); /* Just MAC. */
+
+ if (cmd == ZEBRA_MACIP_ADD) {
+ stream_putc(s, flags); /* sticky mac/gateway mac */
+ stream_putl(s, seq); /* sequence number */
+ stream_put(s, esi, sizeof(esi_t));
+ } else {
+ stream_putl(s, state); /* state - active/inactive */
+ }
+
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ 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,
+ 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++;
+ else
+ client->macipdel_cnt++;
+
+ return zserv_send_message(client, s);
+}
+
+static unsigned int mac_hash_keymake(const void *p)
+{
+ const zebra_mac_t *pmac = p;
+ const void *pnt = (void *)pmac->macaddr.octet;
+
+ return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
+}
+
+/*
+ * Compare two MAC addresses.
+ */
+static bool mac_cmp(const void *p1, const void *p2)
+{
+ const zebra_mac_t *pmac1 = p1;
+ const zebra_mac_t *pmac2 = p2;
+
+ if (pmac1 == NULL && pmac2 == NULL)
+ return true;
+
+ if (pmac1 == NULL || pmac2 == NULL)
+ return false;
+
+ return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
+ == 0);
+}
+
+/*
+ * Callback to allocate MAC hash entry.
+ */
+static void *zebra_evpn_mac_alloc(void *p)
+{
+ const zebra_mac_t *tmp_mac = p;
+ zebra_mac_t *mac;
+
+ mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
+ *mac = *tmp_mac;
+
+ return ((void *)mac);
+}
+
+/*
+ * Add MAC entry.
+ */
+zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr)
+{
+ zebra_mac_t tmp_mac;
+ zebra_mac_t *mac = NULL;
+
+ memset(&tmp_mac, 0, sizeof(zebra_mac_t));
+ memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
+ mac = hash_get(zevpn->mac_table, &tmp_mac, zebra_evpn_mac_alloc);
+ assert(mac);
+
+ mac->zevpn = zevpn;
+ mac->dad_mac_auto_recovery_timer = NULL;
+
+ mac->neigh_list = list_new();
+ mac->neigh_list->cmp = neigh_list_cmp;
+
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ mac->flags);
+ }
+ return mac;
+}
+
+/*
+ * Delete MAC entry.
+ */
+int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+{
+ zebra_mac_t *tmp_mac;
+
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ mac->flags);
+ }
+
+ /* force de-ref any ES entry linked to the MAC */
+ zebra_evpn_es_mac_deref_entry(mac);
+
+ /* Cancel proxy hold timer */
+ zebra_evpn_mac_stop_hold_timer(mac);
+
+ /* Cancel auto recovery */
+ THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+
+ list_delete(&mac->neigh_list);
+
+ /* Free the VNI hash entry and allocated memory. */
+ tmp_mac = hash_release(zevpn->mac_table, mac);
+ XFREE(MTYPE_MAC, tmp_mac);
+
+ return 0;
+}
+
+static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
+ zebra_mac_t *mac)
+{
+ if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
+ return true;
+ else if ((wctx->flags & DEL_REMOTE_MAC)
+ && (mac->flags & ZEBRA_MAC_REMOTE))
+ return true;
+ else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
+ && (mac->flags & ZEBRA_MAC_REMOTE)
+ && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
+ return true;
+ else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO)
+ && !listcount(mac->neigh_list)) {
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug(
+ "%s: Del MAC %s flags 0x%x", __func__,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ mac->flags);
+ }
+ wctx->uninstall = 0;
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Free MAC hash entry (callback)
+ */
+static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
+{
+ struct mac_walk_ctx *wctx = arg;
+ zebra_mac_t *mac = bucket->data;
+
+ if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
+ if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
+ zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
+ &mac->macaddr,
+ mac->flags, false);
+ }
+ if (wctx->uninstall) {
+ if (zebra_evpn_mac_is_static(mac))
+ zebra_evpn_sync_mac_dp_install(
+ mac, false /* set_inactive */,
+ true /* force_clear_static */,
+ __func__);
+
+ if (mac->flags & ZEBRA_MAC_REMOTE)
+ zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac);
+ }
+
+ zebra_evpn_mac_del(wctx->zevpn, mac);
+ }
+
+ return;
+}
+
+/*
+ * Delete all MAC entries for this EVPN.
+ */
+void zebra_evpn_mac_del_all(zebra_evpn_t *zevpn, int uninstall, int upd_client,
+ uint32_t flags)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = uninstall;
+ wctx.upd_client = upd_client;
+ wctx.flags = flags;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_mac_del_hash_entry, &wctx);
+}
+
+/*
+ * Look up MAC hash entry.
+ */
+zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevpn, struct ethaddr *mac)
+{
+ zebra_mac_t tmp;
+ zebra_mac_t *pmac;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp.macaddr, mac, ETH_ALEN);
+ pmac = hash_lookup(zevpn->mac_table, &tmp);
+
+ return pmac;
+}
+
+/*
+ * Inform BGP about local MAC addition.
+ */
+int zebra_evpn_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t mac_flags, uint32_t seq,
+ struct zebra_evpn_es *es)
+{
+ uint8_t flags = 0;
+
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
+ /* host reachability has not been verified locally */
+
+ /* if no ES peer is claiming reachability we can't advertise the
+ * entry
+ */
+ if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ return 0;
+
+ /* ES peers are claiming reachability; we will
+ * advertise the entry but with a proxy flag
+ */
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
+ }
+
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
+ return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
+ seq, ZEBRA_NEIGH_ACTIVE, es,
+ ZEBRA_MACIP_ADD);
+}
+
+/*
+ * Inform BGP about local MAC deletion.
+ */
+int zebra_evpn_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t flags, bool force)
+{
+ if (!force) {
+ if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
+ && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ /* the host was not advertised - nothing to delete */
+ return 0;
+ }
+
+ return zebra_evpn_macip_send_msg_to_client(
+ vni, macaddr, NULL, 0 /* flags */, 0 /* seq */,
+ ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL);
+}
+
+/*
+ * wrapper to create a MAC hash table
+ */
+struct hash *zebra_mac_db_create(const char *desc)
+{
+ return hash_create(mac_hash_keymake, mac_cmp, desc);
+}
+
+/* program sync mac flags in the dataplane */
+void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
+ bool force_clear_static, const char *caller)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ struct interface *ifp;
+ bool sticky;
+ bool set_static;
+ zebra_evpn_t *zevpn = mac->zevpn;
+ vlanid_t vid;
+ struct zebra_if *zif;
+ struct interface *br_ifp;
+
+ /* get the access vlan from the vxlan_device */
+ zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
+
+ if (!ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no access-port",
+ caller, zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags,
+ set_inactive ? "inactive " : "");
+ return;
+ }
+
+ zif = ifp->info;
+ br_ifp = zif->brslave_info.br_if;
+ if (!br_ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no br",
+ caller, zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags,
+ set_inactive ? "inactive " : "");
+ return;
+ }
+
+ sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ if (force_clear_static)
+ set_static = false;
+ else
+ set_static = zebra_evpn_mac_is_static(mac);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "dp-install sync-mac vni %u mac %s es %s 0x%x %s%s",
+ zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags,
+ set_static ? "static " : "",
+ set_inactive ? "inactive " : "");
+
+ dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
+ set_static, set_inactive);
+}
+
+void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,
+ bool new_bgp_ready)
+{
+ if (new_bgp_ready)
+ zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
+ &mac->macaddr, mac->flags,
+ mac->loc_seq, mac->es);
+ else if (old_bgp_ready)
+ zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
+ &mac->macaddr, mac->flags,
+ true /* force */);
+}
+
+/* MAC hold timer is used to age out peer-active flag.
+ *
+ * During this wait time we expect the dataplane component or an
+ * external neighmgr daemon to probe existing hosts to independently
+ * establish their presence on the ES.
+ */
+static int zebra_evpn_mac_hold_exp_cb(struct thread *t)
+{
+ zebra_mac_t *mac;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+ bool old_static;
+ bool new_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ mac = THREAD_ARG(t);
+ /* the purpose of the hold timer is to age out the peer-active
+ * flag
+ */
+ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
+ return 0;
+
+ old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ old_static = zebra_evpn_mac_is_static(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ 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)
+ zlog_debug(
+ "sync-mac vni %u mac %s es %s 0x%x hold expired",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags);
+
+ /* re-program the local mac in the dataplane if the mac is no
+ * longer static
+ */
+ if (old_static != new_static)
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ /* inform bgp if needed */
+ if (old_bgp_ready != new_bgp_ready)
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
+
+ return 0;
+}
+
+static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ if (mac->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "sync-mac vni %u mac %s es %s 0x%x hold started",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags);
+ thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
+ zmh_info->mac_hold_time, &mac->hold_timer);
+}
+
+void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+
+ if (!mac->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "sync-mac vni %u mac %s es %s 0x%x hold stopped",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->flags);
+ THREAD_OFF(mac->hold_timer);
+}
+
+void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ bool old_static;
+ bool new_static;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+ mac->zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
+ mac->es ? mac->es->esi_str : "-", mac->loc_seq,
+ mac->flags);
+ 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))
+ zebra_evpn_mac_start_hold_timer(mac);
+ new_static = zebra_evpn_mac_is_static(mac);
+
+ if (old_static != new_static)
+ /* program the local mac in the kernel */
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+}
+
+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)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ uint32_t tmp_seq;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
+ tmp_seq = mac->loc_seq;
+ else
+ tmp_seq = mac->rem_seq;
+
+ if (seq < tmp_seq) {
+ /* if the mac was never advertised to bgp we must accept
+ * whatever sequence number bgp sends
+ * XXX - check with Vivek
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
+ && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "sync-macip accept vni %u mac %s%s%s lower seq %u f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf))
+ : "",
+ tmp_seq, mac->flags);
+ return true;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "sync-macip ignore vni %u mac %s%s%s as existing has higher seq %u f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(&mac->macaddr, macbuf,
+ sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf))
+ : "",
+ tmp_seq, mac->flags);
+ return false;
+ }
+
+ return true;
+}
+
+zebra_mac_t *
+zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq, esi_t *esi,
+ struct sync_mac_ip_ctx *ctx)
+{
+ zebra_mac_t *mac;
+ bool inform_bgp = false;
+ bool inform_dataplane = false;
+ bool seq_change = false;
+ bool es_change = false;
+ uint32_t tmp_seq;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_local = false;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ /* if it is a new local path we need to inform both
+ * the control protocol and the data-plane
+ */
+ inform_bgp = true;
+ inform_dataplane = true;
+ ctx->mac_created = true;
+ ctx->mac_inactive = true;
+
+ /* create the MAC and associate it with the dest ES */
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ zebra_evpn_es_mac_ref(mac, esi);
+
+ /* local mac activated by an ES peer */
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ /* if mac-only route setup peer flags */
+ if (!ipa_len) {
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
+ else
+ SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ }
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+ old_bgp_ready = false;
+ new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ } else {
+ uint32_t old_flags;
+ uint32_t new_flags;
+ bool old_static;
+ bool new_static;
+ bool sticky;
+ bool remote_gw;
+
+ old_flags = mac->flags;
+ sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
+ remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
+ if (sticky || remote_gw) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "Ignore sync-macip vni %u mac %s%s%s%s%s",
+ zevpn->vni,
+ prefix_mac2str(macaddr, macbuf,
+ sizeof(macbuf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf,
+ sizeof(ipbuf))
+ : "",
+ sticky ? " sticky" : "",
+ remote_gw ? " remote_gw" : "");
+ ctx->ignore_macip = true;
+ return NULL;
+ }
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
+ ipaddr)) {
+ ctx->ignore_macip = true;
+ return NULL;
+ }
+
+ old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
+ old_static = zebra_evpn_mac_is_static(mac);
+
+ /* re-build the mac flags */
+ new_flags = 0;
+ SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
+ /* retain old local activity flag */
+ if (old_flags & ZEBRA_MAC_LOCAL) {
+ new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
+ } else {
+ new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
+ ctx->mac_inactive = true;
+ }
+ if (ipa_len) {
+ /* if mac-ip route do NOT update the peer flags
+ * i.e. retain only flags as is
+ */
+ new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
+ } else {
+ /* if mac-only route update peer flags */
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
+ SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
+ /* if the mac was peer-active previously we
+ * need to keep the flag and start the
+ * holdtimer on it. the peer-active flag is
+ * cleared on holdtimer expiry.
+ */
+ if (CHECK_FLAG(old_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE)) {
+ SET_FLAG(new_flags,
+ ZEBRA_MAC_ES_PEER_ACTIVE);
+ zebra_evpn_mac_start_hold_timer(mac);
+ }
+ } else {
+ SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
+ /* stop hold timer if a peer has verified
+ * reachability
+ */
+ zebra_evpn_mac_stop_hold_timer(mac);
+ }
+ }
+ mac->rem_seq = 0;
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->flags = new_flags;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags))
+ zlog_debug(
+ "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
+ old_flags, mac->flags);
+
+ /* update es */
+ es_change = zebra_evpn_es_mac_ref(mac, esi);
+ /* if mac dest change - inform both sides */
+ if (es_change) {
+ inform_bgp = true;
+ inform_dataplane = true;
+ ctx->mac_inactive = true;
+ }
+ /* if peer-flag is being set notify dataplane that the
+ * entry must not be expired because of local inactivity
+ */
+ new_static = zebra_evpn_mac_is_static(mac);
+ if (old_static != new_static)
+ inform_dataplane = true;
+
+ old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(old_flags);
+ new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ if (old_bgp_ready != new_bgp_ready)
+ inform_bgp = true;
+ }
+
+
+ /* update sequence number; if that results in a new local sequence
+ * inform bgp
+ */
+ tmp_seq = MAX(mac->loc_seq, seq);
+ if (tmp_seq != mac->loc_seq) {
+ mac->loc_seq = tmp_seq;
+ seq_change = true;
+ 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",
+ 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" : "",
+ inform_dataplane ? " inform_dp" : "");
+
+ if (inform_bgp)
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
+
+ /* neighs using the mac may need to be re-sent to
+ * bgp with updated info
+ */
+ if (seq_change || es_change || !old_local)
+ zebra_evpn_process_neigh_on_local_mac_change(
+ zevpn, mac, seq_change, es_change);
+
+ if (inform_dataplane) {
+ if (ipa_len)
+ /* if the mac is being created as a part of MAC-IP
+ * route wait for the neigh to be updated or
+ * created before programming the mac
+ */
+ ctx->mac_dp_update_deferred = true;
+ else
+ /* program the local mac in the kernel. when the ES
+ * change we need to force the dataplane to reset
+ * the activity as we are yet to establish activity
+ * locally
+ */
+ zebra_evpn_sync_mac_dp_install(
+ mac, ctx->mac_inactive,
+ false /* force_clear_static */, __func__);
+ }
+
+ return mac;
+}
+
+/* update local fowarding info. return true if a dest-ES change
+ * is detected
+ */
+static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
+ struct interface *ifp,
+ vlanid_t vid)
+{
+ struct zebra_if *zif = ifp->info;
+ bool es_change;
+
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+
+ es_change = zebra_evpn_es_mac_ref_entry(mac, zif->es_info.es);
+
+ if (!mac->es) {
+ /* if es is set fwd_info is not-relevant/taped-out */
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vid;
+ }
+
+ return es_change;
+}
+
+/* Notify Local MACs to the clienti, skips GW MAC */
+static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct mac_walk_ctx *wctx = arg;
+ zebra_mac_t *zmac = bucket->data;
+
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
+ return;
+
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
+ zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
+ &zmac->macaddr, zmac->flags,
+ zmac->loc_seq, zmac->es);
+}
+
+/* Iterator to Notify Local MACs of a EVPN */
+void zebra_evpn_send_mac_list_to_client(zebra_evpn_t *zevpn)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
+ &wctx);
+}
+
+void zebra_evpn_rem_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
+{
+ zebra_evpn_process_neigh_on_remote_mac_del(zevpn, mac);
+ /* the remote sequence number in the auto mac entry
+ * needs to be reset to 0 as the mac entry may have
+ * been removed on all VTEPs (including
+ * the originating one)
+ */
+ mac->rem_seq = 0;
+
+ /* If all remote neighbors referencing a remote MAC
+ * go away, we need to uninstall the MAC.
+ */
+ if (remote_neigh_count(mac) == 0) {
+ zebra_evpn_rem_mac_uninstall(zevpn, mac);
+ zebra_evpn_es_mac_deref_entry(mac);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ }
+
+ if (list_isempty(mac->neigh_list))
+ zebra_evpn_mac_del(zevpn, mac);
+ else
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+}
+
+/* Print Duplicate MAC */
+void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_mac_t *mac;
+
+ mac = (zebra_mac_t *)bucket->data;
+ if (!mac)
+ return;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ zebra_evpn_print_mac_hash(bucket, ctxt);
+}
+
+/* Print Duplicate MAC in detail */
+void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ zebra_mac_t *mac;
+
+ mac = (zebra_mac_t *)bucket->data;
+ if (!mac)
+ return;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ zebra_evpn_print_mac_hash_detail(bucket, ctxt);
+}
+
+int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
+ struct ethaddr *macaddr, uint16_t ipa_len,
+ struct ipaddr *ipaddr, zebra_mac_t **macp,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, esi_t *esi)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+ uint32_t tmp_seq;
+ bool sticky;
+ bool remote_gw;
+ int update_mac = 0;
+ bool do_dad = false;
+ bool is_dup_detect = false;
+ esi_t *old_esi;
+ bool old_static = false;
+ zebra_mac_t *mac;
+
+ sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+
+ /* Ignore if the mac is already present as a gateway mac */
+ if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
+ && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
+ zevpn->vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipa_len ? " IP " : "",
+ ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
+ : "");
+ return -1;
+ }
+
+ old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
+
+ /* check if the remote MAC is unknown or has a change.
+ * If so, that needs to be updated first. Note that client could
+ * install MAC and MACIP separately or just install the latter.
+ */
+ if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+ || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
+ || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
+ || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
+ || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
+ update_mac = 1;
+
+ if (update_mac) {
+ if (!mac) {
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!mac) {
+ zlog_warn(
+ "Failed to add MAC %s VNI %u Remote VTEP %s",
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ zevpn->vni, inet_ntoa(vtep_ip));
+ return -1;
+ }
+
+ zebra_evpn_es_mac_ref(mac, esi);
+
+ /* Is this MAC created for a MACIP? */
+ 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
+ * in transient situations (because {IP1,M1}
+ * is a different route from {IP1,M2}). Check
+ * 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);
+ return -1;
+ }
+ }
+
+ /* Check MAC's curent state is local (this is the case
+ * where MAC has moved from L->R) and check previous
+ * detection started via local learning.
+ * RFC-7432: A PE/VTEP that detects a MAC mobility
+ * event via local learning starts an M-second timer.
+ *
+ * VTEP-IP or seq. change alone is not considered
+ * for dup. detection.
+ *
+ * MAC is already marked duplicate set dad, then
+ * is_dup_detect will be set to not install the entry.
+ */
+ if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+ && mac->dad_count)
+ || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
+ do_dad = true;
+
+ /* Remove local MAC from BGP. */
+ 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)
+ zlog_debug(
+ "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ mac->es ? mac->es->esi_str : "-",
+ mac->loc_seq, mac->flags);
+ zebra_evpn_mac_clear_sync_info(mac);
+ zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
+ mac->flags,
+ false /* force */);
+ }
+
+ /* Set "auto" and "remote" forwarding info. */
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ mac->fwd_info.r_vtep_ip = vtep_ip;
+
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+
+ if (remote_gw)
+ SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
+
+ zebra_evpn_dup_addr_detect_for_mac(
+ zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad,
+ &is_dup_detect, false);
+
+ if (!is_dup_detect) {
+ zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
+ /* Install the entry. */
+ zebra_evpn_rem_mac_install(zevpn, mac, old_static);
+ }
+ }
+
+ /* Update seq number. */
+ mac->rem_seq = seq;
+
+ /* If there is no IP, return after clearing AUTO flag of MAC. */
+ if (!ipa_len) {
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ return -1;
+ }
+ *macp = mac;
+ return 0;
+}
+
+int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
+ struct interface *ifp,
+ struct ethaddr *macaddr, vlanid_t vid,
+ bool sticky, bool local_inactive,
+ bool dp_static)
+{
+ zebra_mac_t *mac;
+ char buf[ETHER_ADDR_STRLEN];
+ bool mac_sticky = false;
+ bool inform_client = false;
+ bool upd_neigh = false;
+ bool is_dup_detect = false;
+ struct in_addr vtep_ip = {.s_addr = 0};
+ bool es_change = false;
+ bool new_bgp_ready;
+ /* assume inactive if not present or if not local */
+ bool old_local_inactive = true;
+ bool old_bgp_ready = false;
+ bool inform_dataplane = false;
+ bool new_static = false;
+
+ assert(ifp);
+ /* Check if we need to create or update or it is a NO-OP. */
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s",
+ sticky ? "sticky " : "",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zevpn->vni,
+ local_inactive ? " local-inactive" : "");
+
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!mac) {
+ flog_err(
+ EC_ZEBRA_MAC_ADD_FAILED,
+ "Failed to add MAC %s intf %s(%u) VID %u VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zevpn->vni);
+ return -1;
+ }
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ inform_client = true;
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
+ sticky ? "sticky " : "",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid, zevpn->vni,
+ local_inactive ? "local-inactive " : "",
+ mac->flags);
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ struct interface *old_ifp;
+ vlanid_t old_vid;
+ bool old_static;
+
+ zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
+ old_bgp_ready =
+ zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ old_local_inactive =
+ !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
+ old_static = zebra_evpn_mac_is_static(mac);
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ mac_sticky = true;
+
+ /*
+ * Update any changes and if changes are relevant to
+ * BGP, note it.
+ */
+ if (mac_sticky == sticky && old_ifp == ifp
+ && old_vid == vid
+ && old_local_inactive == local_inactive
+ && dp_static == old_static) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, "
+ "entry exists and has not changed ",
+ sticky ? "sticky " : "",
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ ifp->name, ifp->ifindex, vid,
+ zevpn->vni,
+ local_inactive
+ ? " local_inactive"
+ : "");
+ return 0;
+ }
+ if (mac_sticky != sticky) {
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ else
+ UNSET_FLAG(mac->flags,
+ ZEBRA_MAC_STICKY);
+ inform_client = true;
+ }
+
+ es_change = zebra_evpn_local_mac_update_fwd_info(
+ mac, ifp, vid);
+ /* If an es_change is detected we need to advertise
+ * the route with a sequence that is one
+ * greater. This is need to indicate a mac-move
+ * to the ES peers
+ */
+ if (es_change) {
+ mac->loc_seq = mac->loc_seq + 1;
+ /* force drop the peer/sync info as it is
+ * simply no longer relevant
+ */
+ if (CHECK_FLAG(mac->flags,
+ ZEBRA_MAC_ALL_PEER_FLAGS)) {
+ zebra_evpn_mac_clear_sync_info(mac);
+ new_static =
+ zebra_evpn_mac_is_static(mac);
+ /* if we clear peer-flags we
+ * also need to notify the dataplane
+ * to drop the static flag
+ */
+ if (old_static != new_static)
+ inform_dataplane = true;
+ }
+ }
+ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
+ || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
+ bool do_dad = false;
+
+ /*
+ * MAC has either moved or was "internally" created due
+ * to a neighbor learn and is now actually learnt. If
+ * it was learnt as a remote sticky MAC, this is an
+ * operator error.
+ */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
+ flog_warn(
+ EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
+ "MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u",
+ prefix_mac2str(macaddr, buf,
+ sizeof(buf)),
+ inet_ntoa(mac->fwd_info.r_vtep_ip),
+ zevpn->vni);
+ return 0;
+ }
+
+ /* If an actual move, compute MAC's seq number */
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
+ mac->loc_seq =
+ MAX(mac->rem_seq + 1, mac->loc_seq);
+ vtep_ip = mac->fwd_info.r_vtep_ip;
+ /* Trigger DAD for remote MAC */
+ do_dad = true;
+ }
+
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ es_change = zebra_evpn_local_mac_update_fwd_info(
+ mac, ifp, vid);
+ if (sticky)
+ SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
+ /*
+ * We have to inform BGP of this MAC as well as process
+ * all neighbors.
+ */
+ inform_client = true;
+ upd_neigh = true;
+
+ zebra_evpn_dup_addr_detect_for_mac(
+ zvrf, mac, vtep_ip, do_dad, &is_dup_detect,
+ true);
+ if (is_dup_detect) {
+ inform_client = false;
+ upd_neigh = false;
+ }
+ }
+ }
+
+ /* if the dataplane thinks the entry is sync but it is
+ * not sync in zebra we need to re-install to fixup
+ */
+ if (dp_static) {
+ new_static = zebra_evpn_mac_is_static(mac);
+ if (!new_static)
+ inform_dataplane = true;
+ }
+
+ if (local_inactive)
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
+
+ new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ /* if local-activity has changed we need update bgp
+ * even if bgp already knows about the mac
+ */
+ if ((old_local_inactive != local_inactive)
+ || (new_bgp_ready != old_bgp_ready)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug(
+ "local mac vni %u mac %s es %s seq %d f 0x%x%s",
+ zevpn->vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ mac->es ? mac->es->esi_str : "", mac->loc_seq,
+ mac->flags,
+ local_inactive ? " local-inactive" : "");
+ inform_client = true;
+ }
+
+ if (es_change) {
+ inform_client = true;
+ upd_neigh = true;
+ }
+
+ /* Inform dataplane if required. */
+ if (inform_dataplane)
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ /* Inform BGP if required. */
+ if (inform_client)
+ zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
+ new_bgp_ready);
+
+ /* Process all neighbors associated with this MAC, if required. */
+ if (upd_neigh)
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
+ es_change);
+
+ return 0;
+}
+
+int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
+ struct interface *ifp)
+{
+ 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));
+
+ 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 %s es %s seq %d f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ 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, 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 0;
+}
+
+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)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ zebra_mac_t *mac;
+
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!mac) {
+ flog_err(EC_ZEBRA_MAC_ADD_FAILED,
+ "Failed to add MAC %s intf %s(%u) VID %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vlan_id);
+ return -1;
+ }
+ }
+
+ /* Set "local" forwarding info. */
+ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
+ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
+ mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.vid = vlan_id;
+
+ *macp = mac;
+
+ return 0;
+}
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
new file mode 100644
index 0000000000..39aaf1fb30
--- /dev/null
+++ b/zebra/zebra_evpn_mac.h
@@ -0,0 +1,263 @@
+/*
+ * Zebra EVPN MAC Data structures and definitions
+ * These are "internal" to this function.
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ * Copyright (C) 2020 Volta Networks.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EVPN_MAC_H
+#define _ZEBRA_EVPN_MAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zebra_mac_t_ zebra_mac_t;
+
+struct host_rb_entry {
+ RB_ENTRY(host_rb_entry) hl_entry;
+
+ struct prefix p;
+};
+
+RB_HEAD(host_rb_tree_entry, host_rb_entry);
+RB_PROTOTYPE(host_rb_tree_entry, host_rb_entry, hl_entry,
+ host_rb_entry_compare);
+/*
+ * MAC hash table.
+ *
+ * This table contains the MAC addresses pertaining to this VNI.
+ * This includes local MACs learnt on an attached VLAN that maps
+ * to this VNI as well as remote MACs learnt and installed by BGP.
+ * Local MACs will be known either on a VLAN sub-interface or
+ * on (port, VLAN); however, it is sufficient for zebra to maintain
+ * against the VNI i.e., it does not need to retain the local "port"
+ * information. The correct VNI will be obtained as zebra maintains
+ * the mapping (of VLAN to VNI).
+ */
+struct zebra_mac_t_ {
+ /* MAC address. */
+ struct ethaddr macaddr;
+
+ uint32_t flags;
+#define ZEBRA_MAC_LOCAL 0x01
+#define ZEBRA_MAC_REMOTE 0x02
+#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
+#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
+#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */
+#define ZEBRA_MAC_DEF_GW 0x20
+/* remote VTEP advertised MAC as default GW */
+#define ZEBRA_MAC_REMOTE_DEF_GW 0x40
+#define ZEBRA_MAC_DUPLICATE 0x80
+#define ZEBRA_MAC_FPM_SENT 0x100 /* whether or not this entry was sent. */
+/* MAC is locally active on an ethernet segment peer */
+#define ZEBRA_MAC_ES_PEER_ACTIVE 0x200
+/* MAC has been proxy-advertised by peers. This means we need to
+ * keep the entry for forwarding but cannot advertise it
+ */
+#define ZEBRA_MAC_ES_PEER_PROXY 0x400
+/* We have not been able to independently establish that the host is
+ * local connected but one or more ES peers claims it is.
+ * We will maintain the entry for forwarding purposes and continue
+ * to advertise it as locally attached but with a "proxy" flag
+ */
+#define ZEBRA_MAC_LOCAL_INACTIVE 0x800
+
+#define ZEBRA_MAC_ALL_LOCAL_FLAGS (ZEBRA_MAC_LOCAL | ZEBRA_MAC_LOCAL_INACTIVE)
+#define ZEBRA_MAC_ALL_PEER_FLAGS \
+ (ZEBRA_MAC_ES_PEER_PROXY | ZEBRA_MAC_ES_PEER_ACTIVE)
+
+ /* back pointer to zevpn */
+ zebra_evpn_t *zevpn;
+
+ /* Local or remote info. */
+ union {
+ struct {
+ ifindex_t ifindex;
+ vlanid_t vid;
+ } local;
+
+ struct in_addr r_vtep_ip;
+ } fwd_info;
+
+ /* Local or remote ES */
+ struct zebra_evpn_es *es;
+ /* memory used to link the mac to the es */
+ struct listnode es_listnode;
+
+ /* Mobility sequence numbers associated with this entry. */
+ uint32_t rem_seq;
+ uint32_t loc_seq;
+
+ /* List of neigh associated with this mac */
+ struct list *neigh_list;
+
+ /* list of hosts pointing to this remote RMAC */
+ struct host_rb_tree_entry host_rb;
+
+ /* Duplicate mac detection */
+ uint32_t dad_count;
+
+ struct thread *dad_mac_auto_recovery_timer;
+
+ struct timeval detect_start_time;
+
+ time_t dad_dup_detect_time;
+
+ /* used for ageing out the PEER_ACTIVE flag */
+ struct thread *hold_timer;
+
+ /* number of neigh entries (using this mac) that have
+ * ZEBRA_MAC_ES_PEER_ACTIVE or ZEBRA_NEIGH_ES_PEER_PROXY
+ */
+ uint32_t sync_neigh_cnt;
+};
+
+/*
+ * Context for MAC hash walk - used by callbacks.
+ */
+struct mac_walk_ctx {
+ zebra_evpn_t *zevpn; /* EVPN hash */
+ struct zebra_vrf *zvrf; /* VRF - for client notification. */
+ int uninstall; /* uninstall from kernel? */
+ int upd_client; /* uninstall from client? */
+
+ uint32_t flags;
+#define DEL_LOCAL_MAC 0x1
+#define DEL_REMOTE_MAC 0x2
+#define DEL_ALL_MAC (DEL_LOCAL_MAC | DEL_REMOTE_MAC)
+#define DEL_REMOTE_MAC_FROM_VTEP 0x4
+#define SHOW_REMOTE_MAC_FROM_VTEP 0x8
+
+ struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */
+
+ struct vty *vty; /* Used by VTY handlers */
+ uint32_t count; /* Used by VTY handlers */
+ struct json_object *json; /* Used for JSON Output */
+ bool print_dup; /* Used to print dup addr list */
+};
+
+struct rmac_walk_ctx {
+ struct vty *vty;
+ struct json_object *json;
+};
+
+/* temporary datastruct to pass info between the mac-update and
+ * neigh-update while handling mac-ip routes
+ */
+struct sync_mac_ip_ctx {
+ bool ignore_macip;
+ bool mac_created;
+ bool mac_inactive;
+ bool mac_dp_update_deferred;
+ zebra_mac_t *mac;
+};
+
+/**************************** SYNC MAC handling *****************************/
+/**************************** SYNC MAC handling *****************************/
+/* if the mac has been added of a mac-route from the peer
+ * or if it is being referenced by a neigh added by the
+ * peer we cannot let it age out i.e. we set the static bit
+ * in the dataplane
+ */
+static inline bool zebra_evpn_mac_is_static(zebra_mac_t *mac)
+{
+ return ((mac->flags & ZEBRA_MAC_ALL_PEER_FLAGS) || mac->sync_neigh_cnt);
+}
+
+/* mac needs to be locally active or active on an ES peer */
+static inline bool zebra_evpn_mac_is_ready_for_bgp(uint32_t flags)
+{
+ return (flags & ZEBRA_MAC_LOCAL)
+ && (!(flags & ZEBRA_MAC_LOCAL_INACTIVE)
+ || (flags & ZEBRA_MAC_ES_PEER_ACTIVE));
+}
+
+void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac);
+
+static inline void zebra_evpn_mac_clear_sync_info(zebra_mac_t *mac)
+{
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS);
+ zebra_evpn_mac_stop_hold_timer(mac);
+}
+
+struct hash *zebra_mac_db_create(const char *desc);
+uint32_t num_valid_macs(zebra_evpn_t *zevi);
+uint32_t num_dup_detected_macs(zebra_evpn_t *zevi);
+int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevi, zebra_mac_t *mac);
+int zebra_evpn_rem_mac_install(zebra_evpn_t *zevi, zebra_mac_t *mac,
+ bool was_static);
+void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevi, zebra_mac_t *mac);
+zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevi, struct ethaddr *mac);
+zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevi, struct ethaddr *macaddr);
+int zebra_evpn_mac_del(zebra_evpn_t *zevi, zebra_mac_t *mac);
+int zebra_evpn_macip_send_msg_to_client(uint32_t id, struct ethaddr *macaddr,
+ struct ipaddr *ip, uint8_t flags,
+ uint32_t seq, int state,
+ struct zebra_evpn_es *es, uint16_t cmd);
+void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
+void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
+ bool force_clear_static,
+ const char *caller);
+void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready,
+ bool new_bgp_ready);
+
+void zebra_evpn_mac_del_all(zebra_evpn_t *zevi, int uninstall, int upd_client,
+ uint32_t flags);
+int zebra_evpn_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t mac_flags, uint32_t seq,
+ struct zebra_evpn_es *es);
+int zebra_evpn_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
+ uint32_t flags, bool force);
+void zebra_evpn_send_mac_list_to_client(zebra_evpn_t *zevi);
+zebra_mac_t *
+zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevi, struct ethaddr *macaddr,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq, esi_t *esi,
+ struct sync_mac_ip_ctx *ctx);
+void zebra_evpn_sync_mac_del(zebra_mac_t *mac);
+void zebra_evpn_rem_mac_del(zebra_evpn_t *zevi, zebra_mac_t *mac);
+void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
+ void *ctxt);
+int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
+ struct ethaddr *macaddr, uint16_t ipa_len,
+ struct ipaddr *ipaddr, zebra_mac_t **macp,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, esi_t *esi);
+
+int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
+ struct interface *ifp,
+ 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_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_ZEBRA_EVPN_MAC_H */
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index fae36ec6fa..029480eb4a 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -44,6 +44,8 @@
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_evpn_mh.h"
@@ -55,9 +57,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
-static void zebra_evpn_es_get_one_base_vni(void);
+static void zebra_evpn_es_get_one_base_evpn(void);
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
- zebra_vni_t *vni, bool add);
+ zebra_evpn_t *zevpn, bool add);
static void zebra_evpn_local_es_del(struct zebra_evpn_es *es);
static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
struct ethaddr *sysmac);
@@ -67,7 +69,7 @@ esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
/*****************************************************************************/
/* Ethernet Segment to EVI association -
* 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
- * (zebra_vni_t.es_evi_rb_tree).
+ * (zebra_evpn_t.es_evi_rb_tree).
* 2. Each local ES-EVI entry is sent to BGP which advertises it as an
* EAD-EVI (Type-1 EVPN) route
* 3. Local ES-EVI setup is re-evaluated on the following triggers -
@@ -81,7 +83,7 @@ esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
* is then sent to zebra which allocates a NHG for it.
*/
-/* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
+/* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi *es_evi1,
const struct zebra_evpn_es_evi *es_evi2)
{
@@ -94,17 +96,17 @@ RB_GENERATE(zebra_es_evi_rb_head, zebra_evpn_es_evi,
* tables.
*/
static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
- zebra_vni_t *zvni)
+ zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
es_evi = XCALLOC(MTYPE_ZES_EVI, sizeof(struct zebra_evpn_es_evi));
es_evi->es = es;
- es_evi->zvni = zvni;
+ es_evi->zevpn = zevpn;
- /* insert into the VNI-ESI rb tree */
- if (RB_INSERT(zebra_es_evi_rb_head, &zvni->es_evi_rb_tree, es_evi)) {
+ /* insert into the EVPN-ESI rb tree */
+ if (RB_INSERT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi)) {
XFREE(MTYPE_ZES_EVI, es_evi);
return NULL;
}
@@ -115,15 +117,15 @@ static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es %s evi %d new",
- es_evi->es->esi_str, es_evi->zvni->vni);
+ es_evi->es->esi_str, es_evi->zevpn->vni);
return es_evi;
}
-/* returns TRUE if the VNI is ready to be sent to BGP */
-static inline bool zebra_evpn_vni_send_to_client_ok(zebra_vni_t *zvni)
+/* returns TRUE if the EVPN is ready to be sent to BGP */
+static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn)
{
- return !!(zvni->flags & ZVNI_READY_FOR_BGP);
+ return !!(zevpn->flags & ZEVPN_READY_FOR_BGP);
}
/* Evaluate if the es_evi is ready to be sent BGP -
@@ -142,7 +144,7 @@ static void zebra_evpn_es_evi_re_eval_send_to_client(
/* ES and L2-VNI have to be individually ready for BGP */
if ((es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) &&
(es_evi->es->flags & ZEBRA_EVPNES_READY_FOR_BGP) &&
- zebra_evpn_vni_send_to_client_ok(es_evi->zvni))
+ zebra_evpn_send_to_client_ok(es_evi->zevpn))
es_evi->flags |= ZEBRA_EVPNES_EVI_READY_FOR_BGP;
else
es_evi->flags &= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP;
@@ -153,10 +155,10 @@ static void zebra_evpn_es_evi_re_eval_send_to_client(
return;
if (new_ready)
- zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zvni,
+ zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
true /* add */);
else
- zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zvni,
+ zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
false /* add */);
}
@@ -166,17 +168,17 @@ static void zebra_evpn_es_evi_re_eval_send_to_client(
static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
{
struct zebra_evpn_es *es = es_evi->es;
- zebra_vni_t *zvni = es_evi->zvni;
+ zebra_evpn_t *zevpn = es_evi->zevpn;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es %s evi %d free",
- es_evi->es->esi_str, es_evi->zvni->vni);
+ es_evi->es->esi_str, es_evi->zevpn->vni);
/* remove from the ES's VNI list */
list_delete_node(es->es_evi_list, &es_evi->es_listnode);
/* remove from the VNI-ESI rb tree */
- RB_REMOVE(zebra_es_evi_rb_head, &zvni->es_evi_rb_tree, es_evi);
+ RB_REMOVE(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
/* remove from the VNI-ESI rb tree */
XFREE(MTYPE_ZES_EVI, es_evi);
@@ -184,13 +186,13 @@ static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
/* find the ES-EVI in the per-L2-VNI RB tree */
static struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(
- struct zebra_evpn_es *es, zebra_vni_t *zvni)
+ struct zebra_evpn_es *es, zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi es_evi;
es_evi.es = es;
- return RB_FIND(zebra_es_evi_rb_head, &zvni->es_evi_rb_tree, &es_evi);
+ return RB_FIND(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, &es_evi);
}
/* Tell BGP about an ES-EVI deletion and then delete it */
@@ -201,50 +203,50 @@ static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi *es_evi)
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("local es %s evi %d del",
- es_evi->es->esi_str, es_evi->zvni->vni);
+ es_evi->es->esi_str, es_evi->zevpn->vni);
if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) {
/* send a del only if add was sent for it earlier */
zebra_evpn_es_evi_send_to_client(es_evi->es,
- es_evi->zvni, false /* add */);
+ es_evi->zevpn, false /* add */);
}
- /* delete it from the VNI's local list */
- list_delete_node(es_evi->zvni->local_es_evi_list,
+ /* delete it from the EVPN's local list */
+ list_delete_node(es_evi->zevpn->local_es_evi_list,
&es_evi->l2vni_listnode);
es_evi->flags &= ~ZEBRA_EVPNES_EVI_LOCAL;
zebra_evpn_es_evi_free(es_evi);
}
static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es,
- zebra_vni_t *zvni)
+ zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
- es_evi = zebra_evpn_es_evi_find(es, zvni);
+ es_evi = zebra_evpn_es_evi_find(es, zevpn);
if (es_evi)
zebra_evpn_local_es_evi_do_del(es_evi);
}
/* Create an ES-EVI if it doesn't already exist and tell BGP */
static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es,
- zebra_vni_t *zvni)
+ zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
- es_evi = zebra_evpn_es_evi_find(es, zvni);
+ es_evi = zebra_evpn_es_evi_find(es, zevpn);
if (!es_evi) {
- es_evi = zebra_evpn_es_evi_new(es, zvni);
+ es_evi = zebra_evpn_es_evi_new(es, zevpn);
if (!es_evi)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("local es %s evi %d add",
- es_evi->es->esi_str, es_evi->zvni->vni);
+ es_evi->es->esi_str, es_evi->zevpn->vni);
es_evi->flags |= ZEBRA_EVPNES_EVI_LOCAL;
- /* add to the VNI's local list */
+ /* add to the EVPN's local list */
listnode_init(&es_evi->l2vni_listnode, es_evi);
- listnode_add(zvni->local_es_evi_list, &es_evi->l2vni_listnode);
+ listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode);
zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
}
@@ -263,7 +265,7 @@ static void zebra_evpn_es_evi_show_entry(struct vty *vty,
strlcat(type_str, "L", sizeof(type_str));
vty_out(vty, "%-8d %-30s %-4s\n",
- es_evi->zvni->vni, es_evi->es->esi_str,
+ es_evi->zevpn->vni, es_evi->es->esi_str,
type_str);
}
}
@@ -281,7 +283,7 @@ static void zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
strlcat(type_str, "L", sizeof(type_str));
vty_out(vty, "VNI %d ESI: %s\n",
- es_evi->zvni->vni, es_evi->es->esi_str);
+ es_evi->zevpn->vni, es_evi->es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
vty_out(vty, " Ready for BGP: %s\n",
(es_evi->flags &
@@ -291,12 +293,12 @@ static void zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
}
}
-static void zebra_evpn_es_evi_show_one_vni(zebra_vni_t *zvni,
+static void zebra_evpn_es_evi_show_one_evpn(zebra_evpn_t *zevpn,
struct vty *vty, json_object *json, int detail)
{
struct zebra_evpn_es_evi *es_evi;
- RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zvni->es_evi_rb_tree) {
+ RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) {
if (detail)
zebra_evpn_es_evi_show_entry_detail(vty, es_evi, json);
else
@@ -310,13 +312,13 @@ struct evpn_mh_show_ctx {
int detail;
};
-static void zebra_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket *bucket,
+static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket,
void *ctxt)
{
- zebra_vni_t *zvni = (zebra_vni_t *)bucket->data;
+ zebra_evpn_t *zevpn = (zebra_evpn_t *)bucket->data;
struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
- zebra_evpn_es_evi_show_one_vni(zvni, wctx->vty,
+ zebra_evpn_es_evi_show_one_evpn(zevpn, wctx->vty,
wctx->json, wctx->detail);
}
@@ -338,17 +340,17 @@ void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail)
vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
}
/* Display all L2-VNIs */
- hash_iterate(zvrf->vni_table, zebra_evpn_es_evi_show_one_vni_hash_cb,
+ hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb,
&wctx);
}
void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
{
json_object *json = NULL;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
- zvni = zvni_lookup(vni);
- if (zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn) {
if (!detail && !json) {
vty_out(vty, "Type: L local, R remote\n");
vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
@@ -357,52 +359,52 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
if (!uj)
vty_out(vty, "VNI %d doesn't exist\n", vni);
}
- zebra_evpn_es_evi_show_one_vni(zvni, vty, json, detail);
+ zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json, detail);
}
/* Initialize the ES tables maintained per-L2_VNI */
-void zebra_evpn_vni_es_init(zebra_vni_t *zvni)
+void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn)
{
/* Initialize the ES-EVI RB tree */
- RB_INIT(zebra_es_evi_rb_head, &zvni->es_evi_rb_tree);
+ RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
/* Initialize the local and remote ES lists maintained for quick
* walks by type
*/
- zvni->local_es_evi_list = list_new();
- listset_app_node_mem(zvni->local_es_evi_list);
+ zevpn->local_es_evi_list = list_new();
+ listset_app_node_mem(zevpn->local_es_evi_list);
}
-/* Cleanup the ES info maintained per-L2_VNI */
-void zebra_evpn_vni_es_cleanup(zebra_vni_t *zvni)
+/* Cleanup the ES info maintained per- EVPN */
+void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
struct zebra_evpn_es_evi *es_evi_next;
RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
- &zvni->es_evi_rb_tree, es_evi_next) {
+ &zevpn->es_evi_rb_tree, es_evi_next) {
zebra_evpn_local_es_evi_do_del(es_evi);
}
- list_delete(&zvni->local_es_evi_list);
- zebra_evpn_es_clear_base_vni(zvni);
+ list_delete(&zevpn->local_es_evi_list);
+ zebra_evpn_es_clear_base_evpn(zevpn);
}
/* called when the oper state or bridge membership changes for the
* vxlan device
*/
-void zebra_evpn_vni_update_all_es(zebra_vni_t *zvni)
+void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
struct listnode *node;
- /* the VNI is now elgible as a base for EVPN-MH */
- if (zebra_evpn_vni_send_to_client_ok(zvni))
- zebra_evpn_es_set_base_vni(zvni);
+ /* the EVPN is now elgible as a base for EVPN-MH */
+ if (zebra_evpn_send_to_client_ok(zevpn))
+ zebra_evpn_es_set_base_evpn(zevpn);
else
- zebra_evpn_es_clear_base_vni(zvni);
+ zebra_evpn_es_clear_base_evpn(zevpn);
- for (ALL_LIST_ELEMENTS_RO(zvni->local_es_evi_list, node, es_evi))
+ for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
}
@@ -514,24 +516,24 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
}
/* called when a EVPN-L2VNI is set or cleared against a BD */
-static void zebra_evpn_acc_bd_vni_set(struct zebra_evpn_access_bd *acc_bd,
- zebra_vni_t *zvni, zebra_vni_t *old_zvni)
+static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
+ zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn)
{
struct zebra_if *zif;
struct listnode *node;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("access vlan %d l2-vni %u set",
- acc_bd->vid, zvni ? zvni->vni : 0);
+ acc_bd->vid, zevpn ? zevpn->vni : 0);
for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
if (!zif->es_info.es)
continue;
- if (zvni)
- zebra_evpn_local_es_evi_add(zif->es_info.es, zvni);
- else if (old_zvni)
- zebra_evpn_local_es_evi_del(zif->es_info.es, old_zvni);
+ if (zevpn)
+ zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
+ else if (old_zevpn)
+ zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
}
}
@@ -540,7 +542,7 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
{
struct zebra_evpn_access_bd *acc_bd;
struct zebra_if *old_vxlan_zif;
- zebra_vni_t *old_zvni;
+ zebra_evpn_t *old_zevpn;
if (!vid)
return;
@@ -554,20 +556,20 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
if (vxlan_zif == old_vxlan_zif)
return;
- old_zvni = acc_bd->zvni;
- acc_bd->zvni = zvni_lookup(vxlan_zif->l2info.vxl.vni);
- if (acc_bd->zvni == old_zvni)
+ old_zevpn = acc_bd->zevpn;
+ acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
+ if (acc_bd->zevpn == old_zevpn)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("access vlan %d vni %u ref",
acc_bd->vid, vxlan_zif->l2info.vxl.vni);
- if (old_zvni)
- zebra_evpn_acc_bd_vni_set(acc_bd, NULL, old_zvni);
+ if (old_zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
- if (acc_bd->zvni)
- zebra_evpn_acc_bd_vni_set(acc_bd, acc_bd->zvni, NULL);
+ if (acc_bd->zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
}
/* handle VLAN->VxLAN_IF deref */
@@ -590,18 +592,18 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
zlog_debug("access vlan %d vni %u deref",
acc_bd->vid, vxlan_zif->l2info.vxl.vni);
- if (acc_bd->zvni)
- zebra_evpn_acc_bd_vni_set(acc_bd, NULL, acc_bd->zvni);
+ if (acc_bd->zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
- acc_bd->zvni = NULL;
+ acc_bd->zevpn = NULL;
acc_bd->vxlan_zif = NULL;
/* if there are no other references the access_bd can be freed */
zebra_evpn_acc_bd_free_on_deref(acc_bd);
}
-/* handle EVPN L2VNI add/del */
-void zebra_evpn_vxl_vni_set(struct zebra_if *zif, zebra_vni_t *zvni,
+/* handle EVPN add/del */
+void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
bool set)
{
struct zebra_l2info_vxlan *vxl;
@@ -617,16 +619,16 @@ void zebra_evpn_vxl_vni_set(struct zebra_if *zif, zebra_vni_t *zvni,
return;
if (set) {
- zebra_evpn_es_set_base_vni(zvni);
- if (acc_bd->zvni != zvni) {
- acc_bd->zvni = zvni;
- zebra_evpn_acc_bd_vni_set(acc_bd, zvni, NULL);
+ zebra_evpn_es_set_base_evpn(zevpn);
+ if (acc_bd->zevpn != zevpn) {
+ acc_bd->zevpn = zevpn;
+ zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
}
} else {
- if (acc_bd->zvni) {
- zebra_vni_t *old_zvni = acc_bd->zvni;
- acc_bd->zvni = NULL;
- zebra_evpn_acc_bd_vni_set(acc_bd, NULL, old_zvni);
+ if (acc_bd->zevpn) {
+ zebra_evpn_t *old_zevpn = acc_bd->zevpn;
+ acc_bd->zevpn = NULL;
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
}
}
}
@@ -651,8 +653,8 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
vid, zif->ifp->name);
listnode_add(acc_bd->mbr_zifs, zif);
- if (acc_bd->zvni && zif->es_info.es)
- zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zvni);
+ if (acc_bd->zevpn && zif->es_info.es)
+ zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
}
/* handle deletion of VLAN members */
@@ -678,8 +680,8 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
list_delete_node(acc_bd->mbr_zifs, node);
- if (acc_bd->zvni && zif->es_info.es)
- zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zvni);
+ if (acc_bd->zevpn && zif->es_info.es)
+ zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
/* if there are no other references the access_bd can be freed */
zebra_evpn_acc_bd_free_on_deref(acc_bd);
@@ -699,7 +701,7 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
acc_bd->vxlan_zif ?
acc_bd->vxlan_zif->ifp->name : "-");
vty_out(vty, " L2-VNI: %d\n",
- acc_bd->zvni ? acc_bd->zvni->vni : 0);
+ acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
vty_out(vty, " Member Count: %d\n",
listcount(acc_bd->mbr_zifs));
vty_out(vty, " Members: \n");
@@ -717,7 +719,7 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
acc_bd->vid,
acc_bd->vxlan_zif ?
acc_bd->vxlan_zif->ifp->name : "-",
- acc_bd->zvni ? acc_bd->zvni->vni : 0,
+ acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
listcount(acc_bd->mbr_zifs));
}
@@ -961,7 +963,7 @@ static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
/* A list of remote VTEPs is maintained for each ES. This list includes -
* 1. VTEPs for which we have imported the ESR i.e. ES-peers
* 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
- * have been imported into one or more VNIs
+ * have been imported into one or more EVPNs
*/
static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
{
@@ -1257,11 +1259,11 @@ void zebra_evpn_es_send_all_to_client(bool add)
if (add)
zebra_evpn_es_evi_send_to_client(
- es, es_evi->zvni,
+ es, es_evi->zevpn,
true /* add */);
else
zebra_evpn_es_evi_send_to_client(
- es, es_evi->zvni,
+ es, es_evi->zevpn,
false /* add */);
}
if (!add)
@@ -1283,8 +1285,8 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
acc_bd = zebra_evpn_acc_vl_find(vid);
- if (acc_bd->zvni)
- zebra_evpn_local_es_evi_add(es, acc_bd->zvni);
+ if (acc_bd->zevpn)
+ zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
}
}
@@ -1296,9 +1298,9 @@ static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es,
for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
- zebra_vxlan_sync_mac_dp_install(mac,
- false /* set_inactive */,
- force_clear_static, __func__);
+ zebra_evpn_sync_mac_dp_install(
+ mac, false /* set_inactive */,
+ force_clear_static, __func__);
}
}
}
@@ -1328,8 +1330,8 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
/* setup base-vni if one doesn't already exist; the ES will get sent
* to BGP as a part of that process
*/
- if (!zmh_info->es_base_vni)
- zebra_evpn_es_get_one_base_vni();
+ if (!zmh_info->es_base_evpn)
+ zebra_evpn_es_get_one_base_evpn();
else
/* send notification to bgp */
zebra_evpn_es_re_eval_send_to_client(es,
@@ -1621,7 +1623,7 @@ bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
/* Inform BGP about local ES-EVI add or del */
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
- zebra_vni_t *zvni, bool add)
+ zebra_evpn_t *zevpn, bool add)
{
struct zserv *client;
struct stream *s;
@@ -1637,7 +1639,7 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
zebra_vrf_get_evpn_id());
stream_put(s, &es->esi, sizeof(esi_t));
- stream_putl(s, zvni->vni);
+ stream_putl(s, zevpn->vni);
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1645,7 +1647,7 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("send %s local es %s evi %u to %s",
add ? "add" : "del",
- es->esi_str, zvni->vni,
+ es->esi_str, zevpn->vni,
zebra_route_string(client->proto));
client->local_es_add_cnt++;
@@ -1979,39 +1981,39 @@ DEFPY(zebra_evpn_es_id,
* necessary
*/
/* called when a new vni is added or becomes oper up or becomes a bridge port */
-void zebra_evpn_es_set_base_vni(zebra_vni_t *zvni)
+void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn)
{
struct listnode *node;
struct zebra_evpn_es *es;
- if (zmh_info->es_base_vni) {
- if (zmh_info->es_base_vni != zvni) {
- /* unrelated VNI; ignore it */
+ if (zmh_info->es_base_evpn) {
+ if (zmh_info->es_base_evpn != zevpn) {
+ /* unrelated EVPN; ignore it */
return;
}
/* check if the local vtep-ip has changed */
} else {
- /* check if the VNI can be used as base VNI */
- if (!zebra_evpn_vni_send_to_client_ok(zvni))
+ /* check if the EVPN can be used as base EVPN */
+ if (!zebra_evpn_send_to_client_ok(zevpn))
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es base vni set to %d",
- zvni->vni);
- zmh_info->es_base_vni = zvni;
+ zevpn->vni);
+ zmh_info->es_base_evpn = zevpn;
}
/* update local VTEP-IP */
if (zmh_info->es_originator_ip.s_addr ==
- zmh_info->es_base_vni->local_vtep_ip.s_addr)
+ zmh_info->es_base_evpn->local_vtep_ip.s_addr)
return;
zmh_info->es_originator_ip.s_addr =
- zmh_info->es_base_vni->local_vtep_ip.s_addr;
+ zmh_info->es_base_evpn->local_vtep_ip.s_addr;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es originator ip set to %s",
- inet_ntoa(zmh_info->es_base_vni->local_vtep_ip));
+ inet_ntoa(zmh_info->es_base_evpn->local_vtep_ip));
/* if originator ip changes we need to update bgp */
for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
@@ -2026,20 +2028,20 @@ void zebra_evpn_es_set_base_vni(zebra_vni_t *zvni)
/* called when a vni is removed or becomes oper down or is removed from a
* bridge
*/
-void zebra_evpn_es_clear_base_vni(zebra_vni_t *zvni)
+void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn)
{
struct listnode *node;
struct zebra_evpn_es *es;
- if (zmh_info->es_base_vni != zvni)
+ if (zmh_info->es_base_evpn != zevpn)
return;
- zmh_info->es_base_vni = NULL;
- /* lost current base VNI; try to find a new one */
- zebra_evpn_es_get_one_base_vni();
+ zmh_info->es_base_evpn = NULL;
+ /* lost current base EVPN; try to find a new one */
+ zebra_evpn_es_get_one_base_evpn();
- /* couldn't locate an eligible base vni */
- if (!zmh_info->es_base_vni && zmh_info->es_originator_ip.s_addr) {
+ /* couldn't locate an eligible base evpn */
+ if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("es originator ip cleared");
@@ -2053,27 +2055,27 @@ void zebra_evpn_es_clear_base_vni(zebra_vni_t *zvni)
}
/* Locate an "eligible" L2-VNI to follow */
-static int zebra_evpn_es_get_one_base_vni_cb(struct hash_bucket *b, void *data)
+static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
{
- zebra_vni_t *zvni = b->data;
+ zebra_evpn_t *zevpn = b->data;
- zebra_evpn_es_set_base_vni(zvni);
+ zebra_evpn_es_set_base_evpn(zevpn);
- if (zmh_info->es_base_vni)
+ if (zmh_info->es_base_evpn)
return HASHWALK_ABORT;
return HASHWALK_CONTINUE;
}
-/* locate a base_vni to follow for the purposes of common params like
+/* locate a base_evpn to follow for the purposes of common params like
* originator IP
*/
-static void zebra_evpn_es_get_one_base_vni(void)
+static void zebra_evpn_es_get_one_base_evpn(void)
{
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_get_evpn();
- hash_walk(zvrf->vni_table, zebra_evpn_es_get_one_base_vni_cb, NULL);
+ hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
}
/*****************************************************************************/
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 46c25a04bc..ed62677e3b 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -79,8 +79,8 @@ RB_HEAD(zebra_es_rb_head, zebra_evpn_es);
RB_PROTOTYPE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
/* ES per-EVI info
- * - ES-EVIs are maintained per-VNI (vni->es_evi_rb_tree)
- * - Local ES-EVIs are linked to per-VNI list for quick access
+ * - ES-EVIs are maintained per-EVPN (vni->es_evi_rb_tree)
+ * - Local ES-EVIs are linked to per-EVPN list for quick access
* - Although some infrastucture is present for remote ES-EVIs, currently
* BGP does NOT send remote ES-EVIs to zebra. This may change in the
* future (but must be changed thoughtfully and only if needed as ES-EVI
@@ -88,7 +88,7 @@ RB_PROTOTYPE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
*/
struct zebra_evpn_es_evi {
struct zebra_evpn_es *es;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
/* ES-EVI flags */
uint32_t flags;
@@ -97,11 +97,11 @@ struct zebra_evpn_es_evi {
#define ZEBRA_EVPNES_EVI_READY_FOR_BGP (1 << 1) /* ready to be sent to BGP */
/* memory used for adding the es_evi to
- * es_evi->zvni->es_evi_rb_tree
+ * es_evi->zevpn->es_evi_rb_tree
*/
RB_ENTRY(zebra_evpn_es_evi) rb_node;
/* memory used for linking the es_evi to
- * es_evi->zvni->local_es_evi_list
+ * es_evi->zevpn->local_es_evi_list
*/
struct listnode l2vni_listnode;
/* memory used for linking the es_evi to
@@ -135,8 +135,8 @@ struct zebra_evpn_access_bd {
struct zebra_if *vxlan_zif; /* vxlan device */
/* list of members associated with the BD i.e. (potential) ESs */
struct list *mbr_zifs;
- /* presence of zvni activates the EVI on all the ESs in mbr_zifs */
- zebra_vni_t *zvni;
+ /* presence of zevpn activates the EVI on all the ESs in mbr_zifs */
+ zebra_evpn_t *zevpn;
};
/* multihoming information stored in zrouter */
@@ -155,7 +155,7 @@ struct zebra_evpn_mh_info {
* XXX: once single vxlan device model becomes available this will
* not be necessary
*/
- zebra_vni_t *es_base_vni;
+ zebra_evpn_t *es_base_evpn;
struct in_addr es_originator_ip;
/* L2 NH and NHG ids -
@@ -198,12 +198,12 @@ extern void zebra_evpn_mh_terminate(void);
extern bool zebra_evpn_is_if_es_capable(struct zebra_if *zif);
extern void zebra_evpn_if_init(struct zebra_if *zif);
extern void zebra_evpn_if_cleanup(struct zebra_if *zif);
-extern void zebra_evpn_vni_es_init(zebra_vni_t *zvni);
-extern void zebra_evpn_vni_es_cleanup(zebra_vni_t *zvni);
-extern void zebra_evpn_vxl_vni_set(struct zebra_if *zif, zebra_vni_t *zvni,
+extern void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn);
+extern void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn);
+extern void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
bool set);
-extern void zebra_evpn_es_set_base_vni(zebra_vni_t *zvni);
-extern void zebra_evpn_es_clear_base_vni(zebra_vni_t *zvni);
+extern void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn);
+extern void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn);
extern void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif);
extern void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif);
extern void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif);
@@ -213,7 +213,7 @@ extern void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up);
extern void zebra_evpn_es_show(struct vty *vty, bool uj);
extern void zebra_evpn_es_show_detail(struct vty *vty, bool uj);
extern void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi);
-extern void zebra_evpn_vni_update_all_es(zebra_vni_t *zvni);
+extern void zebra_evpn_update_all_es(zebra_evpn_t *zevpn);
extern void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS);
extern void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail);
extern void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj,
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
new file mode 100644
index 0000000000..492052b1b2
--- /dev/null
+++ b/zebra/zebra_evpn_neigh.c
@@ -0,0 +1,2453 @@
+/*
+ * Zebra EVPN Neighbor code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "interface.h"
+#include "jhash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "vlan.h"
+#include "json.h"
+
+#include "zebra/zserv.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_router.h"
+#include "zebra/rt.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_neigh.h"
+#include "zebra/zebra_evpn_mac.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "EVI Neighbor");
+
+/*
+ * Make hash key for neighbors.
+ */
+static unsigned int neigh_hash_keymake(const void *p)
+{
+ const zebra_neigh_t *n = p;
+ const struct ipaddr *ip = &n->ip;
+
+ if (IS_IPADDR_V4(ip))
+ return jhash_1word(ip->ipaddr_v4.s_addr, 0);
+
+ return jhash2(ip->ipaddr_v6.s6_addr32,
+ array_size(ip->ipaddr_v6.s6_addr32), 0);
+}
+
+/*
+ * Compare two neighbor hash structures.
+ */
+static bool neigh_cmp(const void *p1, const void *p2)
+{
+ const zebra_neigh_t *n1 = p1;
+ const zebra_neigh_t *n2 = p2;
+
+ if (n1 == NULL && n2 == NULL)
+ return true;
+
+ if (n1 == NULL || n2 == NULL)
+ return false;
+
+ return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0);
+}
+
+int neigh_list_cmp(void *p1, void *p2)
+{
+ const zebra_neigh_t *n1 = p1;
+ const zebra_neigh_t *n2 = p2;
+
+ return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr));
+}
+
+struct hash *zebra_neigh_db_create(const char *desc)
+{
+ return hash_create(neigh_hash_keymake, neigh_cmp, desc);
+}
+
+uint32_t num_dup_detected_neighs(zebra_evpn_t *zevpn)
+{
+ unsigned int i;
+ uint32_t num_neighs = 0;
+ struct hash *hash;
+ struct hash_bucket *hb;
+ zebra_neigh_t *nbr;
+
+ hash = zevpn->neigh_table;
+ if (!hash)
+ return num_neighs;
+ for (i = 0; i < hash->size; i++) {
+ for (hb = hash->index[i]; hb; hb = hb->next) {
+ nbr = (zebra_neigh_t *)hb->data;
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+ num_neighs++;
+ }
+ }
+
+ return num_neighs;
+}
+
+/*
+ * Helper function to determine maximum width of neighbor IP address for
+ * display - just because we're dealing with IPv6 addresses that can
+ * widely vary.
+ */
+void zebra_evpn_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_neigh_t *n;
+ char buf[INET6_ADDRSTRLEN];
+ struct neigh_walk_ctx *wctx = ctxt;
+ int width;
+
+ n = (zebra_neigh_t *)bucket->data;
+
+ ipaddr2str(&n->ip, buf, sizeof(buf));
+ width = strlen(buf);
+ if (width > wctx->addr_width)
+ wctx->addr_width = width;
+}
+
+/*
+ * Count of remote neighbors referencing this MAC.
+ */
+int remote_neigh_count(zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ int count = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
+ count++;
+ }
+
+ return count;
+}
+
+/*
+ * Install remote neighbor into the kernel.
+ */
+int zebra_evpn_rem_neigh_install(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ bool was_static)
+{
+ struct interface *vlan_if;
+ int flags;
+ int ret = 0;
+
+ if (!(n->flags & ZEBRA_NEIGH_REMOTE))
+ return 0;
+
+ vlan_if = zevpn_map_to_svi(zevpn);
+ if (!vlan_if)
+ return -1;
+
+ flags = DPLANE_NTF_EXT_LEARNED;
+ if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
+ flags |= DPLANE_NTF_ROUTER;
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ dplane_rem_neigh_add(vlan_if, &n->ip, &n->emac, flags, was_static);
+
+ return ret;
+}
+
+/*
+ * Install neighbor hash entry - called upon access VLAN change.
+ */
+void zebra_evpn_install_neigh_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_neigh_t *n;
+ struct neigh_walk_ctx *wctx = ctxt;
+
+ n = (zebra_neigh_t *)bucket->data;
+
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
+ zebra_evpn_rem_neigh_install(wctx->zevpn, n,
+ false /*was_static*/);
+}
+
+/*
+ * Callback to allocate neighbor hash entry.
+ */
+static void *zebra_evpn_neigh_alloc(void *p)
+{
+ const zebra_neigh_t *tmp_n = p;
+ zebra_neigh_t *n;
+
+ n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
+ *n = *tmp_n;
+
+ return ((void *)n);
+}
+
+static void zebra_evpn_local_neigh_ref_mac(zebra_neigh_t *n,
+ struct ethaddr *macaddr,
+ zebra_mac_t *mac,
+ bool send_mac_update)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_static;
+ bool new_static;
+
+ memcpy(&n->emac, macaddr, ETH_ALEN);
+ n->mac = mac;
+
+ /* Link to new MAC */
+ if (!mac)
+ return;
+
+ listnode_add_sort(mac->neigh_list, n);
+ if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
+ old_static = zebra_evpn_mac_is_static(mac);
+ ++mac->sync_neigh_cnt;
+ new_static = zebra_evpn_mac_is_static(mac);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-neigh ref mac vni %u ip %s mac %s ref %d",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ mac->sync_neigh_cnt);
+ if ((old_static != new_static) && send_mac_update)
+ /* program the local mac in the kernel */
+ zebra_evpn_sync_mac_dp_install(
+ mac, false /*set_inactive*/,
+ false /*force_clear_static*/, __func__);
+ }
+}
+
+/* sync-path that is active on an ES peer */
+static void zebra_evpn_sync_neigh_dp_install(zebra_neigh_t *n,
+ bool set_inactive,
+ bool force_clear_static,
+ const char *caller)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ bool set_static;
+ bool set_router;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ ifp = if_lookup_by_index_per_ns(zns, n->ifindex);
+ if (!ifp) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "%s: dp-install sync-neigh vni %u ip %s mac %s if %d f 0x%x skipped",
+ caller, n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->ifindex, n->flags);
+ return;
+ }
+
+ if (force_clear_static)
+ set_static = false;
+ else
+ set_static = zebra_evpn_neigh_is_static(n);
+
+ set_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ /* XXX - this will change post integration with the new kernel */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ set_inactive = true;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "%s: dp-install sync-neigh vni %u ip %s mac %s if %s(%d) f 0x%x%s%s%s",
+ caller, n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ ifp->name, n->ifindex, n->flags,
+ set_router ? " router" : "",
+ set_static ? " static" : "",
+ set_inactive ? " inactive" : "");
+ dplane_local_neigh_add(ifp, &n->ip, &n->emac, set_router, set_static,
+ set_inactive);
+}
+
+/*
+ * Inform BGP about local neighbor addition.
+ */
+int zebra_evpn_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
+ struct ethaddr *macaddr,
+ zebra_mac_t *zmac, uint32_t neigh_flags,
+ uint32_t seq)
+{
+ uint8_t flags = 0;
+
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
+ /* host reachability has not been verified locally */
+
+ /* if no ES peer is claiming reachability we can't advertise
+ * the entry
+ */
+ if (!CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ return 0;
+
+ /* ES peers are claiming reachability; we will
+ * advertise the entry but with a proxy flag
+ */
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
+ }
+
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+ /* Set router flag (R-bit) based on local neigh entry add */
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP);
+
+ return zebra_evpn_macip_send_msg_to_client(
+ vni, macaddr, ip, flags, seq, ZEBRA_NEIGH_ACTIVE,
+ zmac ? zmac->es : NULL, ZEBRA_MACIP_ADD);
+}
+
+/*
+ * Inform BGP about local neighbor deletion.
+ */
+int zebra_evpn_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
+ struct ethaddr *macaddr, uint32_t flags,
+ int state, bool force)
+{
+ if (!force) {
+ if (CHECK_FLAG(flags, ZEBRA_NEIGH_LOCAL_INACTIVE)
+ && !CHECK_FLAG(flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ /* the neigh was not advertised - nothing to delete */
+ return 0;
+ }
+
+ return zebra_evpn_macip_send_msg_to_client(
+ vni, macaddr, ip, flags, 0, state, NULL, ZEBRA_MACIP_DEL);
+}
+
+static void zebra_evpn_neigh_send_add_del_to_client(zebra_neigh_t *n,
+ bool old_bgp_ready,
+ bool new_bgp_ready)
+{
+ if (new_bgp_ready)
+ zebra_evpn_neigh_send_add_to_client(n->zevpn->vni, &n->ip,
+ &n->emac, n->mac, n->flags,
+ n->loc_seq);
+ else if (old_bgp_ready)
+ zebra_evpn_neigh_send_del_to_client(n->zevpn->vni, &n->ip,
+ &n->emac, n->flags,
+ n->state, true /*force*/);
+}
+
+/* if the static flag associated with the neigh changes we need
+ * to update the sync-neigh references against the MAC
+ * and inform the dataplane about the static flag changes.
+ */
+void zebra_evpn_sync_neigh_static_chg(zebra_neigh_t *n, bool old_n_static,
+ bool new_n_static, bool defer_n_dp,
+ bool defer_mac_dp, const char *caller)
+{
+ zebra_mac_t *mac = n->mac;
+ bool old_mac_static;
+ bool new_mac_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (old_n_static == new_n_static)
+ return;
+
+ /* update the neigh sync references in the dataplane. if
+ * the neigh is in the middle of updates the caller can
+ * request for a defer
+ */
+ if (!defer_n_dp)
+ zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ if (!mac)
+ return;
+
+ /* update the mac sync ref cnt */
+ old_mac_static = zebra_evpn_mac_is_static(mac);
+ if (new_n_static) {
+ ++mac->sync_neigh_cnt;
+ } else if (old_n_static) {
+ if (mac->sync_neigh_cnt)
+ --mac->sync_neigh_cnt;
+ }
+ new_mac_static = zebra_evpn_mac_is_static(mac);
+
+ /* update the mac sync references in the dataplane */
+ if ((old_mac_static != new_mac_static) && !defer_mac_dp)
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-neigh ref-chg vni %u ip %s mac %s f 0x%x %d%s%s%s%s by %s",
+ n->zevpn->vni, ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags, mac->sync_neigh_cnt,
+ old_n_static ? " old_n_static" : "",
+ new_n_static ? " new_n_static" : "",
+ old_mac_static ? " old_mac_static" : "",
+ new_mac_static ? " new_mac_static" : "", caller);
+}
+
+/* Neigh hold timer is used to age out peer-active flag.
+ *
+ * During this wait time we expect the dataplane component or an
+ * external neighmgr daemon to probe existing hosts to independently
+ * establish their presence on the ES.
+ */
+static int zebra_evpn_neigh_hold_exp_cb(struct thread *t)
+{
+ zebra_neigh_t *n;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+ bool old_n_static;
+ bool new_n_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ n = THREAD_ARG(t);
+ /* the purpose of the hold timer is to age out the peer-active
+ * flag
+ */
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ return 0;
+
+ old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ old_n_static = zebra_evpn_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ new_n_static = zebra_evpn_neigh_is_static(n);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold expired",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags);
+
+ /* re-program the local neigh in the dataplane if the neigh is no
+ * longer static
+ */
+ if (old_n_static != new_n_static)
+ zebra_evpn_sync_neigh_static_chg(
+ n, old_n_static, new_n_static, false /*defer_n_dp*/,
+ false /*defer_mac_dp*/, __func__);
+
+ /* inform bgp if needed */
+ if (old_bgp_ready != new_bgp_ready)
+ zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready,
+ new_bgp_ready);
+
+ return 0;
+}
+
+static inline void zebra_evpn_neigh_start_hold_timer(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (n->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold start",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags);
+ thread_add_timer(zrouter.master, zebra_evpn_neigh_hold_exp_cb, n,
+ zmh_info->neigh_hold_time, &n->hold_timer);
+}
+
+static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n,
+ bool send_mac_update)
+{
+ zebra_mac_t *mac = n->mac;
+ zebra_evpn_t *zevpn = n->zevpn;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_static;
+ bool new_static;
+
+ n->mac = NULL;
+ if (!mac)
+ return;
+
+ if ((n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) && mac->sync_neigh_cnt) {
+ old_static = zebra_evpn_mac_is_static(mac);
+ --mac->sync_neigh_cnt;
+ new_static = zebra_evpn_mac_is_static(mac);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-neigh deref mac vni %u ip %s mac %s ref %d",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ mac->sync_neigh_cnt);
+ if ((old_static != new_static) && send_mac_update)
+ /* program the local mac in the kernel */
+ zebra_evpn_sync_mac_dp_install(
+ mac, false /* set_inactive */,
+ false /* force_clear_static */, __func__);
+ }
+
+ listnode_delete(mac->neigh_list, n);
+ zebra_evpn_deref_ip2mac(zevpn, mac);
+}
+
+bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ struct ethaddr *macaddr, uint32_t seq)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ uint32_t tmp_seq;
+
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
+ tmp_seq = n->loc_seq;
+ else
+ tmp_seq = n->rem_seq;
+
+ if (seq < tmp_seq) {
+ /* if the neigh was never advertised to bgp we must accept
+ * whatever sequence number bgp sends
+ * XXX - check with Vivek
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
+ && !zebra_evpn_neigh_is_ready_for_bgp(n)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-macip accept vni %u mac %s IP %s lower seq %u f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(macaddr, macbuf,
+ sizeof(macbuf)),
+ ipaddr2str(&n->ip, ipbuf,
+ sizeof(ipbuf)),
+ tmp_seq, n->flags);
+ return true;
+ }
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-macip ignore vni %u mac %s IP %s as existing has higher seq %u f 0x%x",
+ zevpn->vni,
+ prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ tmp_seq, n->flags);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Add neighbor entry.
+ */
+static zebra_neigh_t *zebra_evpn_neigh_add(zebra_evpn_t *zevpn,
+ struct ipaddr *ip,
+ struct ethaddr *mac,
+ zebra_mac_t *zmac, uint32_t n_flags)
+{
+ zebra_neigh_t tmp_n;
+ zebra_neigh_t *n = NULL;
+
+ memset(&tmp_n, 0, sizeof(zebra_neigh_t));
+ memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
+ n = hash_get(zevpn->neigh_table, &tmp_n, zebra_evpn_neigh_alloc);
+ assert(n);
+
+ n->state = ZEBRA_NEIGH_INACTIVE;
+ n->zevpn = zevpn;
+ n->dad_ip_auto_recovery_timer = NULL;
+ n->flags = n_flags;
+
+ if (!zmac)
+ zmac = zebra_evpn_mac_lookup(zevpn, mac);
+ zebra_evpn_local_neigh_ref_mac(n, mac, zmac,
+ false /* send_mac_update */);
+
+ return n;
+}
+
+/*
+ * Delete neighbor entry.
+ */
+int zebra_evpn_neigh_del(zebra_evpn_t *zevpn, zebra_neigh_t *n)
+{
+ zebra_neigh_t *tmp_n;
+
+ if (n->mac)
+ listnode_delete(n->mac->neigh_list, n);
+
+ /* Cancel auto recovery */
+ THREAD_OFF(n->dad_ip_auto_recovery_timer);
+
+ /* Free the VNI hash entry and allocated memory. */
+ tmp_n = hash_release(zevpn->neigh_table, n);
+ XFREE(MTYPE_NEIGH, tmp_n);
+
+ return 0;
+}
+
+void zebra_evpn_sync_neigh_del(zebra_neigh_t *n)
+{
+ bool old_n_static;
+ bool new_n_static;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh del vni %u ip %s mac %s f 0x%x",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags);
+
+ old_n_static = zebra_evpn_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ zebra_evpn_neigh_start_hold_timer(n);
+ new_n_static = zebra_evpn_neigh_is_static(n);
+
+ if (old_n_static != new_n_static)
+ zebra_evpn_sync_neigh_static_chg(
+ n, old_n_static, new_n_static, false /*defer-dp*/,
+ false /*defer_mac_dp*/, __func__);
+}
+
+zebra_neigh_t *
+zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq, esi_t *esi,
+ struct sync_mac_ip_ctx *ctx)
+{
+ struct interface *ifp = NULL;
+ bool is_router;
+ zebra_mac_t *mac = ctx->mac;
+ uint32_t tmp_seq;
+ bool old_router = false;
+ bool old_bgp_ready = false;
+ bool new_bgp_ready;
+ bool inform_dataplane = false;
+ bool inform_bgp = false;
+ bool old_mac_static;
+ bool new_mac_static;
+ bool set_dp_inactive = false;
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool created;
+ ifindex_t ifindex = 0;
+
+ /* locate l3-svi */
+ ifp = zevpn_map_to_svi(zevpn);
+ if (ifp)
+ ifindex = ifp->ifindex;
+
+ is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+ old_mac_static = zebra_evpn_mac_is_static(mac);
+
+ if (!n) {
+ uint32_t n_flags = 0;
+
+ /* New neighbor - create */
+ SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL);
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ else
+ SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+
+ n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr, mac,
+ n_flags);
+ n->ifindex = ifindex;
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ created = true;
+ inform_dataplane = true;
+ inform_bgp = true;
+ set_dp_inactive = true;
+ } else {
+ bool mac_change;
+ uint32_t old_flags = n->flags;
+ bool old_n_static;
+ bool new_n_static;
+
+ created = false;
+ old_n_static = zebra_evpn_neigh_is_static(n);
+ old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ old_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ mac_change = !!memcmp(&n->emac, &mac->macaddr, ETH_ALEN);
+
+ /* deref and clear old info */
+ if (mac_change) {
+ if (old_bgp_ready) {
+ zebra_evpn_neigh_send_del_to_client(
+ zevpn->vni, &n->ip, &n->emac, n->flags,
+ n->state, false /*force*/);
+ old_bgp_ready = false;
+ }
+ if (n->mac)
+ zebra_evpn_local_neigh_deref_mac(
+ n, false /*send_mac_update*/);
+ }
+ /* clear old fwd info */
+ n->rem_seq = 0;
+ n->r_vtep_ip.s_addr = 0;
+
+ /* setup new flags */
+ n->flags = 0;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ /* retain activity flag if the neigh was
+ * previously local
+ */
+ if (old_flags & ZEBRA_NEIGH_LOCAL) {
+ n->flags |= (old_flags & ZEBRA_NEIGH_LOCAL_INACTIVE);
+ } else {
+ inform_dataplane = true;
+ set_dp_inactive = true;
+ n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
+ }
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ else
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
+ /* if the neigh was peer-active previously we
+ * need to keep the flag and start the
+ * holdtimer on it. the peer-active flag is
+ * cleared on holdtimer expiry.
+ */
+ if (CHECK_FLAG(old_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ zebra_evpn_neigh_start_hold_timer(n);
+ }
+ } else {
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
+ /* stop hold timer if a peer has verified
+ * reachability
+ */
+ zebra_evpn_neigh_stop_hold_timer(n);
+ }
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH && (old_flags != n->flags))
+ zlog_debug(
+ "sync-neigh vni %u ip %s mac %s old_f 0x%x new_f 0x%x",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ old_flags, n->flags);
+
+ new_n_static = zebra_evpn_neigh_is_static(n);
+ if (mac_change) {
+ set_dp_inactive = true;
+ n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
+ inform_dataplane = true;
+ zebra_evpn_local_neigh_ref_mac(
+ n, &mac->macaddr, mac,
+ false /*send_mac_update*/);
+ } else if (old_n_static != new_n_static) {
+ inform_dataplane = true;
+ /* if static flags have changed without a mac change
+ * we need to create the correct sync-refs against
+ * the existing mac
+ */
+ zebra_evpn_sync_neigh_static_chg(
+ n, old_n_static, new_n_static,
+ true /*defer_dp*/, true /*defer_mac_dp*/,
+ __func__);
+ }
+
+ /* Update the forwarding info. */
+ if (n->ifindex != ifindex) {
+ n->ifindex = ifindex;
+ inform_dataplane = true;
+ }
+ }
+
+ /* update the neigh seq. we don't bother with the mac seq as
+ * sync_mac_update already took care of that
+ */
+ tmp_seq = MAX(n->loc_seq, seq);
+ if (tmp_seq != n->loc_seq) {
+ n->loc_seq = tmp_seq;
+ inform_bgp = true;
+ }
+
+ /* Mark Router flag (R-bit) */
+ if (is_router)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ if (old_router != is_router)
+ inform_dataplane = true;
+
+ new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ if (old_bgp_ready != new_bgp_ready)
+ inform_bgp = true;
+
+ new_mac_static = zebra_evpn_mac_is_static(mac);
+ if ((old_mac_static != new_mac_static) || ctx->mac_dp_update_deferred)
+ zebra_evpn_sync_mac_dp_install(mac, ctx->mac_inactive,
+ false /* force_clear_static */,
+ __func__);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync-neigh %s vni %u ip %s mac %s if %s(%d) seq %d f 0x%x%s%s",
+ created ? "created" : "updated", n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ ifp ? ifp->name : "", ifindex, n->loc_seq, n->flags,
+ inform_bgp ? " inform_bgp" : "",
+ inform_dataplane ? " inform_dp" : "");
+
+ if (inform_dataplane)
+ zebra_evpn_sync_neigh_dp_install(n, set_dp_inactive,
+ false /* force_clear_static */,
+ __func__);
+
+ if (inform_bgp)
+ zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready,
+ new_bgp_ready);
+
+ return n;
+}
+
+/*
+ * Uninstall remote neighbor from the kernel.
+ */
+static int zebra_evpn_neigh_uninstall(zebra_evpn_t *zevpn, zebra_neigh_t *n)
+{
+ struct interface *vlan_if;
+
+ if (!(n->flags & ZEBRA_NEIGH_REMOTE))
+ return 0;
+
+ vlan_if = zevpn_map_to_svi(zevpn);
+ if (!vlan_if)
+ return -1;
+
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
+
+ dplane_rem_neigh_delete(vlan_if, &n->ip);
+
+ return 0;
+}
+
+/*
+ * Free neighbor hash entry (callback)
+ */
+static void zebra_evpn_neigh_del_hash_entry(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct neigh_walk_ctx *wctx = arg;
+ zebra_neigh_t *n = bucket->data;
+
+ if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL))
+ || ((wctx->flags & DEL_REMOTE_NEIGH)
+ && (n->flags & ZEBRA_NEIGH_REMOTE))
+ || ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP)
+ && (n->flags & ZEBRA_NEIGH_REMOTE)
+ && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
+ if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
+ zebra_evpn_neigh_send_del_to_client(
+ wctx->zevpn->vni, &n->ip, &n->emac, n->flags,
+ n->state, false /*force*/);
+
+ if (wctx->uninstall) {
+ if (zebra_evpn_neigh_is_static(n))
+ zebra_evpn_sync_neigh_dp_install(
+ n, false /* set_inactive */,
+ true /* force_clear_static */,
+ __func__);
+ if ((n->flags & ZEBRA_NEIGH_REMOTE))
+ zebra_evpn_neigh_uninstall(wctx->zevpn, n);
+ }
+
+ zebra_evpn_neigh_del(wctx->zevpn, n);
+ }
+
+ return;
+}
+
+/*
+ * Delete all neighbor entries for this EVPN.
+ */
+void zebra_evpn_neigh_del_all(zebra_evpn_t *zevpn, int uninstall,
+ int upd_client, uint32_t flags)
+{
+ struct neigh_walk_ctx wctx;
+
+ if (!zevpn->neigh_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = uninstall;
+ wctx.upd_client = upd_client;
+ wctx.flags = flags;
+
+ hash_iterate(zevpn->neigh_table, zebra_evpn_neigh_del_hash_entry,
+ &wctx);
+}
+
+/*
+ * Look up neighbor hash entry.
+ */
+zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, struct ipaddr *ip)
+{
+ zebra_neigh_t tmp;
+ zebra_neigh_t *n;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
+ n = hash_lookup(zevpn->neigh_table, &tmp);
+
+ return n;
+}
+
+/*
+ * Process all neighbors associated with a MAC upon the MAC being learnt
+ * locally or undergoing any other change (such as sequence number).
+ */
+void zebra_evpn_process_neigh_on_local_mac_change(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac,
+ bool seq_change,
+ bool es_change)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ struct zebra_vrf *zvrf = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ seq_change ? "CHANGE" : "ADD", zevpn->vni);
+
+ /* Walk all neighbors and mark any inactive local neighbors as
+ * active and/or update sequence number upon a move, and inform BGP.
+ * The action for remote neighbors is TBD.
+ * NOTE: We can't simply uninstall remote neighbors as the kernel may
+ * accidentally end up deleting a just-learnt local neighbor.
+ */
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change
+ || es_change) {
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ n->loc_seq = zmac->loc_seq;
+ if (!(zvrf->dup_addr_detect && zvrf->dad_freeze
+ && !!CHECK_FLAG(n->flags,
+ ZEBRA_NEIGH_DUPLICATE)))
+ zebra_evpn_neigh_send_add_to_client(
+ zevpn->vni, &n->ip, &n->emac,
+ n->mac, n->flags, n->loc_seq);
+ }
+ }
+ }
+}
+
+/*
+ * Process all neighbors associated with a local MAC upon the MAC being
+ * deleted.
+ */
+void zebra_evpn_process_neigh_on_local_mac_del(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ zevpn->vni);
+
+ /* Walk all local neighbors and mark as inactive and inform
+ * BGP, if needed.
+ * TBD: There is currently no handling for remote neighbors. We
+ * don't expect them to exist, if they do, do we install the MAC
+ * as a remote MAC and the neighbor as remote?
+ */
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
+ zebra_evpn_neigh_send_del_to_client(
+ zevpn->vni, &n->ip, &n->emac, n->flags,
+ ZEBRA_NEIGH_ACTIVE, false /*force*/);
+ }
+ }
+ }
+}
+
+/*
+ * Process all neighbors associated with a MAC upon the MAC being remotely
+ * learnt.
+ */
+void zebra_evpn_process_neigh_on_remote_mac_add(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac)
+{
+ zebra_neigh_t *n = NULL;
+ struct listnode *node = NULL;
+ char buf[ETHER_ADDR_STRLEN];
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u",
+ prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
+ zevpn->vni);
+
+ /* Walk all local neighbors and mark as inactive and inform
+ * BGP, if needed.
+ */
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
+ zebra_evpn_neigh_send_del_to_client(
+ zevpn->vni, &n->ip, &n->emac, n->flags,
+ ZEBRA_NEIGH_ACTIVE, false /* force */);
+ }
+ }
+ }
+}
+
+/*
+ * Process all neighbors associated with a remote MAC upon the MAC being
+ * deleted.
+ */
+void zebra_evpn_process_neigh_on_remote_mac_del(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac)
+{
+ /* NOTE: Currently a NO-OP. */
+}
+
+static inline void zebra_evpn_local_neigh_update_log(
+ const char *pfx, zebra_neigh_t *n, bool is_router, bool local_inactive,
+ bool old_bgp_ready, bool new_bgp_ready, bool inform_dataplane,
+ bool inform_bgp, const char *sfx)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (!IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ return;
+
+ zlog_debug("%s neigh vni %u ip %s mac %s f 0x%x%s%s%s%s%s%s %s", pfx,
+ n->zevpn->vni, ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), n->flags,
+ is_router ? " router" : "",
+ local_inactive ? " local-inactive" : "",
+ old_bgp_ready ? " old_bgp_ready" : "",
+ new_bgp_ready ? " new_bgp_ready" : "",
+ inform_dataplane ? " inform_dp" : "",
+ inform_bgp ? " inform_bgp" : "", sfx);
+}
+
+/* As part Duplicate Address Detection (DAD) for IP mobility
+ * MAC binding changes, ensure to inherit duplicate flag
+ * from MAC.
+ */
+static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
+ zebra_mac_t *old_zmac,
+ zebra_mac_t *new_zmac,
+ zebra_neigh_t *nbr)
+{
+ bool is_old_mac_dup = false;
+ bool is_new_mac_dup = false;
+
+ if (!zvrf->dup_addr_detect)
+ return 0;
+ /* Check old or new MAC is detected as duplicate
+ * mark this neigh as duplicate
+ */
+ if (old_zmac)
+ is_old_mac_dup =
+ CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE);
+ if (new_zmac)
+ is_new_mac_dup =
+ CHECK_FLAG(new_zmac->flags, ZEBRA_MAC_DUPLICATE);
+ /* Old and/or new MAC can be in duplicate state,
+ * based on that IP/Neigh Inherits the flag.
+ * If New MAC is marked duplicate, inherit to the IP.
+ * If old MAC is duplicate but new MAC is not, clear
+ * duplicate flag for IP and reset detection params
+ * and let IP DAD retrigger.
+ */
+ if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
+ SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+ /* Capture Duplicate detection time */
+ nbr->dad_dup_detect_time = monotime(NULL);
+ /* Mark neigh inactive */
+ ZEBRA_NEIGH_SET_INACTIVE(nbr);
+
+ return 1;
+ } else if (is_old_mac_dup && !is_new_mac_dup) {
+ UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+ nbr->dad_count = 0;
+ nbr->detect_start_time.tv_sec = 0;
+ nbr->detect_start_time.tv_usec = 0;
+ }
+ return 0;
+}
+
+static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t)
+{
+ struct zebra_vrf *zvrf = NULL;
+ zebra_neigh_t *nbr = NULL;
+ zebra_evpn_t *zevpn = NULL;
+ char buf1[INET6_ADDRSTRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
+
+ nbr = THREAD_ARG(t);
+
+ /* since this is asynchronous we need sanity checks*/
+ zvrf = vrf_info_lookup(nbr->zevpn->vrf_id);
+ if (!zvrf)
+ return 0;
+
+ zevpn = zebra_evpn_lookup(nbr->zevpn->vni);
+ if (!zevpn)
+ return 0;
+
+ nbr = zebra_evpn_neigh_lookup(zevpn, &nbr->ip);
+ if (!nbr)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired",
+ __func__,
+ prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), nbr->flags,
+ nbr->dad_count, zevpn->vni);
+
+ UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+ nbr->dad_count = 0;
+ nbr->detect_start_time.tv_sec = 0;
+ nbr->detect_start_time.tv_usec = 0;
+ nbr->dad_dup_detect_time = 0;
+ nbr->dad_ip_auto_recovery_timer = NULL;
+ ZEBRA_NEIGH_SET_ACTIVE(nbr);
+
+ /* Send to BGP */
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
+ zebra_evpn_neigh_send_add_to_client(zevpn->vni, &nbr->ip,
+ &nbr->emac, nbr->mac,
+ nbr->flags, nbr->loc_seq);
+ } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/);
+ }
+
+ return 0;
+}
+
+static void
+zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr,
+ struct in_addr vtep_ip, bool do_dad,
+ bool *is_dup_detect, bool is_local)
+{
+
+ struct timeval elapsed = {0, 0};
+ char buf[ETHER_ADDR_STRLEN];
+ char buf1[INET6_ADDRSTRLEN];
+ bool reset_params = false;
+
+ if (!zvrf->dup_addr_detect)
+ return;
+
+ /* IP is detected as duplicate or inherit dup
+ * state, hold on to install as remote entry
+ * only if freeze is enabled.
+ */
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s IP %s flags 0x%x skip installing, learn count %u recover time %u",
+ __func__,
+ prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+ nbr->flags, nbr->dad_count,
+ zvrf->dad_freeze_time);
+
+ if (zvrf->dad_freeze)
+ *is_dup_detect = true;
+
+ /* warn-only action, neigh will be installed.
+ * freeze action, it wil not be installed.
+ */
+ return;
+ }
+
+ if (!do_dad)
+ return;
+
+ /* Check if detection time (M-secs) expired.
+ * Reset learn count and detection start time.
+ * During remote mac add, count should already be 1
+ * via local learning.
+ */
+ monotime_since(&nbr->detect_start_time, &elapsed);
+ reset_params = (elapsed.tv_sec > zvrf->dad_time);
+
+ if (is_local && !reset_params) {
+ /* RFC-7432: A PE/VTEP that detects a MAC mobility
+ * event via LOCAL learning starts an M-second timer.
+ *
+ * NOTE: This is the START of the probe with count is
+ * 0 during LOCAL learn event.
+ */
+ reset_params = !nbr->dad_count;
+ }
+
+ if (reset_params) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u",
+ __func__,
+ prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+ nbr->flags, nbr->dad_count);
+ /* Reset learn count but do not start detection
+ * during REMOTE learn event.
+ */
+ nbr->dad_count = 0;
+ /* Start dup. addr detection (DAD) start time,
+ * ONLY during LOCAL learn.
+ */
+ if (is_local)
+ monotime(&nbr->detect_start_time);
+
+ } else if (!is_local) {
+ /* For REMOTE IP/Neigh, increment detection count
+ * ONLY while in probe window, once window passed,
+ * next local learn event should trigger DAD.
+ */
+ nbr->dad_count++;
+ }
+
+ /* For LOCAL IP/Neigh learn event, once count is reset above via either
+ * initial/start detection time or passed the probe time, the count
+ * needs to be incremented.
+ */
+ if (is_local)
+ nbr->dad_count++;
+
+ if (nbr->dad_count >= zvrf->dad_max_moves) {
+ flog_warn(
+ EC_ZEBRA_DUP_IP_DETECTED,
+ "VNI %u: MAC %s IP %s detected as duplicate during %s VTEP %s",
+ nbr->zevpn->vni,
+ prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
+ ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
+ is_local ? "local update, last" : "remote update, from",
+ inet_ntoa(vtep_ip));
+
+ SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+
+ /* Capture Duplicate detection time */
+ nbr->dad_dup_detect_time = monotime(NULL);
+
+ /* Start auto recovery timer for this IP */
+ THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
+ if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start",
+ __func__,
+ prefix_mac2str(&nbr->emac, buf,
+ sizeof(buf)),
+ ipaddr2str(&nbr->ip, buf1,
+ sizeof(buf1)),
+ nbr->flags, zvrf->dad_freeze_time);
+
+ thread_add_timer(zrouter.master,
+ zebra_evpn_dad_ip_auto_recovery_exp,
+ nbr, zvrf->dad_freeze_time,
+ &nbr->dad_ip_auto_recovery_timer);
+ }
+ if (zvrf->dad_freeze)
+ *is_dup_detect = true;
+ }
+}
+
+int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
+ struct ipaddr *ip, struct ethaddr *macaddr,
+ bool is_router, bool local_inactive,
+ bool dp_static)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ struct zebra_vrf *zvrf;
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *zmac = NULL, *old_zmac = NULL;
+ uint32_t old_mac_seq = 0, mac_new_seq = 0;
+ bool upd_mac_seq = false;
+ bool neigh_mac_change = false;
+ bool neigh_on_hold = false;
+ bool neigh_was_remote = false;
+ bool do_dad = false;
+ struct in_addr vtep_ip = {.s_addr = 0};
+ bool inform_dataplane = false;
+ bool created = false;
+ bool new_static = false;
+ bool old_bgp_ready = false;
+ bool new_bgp_ready;
+
+ /* Check if the MAC exists. */
+ zmac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!zmac) {
+ /* create a dummy MAC if the MAC is not already present */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("AUTO MAC %s created for neigh %s on VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ zevpn->vni);
+
+ zmac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!zmac) {
+ zlog_debug("Failed to add MAC %s VNI %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zevpn->vni);
+ return -1;
+ }
+
+ memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
+ memset(&zmac->flags, 0, sizeof(uint32_t));
+ SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ } else {
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
+ /*
+ * We don't change the MAC to local upon a neighbor
+ * learn event, we wait for the explicit local MAC
+ * learn. However, we have to compute its sequence
+ * number in preparation for when it actually turns
+ * local.
+ */
+ upd_mac_seq = true;
+ }
+ }
+
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+ if (!zvrf) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(" Unable to find vrf for: %d",
+ zevpn->vxlan_if->vrf_id);
+ return -1;
+ }
+
+ /* Check if the neighbor exists. */
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
+ if (!n) {
+ /* New neighbor - create */
+ n = zebra_evpn_neigh_add(zevpn, ip, macaddr, zmac, 0);
+ if (!n) {
+ flog_err(
+ EC_ZEBRA_MAC_ADD_FAILED,
+ "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, zevpn->vni);
+ return -1;
+ }
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ created = true;
+ } else {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ bool mac_different;
+ bool cur_is_router;
+ bool old_local_inactive;
+
+ old_local_inactive = !!CHECK_FLAG(
+ n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+
+ old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+
+ /* Note any changes and see if of interest to BGP. */
+ mac_different = !!memcmp(&n->emac, macaddr, ETH_ALEN);
+ cur_is_router =
+ !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ new_static = zebra_evpn_neigh_is_static(n);
+ if (!mac_different && is_router == cur_is_router
+ && old_local_inactive == local_inactive
+ && dp_static != new_static) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ " Ignoring entry mac is the same and is_router == cur_is_router");
+ n->ifindex = ifp->ifindex;
+ return 0;
+ }
+
+ old_zmac = n->mac;
+ if (!mac_different) {
+ /* XXX - cleanup this code duplication */
+ bool is_neigh_freezed = false;
+
+ /* Only the router flag has changed. */
+ if (is_router)
+ SET_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags,
+ ZEBRA_NEIGH_ROUTER_FLAG);
+
+ if (local_inactive)
+ SET_FLAG(n->flags,
+ ZEBRA_NEIGH_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(n->flags,
+ ZEBRA_NEIGH_LOCAL_INACTIVE);
+ new_bgp_ready =
+ zebra_evpn_neigh_is_ready_for_bgp(n);
+
+ /* Neigh is in freeze state and freeze action
+ * is enabled, do not send update to client.
+ */
+ is_neigh_freezed =
+ (zvrf->dup_addr_detect
+ && zvrf->dad_freeze
+ && CHECK_FLAG(n->flags,
+ ZEBRA_NEIGH_DUPLICATE));
+
+ zebra_evpn_local_neigh_update_log(
+ "local", n, is_router, local_inactive,
+ old_bgp_ready, new_bgp_ready, false,
+ false, "flag-update");
+
+ /* if the neigh can no longer be advertised
+ * remove it from bgp
+ */
+ if (!is_neigh_freezed) {
+ zebra_evpn_neigh_send_add_del_to_client(
+ n, old_bgp_ready,
+ new_bgp_ready);
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN
+ && IS_ZEBRA_NEIGH_ACTIVE(n))
+ zlog_debug(
+ " Neighbor active and frozen");
+ }
+ return 0;
+ }
+
+ /* The MAC has changed, need to issue a delete
+ * first as this means a different MACIP route.
+ * Also, need to do some unlinking/relinking.
+ * We also need to update the MAC's sequence number
+ * in different situations.
+ */
+ if (old_bgp_ready) {
+ zebra_evpn_neigh_send_del_to_client(
+ zevpn->vni, &n->ip, &n->emac, n->flags,
+ n->state, false /*force*/);
+ old_bgp_ready = false;
+ }
+ if (old_zmac) {
+ old_mac_seq = CHECK_FLAG(old_zmac->flags,
+ ZEBRA_MAC_REMOTE)
+ ? old_zmac->rem_seq
+ : old_zmac->loc_seq;
+ neigh_mac_change = upd_mac_seq = true;
+ zebra_evpn_local_neigh_deref_mac(
+ n, true /* send_mac_update */);
+ }
+
+ /* if mac changes abandon peer flags and tell
+ * dataplane to clear the static flag
+ */
+ if (zebra_evpn_neigh_clear_sync_info(n))
+ inform_dataplane = true;
+ /* Update the forwarding info. */
+ n->ifindex = ifp->ifindex;
+
+ /* Link to new MAC */
+ zebra_evpn_local_neigh_ref_mac(
+ n, macaddr, zmac, true /* send_mac_update */);
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ /*
+ * Neighbor has moved from remote to local. Its
+ * MAC could have also changed as part of the move.
+ */
+ if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN)
+ != 0) {
+ old_zmac = n->mac;
+ if (old_zmac) {
+ old_mac_seq =
+ CHECK_FLAG(old_zmac->flags,
+ ZEBRA_MAC_REMOTE)
+ ? old_zmac->rem_seq
+ : old_zmac->loc_seq;
+ neigh_mac_change = upd_mac_seq = true;
+ zebra_evpn_local_neigh_deref_mac(
+ n, true /* send_update */);
+ }
+
+ /* Link to new MAC */
+ zebra_evpn_local_neigh_ref_mac(
+ n, macaddr, zmac, true /*send_update*/);
+ }
+ /* Based on Mobility event Scenario-B from the
+ * draft, neigh's previous state was remote treat this
+ * event for DAD.
+ */
+ neigh_was_remote = true;
+ vtep_ip = n->r_vtep_ip;
+ /* Mark appropriately */
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+ n->r_vtep_ip.s_addr = INADDR_ANY;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ n->ifindex = ifp->ifindex;
+ }
+ }
+
+ /* If MAC was previously remote, or the neighbor had a different
+ * MAC earlier, recompute the sequence number.
+ */
+ if (upd_mac_seq) {
+ uint32_t seq1, seq2;
+
+ seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)
+ ? zmac->rem_seq + 1
+ : zmac->loc_seq;
+ seq2 = neigh_mac_change ? old_mac_seq + 1 : 0;
+ mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ? MAX(seq1, seq2)
+ : zmac->loc_seq;
+ }
+
+ if (local_inactive)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+
+ /* Mark Router flag (R-bit) */
+ if (is_router)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ 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;
+ }
+
+ /* Check old and/or new MAC detected as duplicate mark
+ * the neigh as duplicate
+ */
+ if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) {
+ flog_warn(
+ EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
+ "VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC",
+ zevpn->vni, prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ }
+
+ /* For IP Duplicate Address Detection (DAD) is trigger,
+ * when the event is extended mobility based on scenario-B
+ * from the draft, IP/Neigh's MAC binding changed and
+ * neigh's previous state was remote.
+ */
+ if (neigh_mac_change && neigh_was_remote)
+ do_dad = true;
+
+ zebra_evpn_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad,
+ &neigh_on_hold, true);
+
+ if (inform_dataplane)
+ zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ /* Before we program this in BGP, we need to check if MAC is locally
+ * learnt. If not, force neighbor to be inactive and reset its seq.
+ */
+ if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
+ zebra_evpn_local_neigh_update_log(
+ "local", n, is_router, local_inactive, false, false,
+ inform_dataplane, false, "auto-mac");
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+ n->loc_seq = 0;
+ zmac->loc_seq = mac_new_seq;
+ return 0;
+ }
+
+ zebra_evpn_local_neigh_update_log("local", n, is_router, local_inactive,
+ false, false, inform_dataplane, true,
+ created ? "created" : "updated");
+
+ /* If the MAC's sequence number has changed, inform the MAC and all
+ * neighbors associated with the MAC to BGP, else just inform this
+ * neighbor.
+ */
+ if (upd_mac_seq && zmac->loc_seq != mac_new_seq) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Seq changed for MAC %s VNI %u - old %u new %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zevpn->vni, zmac->loc_seq, mac_new_seq);
+ zmac->loc_seq = mac_new_seq;
+ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, macaddr,
+ zmac->flags,
+ zmac->loc_seq, zmac->es))
+ return -1;
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, zmac, 1,
+ 0 /*es_change*/);
+ return 0;
+ }
+
+ n->loc_seq = zmac->loc_seq;
+
+ if (!neigh_on_hold) {
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready,
+ new_bgp_ready);
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(" Neighbor on hold not sending");
+ }
+ return 0;
+}
+
+int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
+ struct ipaddr *ip, struct ethaddr *macaddr,
+ uint16_t state)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ zebra_neigh_t *n = NULL;
+ zebra_mac_t *zmac = NULL;
+
+ /* If the neighbor is unknown, there is no further action. */
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
+ if (!n)
+ return 0;
+
+ /* If a remote entry, see if it needs to be refreshed */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+#ifdef GNU_LINUX
+ if (state & NUD_STALE)
+ zebra_evpn_rem_neigh_install(zevpn, n,
+ false /*was_static*/);
+#endif
+ } else {
+ /* We got a "remote" neighbor notification for an entry
+ * we think is local. This can happen in a multihoming
+ * scenario - but only if the MAC is already "remote".
+ * Just mark our entry as "remote".
+ */
+ zmac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
+ zlog_debug(
+ "Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zevpn->vni);
+ return -1;
+ }
+
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
+ SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
+ }
+
+ return 0;
+}
+
+/* Notify Neighbor entries to the Client, skips the GW entry */
+static void
+zebra_evpn_send_neigh_hash_entry_to_client(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct mac_walk_ctx *wctx = arg;
+ zebra_neigh_t *zn = bucket->data;
+ zebra_mac_t *zmac = NULL;
+
+ if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW))
+ return;
+
+ if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL)
+ && IS_ZEBRA_NEIGH_ACTIVE(zn)) {
+ zmac = zebra_evpn_mac_lookup(wctx->zevpn, &zn->emac);
+ if (!zmac)
+ return;
+
+ zebra_evpn_neigh_send_add_to_client(wctx->zevpn->vni, &zn->ip,
+ &zn->emac, zn->mac,
+ zn->flags, zn->loc_seq);
+ }
+}
+
+/* Iterator of a specific EVPN */
+void zebra_evpn_send_neigh_to_client(zebra_evpn_t *zevpn)
+{
+ struct neigh_walk_ctx wctx;
+
+ memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+ wctx.zevpn = zevpn;
+
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_send_neigh_hash_entry_to_client, &wctx);
+}
+
+void zebra_evpn_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ struct neigh_walk_ctx *wctx = ctxt;
+ zebra_neigh_t *nbr;
+ zebra_evpn_t *zevpn;
+ char buf[INET6_ADDRSTRLEN];
+
+ nbr = (zebra_neigh_t *)bucket->data;
+ if (!nbr)
+ return;
+
+ zevpn = wctx->zevpn;
+
+ if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+ return;
+
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ ipaddr2str(&nbr->ip, buf, sizeof(buf));
+ zlog_debug("%s: clear neigh %s dup state, flags 0x%x seq %u",
+ __func__, buf, nbr->flags, nbr->loc_seq);
+ }
+
+ UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
+ nbr->dad_count = 0;
+ nbr->detect_start_time.tv_sec = 0;
+ nbr->detect_start_time.tv_usec = 0;
+ nbr->dad_dup_detect_time = 0;
+ THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
+
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
+ zebra_evpn_neigh_send_add_to_client(zevpn->vni, &nbr->ip,
+ &nbr->emac, nbr->mac,
+ nbr->flags, nbr->loc_seq);
+ } else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/);
+ }
+}
+
+/*
+ * Print a specific neighbor entry.
+ */
+void zebra_evpn_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
+{
+ struct vty *vty;
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ const char *type_str;
+ const char *state_str;
+ bool flags_present = false;
+ struct zebra_vrf *zvrf = NULL;
+ struct timeval detect_start_time = {0, 0};
+ char timebuf[MONOTIME_STRLEN];
+ char thread_buf[THREAD_TIMER_STRLEN];
+
+ zvrf = zebra_vrf_get_evpn();
+ if (!zvrf)
+ return;
+
+ ipaddr2str(&n->ip, buf2, sizeof(buf2));
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1));
+ type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ? "local" : "remote";
+ state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
+ vty = (struct vty *)ctxt;
+ if (json == NULL) {
+ bool sync_info = false;
+
+ vty_out(vty, "IP: %s\n",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ vty_out(vty, " Type: %s\n", type_str);
+ vty_out(vty, " State: %s\n", state_str);
+ vty_out(vty, " MAC: %s\n",
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+ vty_out(vty, " Sync-info:");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
+ vty_out(vty, " local-inactive");
+ sync_info = true;
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY)) {
+ vty_out(vty, " peer-proxy");
+ sync_info = true;
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
+ vty_out(vty, " peer-active");
+ sync_info = true;
+ }
+ if (n->hold_timer) {
+ vty_out(vty, " (ht: %s)",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ n->hold_timer));
+ sync_info = true;
+ }
+ if (!sync_info)
+ vty_out(vty, " -");
+ vty_out(vty, "\n");
+ } else {
+ json_object_string_add(json, "ip", buf2);
+ json_object_string_add(json, "type", type_str);
+ json_object_string_add(json, "state", state_str);
+ json_object_string_add(json, "mac", buf1);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ json_object_boolean_true_add(json, "localInactive");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY))
+ json_object_boolean_true_add(json, "peerProxy");
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
+ json_object_boolean_true_add(json, "peerActive");
+ if (n->hold_timer)
+ json_object_string_add(
+ json, "peerActiveHold",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ n->hold_timer));
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ if (n->mac->es) {
+ if (json)
+ json_object_string_add(json, "remoteEs",
+ n->mac->es->esi_str);
+ else
+ vty_out(vty, " Remote ES: %s\n",
+ n->mac->es->esi_str);
+ } else {
+ if (json)
+ json_object_string_add(json, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ else
+ vty_out(vty, " Remote VTEP: %s\n",
+ inet_ntoa(n->r_vtep_ip));
+ }
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
+ if (!json) {
+ vty_out(vty, " Flags: Default-gateway");
+ flags_present = true;
+ } else
+ json_object_boolean_true_add(json, "defaultGateway");
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) {
+ if (!json) {
+ vty_out(vty,
+ flags_present ? " ,Router" : " Flags: Router");
+ flags_present = true;
+ }
+ }
+ if (json == NULL) {
+ if (flags_present)
+ vty_out(vty, "\n");
+ vty_out(vty, " Local Seq: %u Remote Seq: %u\n", n->loc_seq,
+ n->rem_seq);
+
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
+ vty_out(vty, " Duplicate, detected at %s",
+ time_to_string(n->dad_dup_detect_time,
+ timebuf));
+ } else if (n->dad_count) {
+ monotime_since(&n->detect_start_time,
+ &detect_start_time);
+ if (detect_start_time.tv_sec <= zvrf->dad_time) {
+ time_to_string(n->detect_start_time.tv_sec,
+ timebuf);
+ vty_out(vty,
+ " Duplicate detection started at %s, detection count %u\n",
+ timebuf, n->dad_count);
+ }
+ }
+ } else {
+ json_object_int_add(json, "localSequence", n->loc_seq);
+ json_object_int_add(json, "remoteSequence", n->rem_seq);
+ json_object_int_add(json, "detectionCount", n->dad_count);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+ json_object_boolean_true_add(json, "isDuplicate");
+ else
+ json_object_boolean_false_add(json, "isDuplicate");
+ }
+}
+
+void zebra_evpn_print_neigh_hdr(struct vty *vty, struct neigh_walk_ctx *wctx)
+{
+ vty_out(vty, "Flags: I=local-inactive, P=peer-active, X=peer-proxy\n");
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %s\n", -wctx->addr_width,
+ "Neighbor", "Type", "Flags", "State", "MAC", "Remote ES/VTEP",
+ "Seq #'s");
+}
+
+static char *zebra_evpn_print_neigh_flags(zebra_neigh_t *n, char *flags_buf,
+ uint32_t flags_buf_sz)
+{
+ snprintf(flags_buf, flags_buf_sz, "%s%s%s",
+ (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE) ?
+ "P" : "",
+ (n->flags & ZEBRA_NEIGH_ES_PEER_PROXY) ?
+ "X" : "",
+ (n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ?
+ "I" : "");
+
+ return flags_buf;
+}
+
+/*
+ * Print neighbor hash entry - called for display of all neighbors.
+ */
+void zebra_evpn_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ struct vty *vty;
+ json_object *json_evpn = NULL, *json_row = NULL;
+ zebra_neigh_t *n;
+ char buf1[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+ struct neigh_walk_ctx *wctx = ctxt;
+ const char *state_str;
+ char flags_buf[6];
+
+ vty = wctx->vty;
+ json_evpn = wctx->json;
+ n = (zebra_neigh_t *)bucket->data;
+
+ if (json_evpn)
+ json_row = json_object_new_object();
+
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1));
+ ipaddr2str(&n->ip, buf2, sizeof(buf2));
+ state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
+ return;
+
+ if (json_evpn == NULL) {
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
+ -wctx->addr_width, buf2, "local",
+ zebra_evpn_print_neigh_flags(n, flags_buf,
+ sizeof(flags_buf)), state_str, buf1,
+ "", n->loc_seq, n->rem_seq);
+ } else {
+ json_object_string_add(json_row, "type", "local");
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "mac", buf1);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
+ json_object_boolean_true_add(json_row,
+ "defaultGateway");
+ json_object_int_add(json_row, "localSequence",
+ n->loc_seq);
+ json_object_int_add(json_row, "remoteSequence",
+ n->rem_seq);
+ json_object_int_add(json_row, "detectionCount",
+ n->dad_count);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+ json_object_boolean_true_add(json_row,
+ "isDuplicate");
+ else
+ json_object_boolean_false_add(json_row,
+ "isDuplicate");
+ }
+ wctx->count++;
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
+ && !IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))
+ return;
+
+ if (json_evpn == NULL) {
+ if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
+ && (wctx->count == 0))
+ zebra_evpn_print_neigh_hdr(vty, wctx);
+ vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
+ -wctx->addr_width, buf2, "remote",
+ zebra_evpn_print_neigh_flags(n, flags_buf,
+ sizeof(flags_buf)), state_str, buf1,
+ n->mac->es ? n->mac->es->esi_str
+ : inet_ntoa(n->r_vtep_ip),
+ n->loc_seq, n->rem_seq);
+ } else {
+ json_object_string_add(json_row, "type", "remote");
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "mac", buf1);
+ if (n->mac->es)
+ json_object_string_add(json_row, "remoteEs",
+ n->mac->es->esi_str);
+ else
+ json_object_string_add(json_row, "remoteVtep",
+ inet_ntoa(n->r_vtep_ip));
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
+ json_object_boolean_true_add(json_row,
+ "defaultGateway");
+ json_object_int_add(json_row, "localSequence",
+ n->loc_seq);
+ json_object_int_add(json_row, "remoteSequence",
+ n->rem_seq);
+ json_object_int_add(json_row, "detectionCount",
+ n->dad_count);
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+ json_object_boolean_true_add(json_row,
+ "isDuplicate");
+ else
+ json_object_boolean_false_add(json_row,
+ "isDuplicate");
+ }
+ wctx->count++;
+ }
+
+ if (json_evpn)
+ json_object_object_add(json_evpn, buf2, json_row);
+}
+
+/*
+ * Print neighbor hash entry in detail - called for display of all neighbors.
+ */
+void zebra_evpn_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt)
+{
+ struct vty *vty;
+ json_object *json_evpn = NULL, *json_row = NULL;
+ zebra_neigh_t *n;
+ char buf[INET6_ADDRSTRLEN];
+ struct neigh_walk_ctx *wctx = ctxt;
+
+ vty = wctx->vty;
+ json_evpn = wctx->json;
+ n = (zebra_neigh_t *)bucket->data;
+ if (!n)
+ return;
+
+ ipaddr2str(&n->ip, buf, sizeof(buf));
+ if (json_evpn)
+ json_row = json_object_new_object();
+
+ zebra_evpn_print_neigh(n, vty, json_row);
+
+ if (json_evpn)
+ json_object_object_add(json_evpn, buf, json_row);
+}
+
+void zebra_evpn_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt)
+{
+ zebra_neigh_t *nbr;
+
+ nbr = (zebra_neigh_t *)bucket->data;
+ if (!nbr)
+ return;
+
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+ zebra_evpn_print_neigh_hash(bucket, ctxt);
+}
+
+void zebra_evpn_print_dad_neigh_hash_detail(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ zebra_neigh_t *nbr;
+
+ nbr = (zebra_neigh_t *)bucket->data;
+ if (!nbr)
+ return;
+
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
+ zebra_evpn_print_neigh_hash_detail(bucket, ctxt);
+}
+
+void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
+ struct ipaddr *ipaddr, zebra_mac_t *mac,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq)
+{
+ 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;
+ bool old_static = false;
+ bool do_dad = false;
+ bool is_dup_detect = false;
+ bool is_router;
+
+ assert(mac);
+ is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+
+ /* Check if the remote neighbor itself is unknown or has a
+ * change. If so, create or update and then install the entry.
+ */
+ n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
+ if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
+ || (memcmp(&n->emac, &mac->macaddr, sizeof(struct ethaddr)) != 0)
+ || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip) || seq != n->rem_seq)
+ update_neigh = 1;
+
+ if (update_neigh) {
+ if (!n) {
+ n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr,
+ mac, 0);
+ if (!n) {
+ zlog_warn(
+ "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
+ prefix_mac2str(&mac->macaddr, buf,
+ sizeof(buf)),
+ zevpn->vni, inet_ntoa(vtep_ip));
+ return;
+ }
+
+ } 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
+ * in transient situations (because {IP1,M1}
+ * is a different route from {IP1,M2}). Check
+ * 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);
+ return;
+ }
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ old_static = zebra_evpn_neigh_is_static(n);
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug(
+ "sync->remote neigh vni %u ip %s mac %s seq %d f0x%x",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, buf1,
+ sizeof(buf1)),
+ prefix_mac2str(&n->emac, buf,
+ sizeof(buf)),
+ seq, n->flags);
+ zebra_evpn_neigh_clear_sync_info(n);
+ if (IS_ZEBRA_NEIGH_ACTIVE(n))
+ zebra_evpn_mac_send_del_to_client(
+ zevpn->vni, &mac->macaddr,
+ mac->flags, false /*force*/);
+ }
+ if (memcmp(&n->emac, &mac->macaddr,
+ sizeof(struct ethaddr))
+ != 0) {
+ /* update neigh list for macs */
+ old_mac =
+ zebra_evpn_mac_lookup(zevpn, &n->emac);
+ if (old_mac) {
+ listnode_delete(old_mac->neigh_list, n);
+ n->mac = NULL;
+ zebra_evpn_deref_ip2mac(zevpn, old_mac);
+ }
+ n->mac = mac;
+ listnode_add_sort(mac->neigh_list, n);
+ memcpy(&n->emac, &mac->macaddr, ETH_ALEN);
+
+ /* Check Neigh's curent state is local
+ * (this is the case where neigh/host has moved
+ * from L->R) and check previous detction
+ * started via local learning.
+ *
+ * RFC-7432: A PE/VTEP that detects a MAC
+ * mobilit event via local learning starts
+ * an M-second timer.
+ * VTEP-IP or seq. change along is not
+ * considered for dup. detection.
+ *
+ * Mobilty event scenario-B IP-MAC binding
+ * changed.
+ */
+ if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
+ && n->dad_count)
+ do_dad = true;
+ }
+ }
+
+ /* Set "remote" forwarding info. */
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
+ n->r_vtep_ip = vtep_ip;
+ SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+
+ /* Set router flag (R-bit) to this Neighbor entry */
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+ else
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ /* Check old or new MAC detected as duplicate,
+ * inherit duplicate flag to this neigh.
+ */
+ if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_mac, mac, n)) {
+ flog_warn(
+ EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
+ "VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC",
+ zevpn->vni,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ ipaddr2str(&n->ip, buf1, sizeof(buf1)));
+ }
+
+ /* Check duplicate address detection for IP */
+ zebra_evpn_dup_addr_detect_for_neigh(
+ zvrf, n, n->r_vtep_ip, do_dad, &is_dup_detect, false);
+ /* Install the entry. */
+ if (!is_dup_detect)
+ zebra_evpn_rem_neigh_install(zevpn, n, old_static);
+ }
+
+ /* Update seq number. */
+ n->rem_seq = seq;
+}
+
+int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ipaddr *ip, zebra_mac_t *mac)
+{
+ zebra_neigh_t *n;
+ char buf[ETHER_ADDR_STRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ assert(mac);
+
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
+ if (!n) {
+ n = zebra_evpn_neigh_add(zevpn, ip, &mac->macaddr, mac, 0);
+ if (!n) {
+ flog_err(
+ EC_ZEBRA_MAC_ADD_FAILED,
+ "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
+ ipaddr2str(ip, buf2, sizeof(buf2)),
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, zevpn->vni);
+ return -1;
+ }
+ }
+
+ /* Set "local" forwarding info. */
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ ZEBRA_NEIGH_SET_ACTIVE(n);
+ memcpy(&n->emac, &mac->macaddr, ETH_ALEN);
+ n->ifindex = ifp->ifindex;
+
+ /* Only advertise in BGP if the knob is enabled */
+ if (advertise_gw_macip_enabled(zevpn)) {
+
+ SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
+ SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
+ /* Set Router flag (R-bit) */
+ if (ip->ipa_type == IPADDR_V6)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x",
+ ifp->name, ifp->ifindex, zevpn->vni,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
+
+ zebra_evpn_neigh_send_add_to_client(
+ zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq);
+ } else if (advertise_svi_macip_enabled(zevpn)) {
+
+ SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x",
+ ifp->name, ifp->ifindex, zevpn->vni,
+ prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
+
+ zebra_evpn_neigh_send_add_to_client(
+ zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq);
+ }
+
+ return 0;
+}
+
+void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn,
+ struct zebra_vrf *zvrf, zebra_neigh_t *n,
+ zebra_mac_t *mac, struct ipaddr *ipaddr)
+{
+ char buf1[INET6_ADDRSTRLEN];
+
+ if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)
+ && CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ && (memcmp(n->emac.octet, mac->macaddr.octet, ETH_ALEN) == 0)) {
+ struct interface *vlan_if;
+
+ vlan_if = zevpn_map_to_svi(zevpn);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
+ __func__,
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
+ n->flags, vlan_if ? vlan_if->name : "Unknown");
+ if (vlan_if)
+ neigh_read_specific_ip(ipaddr, vlan_if);
+ }
+
+ /* When the MAC changes for an IP, it is possible the
+ * client may update the new MAC before trying to delete the
+ * "old" neighbor (as these are two different MACIP routes).
+ * Do the delete only if the MAC matches.
+ */
+ if (!memcmp(n->emac.octet, mac->macaddr.octet, ETH_ALEN)) {
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
+ zebra_evpn_sync_neigh_del(n);
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_evpn_neigh_uninstall(zevpn, n);
+ zebra_evpn_neigh_del(zevpn, n);
+ zebra_evpn_deref_ip2mac(zevpn, mac);
+ }
+ }
+}
+
+int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip)
+{
+ zebra_neigh_t *n;
+ zebra_mac_t *zmac;
+ bool old_bgp_ready;
+ bool new_bgp_ready;
+ char buf[INET6_ADDRSTRLEN];
+ char buf2[ETHER_ADDR_STRLEN];
+ struct zebra_vrf *zvrf;
+
+ /* If entry doesn't exist, nothing to do. */
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
+ if (!n)
+ return 0;
+
+ zmac = zebra_evpn_mac_lookup(zevpn, &n->emac);
+ if (!zmac) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Trying to del a neigh %s without a mac %s on VNI %u",
+ ipaddr2str(ip, buf, sizeof(buf)),
+ prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
+ zevpn->vni);
+
+ return 0;
+ }
+
+ /* If it is a remote entry, the kernel has aged this out or someone has
+ * deleted it, it needs to be re-installed as Quagga is the owner.
+ */
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
+ zebra_evpn_rem_neigh_install(zevpn, n, false /*was_static*/);
+ return 0;
+ }
+
+ /* if this is a sync entry it cannot be dropped re-install it in
+ * the dataplane
+ */
+ old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ if (zebra_evpn_neigh_is_static(n)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("re-add sync neigh vni %u ip %s mac %s 0x%x",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, buf, sizeof(buf)),
+ prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
+ n->flags);
+
+ if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
+ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
+ /* inform-bgp about change in local-activity if any */
+ new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n);
+ zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready,
+ new_bgp_ready);
+
+ /* re-install the entry in the kernel */
+ zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
+
+ return 0;
+ }
+
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+ if (!zvrf) {
+ zlog_debug("%s: VNI %u vrf lookup failed.", __func__,
+ zevpn->vni);
+ return -1;
+ }
+
+ /* In case of feeze action, if local neigh is in duplicate state,
+ * Mark the Neigh as inactive before sending delete request to BGPd,
+ * If BGPd has remote entry, it will re-install
+ */
+ if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+
+ /* Remove neighbor from BGP. */
+ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac,
+ n->flags, n->state,
+ false /* force */);
+
+ /* Delete this neighbor entry. */
+ zebra_evpn_neigh_del(zevpn, n);
+
+ /* see if the AUTO mac needs to be deleted */
+ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
+ && !listcount(zmac->neigh_list))
+ zebra_evpn_mac_del(zevpn, zmac);
+
+ return 0;
+}
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
new file mode 100644
index 0000000000..4b98266c86
--- /dev/null
+++ b/zebra/zebra_evpn_neigh.h
@@ -0,0 +1,294 @@
+/*
+ * Zebra EVPN Neighbor Data structures and definitions
+ * These are "internal" to this function.
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ * Copyright (C) 2020 Volta Networks.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_EVPN_NEIGH_H
+#define _ZEBRA_EVPN_NEIGH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zebra_neigh_t_ zebra_neigh_t;
+
+#define IS_ZEBRA_NEIGH_ACTIVE(n) (n->state == ZEBRA_NEIGH_ACTIVE)
+
+#define IS_ZEBRA_NEIGH_INACTIVE(n) (n->state == ZEBRA_NEIGH_INACTIVE)
+
+#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE
+
+#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE
+
+/*
+ * Neighbor hash table.
+ *
+ * This table contains the neighbors (IP to MAC bindings) pertaining to
+ * this VNI. This includes local neighbors learnt on the attached VLAN
+ * device that maps to this VNI as well as remote neighbors learnt and
+ * installed by BGP.
+ * Local neighbors will be known against the VLAN device (SVI); however,
+ * it is sufficient for zebra to maintain against the VNI. The correct
+ * VNI will be obtained as zebra maintains the mapping (of VLAN to VNI).
+ */
+struct zebra_neigh_t_ {
+ /* IP address. */
+ struct ipaddr ip;
+
+ /* MAC address. */
+ struct ethaddr emac;
+
+ /* Back pointer to MAC. Only applicable to hosts in a L2-VNI. */
+ zebra_mac_t *mac;
+
+ /* Underlying interface. */
+ ifindex_t ifindex;
+
+ zebra_evpn_t *zevpn;
+
+ uint32_t flags;
+#define ZEBRA_NEIGH_LOCAL 0x01
+#define ZEBRA_NEIGH_REMOTE 0x02
+#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */
+#define ZEBRA_NEIGH_DEF_GW 0x08
+#define ZEBRA_NEIGH_ROUTER_FLAG 0x10
+#define ZEBRA_NEIGH_DUPLICATE 0x20
+#define ZEBRA_NEIGH_SVI_IP 0x40
+/* rxed from an ES peer */
+#define ZEBRA_NEIGH_ES_PEER_ACTIVE 0x80
+/* rxed from an ES peer as a proxy advertisement */
+#define ZEBRA_NEIGH_ES_PEER_PROXY 0x100
+/* We have not been able to independently establish that the host
+ * is local connected
+ */
+#define ZEBRA_NEIGH_LOCAL_INACTIVE 0x200
+#define ZEBRA_NEIGH_ALL_LOCAL_FLAGS \
+ (ZEBRA_NEIGH_LOCAL | ZEBRA_NEIGH_LOCAL_INACTIVE)
+#define ZEBRA_NEIGH_ALL_PEER_FLAGS \
+ (ZEBRA_NEIGH_ES_PEER_PROXY | ZEBRA_NEIGH_ES_PEER_ACTIVE)
+
+ enum zebra_neigh_state state;
+
+ /* Remote VTEP IP - applicable only for remote neighbors. */
+ struct in_addr r_vtep_ip;
+
+ /*
+ * Mobility sequence numbers associated with this entry. The rem_seq
+ * represents the sequence number from the client (BGP) for the most
+ * recent add or update of this entry while the loc_seq represents
+ * the sequence number informed (or to be informed) by zebra to BGP
+ * for this entry.
+ */
+ uint32_t rem_seq;
+ uint32_t loc_seq;
+
+ /* list of hosts pointing to this remote NH entry */
+ struct host_rb_tree_entry host_rb;
+
+ /* Duplicate ip detection */
+ uint32_t dad_count;
+
+ struct thread *dad_ip_auto_recovery_timer;
+
+ struct timeval detect_start_time;
+
+ time_t dad_dup_detect_time;
+
+ /* used for ageing out the PEER_ACTIVE flag */
+ struct thread *hold_timer;
+};
+
+/*
+ * Context for neighbor hash walk - used by callbacks.
+ */
+struct neigh_walk_ctx {
+ zebra_evpn_t *zevpn; /* VNI hash */
+ struct zebra_vrf *zvrf; /* VRF - for client notification. */
+ int uninstall; /* uninstall from kernel? */
+ int upd_client; /* uninstall from client? */
+
+ uint32_t flags;
+#define DEL_LOCAL_NEIGH 0x1
+#define DEL_REMOTE_NEIGH 0x2
+#define DEL_ALL_NEIGH (DEL_LOCAL_NEIGH | DEL_REMOTE_NEIGH)
+#define DEL_REMOTE_NEIGH_FROM_VTEP 0x4
+#define SHOW_REMOTE_NEIGH_FROM_VTEP 0x8
+
+ struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */
+
+ struct vty *vty; /* Used by VTY handlers */
+ uint32_t count; /* Used by VTY handlers */
+ uint8_t addr_width; /* Used by VTY handlers */
+ struct json_object *json; /* Used for JSON Output */
+};
+
+/**************************** SYNC neigh handling **************************/
+static inline bool zebra_evpn_neigh_is_static(zebra_neigh_t *neigh)
+{
+ return !!(neigh->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS);
+}
+
+static inline bool zebra_evpn_neigh_is_ready_for_bgp(zebra_neigh_t *n)
+{
+ bool mac_ready;
+ bool neigh_ready;
+
+ mac_ready = !!(n->mac->flags & ZEBRA_MAC_LOCAL);
+ neigh_ready =
+ ((n->flags & ZEBRA_NEIGH_LOCAL) && IS_ZEBRA_NEIGH_ACTIVE(n)
+ && (!(n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE)
+ || (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE)))
+ ? true
+ : false;
+
+ return mac_ready && neigh_ready;
+}
+
+static inline void zebra_evpn_neigh_stop_hold_timer(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+
+ if (!n->hold_timer)
+ return;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold stop",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
+ n->flags);
+ THREAD_OFF(n->hold_timer);
+}
+
+void zebra_evpn_sync_neigh_static_chg(zebra_neigh_t *n, bool old_n_static,
+ bool new_n_static, bool defer_n_dp,
+ bool defer_mac_dp, const char *caller);
+
+static inline bool zebra_evpn_neigh_clear_sync_info(zebra_neigh_t *n)
+{
+ char macbuf[ETHER_ADDR_STRLEN];
+ char ipbuf[INET6_ADDRSTRLEN];
+ bool old_n_static = false;
+ bool new_n_static = false;
+
+ if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
+ zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x clear",
+ n->zevpn->vni,
+ ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
+ prefix_mac2str(&n->emac, macbuf,
+ sizeof(macbuf)),
+ n->flags);
+
+ old_n_static = zebra_evpn_neigh_is_static(n);
+ UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_PEER_FLAGS);
+ new_n_static = zebra_evpn_neigh_is_static(n);
+ if (old_n_static != new_n_static)
+ zebra_evpn_sync_neigh_static_chg(
+ n, old_n_static, new_n_static,
+ true /*defer_dp)*/, false /*defer_mac_dp*/,
+ __func__);
+ }
+ zebra_evpn_neigh_stop_hold_timer(n);
+
+ /* if the neigh static flag changed inform that a dp
+ * re-install maybe needed
+ */
+ return old_n_static != new_n_static;
+}
+
+int remote_neigh_count(zebra_mac_t *zmac);
+
+int neigh_list_cmp(void *p1, void *p2);
+struct hash *zebra_neigh_db_create(const char *desc);
+uint32_t num_dup_detected_neighs(zebra_evpn_t *zevpn);
+void zebra_evpn_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt);
+int remote_neigh_count(zebra_mac_t *zmac);
+int zebra_evpn_rem_neigh_install(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ bool was_static);
+void zebra_evpn_install_neigh_hash(struct hash_bucket *bucket, void *ctxt);
+int zebra_evpn_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
+ struct ethaddr *macaddr,
+ zebra_mac_t *zmac, uint32_t neigh_flags,
+ uint32_t seq);
+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);
+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 *
+zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ uint16_t ipa_len, struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq, esi_t *esi,
+ struct sync_mac_ip_ctx *ctx);
+void zebra_evpn_neigh_del_all(zebra_evpn_t *zevpn, int uninstall,
+ int upd_client, uint32_t flags);
+zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, struct ipaddr *ip);
+
+int zebra_evpn_rem_neigh_install(zebra_evpn_t *zevpn, zebra_neigh_t *n,
+ bool was_static);
+void zebra_evpn_process_neigh_on_remote_mac_add(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac);
+void zebra_evpn_process_neigh_on_local_mac_del(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac);
+void zebra_evpn_process_neigh_on_local_mac_change(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac,
+ bool seq_change,
+ bool es_change);
+void zebra_evpn_process_neigh_on_remote_mac_del(zebra_evpn_t *zevpn,
+ zebra_mac_t *zmac);
+int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
+ struct ipaddr *ip, struct ethaddr *macaddr,
+ bool is_router, bool local_inactive,
+ bool dp_static);
+int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp,
+ struct ipaddr *ip, struct ethaddr *macaddr,
+ uint16_t state);
+void zebra_evpn_send_neigh_to_client(zebra_evpn_t *zevpn);
+void zebra_evpn_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
+void zebra_evpn_print_neigh_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_neigh_hdr(struct vty *vty, struct neigh_walk_ctx *wctx);
+void zebra_evpn_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_print_dad_neigh_hash_detail(struct hash_bucket *bucket,
+ void *ctxt);
+void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
+ struct ipaddr *ipaddr, zebra_mac_t *mac,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq);
+int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
+ struct ipaddr *ip, zebra_mac_t *mac);
+void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn,
+ struct zebra_vrf *zvrf, zebra_neigh_t *n,
+ zebra_mac_t *mac, struct ipaddr *ipaddr);
+int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_ZEBRA_EVPN_NEIGH_H */
diff --git a/zebra/zebra_evpn_vxlan.h b/zebra/zebra_evpn_vxlan.h
new file mode 100644
index 0000000000..bf8904d492
--- /dev/null
+++ b/zebra/zebra_evpn_vxlan.h
@@ -0,0 +1,71 @@
+/*
+ * Zebra EVPN for VxLAN code
+ * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/* Get the VRR interface for SVI if any */
+static inline struct interface *
+zebra_get_vrr_intf_for_svi(struct interface *ifp)
+{
+ struct zebra_vrf *zvrf = NULL;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif = NULL;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
+ assert(zvrf);
+
+ FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) {
+ zif = tmp_if->info;
+ if (!zif)
+ continue;
+
+ if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
+ continue;
+
+ if (zif->link == ifp)
+ return tmp_if;
+ }
+
+ return NULL;
+}
+
+/* EVPN<=>vxlan_zif association */
+static inline void zevpn_vxlan_if_set(zebra_evpn_t *zevpn,
+ struct interface *ifp, bool set)
+{
+ struct zebra_if *zif;
+
+ if (set) {
+ if (zevpn->vxlan_if == ifp)
+ return;
+ zevpn->vxlan_if = ifp;
+ } else {
+ if (!zevpn->vxlan_if)
+ return;
+ zevpn->vxlan_if = NULL;
+ }
+
+ if (ifp)
+ zif = ifp->info;
+ else
+ zif = NULL;
+
+ zebra_evpn_vxl_evpn_set(zif, zevpn, set);
+}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index d1d56f2cdb..8852ee9467 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -120,6 +120,7 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
char buf[SRCDEST2STR_BUFFER + sizeof(" (MRIB)")];
char msgbuf[512];
va_list ap;
+ uint32_t table = 0;
va_start(ap, msgfmt);
vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap);
@@ -127,15 +128,24 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
if (rn) {
struct rib_table_info *info = srcdest_rnode_table_info(rn);
+ rib_dest_t *dest = NULL;
+ struct route_entry *re = NULL;
+
srcdest_rnode2str(rn, buf, sizeof(buf));
if (info->safi == SAFI_MULTICAST)
strlcat(buf, " (MRIB)", sizeof(buf));
+
+ dest = rib_dest_from_rnode(rn);
+ if (dest)
+ re = re_list_first(&dest->routes);
+ if (re)
+ table = re->table;
} else {
snprintf(buf, sizeof(buf), "{(route_node *) NULL}");
}
- zlog(priority, "%s: %d:%s: %s", _func, vrf_id, buf, msgbuf);
+ zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf);
}
#define rnode_debug(node, vrf_id, ...) \
@@ -758,9 +768,9 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%s(%u):%s: Adding route rn %p, re %p (%s)",
- zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, new,
- zebra_route_string(new->type));
+ zlog_debug("%s(%u:%u):%s: Adding route rn %p, re %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf), new->table, buf, rn,
+ new, zebra_route_string(new->type));
}
/* If labeled-unicast route, install transit LSP. */
@@ -781,9 +791,9 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%s(%u):%s: Deleting route rn %p, re %p (%s)",
- zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, old,
- zebra_route_string(old->type));
+ zlog_debug("%s(%u:%u):%s: Deleting route rn %p, re %p (%s)",
+ zvrf_name(zvrf), zvrf_id(zvrf), old->table, buf, rn,
+ old, zebra_route_string(old->type));
}
/* If labeled-unicast route, uninstall transit LSP. */
@@ -834,17 +844,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%s(%u):%s: Updating route rn %p, re %p (%s) old %p (%s)",
+ "%s(%u:%u):%s: Updating route rn %p, re %p (%s) old %p (%s)",
zvrf_name(zvrf), zvrf_id(zvrf),
- buf, rn, new,
+ new->table, buf, rn, new,
zebra_route_string(new->type),
old,
zebra_route_string(old->type));
else
zlog_debug(
- "%s(%u):%s: Updating route rn %p, re %p (%s)",
+ "%s(%u:%u):%s: Updating route rn %p, re %p (%s)",
zvrf_name(zvrf), zvrf_id(zvrf),
- buf, rn, new,
+ new->table, buf, rn, new,
zebra_route_string(new->type));
}
@@ -874,17 +884,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%s(%u):%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive",
+ "%s(%u:%u):%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive",
zvrf_name(zvrf), zvrf_id(zvrf),
- buf, rn, new,
+ new->table, buf, rn, new,
zebra_route_string(new->type),
old,
zebra_route_string(old->type));
else
zlog_debug(
- "%s(%u):%s: Deleting route rn %p, re %p (%s) - nexthop inactive",
+ "%s(%u:%u):%s: Deleting route rn %p, re %p (%s) - nexthop inactive",
zvrf_name(zvrf), zvrf_id(zvrf),
- buf, rn, new,
+ new->table, buf, rn, new,
zebra_route_string(new->type));
}
@@ -1018,24 +1028,29 @@ static void rib_process(struct route_node *rn)
if (IS_ZEBRA_DEBUG_RIB)
srcdest_rnode2str(rn, buf, sizeof(buf));
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%s(%u):%s: Processing rn %p", VRF_LOGNAME(vrf),
- vrf_id, buf, rn);
-
/*
* we can have rn's that have a NULL info pointer
* (dest). As such let's not let the deref happen
* additionally we know RNODE_FOREACH_RE_SAFE
* will not iterate so we are ok.
*/
- if (dest)
+ if (dest) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ struct route_entry *re = re_list_first(&dest->routes);
+
+ zlog_debug("%s(%u:%u):%s: Processing rn %p",
+ VRF_LOGNAME(vrf), vrf_id, re->table, buf,
+ rn);
+ }
+
old_fib = dest->selected_fib;
+ }
RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%s(%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
- VRF_LOGNAME(vrf), vrf_id, buf, re,
+ "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %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);
@@ -1131,10 +1146,20 @@ static void rib_process(struct route_node *rn)
*/
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ struct route_entry *entry;
+
+ entry = old_selected
+ ? old_selected
+ : new_selected
+ ? new_selected
+ : old_fib ? old_fib
+ : new_fib ? new_fib : NULL;
+
zlog_debug(
- "%s(%u):%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
- VRF_LOGNAME(vrf), vrf_id, buf, (void *)old_selected,
- (void *)new_selected, (void *)old_fib, (void *)new_fib);
+ "%s(%u:%u):%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p",
+ VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, buf,
+ (void *)old_selected, (void *)new_selected,
+ (void *)old_fib, (void *)new_fib);
}
/* Buffer ROUTE_ENTRY_CHANGED here, because it will get cleared if
@@ -1456,8 +1481,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
is_selected = (re == dest->selected_fib);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("update_from_ctx: %s(%u):%s: %sSELECTED, re %p",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ zlog_debug("update_from_ctx: %s(%u:%u):%s: %sSELECTED, re %p",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table, dest_str,
(is_selected ? "" : "NOT "), re);
/* Update zebra's nexthop FIB flag for each nexthop that was installed.
@@ -1483,8 +1508,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
if (matched) {
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s(%u):%s update_from_ctx(): existing fib nhg, no change",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ "%s(%u:%u):%s update_from_ctx(): existing fib nhg, no change",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table,
+ dest_str);
goto check_backups;
} else if (CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG)) {
@@ -1493,8 +1519,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
*/
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s(%u):%s update_from_ctx(): replacing fib nhg",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ "%s(%u:%u):%s update_from_ctx(): replacing fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table,
+ dest_str);
nexthops_free(re->fib_ng.nexthop);
re->fib_ng.nexthop = NULL;
@@ -1504,8 +1531,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
changed_p = true;
} else {
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%s(%u):%s update_from_ctx(): no fib nhg",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str);
+ zlog_debug("%s(%u:%u):%s update_from_ctx(): no fib nhg",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table,
+ dest_str);
}
/*
@@ -1532,9 +1560,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re,
if (matched) {
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s(%u):%s update_from_ctx(): rib nhg matched, changed '%s'",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str,
- (changed_p ? "true" : "false"));
+ "%s(%u:%u):%s update_from_ctx(): rib nhg matched, changed '%s'",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table,
+ dest_str, (changed_p ? "true" : "false"));
goto check_backups;
}
@@ -1545,8 +1573,8 @@ no_nexthops:
*/
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s(%u):%s update_from_ctx(): changed %s, adding new fib nhg%s",
- VRF_LOGNAME(vrf), re->vrf_id, dest_str,
+ "%s(%u:%u):%s update_from_ctx(): changed %s, adding new fib nhg%s",
+ VRF_LOGNAME(vrf), re->vrf_id, re->table, dest_str,
(changed_p ? "true" : "false"),
ctxnhg->nexthop != NULL ? "" : " (empty)");
@@ -1722,9 +1750,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug(
- "%s(%u):%s Processing dplane result ctx %p, op %s result %s",
- VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str,
- ctx, dplane_op2str(op), dplane_res2str(status));
+ "%s(%u:%u):%s Processing dplane result ctx %p, op %s result %s",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), dest_str, ctx,
+ dplane_op2str(op), dplane_res2str(status));
/*
* Update is a bit of a special case, where we may have both old and new
@@ -1774,10 +1803,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug(
- "%s(%u):%s Stale dplane result for old_re %p",
+ "%s(%u:%u):%s Stale dplane result for old_re %p",
VRF_LOGNAME(vrf),
- dplane_ctx_get_vrf(ctx), dest_str,
- old_re);
+ dplane_ctx_get_vrf(ctx), old_re->table,
+ dest_str, old_re);
} else
UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
}
@@ -1815,9 +1844,11 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (!fib_changed) {
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
zlog_debug(
- "%s(%u):%s no fib change for re",
+ "%s(%u:%u):%s no fib change for re",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(
+ ctx),
dest_str);
}
@@ -1854,8 +1885,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
zsend_route_notify_owner(re, dest_pfx,
ZAPI_ROUTE_FAIL_INSTALL);
- zlog_warn("%s(%u):%s: Route install failed",
+ zlog_warn("%s(%u:%u):%s: Route install failed",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx),
prefix2str(dest_pfx, dest_str,
sizeof(dest_str)));
}
@@ -1883,8 +1915,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
zsend_route_notify_owner_ctx(ctx,
ZAPI_ROUTE_REMOVE_FAIL);
- zlog_warn("%s(%u):%s: Route Deletion failure",
+ zlog_warn("%s(%u:%u):%s: Route Deletion failure",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx),
prefix2str(dest_pfx, dest_str,
sizeof(dest_str)));
}
@@ -1981,9 +2014,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (rn == NULL) {
if (debug_p) {
zlog_debug(
- "Failed to process dplane notification: no routes for %s(%u):%s",
+ "Failed to process dplane notification: no routes for %s(%u:%u):%s",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str);
+ dplane_ctx_get_table(ctx), dest_str);
}
goto done;
}
@@ -1992,9 +2025,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
if (debug_p)
- zlog_debug("%s(%u):%s Processing dplane notif ctx %p",
- VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str,
- ctx);
+ zlog_debug("%s(%u:%u):%s Processing dplane notif ctx %p",
+ VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), dest_str, ctx);
/*
* Take a pass through the routes, look for matches with the context
@@ -2009,9 +2042,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (re == NULL) {
if (debug_p)
zlog_debug(
- "%s(%u):%s Unable to process dplane notification: no entry for type %s",
+ "%s(%u:%u):%s Unable to process dplane notification: no entry for type %s",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str,
+ dplane_ctx_get_table(ctx), dest_str,
zebra_route_string(dplane_ctx_get_type(ctx)));
goto done;
@@ -2043,18 +2076,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
if (debug_p)
zlog_debug(
- "%s(%u):%s dplane notif, uninstalled type %s route",
+ "%s(%u:%u):%s dplane notif, uninstalled type %s route",
VRF_LOGNAME(vrf),
- dplane_ctx_get_vrf(ctx), dest_str,
+ dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), dest_str,
zebra_route_string(
dplane_ctx_get_type(ctx)));
} else {
/* At least report on the event. */
if (debug_p)
zlog_debug(
- "%s(%u):%s dplane notif, but type %s not selected_fib",
+ "%s(%u:%u):%s dplane notif, but type %s not selected_fib",
VRF_LOGNAME(vrf),
- dplane_ctx_get_vrf(ctx), dest_str,
+ dplane_ctx_get_vrf(ctx),
+ dplane_ctx_get_table(ctx), dest_str,
zebra_route_string(
dplane_ctx_get_type(ctx)));
}
@@ -2078,9 +2113,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (!fib_changed) {
if (debug_p)
zlog_debug(
- "%s(%u):%s dplane notification: rib_update returns FALSE",
+ "%s(%u:%u):%s dplane notification: rib_update returns FALSE",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str);
+ dplane_ctx_get_table(ctx), dest_str);
}
/*
@@ -2095,9 +2130,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (start_count > 0 && end_count > 0) {
if (debug_p)
zlog_debug(
- "%s(%u):%s applied nexthop changes from dplane notification",
+ "%s(%u:%u):%s applied nexthop changes from dplane notification",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str);
+ dplane_ctx_get_table(ctx), dest_str);
/* Changed nexthops - update kernel/others */
dplane_route_notif_update(rn, re,
@@ -2106,9 +2141,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
} else if (start_count == 0 && end_count > 0) {
if (debug_p)
zlog_debug(
- "%s(%u):%s installed transition from dplane notification",
+ "%s(%u:%u):%s installed transition from dplane notification",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str);
+ dplane_ctx_get_table(ctx), dest_str);
/* We expect this to be the selected route, so we want
* to tell others about this transition.
@@ -2124,9 +2159,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
} else if (start_count > 0 && end_count == 0) {
if (debug_p)
zlog_debug(
- "%s(%u):%s un-installed transition from dplane notification",
+ "%s(%u:%u):%s un-installed transition from dplane notification",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
- dest_str);
+ dplane_ctx_get_table(ctx), dest_str);
/* Transition from _something_ installed to _nothing_
* installed.
@@ -2182,17 +2217,20 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex)
rnode = listgetdata(lnode);
dest = rib_dest_from_rnode(rnode);
- if (dest)
- zvrf = rib_dest_vrf(dest);
+ assert(dest);
+
+ zvrf = rib_dest_vrf(dest);
rib_process(rnode);
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ struct route_entry *re = re_list_first(&dest->routes);
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rnode, buf, sizeof(buf));
- zlog_debug("%s(%u):%s: rn %p dequeued from sub-queue %u",
- zvrf_name(zvrf), zvrf_id(zvrf), buf, rnode, qindex);
+ zlog_debug("%s(%u:%u):%s: rn %p dequeued from sub-queue %u",
+ zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, buf,
+ rnode, qindex);
}
if (rnode->info)
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index d200f5a4c8..910d192317 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -130,9 +130,9 @@ struct zebra_vrf {
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
/*
- * VNI hash table (for EVPN). Only in the EVPN instance.
+ * EVPN hash table. Only in the EVPN instance.
*/
- struct hash *vni_table;
+ struct hash *evpn_table;
/*
* Whether EVPN is enabled or not. Only in the EVPN instance.
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index ee167fa5a3..13a58bc34a 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -49,79 +49,31 @@
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
+#include "zebra/zebra_evpn_neigh.h"
#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_vxlan.h"
#include "zebra/zebra_router.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
-DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
-DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
-DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
-DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
+DEFINE_MTYPE_STATIC(ZEBRA, L3VNI_MAC, "EVPN L3VNI MAC");
+DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor");
DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
bool delete, const char *reason), (rmac, zl3vni, delete, reason))
-/* definitions */
-/* PMSI strings. */
-#define VXLAN_FLOOD_STR_NO_INFO "-"
-#define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO
-static const struct message zvtep_flood_str[] = {
- {VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO},
- {VXLAN_FLOOD_PIM_SM, "PIM-SM"},
- {VXLAN_FLOOD_HEAD_END_REPL, "HER"},
- {0}
-};
-
/* static function declarations */
-static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
- uint16_t cmd);
-static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
-static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt);
-static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt);
-static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
- void **args);
+static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
+ void **args);
static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
json_object *json);
static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
json_object *json);
-static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json);
-static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt);
-static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt);
-static void zvni_print(zebra_vni_t *zvni, void **ctxt);
-static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]);
-
-static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
- struct ipaddr *ip, uint8_t flags,
- uint32_t seq, int state,
- struct zebra_evpn_es *es,
- uint16_t cmd);
-static unsigned int neigh_hash_keymake(const void *p);
-static void *zvni_neigh_alloc(void *p);
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
- struct ethaddr *mac, zebra_mac_t *zmac,
- uint32_t n_flags);
-static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n);
-static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
- uint32_t flags);
-static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip);
-static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *mac, zebra_mac_t *zmac,
- uint32_t flags, uint32_t seq);
-static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *mac,
- uint32_t flags, int state, bool force);
-static int zvni_rem_neigh_install(zebra_vni_t *zvni,
- zebra_neigh_t *n, bool was_static);
-static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
-static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
-static zebra_vni_t *zvni_from_svi(struct interface *ifp,
- struct interface *br_if);
-static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
-static struct interface *zvni_map_to_macvlan(struct interface *br_if,
- struct interface *svi_if);
+static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt);
/* l3-vni next-hop neigh related APIs */
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
@@ -152,69 +104,7 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni);
static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
-static unsigned int mac_hash_keymake(const void *p);
-static bool mac_cmp(const void *p1, const void *p2);
-static void *zvni_mac_alloc(void *p);
-static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr);
-static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac);
-static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
- uint32_t flags);
-static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr);
-static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint32_t flags, uint32_t seq, struct zebra_evpn_es *es);
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
- uint32_t flags, bool force);
-static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
- struct interface *br_if, vlanid_t vid);
-static int zvni_rem_mac_install(zebra_vni_t *zvni,
- zebra_mac_t *mac, bool was_static);
-static int zvni_rem_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac);
-static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
-
-static unsigned int vni_hash_keymake(const void *p);
-static void *zvni_alloc(void *p);
-static zebra_vni_t *zvni_add(vni_t vni);
-static int zvni_del(zebra_vni_t *zvni);
-static int zvni_send_add_to_client(zebra_vni_t *zvni);
-static int zvni_send_del_to_client(zebra_vni_t *zvni);
-static void zvni_build_hash_table(void);
-static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep);
-static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip);
-static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
- int flood_control);
-static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
-static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall);
-static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep);
-static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip);
-static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
-static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni);
-static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
- struct ethaddr *macaddr, struct ipaddr *ip);
-static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
- struct ipaddr *ip);
-struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
-static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
-static int advertise_svi_macip_enabled(zebra_vni_t *zvni);
-static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
- zebra_mac_t *old_zmac,
- zebra_mac_t *new_zmac,
- zebra_neigh_t *nbr);
-static int remote_neigh_count(zebra_mac_t *zmac);
-static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac);
-static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t);
-static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t);
-static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
- zebra_neigh_t *nbr,
- struct in_addr vtep_ip,
- bool do_dad,
- bool *is_dup_detect,
- bool is_local);
-static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
- zebra_mac_t *mac,
- struct in_addr vtep_ip,
- bool do_dad,
- bool *is_dup_detect,
- bool is_local);
+static void zevpn_build_hash_table(void);
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2);
static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
@@ -227,25 +117,6 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
struct in_addr mcast_grp);
static void zebra_vxlan_sg_cleanup(struct hash_bucket *bucket, void *arg);
-static void zvni_send_mac_to_client(zebra_vni_t *zvn);
-static void zvni_send_neigh_to_client(zebra_vni_t *zvni);
-static void zebra_vxlan_rem_mac_del(zebra_vni_t *zvni,
- zebra_mac_t *zmac);
-static inline void zebra_vxlan_mac_stop_hold_timer(zebra_mac_t *mac);
-static inline bool zebra_vxlan_mac_is_static(zebra_mac_t *mac);
-static void zebra_vxlan_local_neigh_ref_mac(zebra_neigh_t *n,
- struct ethaddr *macaddr, zebra_mac_t *mac,
- bool send_mac_update);
-static void zebra_vxlan_local_neigh_deref_mac(zebra_neigh_t *n,
- bool send_mac_update);
-static inline bool zebra_vxlan_neigh_is_ready_for_bgp(zebra_neigh_t *n);
-static inline bool zebra_vxlan_neigh_clear_sync_info(zebra_neigh_t *n);
-static void zebra_vxlan_sync_neigh_dp_install(zebra_neigh_t *n,
- bool set_inactive, bool force_clear_static, const char *caller);
-static inline bool zebra_vxlan_neigh_is_static(zebra_neigh_t *neigh);
-static void zebra_vxlan_neigh_send_add_del_to_client(zebra_neigh_t *n,
- bool old_bgp_ready, bool new_bgp_ready);
-
/* Private functions */
static int host_rb_entry_compare(const struct host_rb_entry *hle1,
const struct host_rb_entry *hle2)
@@ -293,761 +164,14 @@ static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe)
}
/*
- * Return number of valid MACs in a VNI's MAC hash table - all
- * remote MACs and non-internal (auto) local MACs count.
- */
-static uint32_t num_valid_macs(zebra_vni_t *zvni)
-{
- unsigned int i;
- uint32_t num_macs = 0;
- struct hash *hash;
- struct hash_bucket *hb;
- zebra_mac_t *mac;
-
- hash = zvni->mac_table;
- if (!hash)
- return num_macs;
- for (i = 0; i < hash->size; i++) {
- for (hb = hash->index[i]; hb; hb = hb->next) {
- mac = (zebra_mac_t *)hb->data;
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
- || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
- num_macs++;
- }
- }
-
- return num_macs;
-}
-
-static uint32_t num_dup_detected_macs(zebra_vni_t *zvni)
-{
- unsigned int i;
- uint32_t num_macs = 0;
- struct hash *hash;
- struct hash_bucket *hb;
- zebra_mac_t *mac;
-
- hash = zvni->mac_table;
- if (!hash)
- return num_macs;
- for (i = 0; i < hash->size; i++) {
- for (hb = hash->index[i]; hb; hb = hb->next) {
- mac = (zebra_mac_t *)hb->data;
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- num_macs++;
- }
- }
-
- return num_macs;
-}
-
-static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni)
-{
- unsigned int i;
- uint32_t num_neighs = 0;
- struct hash *hash;
- struct hash_bucket *hb;
- zebra_neigh_t *nbr;
-
- hash = zvni->neigh_table;
- if (!hash)
- return num_neighs;
- for (i = 0; i < hash->size; i++) {
- for (hb = hash->index[i]; hb; hb = hb->next) {
- nbr = (zebra_neigh_t *)hb->data;
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
- num_neighs++;
- }
- }
-
- return num_neighs;
-}
-
-static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
-{
- struct zebra_vrf *zvrf;
-
- zvrf = zebra_vrf_get_evpn();
- if (zvrf && zvrf->advertise_gw_macip)
- return 1;
-
- if (zvni && zvni->advertise_gw_macip)
- return 1;
-
- return 0;
-}
-
-static int advertise_svi_macip_enabled(zebra_vni_t *zvni)
-{
- struct zebra_vrf *zvrf;
-
- zvrf = zebra_vrf_get_evpn();
- if (zvrf && zvrf->advertise_svi_macip)
- return 1;
-
- if (zvni && zvni->advertise_svi_macip)
- return 1;
-
- return 0;
-}
-
-/* As part Duplicate Address Detection (DAD) for IP mobility
- * MAC binding changes, ensure to inherit duplicate flag
- * from MAC.
- */
-static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
- zebra_mac_t *old_zmac,
- zebra_mac_t *new_zmac,
- zebra_neigh_t *nbr)
-{
- bool is_old_mac_dup = false;
- bool is_new_mac_dup = false;
-
- if (!zvrf->dup_addr_detect)
- return 0;
- /* Check old or new MAC is detected as duplicate
- * mark this neigh as duplicate
- */
- if (old_zmac)
- is_old_mac_dup = CHECK_FLAG(old_zmac->flags,
- ZEBRA_MAC_DUPLICATE);
- if (new_zmac)
- is_new_mac_dup = CHECK_FLAG(new_zmac->flags,
- ZEBRA_MAC_DUPLICATE);
- /* Old and/or new MAC can be in duplicate state,
- * based on that IP/Neigh Inherits the flag.
- * If New MAC is marked duplicate, inherit to the IP.
- * If old MAC is duplicate but new MAC is not, clear
- * duplicate flag for IP and reset detection params
- * and let IP DAD retrigger.
- */
- if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
- SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
- /* Capture Duplicate detection time */
- nbr->dad_dup_detect_time = monotime(NULL);
- /* Mark neigh inactive */
- ZEBRA_NEIGH_SET_INACTIVE(nbr);
-
- return 1;
- } else if (is_old_mac_dup && !is_new_mac_dup) {
- UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
- nbr->dad_count = 0;
- nbr->detect_start_time.tv_sec = 0;
- nbr->detect_start_time.tv_usec = 0;
- }
- return 0;
-}
-
-static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
- zebra_mac_t *mac,
- struct in_addr vtep_ip,
- bool do_dad,
- bool *is_dup_detect,
- bool is_local)
-{
- zebra_neigh_t *nbr;
- struct listnode *node = NULL;
- struct timeval elapsed = {0, 0};
- char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
- bool reset_params = false;
-
- if (!(zvrf->dup_addr_detect && do_dad))
- return;
-
- /* MAC is detected as duplicate,
- * Local MAC event -> hold on advertising to BGP.
- * Remote MAC event -> hold on installing it.
- */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x skip 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);
-
- /* For duplicate MAC do not update
- * client but update neigh due to
- * this MAC update.
- */
- if (zvrf->dad_freeze)
- *is_dup_detect = true;
-
- return;
- }
-
- /* Check if detection time (M-secs) expired.
- * Reset learn count and detection start time.
- */
- monotime_since(&mac->detect_start_time, &elapsed);
- reset_params = (elapsed.tv_sec > zvrf->dad_time);
- if (is_local && !reset_params) {
- /* RFC-7432: A PE/VTEP that detects a MAC mobility
- * event via LOCAL learning starts an M-second timer.
- *
- * NOTE: This is the START of the probe with count is
- * 0 during LOCAL learn event.
- * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
- */
- reset_params = !mac->dad_count;
- }
-
- if (reset_params) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
- __func__,
- prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count);
-
- mac->dad_count = 0;
- /* Start dup. addr detection (DAD) start time,
- * ONLY during LOCAL learn.
- */
- if (is_local)
- monotime(&mac->detect_start_time);
-
- } else if (!is_local) {
- /* For REMOTE MAC, increment detection count
- * ONLY while in probe window, once window passed,
- * next local learn event should trigger DAD.
- */
- mac->dad_count++;
- }
-
- /* For LOCAL MAC learn event, once count is reset above via either
- * initial/start detection time or passed the probe time, the count
- * needs to be incremented.
- */
- if (is_local)
- mac->dad_count++;
-
- if (mac->dad_count >= zvrf->dad_max_moves) {
- flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
- "VNI %u: MAC %s detected as duplicate during %s VTEP %s",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- is_local ? "local update, last" :
- "remote update, from", inet_ntoa(vtep_ip));
-
- SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
-
- /* Capture Duplicate detection time */
- mac->dad_dup_detect_time = monotime(NULL);
-
- /* Mark all IPs/Neighs as duplicate
- * associcated with this MAC
- */
- for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
-
- /* Ony Mark IPs which are Local */
- if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
- continue;
-
- SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
-
- nbr->dad_dup_detect_time = monotime(NULL);
-
- flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
- "VNI %u: MAC %s IP %s detected as duplicate during %s update, inherit duplicate from MAC",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr,
- buf, sizeof(buf)),
- ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
- is_local ? "local" : "remote");
- }
-
- /* 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)
- zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
- __func__,
- prefix_mac2str(&mac->macaddr, buf,
- sizeof(buf)),
- mac->flags, zvrf->dad_freeze_time);
-
- thread_add_timer(zrouter.master,
- zebra_vxlan_dad_mac_auto_recovery_exp,
- mac, zvrf->dad_freeze_time,
- &mac->dad_mac_auto_recovery_timer);
- }
-
- /* In case of local update, do not inform to client (BGPd),
- * upd_neigh for neigh sequence change.
- */
- if (zvrf->dad_freeze)
- *is_dup_detect = true;
- }
-}
-
-static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
- zebra_neigh_t *nbr,
- struct in_addr vtep_ip,
- bool do_dad,
- bool *is_dup_detect,
- bool is_local)
-{
-
- struct timeval elapsed = {0, 0};
- char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
- bool reset_params = false;
-
- if (!zvrf->dup_addr_detect)
- return;
-
- /* IP is detected as duplicate or inherit dup
- * state, hold on to install as remote entry
- * only if freeze is enabled.
- */
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s IP %s flags 0x%x skip installing, learn count %u recover time %u",
- __func__,
- prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
- ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
- nbr->flags, nbr->dad_count,
- zvrf->dad_freeze_time);
-
- if (zvrf->dad_freeze)
- *is_dup_detect = true;
-
- /* warn-only action, neigh will be installed.
- * freeze action, it wil not be installed.
- */
- return;
- }
-
- if (!do_dad)
- return;
-
- /* Check if detection time (M-secs) expired.
- * Reset learn count and detection start time.
- * During remote mac add, count should already be 1
- * via local learning.
- */
- monotime_since(&nbr->detect_start_time, &elapsed);
- reset_params = (elapsed.tv_sec > zvrf->dad_time);
-
- if (is_local && !reset_params) {
- /* RFC-7432: A PE/VTEP that detects a MAC mobility
- * event via LOCAL learning starts an M-second timer.
- *
- * NOTE: This is the START of the probe with count is
- * 0 during LOCAL learn event.
- */
- reset_params = !nbr->dad_count;
- }
-
- if (reset_params) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u",
- __func__,
- prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
- ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
- nbr->flags, nbr->dad_count);
- /* Reset learn count but do not start detection
- * during REMOTE learn event.
- */
- nbr->dad_count = 0;
- /* Start dup. addr detection (DAD) start time,
- * ONLY during LOCAL learn.
- */
- if (is_local)
- monotime(&nbr->detect_start_time);
-
- } else if (!is_local) {
- /* For REMOTE IP/Neigh, increment detection count
- * ONLY while in probe window, once window passed,
- * next local learn event should trigger DAD.
- */
- nbr->dad_count++;
- }
-
- /* For LOCAL IP/Neigh learn event, once count is reset above via either
- * initial/start detection time or passed the probe time, the count
- * needs to be incremented.
- */
- if (is_local)
- nbr->dad_count++;
-
- if (nbr->dad_count >= zvrf->dad_max_moves) {
- flog_warn(EC_ZEBRA_DUP_IP_DETECTED,
- "VNI %u: MAC %s IP %s detected as duplicate during %s VTEP %s",
- nbr->zvni->vni,
- prefix_mac2str(&nbr->emac, buf, sizeof(buf)),
- ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
- is_local ? "local update, last" :
- "remote update, from",
- inet_ntoa(vtep_ip));
-
- SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
-
- /* Capture Duplicate detection time */
- nbr->dad_dup_detect_time = monotime(NULL);
-
- /* Start auto recovery timer for this IP */
- THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
- if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start",
- __func__,
- prefix_mac2str(&nbr->emac, buf,
- sizeof(buf)),
- ipaddr2str(&nbr->ip, buf1,
- sizeof(buf1)),
- nbr->flags, zvrf->dad_freeze_time);
-
- thread_add_timer(zrouter.master,
- zebra_vxlan_dad_ip_auto_recovery_exp,
- nbr, zvrf->dad_freeze_time,
- &nbr->dad_ip_auto_recovery_timer);
- }
- if (zvrf->dad_freeze)
- *is_dup_detect = true;
- }
-}
-
-/*
- * Helper function to determine maximum width of neighbor IP address for
- * display - just because we're dealing with IPv6 addresses that can
- * widely vary.
- */
-static void zvni_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_neigh_t *n;
- char buf[INET6_ADDRSTRLEN];
- struct neigh_walk_ctx *wctx = ctxt;
- int width;
-
- n = (zebra_neigh_t *)bucket->data;
-
- ipaddr2str(&n->ip, buf, sizeof(buf));
- width = strlen(buf);
- if (width > wctx->addr_width)
- wctx->addr_width = width;
-
-}
-
-/*
- * Print a specific neighbor entry.
- */
-static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
-{
- struct vty *vty;
- char buf1[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- const char *type_str;
- const char *state_str;
- bool flags_present = false;
- struct zebra_vrf *zvrf = NULL;
- struct timeval detect_start_time = {0, 0};
- char timebuf[MONOTIME_STRLEN];
- char thread_buf[THREAD_TIMER_STRLEN];
-
- zvrf = zebra_vrf_get_evpn();
- if (!zvrf)
- return;
-
- ipaddr2str(&n->ip, buf2, sizeof(buf2));
- prefix_mac2str(&n->emac, buf1, sizeof(buf1));
- type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
- "local" : "remote";
- state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
- vty = (struct vty *)ctxt;
- if (json == NULL) {
- bool sync_info = false;
-
- vty_out(vty, "IP: %s\n",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- vty_out(vty, " Type: %s\n", type_str);
- vty_out(vty, " State: %s\n", state_str);
- vty_out(vty, " MAC: %s\n",
- prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- vty_out(vty, " Sync-info:");
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
- vty_out(vty, " local-inactive");
- sync_info = true;
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY)) {
- vty_out(vty, " peer-proxy");
- sync_info = true;
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
- vty_out(vty, " peer-active");
- sync_info = true;
- }
- if (n->hold_timer) {
- vty_out(vty, " (ht: %s)",
- thread_timer_to_hhmmss(
- thread_buf,
- sizeof(thread_buf),
- n->hold_timer));
- sync_info = true;
- }
- if (!sync_info)
- vty_out(vty, " -");
- vty_out(vty, "\n");
- } else {
- json_object_string_add(json, "ip", buf2);
- json_object_string_add(json, "type", type_str);
- json_object_string_add(json, "state", state_str);
- json_object_string_add(json, "mac", buf1);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
- json_object_boolean_true_add(json,
- "localInactive");
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY))
- json_object_boolean_true_add(json,
- "peerProxy");
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
- json_object_boolean_true_add(json,
- "peerActive");
- if (n->hold_timer)
- json_object_string_add(json, "peerActiveHold",
- thread_timer_to_hhmmss(
- thread_buf,
- sizeof(thread_buf),
- n->hold_timer));
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- if (n->mac->es) {
- if (json)
- json_object_string_add(json, "remoteEs",
- n->mac->es->esi_str);
- else
- vty_out(vty, " Remote ES: %s\n",
- n->mac->es->esi_str);
- } else {
- if (json)
- json_object_string_add(json, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
- else
- vty_out(vty, " Remote VTEP: %s\n",
- inet_ntoa(n->r_vtep_ip));
- }
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
- if (!json) {
- vty_out(vty, " Flags: Default-gateway");
- flags_present = true;
- } else
- json_object_boolean_true_add(json, "defaultGateway");
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) {
- if (!json) {
- vty_out(vty,
- flags_present ? " ,Router" : " Flags: Router");
- flags_present = true;
- }
- }
- if (json == NULL) {
- if (flags_present)
- vty_out(vty, "\n");
- vty_out(vty, " Local Seq: %u Remote Seq: %u\n",
- n->loc_seq, n->rem_seq);
-
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) {
- vty_out(vty, " Duplicate, detected at %s",
- time_to_string(n->dad_dup_detect_time,
- timebuf));
- } else if (n->dad_count) {
- monotime_since(&n->detect_start_time,
- &detect_start_time);
- if (detect_start_time.tv_sec <= zvrf->dad_time) {
- time_to_string(n->detect_start_time.tv_sec,
- timebuf);
- vty_out(vty,
- " Duplicate detection started at %s, detection count %u\n",
- timebuf, n->dad_count);
- }
- }
- } else {
- json_object_int_add(json, "localSequence", n->loc_seq);
- json_object_int_add(json, "remoteSequence", n->rem_seq);
- json_object_int_add(json, "detectionCount",
- n->dad_count);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
- json_object_boolean_true_add(json, "isDuplicate");
- else
- json_object_boolean_false_add(json, "isDuplicate");
-
-
- }
-}
-
-static void zvni_print_neigh_hdr(struct vty *vty,
- struct neigh_walk_ctx *wctx)
-{
- vty_out(vty,
- "Flags: I=local-inactive, P=peer-active, X=peer-proxy\n");
- vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %s\n",
- -wctx->addr_width, "Neighbor", "Type", "Flags",
- "State", "MAC", "Remote ES/VTEP", "Seq #'s");
-}
-
-static char *zvni_print_neigh_flags(zebra_neigh_t *n, char *flags_buf,
- uint32_t flags_buf_sz)
-{
- snprintf(flags_buf, flags_buf_sz, "%s%s%s",
- (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE) ?
- "P" : "",
- (n->flags & ZEBRA_NEIGH_ES_PEER_PROXY) ?
- "X" : "",
- (n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ?
- "I" : "");
-
- return flags_buf;
-}
-
-/*
- * Print neighbor hash entry - called for display of all neighbors.
+ * Print neighbors for all EVPN.
*/
-static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
-{
- struct vty *vty;
- json_object *json_vni = NULL, *json_row = NULL;
- zebra_neigh_t *n;
- char buf1[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- struct neigh_walk_ctx *wctx = ctxt;
- const char *state_str;
- char flags_buf[6];
-
- vty = wctx->vty;
- json_vni = wctx->json;
- n = (zebra_neigh_t *)bucket->data;
-
- if (json_vni)
- json_row = json_object_new_object();
-
- prefix_mac2str(&n->emac, buf1, sizeof(buf1));
- ipaddr2str(&n->ip, buf2, sizeof(buf2));
- state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive";
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)
- return;
-
- if (json_vni == NULL) {
- vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
- -wctx->addr_width, buf2, "local",
- zvni_print_neigh_flags(n, flags_buf,
- sizeof(flags_buf)), state_str,
- buf1, "", n->loc_seq, n->rem_seq);
- } else {
- json_object_string_add(json_row, "type", "local");
- json_object_string_add(json_row, "state", state_str);
- json_object_string_add(json_row, "mac", buf1);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
- json_object_boolean_true_add(
- json_row, "defaultGateway");
- json_object_int_add(json_row, "localSequence",
- n->loc_seq);
- json_object_int_add(json_row, "remoteSequence",
- n->rem_seq);
- json_object_int_add(json_row, "detectionCount",
- n->dad_count);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
- json_object_boolean_true_add(json_row,
- "isDuplicate");
- else
- json_object_boolean_false_add(json_row,
- "isDuplicate");
- }
- wctx->count++;
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
- !IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))
- return;
-
- if (json_vni == NULL) {
- if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) &&
- (wctx->count == 0))
- zvni_print_neigh_hdr(vty, wctx);
- vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n",
- -wctx->addr_width, buf2, "remote",
- zvni_print_neigh_flags(n, flags_buf,
- sizeof(flags_buf)),
- state_str, buf1,
- n->mac->es ? n->mac->es->esi_str :
- inet_ntoa(n->r_vtep_ip),
- n->loc_seq, n->rem_seq);
- } else {
- json_object_string_add(json_row, "type", "remote");
- json_object_string_add(json_row, "state", state_str);
- json_object_string_add(json_row, "mac", buf1);
- if (n->mac->es)
- json_object_string_add(json_row, "remoteEs",
- n->mac->es->esi_str);
- else
- json_object_string_add(json_row, "remoteVtep",
- inet_ntoa(n->r_vtep_ip));
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW))
- json_object_boolean_true_add(json_row,
- "defaultGateway");
- json_object_int_add(json_row, "localSequence",
- n->loc_seq);
- json_object_int_add(json_row, "remoteSequence",
- n->rem_seq);
- json_object_int_add(json_row, "detectionCount",
- n->dad_count);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
- json_object_boolean_true_add(json_row,
- "isDuplicate");
- else
- json_object_boolean_false_add(json_row,
- "isDuplicate");
- }
- wctx->count++;
- }
-
- if (json_vni)
- json_object_object_add(json_vni, buf2, json_row);
-}
-
-/*
- * Print neighbor hash entry in detail - called for display of all neighbors.
- */
-static void zvni_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt)
-{
- struct vty *vty;
- json_object *json_vni = NULL, *json_row = NULL;
- zebra_neigh_t *n;
- char buf[INET6_ADDRSTRLEN];
- struct neigh_walk_ctx *wctx = ctxt;
-
- vty = wctx->vty;
- json_vni = wctx->json;
- n = (zebra_neigh_t *)bucket->data;
- if (!n)
- return;
-
- ipaddr2str(&n->ip, buf, sizeof(buf));
- if (json_vni)
- json_row = json_object_new_object();
-
- zvni_print_neigh(n, vty, json_row);
-
- if (json_vni)
- json_object_object_add(json_vni, buf, json_row);
-}
-
-/*
- * Print neighbors for all VNI.
- */
-static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
+static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
void **args)
{
struct vty *vty;
- json_object *json = NULL, *json_vni = NULL;
- zebra_vni_t *zvni;
+ json_object *json = NULL, *json_evpn = NULL;
+ zebra_evpn_t *zevpn;
uint32_t num_neigh;
struct neigh_walk_ctx wctx;
char vni_str[VNI_STR_LEN];
@@ -1057,26 +181,26 @@ static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
json = (json_object *)args[1];
print_dup = (uint32_t)(uintptr_t)args[2];
- zvni = (zebra_vni_t *)bucket->data;
+ zevpn = (zebra_evpn_t *)bucket->data;
- num_neigh = hashcount(zvni->neigh_table);
+ num_neigh = hashcount(zevpn->neigh_table);
if (print_dup)
- num_neigh = num_dup_detected_neighs(zvni);
+ num_neigh = num_dup_detected_neighs(zevpn);
if (json == NULL) {
vty_out(vty,
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
- zvni->vni, num_neigh);
+ zevpn->vni, num_neigh);
} else {
- json_vni = json_object_new_object();
- json_object_int_add(json_vni, "numArpNd", num_neigh);
- snprintf(vni_str, sizeof(vni_str), "%u", zvni->vni);
+ json_evpn = json_object_new_object();
+ json_object_int_add(json_evpn, "numArpNd", num_neigh);
+ snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
}
if (!num_neigh) {
if (json)
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
return;
}
@@ -1085,59 +209,36 @@ static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
* the maximum width.
*/
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.addr_width = 15;
- wctx.json = json_vni;
- hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+ wctx.json = json_evpn;
+ hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
+ &wctx);
if (json == NULL)
- zvni_print_neigh_hdr(vty, &wctx);
+ zebra_evpn_print_neigh_hdr(vty, &wctx);
if (print_dup)
- hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash,
- &wctx);
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_print_dad_neigh_hash, &wctx);
else
- hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash,
+ &wctx);
if (json)
- json_object_object_add(json, vni_str, json_vni);
-}
-
-static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_neigh_t *nbr;
-
- nbr = (zebra_neigh_t *)bucket->data;
- if (!nbr)
- return;
-
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
- zvni_print_neigh_hash(bucket, ctxt);
-}
-
-static void zvni_print_dad_neigh_hash_detail(struct hash_bucket *bucket,
- void *ctxt)
-{
- zebra_neigh_t *nbr;
-
- nbr = (zebra_neigh_t *)bucket->data;
- if (!nbr)
- return;
-
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
- zvni_print_neigh_hash_detail(bucket, ctxt);
+ json_object_object_add(json, vni_str, json_evpn);
}
/*
- * Print neighbors for all VNIs in detail.
+ * Print neighbors for all EVPNs in detail.
*/
-static void zvni_print_neigh_hash_all_vni_detail(struct hash_bucket *bucket,
+static void zevpn_print_neigh_hash_all_evpn_detail(struct hash_bucket *bucket,
void **args)
{
struct vty *vty;
- json_object *json = NULL, *json_vni = NULL;
- zebra_vni_t *zvni;
+ json_object *json = NULL, *json_evpn = NULL;
+ zebra_evpn_t *zevpn;
uint32_t num_neigh;
struct neigh_walk_ctx wctx;
char vni_str[VNI_STR_LEN];
@@ -1147,47 +248,47 @@ static void zvni_print_neigh_hash_all_vni_detail(struct hash_bucket *bucket,
json = (json_object *)args[1];
print_dup = (uint32_t)(uintptr_t)args[2];
- zvni = (zebra_vni_t *)bucket->data;
- if (!zvni) {
+ zevpn = (zebra_evpn_t *)bucket->data;
+ if (!zevpn) {
if (json)
vty_out(vty, "{}\n");
return;
}
- num_neigh = hashcount(zvni->neigh_table);
+ num_neigh = hashcount(zevpn->neigh_table);
- if (print_dup && num_dup_detected_neighs(zvni) == 0)
+ if (print_dup && num_dup_detected_neighs(zevpn) == 0)
return;
if (json == NULL) {
vty_out(vty,
"\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n",
- zvni->vni, num_neigh);
+ zevpn->vni, num_neigh);
} else {
- json_vni = json_object_new_object();
- json_object_int_add(json_vni, "numArpNd", num_neigh);
- snprintf(vni_str, sizeof(vni_str), "%u", zvni->vni);
+ json_evpn = json_object_new_object();
+ json_object_int_add(json_evpn, "numArpNd", num_neigh);
+ snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
}
if (!num_neigh) {
if (json)
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
return;
}
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.addr_width = 15;
- wctx.json = json_vni;
+ wctx.json = json_evpn;
if (print_dup)
- hash_iterate(zvni->neigh_table,
- zvni_print_dad_neigh_hash_detail, &wctx);
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_print_dad_neigh_hash_detail, &wctx);
else
- hash_iterate(zvni->neigh_table, zvni_print_neigh_hash_detail,
- &wctx);
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_print_neigh_hash_detail, &wctx);
if (json)
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
}
/* print a specific next hop for an l3vni */
@@ -1266,442 +367,15 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
}
}
-static void
-zebra_vxlan_mac_get_access_info(zebra_mac_t *mac,
- struct interface **ifpP, vlanid_t *vid)
-{
- /* if the mac is associated with an ES we must get the access
- * info from the ES
- */
- if (mac->es) {
- struct zebra_if *zif;
-
- /* get the access port from the es */
- *ifpP = mac->es->zif ? mac->es->zif->ifp : NULL;
- /* get the vlan from the VNI */
- if (mac->zvni->vxlan_if) {
- zif = mac->zvni->vxlan_if->info;
- *vid = zif->l2info.vxl.access_vlan;
- } else {
- *vid = 0;
- }
- } else {
- struct zebra_ns *zns;
-
- *vid = mac->fwd_info.local.vid;
- zns = zebra_ns_lookup(NS_DEFAULT);
- *ifpP = if_lookup_by_index_per_ns(zns,
- mac->fwd_info.local.ifindex);
- }
-}
-
/*
- * Print a specific MAC entry.
+ * Print MACs for all EVPNs.
*/
-static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
+static void zevpn_print_mac_hash_all_evpn(struct hash_bucket *bucket, void *ctxt)
{
struct vty *vty;
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- char buf1[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- struct zebra_vrf *zvrf;
- struct timeval detect_start_time = {0, 0};
- char timebuf[MONOTIME_STRLEN];
- char thread_buf[THREAD_TIMER_STRLEN];
-
- zvrf = zebra_vrf_get_evpn();
- if (!zvrf)
- return;
-
- vty = (struct vty *)ctxt;
- prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
-
- if (json) {
- json_object *json_mac = json_object_new_object();
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct interface *ifp;
- vlanid_t vid;
-
- zebra_vxlan_mac_get_access_info(mac,
- &ifp, &vid);
- json_object_string_add(json_mac, "type", "local");
- if (ifp) {
- json_object_string_add(json_mac,
- "intf", ifp->name);
- json_object_int_add(json_mac,
- "ifindex", ifp->ifindex);
- }
- if (vid)
- json_object_int_add(json_mac, "vlan",
- vid);
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- json_object_string_add(json_mac, "type", "remote");
- json_object_string_add(
- json_mac, "remoteVtep",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
- json_object_string_add(json_mac, "type", "auto");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
- json_object_boolean_true_add(json_mac, "stickyMac");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
- json_object_boolean_true_add(json_mac,
- "defaultGateway");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
- json_object_boolean_true_add(json_mac,
- "remoteGatewayMac");
-
- json_object_int_add(json_mac, "localSequence", mac->loc_seq);
- json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
-
- json_object_int_add(json_mac, "detectionCount", mac->dad_count);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- json_object_boolean_true_add(json_mac, "isDuplicate");
- else
- json_object_boolean_false_add(json_mac, "isDuplicate");
-
- json_object_int_add(json_mac, "syncNeighCount", mac->sync_neigh_cnt);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
- json_object_boolean_true_add(json_mac,
- "localInactive");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
- json_object_boolean_true_add(json_mac,
- "peerProxy");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- json_object_boolean_true_add(json_mac,
- "peerActive");
- if (mac->hold_timer)
- json_object_string_add(json_mac, "peerActiveHold",
- thread_timer_to_hhmmss(
- thread_buf,
- sizeof(thread_buf),
- mac->hold_timer));
- if (mac->es)
- json_object_string_add(json_mac, "esi",
- mac->es->esi_str);
- /* print all the associated neigh */
- if (!listcount(mac->neigh_list))
- json_object_string_add(json_mac, "neighbors", "none");
- else {
- json_object *json_active_nbrs = json_object_new_array();
- json_object *json_inactive_nbrs =
- json_object_new_array();
- json_object *json_nbrs = json_object_new_object();
-
- for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
- json_object_array_add(
- json_active_nbrs,
- json_object_new_string(
- ipaddr2str(
- &n->ip, buf2,
- sizeof(buf2))));
- else
- json_object_array_add(
- json_inactive_nbrs,
- json_object_new_string(
- ipaddr2str(
- &n->ip, buf2,
- sizeof(buf2))));
- }
-
- json_object_object_add(json_nbrs, "active",
- json_active_nbrs);
- json_object_object_add(json_nbrs, "inactive",
- json_inactive_nbrs);
- json_object_object_add(json_mac, "neighbors",
- json_nbrs);
- }
-
- json_object_object_add(json, buf1, json_mac);
- } else {
- vty_out(vty, "MAC: %s\n", buf1);
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct interface *ifp;
- vlanid_t vid;
-
- zebra_vxlan_mac_get_access_info(mac,
- &ifp, &vid);
-
- if (mac->es)
- vty_out(vty, " ESI: %s\n", mac->es->esi_str);
-
- if (ifp)
- vty_out(vty, " Intf: %s(%u)",
- ifp->name, ifp->ifindex);
- else
- vty_out(vty, " Intf: -");
- vty_out(vty, " VLAN: %u", vid);
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- if (mac->es)
- vty_out(vty, " Remote ES: %s",
- mac->es->esi_str);
- else
- vty_out(vty, " Remote VTEP: %s",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
- vty_out(vty, " Auto Mac ");
- }
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
- vty_out(vty, " Sticky Mac ");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
- vty_out(vty, " Default-gateway Mac ");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
- vty_out(vty, " Remote-gateway Mac ");
-
- vty_out(vty, "\n");
- vty_out(vty, " Sync-info: neigh#: %u", mac->sync_neigh_cnt);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
- vty_out(vty, " local-inactive");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
- vty_out(vty, " peer-proxy");
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- vty_out(vty, " peer-active");
- if (mac->hold_timer)
- vty_out(vty, " (ht: %s)",
- thread_timer_to_hhmmss(
- thread_buf,
- sizeof(thread_buf),
- mac->hold_timer));
- vty_out(vty, "\n");
- vty_out(vty, " Local Seq: %u Remote Seq: %u",
- mac->loc_seq, mac->rem_seq);
- vty_out(vty, "\n");
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- vty_out(vty, " Duplicate, detected at %s",
- time_to_string(mac->dad_dup_detect_time,
- timebuf));
- } else if (mac->dad_count) {
- monotime_since(&mac->detect_start_time,
- &detect_start_time);
- if (detect_start_time.tv_sec <= zvrf->dad_time) {
- time_to_string(mac->detect_start_time.tv_sec,
- timebuf);
- vty_out(vty,
- " Duplicate detection started at %s, detection count %u\n",
- timebuf, mac->dad_count);
- }
- }
-
- /* print all the associated neigh */
- vty_out(vty, " Neighbors:\n");
- if (!listcount(mac->neigh_list))
- vty_out(vty, " No Neighbors\n");
- else {
- for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
- vty_out(vty, " %s %s\n",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- (IS_ZEBRA_NEIGH_ACTIVE(n)
- ? "Active"
- : "Inactive"));
- }
- }
-
- vty_out(vty, "\n");
- }
-}
-
-static char *zvni_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
- uint32_t flags_buf_sz)
-{
- snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
- mac->sync_neigh_cnt ?
- "N" : "",
- (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ?
- "P" : "",
- (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ?
- "X" : "",
- (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ?
- "I" : "");
-
- return flags_buf;
-}
-
-/*
- * Print MAC hash entry - called for display of all MACs.
- */
-static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
-{
- struct vty *vty;
- json_object *json_mac_hdr = NULL, *json_mac = NULL;
- zebra_mac_t *mac;
- char buf1[ETHER_ADDR_STRLEN];
- struct mac_walk_ctx *wctx = ctxt;
- char flags_buf[6];
-
- vty = wctx->vty;
- json_mac_hdr = wctx->json;
- mac = (zebra_mac_t *)bucket->data;
-
- prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
-
- if (json_mac_hdr)
- json_mac = json_object_new_object();
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct interface *ifp;
- vlanid_t vid;
-
- if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
- return;
-
- zebra_vxlan_mac_get_access_info(mac,
- &ifp, &vid);
- if (json_mac_hdr == NULL) {
- vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
- zvni_print_mac_flags(mac, flags_buf,
- sizeof(flags_buf)),
- ifp ? ifp->name : "-");
- } else {
- json_object_string_add(json_mac, "type", "local");
- if (ifp)
- json_object_string_add(json_mac,
- "intf", ifp->name);
- }
- if (vid) {
- if (json_mac_hdr == NULL)
- vty_out(vty, " %-5u", vid);
- else
- json_object_int_add(json_mac, "vlan", vid);
- } else /* No vid? fill out the space */
- if (json_mac_hdr == NULL)
- vty_out(vty, " %-5s", "");
- if (json_mac_hdr == NULL) {
- vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
- vty_out(vty, "\n");
- } else {
- json_object_int_add(json_mac, "localSequence",
- mac->loc_seq);
- json_object_int_add(json_mac, "remoteSequence",
- mac->rem_seq);
- json_object_int_add(json_mac, "detectionCount",
- mac->dad_count);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- json_object_boolean_true_add(json_mac,
- "isDuplicate");
- else
- json_object_boolean_false_add(json_mac,
- "isDuplicate");
- json_object_object_add(json_mac_hdr, buf1, json_mac);
- }
-
- wctx->count++;
-
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
-
- if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
- !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
- &wctx->r_vtep_ip))
- return;
-
- if (json_mac_hdr == NULL) {
- if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) &&
- (wctx->count == 0)) {
- vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni);
- vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
- "MAC", "Type", "Flags",
- "Intf/Remote ES/VTEP",
- "VLAN", "Seq #'s");
- }
- vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
- "remote",
- zvni_print_mac_flags(mac, flags_buf,
- sizeof(flags_buf)),
- mac->es ? mac->es->esi_str :
- inet_ntoa(mac->fwd_info.r_vtep_ip),
- "", mac->loc_seq, mac->rem_seq);
- } else {
- json_object_string_add(json_mac, "type", "remote");
- json_object_string_add(json_mac, "remoteVtep",
- inet_ntoa(mac->fwd_info.r_vtep_ip));
- json_object_object_add(json_mac_hdr, buf1, json_mac);
- json_object_int_add(json_mac, "localSequence",
- mac->loc_seq);
- json_object_int_add(json_mac, "remoteSequence",
- mac->rem_seq);
- json_object_int_add(json_mac, "detectionCount",
- mac->dad_count);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- json_object_boolean_true_add(json_mac,
- "isDuplicate");
- else
- json_object_boolean_false_add(json_mac,
- "isDuplicate");
-
- }
-
- wctx->count++;
- }
-}
-
-/* Print Duplicate MAC */
-static void zvni_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_mac_t *mac;
-
- mac = (zebra_mac_t *)bucket->data;
- if (!mac)
- return;
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- zvni_print_mac_hash(bucket, ctxt);
-}
-
-/*
- * Print MAC hash entry in detail - called for display of all MACs.
- */
-static void zvni_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
-{
- struct vty *vty;
- json_object *json_mac_hdr = NULL;
- zebra_mac_t *mac;
- struct mac_walk_ctx *wctx = ctxt;
- char buf1[ETHER_ADDR_STRLEN];
-
- vty = wctx->vty;
- json_mac_hdr = wctx->json;
- mac = (zebra_mac_t *)bucket->data;
- if (!mac)
- return;
-
- wctx->count++;
- prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
-
- zvni_print_mac(mac, vty, json_mac_hdr);
-}
-
-/* Print Duplicate MAC in detail */
-static void zvni_print_dad_mac_hash_detail(struct hash_bucket *bucket,
- void *ctxt)
-{
- zebra_mac_t *mac;
-
- mac = (zebra_mac_t *)bucket->data;
- if (!mac)
- return;
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- zvni_print_mac_hash_detail(bucket, ctxt);
-}
-
-/*
- * Print MACs for all VNI.
- */
-static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt)
-{
- struct vty *vty;
- json_object *json = NULL, *json_vni = NULL;
+ json_object *json = NULL, *json_evpn = NULL;
json_object *json_mac = NULL;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_macs;
struct mac_walk_ctx *wctx = ctxt;
char vni_str[VNI_STR_LEN];
@@ -1709,73 +383,74 @@ static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt)
vty = wctx->vty;
json = wctx->json;
- zvni = (zebra_vni_t *)bucket->data;
- wctx->zvni = zvni;
+ zevpn = (zebra_evpn_t *)bucket->data;
+ wctx->zevpn = zevpn;
/*We are iterating over a new VNI, set the count to 0*/
wctx->count = 0;
- num_macs = num_valid_macs(zvni);
+ num_macs = num_valid_macs(zevpn);
if (!num_macs)
return;
if (wctx->print_dup)
- num_macs = num_dup_detected_macs(zvni);
+ num_macs = num_dup_detected_macs(zevpn);
if (json) {
- json_vni = json_object_new_object();
+ json_evpn = json_object_new_object();
json_mac = json_object_new_object();
- snprintf(vni_str, sizeof(vni_str), "%u", zvni->vni);
+ snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
}
if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
if (json == NULL) {
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
- zvni->vni, num_macs);
+ zevpn->vni, num_macs);
vty_out(vty,
"Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n");
vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC",
"Type", "Flags", "Intf/Remote ES/VTEP",
"VLAN", "Seq #'s");
} else
- json_object_int_add(json_vni, "numMacs", num_macs);
+ json_object_int_add(json_evpn, "numMacs", num_macs);
}
if (!num_macs) {
if (json) {
- json_object_int_add(json_vni, "numMacs", num_macs);
- json_object_object_add(json, vni_str, json_vni);
+ json_object_int_add(json_evpn, "numMacs", num_macs);
+ json_object_object_add(json, vni_str, json_evpn);
}
return;
}
- /* assign per-vni to wctx->json object to fill macs
- * under the vni. Re-assign primary json object to fill
- * next vni information.
+ /* assign per-evpn to wctx->json object to fill macs
+ * under the evpn. Re-assign primary json object to fill
+ * next evpn information.
*/
wctx->json = json_mac;
if (wctx->print_dup)
- hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash,
+ wctx);
else
- hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, wctx);
wctx->json = json;
if (json) {
if (wctx->count)
- json_object_object_add(json_vni, "macs", json_mac);
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json_evpn, "macs", json_mac);
+ json_object_object_add(json, vni_str, json_evpn);
}
}
/*
- * Print MACs in detail for all VNI.
+ * Print MACs in detail for all EVPNs.
*/
-static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket,
+static void zevpn_print_mac_hash_all_evpn_detail(struct hash_bucket *bucket,
void *ctxt)
{
struct vty *vty;
- json_object *json = NULL, *json_vni = NULL;
+ json_object *json = NULL, *json_evpn = NULL;
json_object *json_mac = NULL;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_macs;
struct mac_walk_ctx *wctx = ctxt;
char vni_str[VNI_STR_LEN];
@@ -1783,52 +458,53 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket,
vty = wctx->vty;
json = wctx->json;
- zvni = (zebra_vni_t *)bucket->data;
- if (!zvni) {
+ zevpn = (zebra_evpn_t *)bucket->data;
+ if (!zevpn) {
if (json)
vty_out(vty, "{}\n");
return;
}
- wctx->zvni = zvni;
+ wctx->zevpn = zevpn;
- /*We are iterating over a new VNI, set the count to 0*/
+ /*We are iterating over a new EVPN, set the count to 0*/
wctx->count = 0;
- num_macs = num_valid_macs(zvni);
+ num_macs = num_valid_macs(zevpn);
if (!num_macs)
return;
- if (wctx->print_dup && (num_dup_detected_macs(zvni) == 0))
+ if (wctx->print_dup && (num_dup_detected_macs(zevpn) == 0))
return;
if (json) {
- json_vni = json_object_new_object();
+ json_evpn = json_object_new_object();
json_mac = json_object_new_object();
- snprintf(vni_str, sizeof(vni_str), "%u", zvni->vni);
+ snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni);
}
if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) {
if (json == NULL) {
vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n",
- zvni->vni, num_macs);
+ zevpn->vni, num_macs);
} else
- json_object_int_add(json_vni, "numMacs", num_macs);
+ json_object_int_add(json_evpn, "numMacs", num_macs);
}
- /* assign per-vni to wctx->json object to fill macs
- * under the vni. Re-assign primary json object to fill
- * next vni information.
+ /* assign per-evpn to wctx->json object to fill macs
+ * under the evpn. Re-assign primary json object to fill
+ * next evpn information.
*/
wctx->json = json_mac;
if (wctx->print_dup)
- hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash_detail,
- wctx);
+ hash_iterate(zevpn->mac_table,
+ zebra_evpn_print_dad_mac_hash_detail, wctx);
else
- hash_iterate(zvni->mac_table, zvni_print_mac_hash_detail, wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash_detail,
+ wctx);
wctx->json = json;
if (json) {
if (wctx->count)
- json_object_object_add(json_vni, "macs", json_mac);
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json_evpn, "macs", json_mac);
+ json_object_object_add(json, vni_str, json_evpn);
}
}
@@ -1836,7 +512,7 @@ static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
{
struct nh_walk_ctx *wctx = NULL;
struct vty *vty = NULL;
- struct json_object *json_vni = NULL;
+ struct json_object *json_evpn = NULL;
struct json_object *json_nh = NULL;
zebra_neigh_t *n = NULL;
char buf1[ETHER_ADDR_STRLEN];
@@ -1844,12 +520,12 @@ static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
wctx = (struct nh_walk_ctx *)ctx;
vty = wctx->vty;
- json_vni = wctx->json;
- if (json_vni)
+ json_evpn = wctx->json;
+ if (json_evpn)
json_nh = json_object_new_object();
n = (zebra_neigh_t *)bucket->data;
- if (!json_vni) {
+ if (!json_evpn) {
vty_out(vty, "%-15s %-17s\n",
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
@@ -1859,7 +535,7 @@ static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
json_object_string_add(
json_nh, "routerMac",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- json_object_object_add(json_vni,
+ json_object_object_add(json_evpn,
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
json_nh);
}
@@ -1870,7 +546,7 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
{
struct vty *vty = NULL;
json_object *json = NULL;
- json_object *json_vni = NULL;
+ json_object *json_evpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
uint32_t num_nh = 0;
struct nh_walk_ctx wctx;
@@ -1886,22 +562,22 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
return;
if (json) {
- json_vni = json_object_new_object();
- snprintf(vni_str, sizeof(vni_str), "%u", zl3vni->vni);
+ json_evpn = json_object_new_object();
+ snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
}
if (json == NULL) {
vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh);
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
} else
- json_object_int_add(json_vni, "numNextHops", num_nh);
+ json_object_int_add(json_evpn, "numNextHops", num_nh);
memset(&wctx, 0, sizeof(struct nh_walk_ctx));
wctx.vty = vty;
- wctx.json = json_vni;
+ wctx.json = json_evpn;
hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
if (json)
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
}
static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
@@ -1909,7 +585,7 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
{
struct vty *vty = NULL;
json_object *json = NULL;
- json_object *json_vni = NULL;
+ json_object *json_evpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
uint32_t num_rmacs;
struct rmac_walk_ctx wctx;
@@ -1925,15 +601,15 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
return;
if (json) {
- json_vni = json_object_new_object();
- snprintf(vni_str, sizeof(vni_str), "%u", zl3vni->vni);
+ json_evpn = json_object_new_object();
+ snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
}
if (json == NULL) {
vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs);
vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
} else
- json_object_int_add(json_vni, "numRmacs", num_rmacs);
+ json_object_int_add(json_evpn, "numRmacs", num_rmacs);
/* assign per-vni to wctx->json object to fill macs
* under the vni. Re-assign primary json object to fill
@@ -1941,10 +617,10 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
*/
memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
wctx.vty = vty;
- wctx.json = json_vni;
+ wctx.json = json_evpn;
hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
if (json)
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
}
static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx)
@@ -1985,8 +661,8 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
char buf[ETHER_ADDR_STRLEN];
struct vty *vty = NULL;
json_object *json = NULL;
- zebra_vni_t *zvni = NULL;
- json_object *json_vni_list = NULL;
+ zebra_evpn_t *zevpn = NULL;
+ json_object *json_evpn_list = NULL;
struct listnode *node = NULL, *nnode = NULL;
vty = ctx[0];
@@ -2011,11 +687,11 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
vty_out(vty, " Router MAC: %s\n",
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
vty_out(vty, " L2 VNIs: ");
- for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
- vty_out(vty, "%u ", zvni->vni);
+ for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn))
+ vty_out(vty, "%u ", zevpn->vni);
vty_out(vty, "\n");
} else {
- json_vni_list = json_object_new_array();
+ json_evpn_list = json_object_new_array();
json_object_int_add(json, "vni", zl3vni->vni);
json_object_string_add(json, "type", "L3");
json_object_string_add(json, "localVtepIp",
@@ -2037,105 +713,11 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)
? "prefix-routes-only"
: "none");
- for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
- json_object_array_add(json_vni_list,
- json_object_new_int(zvni->vni));
+ for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zevpn)) {
+ json_object_array_add(json_evpn_list,
+ json_object_new_int(zevpn->vni));
}
- json_object_object_add(json, "l2Vnis", json_vni_list);
- }
-}
-
-/*
- * Print a specific VNI entry.
- */
-static void zvni_print(zebra_vni_t *zvni, void **ctxt)
-{
- struct vty *vty;
- zebra_vtep_t *zvtep;
- uint32_t num_macs;
- uint32_t num_neigh;
- json_object *json = NULL;
- json_object *json_vtep_list = NULL;
- json_object *json_ip_str = NULL;
-
- vty = ctxt[0];
- json = ctxt[1];
-
- if (json == NULL) {
- vty_out(vty, "VNI: %u\n", zvni->vni);
- vty_out(vty, " Type: %s\n", "L2");
- vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
- } else {
- json_object_int_add(json, "vni", zvni->vni);
- json_object_string_add(json, "type", "L2");
- json_object_string_add(json, "vrf",
- vrf_id_to_name(zvni->vrf_id));
- }
-
- if (!zvni->vxlan_if) { // unexpected
- if (json == NULL)
- vty_out(vty, " VxLAN interface: unknown\n");
- return;
- }
- num_macs = num_valid_macs(zvni);
- num_neigh = hashcount(zvni->neigh_table);
- if (json == NULL) {
- vty_out(vty, " VxLAN interface: %s\n", zvni->vxlan_if->name);
- vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
- vty_out(vty, " Local VTEP IP: %s\n",
- inet_ntoa(zvni->local_vtep_ip));
- vty_out(vty, " Mcast group: %s\n",
- inet_ntoa(zvni->mcast_grp));
- } else {
- json_object_string_add(json, "vxlanInterface",
- zvni->vxlan_if->name);
- json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
- json_object_string_add(json, "vtepIp",
- inet_ntoa(zvni->local_vtep_ip));
- json_object_string_add(json, "mcastGroup",
- inet_ntoa(zvni->mcast_grp));
- json_object_string_add(json, "advertiseGatewayMacip",
- zvni->advertise_gw_macip ? "Yes" : "No");
- json_object_int_add(json, "numMacs", num_macs);
- json_object_int_add(json, "numArpNd", num_neigh);
- }
- if (!zvni->vteps) {
- if (json == NULL)
- vty_out(vty, " No remote VTEPs known for this VNI\n");
- } else {
- if (json == NULL)
- vty_out(vty, " Remote VTEPs for this VNI:\n");
- else
- json_vtep_list = json_object_new_array();
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
- const char *flood_str = lookup_msg(zvtep_flood_str,
- zvtep->flood_control,
- VXLAN_FLOOD_STR_DEFAULT);
-
- if (json == NULL) {
- vty_out(vty, " %s flood: %s\n",
- inet_ntoa(zvtep->vtep_ip),
- flood_str);
- } else {
- json_ip_str = json_object_new_string(
- inet_ntoa(zvtep->vtep_ip));
- json_object_array_add(json_vtep_list,
- json_ip_str);
- }
- }
- if (json)
- json_object_object_add(json, "numRemoteVteps",
- json_vtep_list);
- }
- if (json == NULL) {
- vty_out(vty,
- " Number of MACs (local and remote) known for this VNI: %u\n",
- num_macs);
- vty_out(vty,
- " Number of ARPs (IPv4 and IPv6, local and remote) known for this VNI: %u\n",
- num_neigh);
- vty_out(vty, " Advertise-gw-macip: %s\n",
- zvni->advertise_gw_macip ? "Yes" : "No");
+ json_object_object_add(json, "l2Vnis", json_evpn_list);
}
}
@@ -2144,7 +726,7 @@ static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[])
{
struct vty *vty = NULL;
json_object *json = NULL;
- json_object *json_vni = NULL;
+ json_object *json_evpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
vty = (struct vty *)ctx[0];
@@ -2161,31 +743,23 @@ static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[])
} else {
char vni_str[VNI_STR_LEN];
- snprintf(vni_str, sizeof(vni_str), "%u", zl3vni->vni);
- json_vni = json_object_new_object();
- json_object_int_add(json_vni, "vni", zl3vni->vni);
- json_object_string_add(json_vni, "vxlanIf",
+ snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+ json_evpn = json_object_new_object();
+ json_object_int_add(json_evpn, "vni", zl3vni->vni);
+ json_object_string_add(json_evpn, "vxlanIf",
zl3vni_vxlan_if_name(zl3vni));
- json_object_int_add(json_vni, "numMacs",
+ json_object_int_add(json_evpn, "numMacs",
hashcount(zl3vni->rmac_table));
- json_object_int_add(json_vni, "numArpNd",
+ json_object_int_add(json_evpn, "numArpNd",
hashcount(zl3vni->nh_table));
- json_object_string_add(json_vni, "numRemoteVteps", "n/a");
- json_object_string_add(json_vni, "type", "L3");
- json_object_string_add(json_vni, "tenantVrf",
+ json_object_string_add(json_evpn, "numRemoteVteps", "n/a");
+ json_object_string_add(json_evpn, "type", "L3");
+ json_object_string_add(json_evpn, "tenantVrf",
zl3vni_vrf_name(zl3vni));
- json_object_object_add(json, vni_str, json_vni);
+ json_object_object_add(json, vni_str, json_evpn);
}
}
-/* Private Structure to pass callback data for hash iterator */
-struct zvni_evpn_show {
- struct vty *vty;
- json_object *json;
- struct zebra_vrf *zvrf;
- bool use_json;
-};
-
/* print a L3 VNI hash entry in detail*/
static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
{
@@ -2193,7 +767,7 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
zebra_l3vni_t *zl3vni = NULL;
json_object *json_array = NULL;
bool use_json = false;
- struct zvni_evpn_show *zes = data;
+ struct zebra_evpn_show *zes = data;
vty = zes->vty;
json_array = zes->json;
@@ -2208,1833 +782,6 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
vty_out(vty, "\n");
}
-
-/*
- * Print a VNI hash entry - called for display of all VNIs.
- */
-static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[])
-{
- struct vty *vty;
- zebra_vni_t *zvni;
- zebra_vtep_t *zvtep;
- uint32_t num_vteps = 0;
- uint32_t num_macs = 0;
- uint32_t num_neigh = 0;
- json_object *json = NULL;
- json_object *json_vni = NULL;
- json_object *json_ip_str = NULL;
- json_object *json_vtep_list = NULL;
-
- vty = ctxt[0];
- json = ctxt[1];
-
- zvni = (zebra_vni_t *)bucket->data;
-
- zvtep = zvni->vteps;
- while (zvtep) {
- num_vteps++;
- zvtep = zvtep->next;
- }
-
- num_macs = num_valid_macs(zvni);
- num_neigh = hashcount(zvni->neigh_table);
- if (json == NULL)
- vty_out(vty, "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
- zvni->vni, "L2",
- zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
- num_macs, num_neigh, num_vteps,
- vrf_id_to_name(zvni->vrf_id));
- else {
- char vni_str[VNI_STR_LEN];
- snprintf(vni_str, sizeof(vni_str), "%u", zvni->vni);
- json_vni = json_object_new_object();
- json_object_int_add(json_vni, "vni", zvni->vni);
- json_object_string_add(json_vni, "type", "L2");
- json_object_string_add(json_vni, "vxlanIf",
- zvni->vxlan_if ? zvni->vxlan_if->name
- : "unknown");
- json_object_int_add(json_vni, "numMacs", num_macs);
- json_object_int_add(json_vni, "numArpNd", num_neigh);
- json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
- json_object_string_add(json_vni, "tenantVrf",
- vrf_id_to_name(zvni->vrf_id));
- if (num_vteps) {
- json_vtep_list = json_object_new_array();
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
- json_ip_str = json_object_new_string(
- inet_ntoa(zvtep->vtep_ip));
- json_object_array_add(json_vtep_list,
- json_ip_str);
- }
- json_object_object_add(json_vni, "remoteVteps",
- json_vtep_list);
- }
- json_object_object_add(json, vni_str, json_vni);
- }
-}
-
-/*
- * Print a VNI hash entry in detail - called for display of all VNIs.
- */
-static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data)
-{
- struct vty *vty;
- zebra_vni_t *zvni;
- json_object *json_array = NULL;
- bool use_json = false;
- struct zvni_evpn_show *zes = data;
-
- vty = zes->vty;
- json_array = zes->json;
- use_json = zes->use_json;
-
- zvni = (zebra_vni_t *)bucket->data;
-
- zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json, json_array);
-
- if (!use_json)
- vty_out(vty, "\n");
-}
-
-/*
- * Inform BGP about local MACIP.
- */
-static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
- struct ipaddr *ip, uint8_t flags,
- uint32_t seq, int state,
- struct zebra_evpn_es *es,
- uint16_t cmd)
-{
- char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- int ipa_len;
- struct zserv *client = NULL;
- struct stream *s = NULL;
- esi_t *esi = es ? &es->esi : zero_esi;
-
- client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
- /* BGP may not be running. */
- if (!client)
- return 0;
-
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
-
- zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
- stream_putl(s, vni);
- stream_put(s, macaddr->octet, ETH_ALEN);
- if (ip) {
- ipa_len = 0;
- if (IS_IPADDR_V4(ip))
- ipa_len = IPV4_MAX_BYTELEN;
- else if (IS_IPADDR_V6(ip))
- ipa_len = IPV6_MAX_BYTELEN;
-
- stream_putl(s, ipa_len); /* IP address length */
- if (ipa_len)
- stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
- } else
- stream_putl(s, 0); /* Just MAC. */
-
- if (cmd == ZEBRA_MACIP_ADD) {
- stream_putc(s, flags); /* sticky mac/gateway mac */
- stream_putl(s, seq); /* sequence number */
- stream_put(s, esi, sizeof(esi_t));
- } else {
- stream_putl(s, state); /* state - active/inactive */
- }
-
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- 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,
- 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++;
- else
- client->macipdel_cnt++;
-
- return zserv_send_message(client, s);
-}
-
-/*
- * Make hash key for neighbors.
- */
-static unsigned int neigh_hash_keymake(const void *p)
-{
- const zebra_neigh_t *n = p;
- const struct ipaddr *ip = &n->ip;
-
- if (IS_IPADDR_V4(ip))
- return jhash_1word(ip->ipaddr_v4.s_addr, 0);
-
- return jhash2(ip->ipaddr_v6.s6_addr32,
- array_size(ip->ipaddr_v6.s6_addr32), 0);
-}
-
-/*
- * Compare two neighbor hash structures.
- */
-static bool neigh_cmp(const void *p1, const void *p2)
-{
- const zebra_neigh_t *n1 = p1;
- const zebra_neigh_t *n2 = p2;
-
- if (n1 == NULL && n2 == NULL)
- return true;
-
- if (n1 == NULL || n2 == NULL)
- return false;
-
- return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0);
-}
-
-static int neigh_list_cmp(void *p1, void *p2)
-{
- const zebra_neigh_t *n1 = p1;
- const zebra_neigh_t *n2 = p2;
-
- return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr));
-}
-
-/*
- * Callback to allocate neighbor hash entry.
- */
-static void *zvni_neigh_alloc(void *p)
-{
- const zebra_neigh_t *tmp_n = p;
- zebra_neigh_t *n;
-
- n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
- *n = *tmp_n;
-
- return ((void *)n);
-}
-
-/*
- * Add neighbor entry.
- */
-static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
- struct ethaddr *mac, zebra_mac_t *zmac,
- uint32_t n_flags)
-{
- zebra_neigh_t tmp_n;
- zebra_neigh_t *n = NULL;
-
- memset(&tmp_n, 0, sizeof(zebra_neigh_t));
- memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
- n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc);
- assert(n);
-
- n->state = ZEBRA_NEIGH_INACTIVE;
- n->zvni = zvni;
- n->dad_ip_auto_recovery_timer = NULL;
- n->flags = n_flags;
-
- if (!zmac)
- zmac = zvni_mac_lookup(zvni, mac);
- zebra_vxlan_local_neigh_ref_mac(n, mac,
- zmac, false /* send_mac_update */);
-
- return n;
-}
-
-/*
- * Delete neighbor entry.
- */
-static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
-{
- zebra_neigh_t *tmp_n;
-
- if (n->mac)
- listnode_delete(n->mac->neigh_list, n);
-
- /* Cancel auto recovery */
- THREAD_OFF(n->dad_ip_auto_recovery_timer);
-
- /* Free the VNI hash entry and allocated memory. */
- tmp_n = hash_release(zvni->neigh_table, n);
- XFREE(MTYPE_NEIGH, tmp_n);
-
- return 0;
-}
-
-/*
- * Free neighbor hash entry (callback)
- */
-static void zvni_neigh_del_hash_entry(struct hash_bucket *bucket, void *arg)
-{
- struct neigh_walk_ctx *wctx = arg;
- zebra_neigh_t *n = bucket->data;
-
- if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL))
- || ((wctx->flags & DEL_REMOTE_NEIGH)
- && (n->flags & ZEBRA_NEIGH_REMOTE))
- || ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP)
- && (n->flags & ZEBRA_NEIGH_REMOTE)
- && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
- if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
- zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
- &n->emac, n->flags, n->state,
- false /*force*/);
-
- if (wctx->uninstall) {
- if (zebra_vxlan_neigh_is_static(n))
- zebra_vxlan_sync_neigh_dp_install(n,
- false /* set_inactive */,
- true /* force_clear_static */,
- __func__);
- if ((n->flags & ZEBRA_NEIGH_REMOTE))
- zvni_neigh_uninstall(wctx->zvni, n);
- }
-
- zvni_neigh_del(wctx->zvni, n);
- }
-
- return;
-}
-
-/*
- * Delete all neighbor entries for this VNI.
- */
-static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
- uint32_t flags)
-{
- struct neigh_walk_ctx wctx;
-
- if (!zvni->neigh_table)
- return;
-
- memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
- wctx.uninstall = uninstall;
- wctx.upd_client = upd_client;
- wctx.flags = flags;
-
- hash_iterate(zvni->neigh_table, zvni_neigh_del_hash_entry, &wctx);
-}
-
-/*
- * Look up neighbor hash entry.
- */
-static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip)
-{
- zebra_neigh_t tmp;
- zebra_neigh_t *n;
-
- memset(&tmp, 0, sizeof(tmp));
- memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
- n = hash_lookup(zvni->neigh_table, &tmp);
-
- return n;
-}
-
-/*
- * Process all neighbors associated with a MAC upon the MAC being learnt
- * locally or undergoing any other change (such as sequence number).
- */
-static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni,
- zebra_mac_t *zmac, bool seq_change, bool es_change)
-{
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- struct zebra_vrf *zvrf = NULL;
- char buf[ETHER_ADDR_STRLEN];
-
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
- prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
- seq_change ? "CHANGE" : "ADD", zvni->vni);
-
- /* Walk all neighbors and mark any inactive local neighbors as
- * active and/or update sequence number upon a move, and inform BGP.
- * The action for remote neighbors is TBD.
- * NOTE: We can't simply uninstall remote neighbors as the kernel may
- * accidentally end up deleting a just-learnt local neighbor.
- */
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change ||
- es_change) {
- ZEBRA_NEIGH_SET_ACTIVE(n);
- n->loc_seq = zmac->loc_seq;
- if (!(zvrf->dup_addr_detect &&
- zvrf->dad_freeze && !!CHECK_FLAG(n->flags,
- ZEBRA_NEIGH_DUPLICATE)))
- zvni_neigh_send_add_to_client(
- zvni->vni, &n->ip, &n->emac,
- n->mac, n->flags, n->loc_seq);
- }
- }
- }
-}
-
-/*
- * Process all neighbors associated with a local MAC upon the MAC being
- * deleted.
- */
-static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
- zebra_mac_t *zmac)
-{
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- char buf[ETHER_ADDR_STRLEN];
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u",
- prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
- zvni->vni);
-
- /* Walk all local neighbors and mark as inactive and inform
- * BGP, if needed.
- * TBD: There is currently no handling for remote neighbors. We
- * don't expect them to exist, if they do, do we install the MAC
- * as a remote MAC and the neighbor as remote?
- */
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
- ZEBRA_NEIGH_SET_INACTIVE(n);
- n->loc_seq = 0;
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, n->flags,
- ZEBRA_NEIGH_ACTIVE,
- false /*force*/);
- }
- }
- }
-}
-
-/*
- * Process all neighbors associated with a MAC upon the MAC being remotely
- * learnt.
- */
-static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
- zebra_mac_t *zmac)
-{
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- char buf[ETHER_ADDR_STRLEN];
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u",
- prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)),
- zvni->vni);
-
- /* Walk all local neighbors and mark as inactive and inform
- * BGP, if needed.
- */
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
- ZEBRA_NEIGH_SET_INACTIVE(n);
- n->loc_seq = 0;
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, n->flags,
- ZEBRA_NEIGH_ACTIVE,
- false /* force */);
- }
- }
- }
-}
-
-/*
- * Process all neighbors associated with a remote MAC upon the MAC being
- * deleted.
- */
-static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
- zebra_mac_t *zmac)
-{
- /* NOTE: Currently a NO-OP. */
-}
-
-static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac)
-{
- zebra_neigh_t *nbr = NULL;
- struct listnode *node = NULL;
-
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, nbr)) {
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) &&
- IS_ZEBRA_NEIGH_INACTIVE(nbr))
- zvni_neigh_probe(zvni, nbr);
- }
-}
-
-/*
- * Inform BGP about local neighbor addition.
- */
-static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr,
- zebra_mac_t *zmac,
- uint32_t neigh_flags,
- uint32_t seq)
-{
- uint8_t flags = 0;
-
- if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) {
- /* host reachability has not been verified locally */
-
- /* if no ES peer is claiming reachability we can't advertise
- * the entry
- */
- if (!CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
- return 0;
-
- /* ES peers are claiming reachability; we will
- * advertise the entry but with a proxy flag
- */
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
- }
-
- if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- /* Set router flag (R-bit) based on local neigh entry add */
- if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
- if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP);
-
- return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- seq, ZEBRA_NEIGH_ACTIVE,
- zmac ? zmac->es : NULL,
- ZEBRA_MACIP_ADD);
-}
-
-/*
- * Inform BGP about local neighbor deletion.
- */
-static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
- struct ethaddr *macaddr, uint32_t flags,
- int state, bool force)
-{
- if (!force) {
- if (CHECK_FLAG(flags, ZEBRA_NEIGH_LOCAL_INACTIVE) &&
- !CHECK_FLAG(flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
- /* the neigh was not advertised - nothing to delete */
- return 0;
- }
-
- return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
- 0, state, NULL, ZEBRA_MACIP_DEL);
-}
-
-/*
- * Install remote neighbor into the kernel.
- */
-static int zvni_rem_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n,
- bool was_static)
-{
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
- struct interface *vlan_if;
- int flags;
- int ret = 0;
-
- if (!(n->flags & ZEBRA_NEIGH_REMOTE))
- return 0;
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
- vxl = &zif->l2info.vxl;
-
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
- if (!vlan_if)
- return -1;
-
- flags = DPLANE_NTF_EXT_LEARNED;
- if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
- flags |= DPLANE_NTF_ROUTER;
- ZEBRA_NEIGH_SET_ACTIVE(n);
-
- dplane_rem_neigh_add(vlan_if, &n->ip, &n->emac, flags,
- was_static);
-
- return ret;
-}
-
-/*
- * Uninstall remote neighbor from the kernel.
- */
-static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
-{
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
- struct interface *vlan_if;
-
- if (!(n->flags & ZEBRA_NEIGH_REMOTE))
- return 0;
-
- if (!zvni->vxlan_if) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
- return -1;
- }
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
- vxl = &zif->l2info.vxl;
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
- if (!vlan_if)
- return -1;
-
- ZEBRA_NEIGH_SET_INACTIVE(n);
- n->loc_seq = 0;
-
- dplane_rem_neigh_delete(vlan_if, &n->ip);
-
- return 0;
-}
-
-/*
- * Probe neighbor from the kernel.
- */
-static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n)
-{
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
- struct interface *vlan_if;
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
- vxl = &zif->l2info.vxl;
-
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
- if (!vlan_if)
- return -1;
-
- dplane_rem_neigh_update(vlan_if, &n->ip, &n->emac);
-
- return 0;
-}
-
-/*
- * Install neighbor hash entry - called upon access VLAN change.
- */
-static void zvni_install_neigh_hash(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_neigh_t *n;
- struct neigh_walk_ctx *wctx = ctxt;
-
- n = (zebra_neigh_t *)bucket->data;
-
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
- zvni_rem_neigh_install(wctx->zvni, n, false /*was_static*/);
-}
-
-/* Get the VRR interface for SVI if any */
-struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp)
-{
- struct zebra_vrf *zvrf = NULL;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif = NULL;
-
- zvrf = vrf_info_lookup(ifp->vrf_id);
- assert(zvrf);
-
- FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) {
- zif = tmp_if->info;
- if (!zif)
- continue;
-
- if (!IS_ZEBRA_IF_MACVLAN(tmp_if))
- continue;
-
- if (zif->link == ifp)
- return tmp_if;
- }
-
- return NULL;
-}
-
-static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
-{
- struct listnode *cnode = NULL, *cnnode = NULL;
- struct connected *c = NULL;
- struct ethaddr macaddr;
-
- memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
-
- for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
- struct ipaddr ip;
-
- memset(&ip, 0, sizeof(struct ipaddr));
- if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
- continue;
-
- if (c->address->family == AF_INET) {
- ip.ipa_type = IPADDR_V4;
- memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
- sizeof(struct in_addr));
- } else if (c->address->family == AF_INET6) {
- ip.ipa_type = IPADDR_V6;
- memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
- sizeof(struct in6_addr));
- } else {
- continue;
- }
-
- zvni_gw_macip_del(ifp, zvni, &ip);
- }
-
- return 0;
-}
-
-static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
-{
- struct listnode *cnode = NULL, *cnnode = NULL;
- struct connected *c = NULL;
- struct ethaddr macaddr;
-
- memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
-
- for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
- struct ipaddr ip;
-
- memset(&ip, 0, sizeof(struct ipaddr));
- if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
- continue;
-
- if (c->address->family == AF_INET) {
- ip.ipa_type = IPADDR_V4;
- memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4),
- sizeof(struct in_addr));
- } else if (c->address->family == AF_INET6) {
- ip.ipa_type = IPADDR_V6;
- memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6),
- sizeof(struct in6_addr));
- } else {
- continue;
- }
-
- zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
- }
- return 0;
-}
-
-
-static int zvni_advertise_subnet(zebra_vni_t *zvni, struct interface *ifp,
- int advertise)
-{
- struct listnode *cnode = NULL, *cnnode = NULL;
- struct connected *c = NULL;
- struct ethaddr macaddr;
-
- memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
-
- for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
- struct prefix p;
-
- memcpy(&p, c->address, sizeof(struct prefix));
-
- /* skip link local address */
- if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
- continue;
-
- apply_mask(&p);
- if (advertise)
- ip_prefix_send_to_client(ifp->vrf_id, &p,
- ZEBRA_IP_PREFIX_ROUTE_ADD);
- else
- ip_prefix_send_to_client(ifp->vrf_id, &p,
- ZEBRA_IP_PREFIX_ROUTE_DEL);
- }
- return 0;
-}
-
-/*
- * zvni_gw_macip_add_to_client
- */
-static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
- struct ethaddr *macaddr, struct ipaddr *ip)
-{
- char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- zebra_neigh_t *n = NULL;
- zebra_mac_t *mac = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
-
- vxl = &zif->l2info.vxl;
-
- mac = zvni_mac_lookup(zvni, macaddr);
- if (!mac) {
- mac = zvni_mac_add(zvni, macaddr);
- if (!mac) {
- flog_err(EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add MAC %s intf %s(%u) VID %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vxl->access_vlan);
- return -1;
- }
- }
-
- /* Set "local" forwarding info. */
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.vid = vxl->access_vlan;
-
- n = zvni_neigh_lookup(zvni, ip);
- if (!n) {
- n = zvni_neigh_add(zvni, ip, macaddr, mac, 0);
- if (!n) {
- flog_err(
- EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni);
- return -1;
- }
- }
-
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- ZEBRA_NEIGH_SET_ACTIVE(n);
- memcpy(&n->emac, macaddr, ETH_ALEN);
- n->ifindex = ifp->ifindex;
-
- /* Only advertise in BGP if the knob is enabled */
- if (advertise_gw_macip_enabled(zvni)) {
-
- SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
- SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
- /* Set Router flag (R-bit) */
- if (ip->ipa_type == IPADDR_V6)
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x",
- ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
-
- zvni_neigh_send_add_to_client(zvni->vni, ip, &n->emac, n->mac,
- n->flags, n->loc_seq);
- } else if (advertise_svi_macip_enabled(zvni)) {
-
- SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP);
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x",
- ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
-
- zvni_neigh_send_add_to_client(zvni->vni, ip, &n->emac, n->mac,
- n->flags, n->loc_seq);
- }
-
- return 0;
-}
-
-/*
- * zvni_gw_macip_del_from_client
- */
-static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
- struct ipaddr *ip)
-{
- char buf1[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- zebra_neigh_t *n = NULL;
- zebra_mac_t *mac = NULL;
-
- /* If the neigh entry is not present nothing to do*/
- n = zvni_neigh_lookup(zvni, ip);
- if (!n)
- return 0;
-
- /* mac entry should be present */
- mac = zvni_mac_lookup(zvni, &n->emac);
- if (!mac) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u",
- prefix_mac2str(&n->emac,
- buf1, sizeof(buf1)),
- ipaddr2str(ip, buf2, sizeof(buf2)),
- zvni->vni);
- return -1;
- }
-
- /* If the entry is not local nothing to do*/
- if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
- return -1;
-
- /* only need to delete the entry from bgp if we sent it before */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
- ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
- ipaddr2str(ip, buf2, sizeof(buf2)));
-
- /* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- n->flags, ZEBRA_NEIGH_ACTIVE,
- false /*force*/);
-
- /* Delete this neighbor entry. */
- zvni_neigh_del(zvni, n);
-
- /* see if the mac needs to be deleted as well*/
- if (mac)
- zvni_deref_ip2mac(zvni, mac);
-
- return 0;
-}
-
-static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket,
- void *ctxt)
-{
- zebra_vni_t *zvni = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
- struct interface *vlan_if = NULL;
- struct interface *vrr_if = NULL;
- struct interface *ifp;
-
- /* Add primary SVI MAC*/
- zvni = (zebra_vni_t *)bucket->data;
-
- /* Global (Zvrf) advertise-default-gw is disabled,
- * but zvni advertise-default-gw is enabled
- */
- if (zvni->advertise_gw_macip) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip",
- zvni->vni);
- return;
- }
-
- ifp = zvni->vxlan_if;
- if (!ifp)
- return;
- zif = ifp->info;
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return;
-
- zl2_info = zif->l2info.vxl;
-
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
- if (!vlan_if)
- return;
-
- /* Del primary MAC-IP */
- zvni_del_macip_for_intf(vlan_if, zvni);
-
- /* Del VRR MAC-IP - if any*/
- vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
- if (vrr_if)
- zvni_del_macip_for_intf(vrr_if, zvni);
-
- return;
-}
-
-static void zvni_gw_macip_add_for_vni_hash(struct hash_bucket *bucket,
- void *ctxt)
-{
- zebra_vni_t *zvni = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
- struct interface *vlan_if = NULL;
- struct interface *vrr_if = NULL;
- struct interface *ifp = NULL;
-
- zvni = (zebra_vni_t *)bucket->data;
-
- ifp = zvni->vxlan_if;
- if (!ifp)
- return;
- zif = ifp->info;
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return;
- zl2_info = zif->l2info.vxl;
-
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
- if (!vlan_if)
- return;
-
- /* Add primary SVI MAC-IP */
- zvni_add_macip_for_intf(vlan_if, zvni);
-
- if (advertise_gw_macip_enabled(zvni)) {
- /* Add VRR MAC-IP - if any*/
- vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
- if (vrr_if)
- zvni_add_macip_for_intf(vrr_if, zvni);
- }
-
- return;
-}
-
-static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket,
- void *ctxt)
-{
- zebra_vni_t *zvni = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
- struct interface *vlan_if = NULL;
- struct interface *ifp;
-
- /* Add primary SVI MAC*/
- zvni = (zebra_vni_t *)bucket->data;
- if (!zvni)
- return;
-
- /* Global(vrf) advertise-svi-ip disabled, but zvni advertise-svi-ip
- * enabled
- */
- if (zvni->advertise_svi_macip) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip",
- zvni->vni);
- return;
- }
-
- ifp = zvni->vxlan_if;
- if (!ifp)
- return;
- zif = ifp->info;
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return;
-
- zl2_info = zif->l2info.vxl;
-
- vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
- zif->brslave_info.br_if);
- if (!vlan_if)
- return;
-
- /* Del primary MAC-IP */
- zvni_del_macip_for_intf(vlan_if, zvni);
-
- return;
-}
-
-static inline void zvni_local_neigh_update_log(const char *pfx,
- zebra_neigh_t *n, bool is_router, bool local_inactive,
- bool old_bgp_ready, bool new_bgp_ready,
- bool inform_dataplane, bool inform_bgp, const char *sfx)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- if (!IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- return;
-
- zlog_debug("%s neigh vni %u ip %s mac %s f 0x%x%s%s%s%s%s%s %s",
- pfx, n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)),
- n->flags, is_router ? " router" : "",
- local_inactive ? " local-inactive" : "",
- old_bgp_ready ? " old_bgp_ready" : "",
- new_bgp_ready ? " new_bgp_ready" : "",
- inform_dataplane ? " inform_dp" : "",
- inform_bgp ? " inform_bgp" : "",
- sfx);
-}
-
-static int zvni_local_neigh_update(zebra_vni_t *zvni,
- struct interface *ifp,
- struct ipaddr *ip,
- struct ethaddr *macaddr,
- bool is_router,
- bool local_inactive, bool dp_static)
-{
- char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- struct zebra_vrf *zvrf;
- zebra_neigh_t *n = NULL;
- zebra_mac_t *zmac = NULL, *old_zmac = NULL;
- uint32_t old_mac_seq = 0, mac_new_seq = 0;
- bool upd_mac_seq = false;
- bool neigh_mac_change = false;
- bool neigh_on_hold = false;
- bool neigh_was_remote = false;
- bool do_dad = false;
- struct in_addr vtep_ip = {.s_addr = 0};
- bool inform_dataplane = false;
- bool created = false;
- bool new_static = false;
- bool old_bgp_ready = false;
- bool new_bgp_ready;
-
- /* Check if the MAC exists. */
- zmac = zvni_mac_lookup(zvni, macaddr);
- if (!zmac) {
- /* create a dummy MAC if the MAC is not already present */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "AUTO MAC %s created for neigh %s on VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
-
- zmac = zvni_mac_add(zvni, macaddr);
- if (!zmac) {
- zlog_debug("Failed to add MAC %s VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
- return -1;
- }
-
- memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
- memset(&zmac->flags, 0, sizeof(uint32_t));
- SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
- } else {
- if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
- /*
- * We don't change the MAC to local upon a neighbor
- * learn event, we wait for the explicit local MAC
- * learn. However, we have to compute its sequence
- * number in preparation for when it actually turns
- * local.
- */
- upd_mac_seq = true;
- }
- }
-
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(" Unable to find vrf for: %d",
- zvni->vxlan_if->vrf_id);
- return -1;
- }
-
- /* Check if the neighbor exists. */
- n = zvni_neigh_lookup(zvni, ip);
- if (!n) {
- /* New neighbor - create */
- n = zvni_neigh_add(zvni, ip, macaddr, zmac, 0);
- if (!n) {
- flog_err(
- EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
- ipaddr2str(ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, zvni->vni);
- return -1;
- }
- /* Set "local" forwarding info. */
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- created = true;
- } else {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- bool mac_different;
- bool cur_is_router;
- bool old_local_inactive;
-
- old_local_inactive = !!CHECK_FLAG(n->flags,
- ZEBRA_NEIGH_LOCAL_INACTIVE);
-
- old_bgp_ready =
- zebra_vxlan_neigh_is_ready_for_bgp(n);
-
- /* Note any changes and see if of interest to BGP. */
- mac_different = !!memcmp(&n->emac,
- macaddr, ETH_ALEN);
- cur_is_router = !!CHECK_FLAG(n->flags,
- ZEBRA_NEIGH_ROUTER_FLAG);
- new_static = zebra_vxlan_neigh_is_static(n);
- if (!mac_different && is_router == cur_is_router &&
- old_local_inactive == local_inactive &&
- dp_static != new_static) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- " Ignoring entry mac is the same and is_router == cur_is_router");
- n->ifindex = ifp->ifindex;
- return 0;
- }
-
- old_zmac = n->mac;
- if (!mac_different) {
- /* XXX - cleanup this code duplication */
- bool is_neigh_freezed = false;
-
- /* Only the router flag has changed. */
- if (is_router)
- SET_FLAG(n->flags,
- ZEBRA_NEIGH_ROUTER_FLAG);
- else
- UNSET_FLAG(n->flags,
- ZEBRA_NEIGH_ROUTER_FLAG);
-
- if (local_inactive)
- SET_FLAG(n->flags,
- ZEBRA_NEIGH_LOCAL_INACTIVE);
- else
- UNSET_FLAG(n->flags,
- ZEBRA_NEIGH_LOCAL_INACTIVE);
- new_bgp_ready =
- zebra_vxlan_neigh_is_ready_for_bgp(n);
-
- /* Neigh is in freeze state and freeze action
- * is enabled, do not send update to client.
- */
- is_neigh_freezed = (zvrf->dup_addr_detect &&
- zvrf->dad_freeze &&
- CHECK_FLAG(n->flags,
- ZEBRA_NEIGH_DUPLICATE));
-
- zvni_local_neigh_update_log("local", n,
- is_router, local_inactive,
- old_bgp_ready, new_bgp_ready,
- false, false, "flag-update");
-
- /* if the neigh can no longer be advertised
- * remove it from bgp
- */
- if (!is_neigh_freezed) {
- zebra_vxlan_neigh_send_add_del_to_client(
- n, old_bgp_ready, new_bgp_ready);
- } else {
- if (IS_ZEBRA_DEBUG_VXLAN &&
- IS_ZEBRA_NEIGH_ACTIVE(n))
- zlog_debug(
- " Neighbor active and frozen");
- }
- return 0;
- }
-
- /* The MAC has changed, need to issue a delete
- * first as this means a different MACIP route.
- * Also, need to do some unlinking/relinking.
- * We also need to update the MAC's sequence number
- * in different situations.
- */
- if (old_bgp_ready) {
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, n->flags, n->state,
- false /*force*/);
- old_bgp_ready = false;
- }
- if (old_zmac) {
- old_mac_seq = CHECK_FLAG(old_zmac->flags,
- ZEBRA_MAC_REMOTE) ?
- old_zmac->rem_seq : old_zmac->loc_seq;
- neigh_mac_change = upd_mac_seq = true;
- zebra_vxlan_local_neigh_deref_mac(n,
- true /* send_mac_update */);
- }
-
- /* if mac changes abandon peer flags and tell
- * dataplane to clear the static flag
- */
- if (zebra_vxlan_neigh_clear_sync_info(n))
- inform_dataplane = true;
- /* Update the forwarding info. */
- n->ifindex = ifp->ifindex;
-
- /* Link to new MAC */
- zebra_vxlan_local_neigh_ref_mac(n, macaddr, zmac,
- true /* send_mac_update */);
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- /*
- * Neighbor has moved from remote to local. Its
- * MAC could have also changed as part of the move.
- */
- if (memcmp(n->emac.octet, macaddr->octet,
- ETH_ALEN) != 0) {
- old_zmac = n->mac;
- if (old_zmac) {
- old_mac_seq = CHECK_FLAG(
- old_zmac->flags,
- ZEBRA_MAC_REMOTE) ?
- old_zmac->rem_seq :
- old_zmac->loc_seq;
- neigh_mac_change = upd_mac_seq = true;
- zebra_vxlan_local_neigh_deref_mac(n,
- true /* send_update */);
- }
-
- /* Link to new MAC */
- zebra_vxlan_local_neigh_ref_mac(n, macaddr,
- zmac, true /*send_update*/);
- }
- /* Based on Mobility event Scenario-B from the
- * draft, neigh's previous state was remote treat this
- * event for DAD.
- */
- neigh_was_remote = true;
- vtep_ip = n->r_vtep_ip;
- /* Mark appropriately */
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
- n->r_vtep_ip.s_addr = INADDR_ANY;
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- n->ifindex = ifp->ifindex;
- }
- }
-
- /* If MAC was previously remote, or the neighbor had a different
- * MAC earlier, recompute the sequence number.
- */
- if (upd_mac_seq) {
- uint32_t seq1, seq2;
-
- seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ?
- zmac->rem_seq + 1 : zmac->loc_seq;
- seq2 = neigh_mac_change ? old_mac_seq + 1 : 0;
- mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ?
- MAX(seq1, seq2) : zmac->loc_seq;
- }
-
- if (local_inactive)
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
- else
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
-
- /* Mark Router flag (R-bit) */
- if (is_router)
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
- 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_vxlan_neigh_is_static(n);
- if (!new_static)
- inform_dataplane = true;
- }
-
- /* Check old and/or new MAC detected as duplicate mark
- * the neigh as duplicate
- */
- if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) {
- flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
- "VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC",
- zvni->vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- }
-
- /* For IP Duplicate Address Detection (DAD) is trigger,
- * when the event is extended mobility based on scenario-B
- * from the draft, IP/Neigh's MAC binding changed and
- * neigh's previous state was remote.
- */
- if (neigh_mac_change && neigh_was_remote)
- do_dad = true;
-
- zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad,
- &neigh_on_hold, true);
-
- if (inform_dataplane)
- zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
- false /* force_clear_static */, __func__);
-
- /* Before we program this in BGP, we need to check if MAC is locally
- * learnt. If not, force neighbor to be inactive and reset its seq.
- */
- if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) {
- zvni_local_neigh_update_log("local",
- n, is_router, local_inactive,
- false, false, inform_dataplane, false,
- "auto-mac");
- ZEBRA_NEIGH_SET_INACTIVE(n);
- n->loc_seq = 0;
- zmac->loc_seq = mac_new_seq;
- return 0;
- }
-
- zvni_local_neigh_update_log("local",
- n, is_router, local_inactive, false, false, inform_dataplane,
- true, created ? "created" : "updated");
-
- /* If the MAC's sequence number has changed, inform the MAC and all
- * neighbors associated with the MAC to BGP, else just inform this
- * neighbor.
- */
- if (upd_mac_seq && zmac->loc_seq != mac_new_seq) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni, zmac->loc_seq, mac_new_seq);
- zmac->loc_seq = mac_new_seq;
- if (zvni_mac_send_add_to_client(zvni->vni, macaddr,
- zmac->flags, zmac->loc_seq, zmac->es))
- return -1;
- zvni_process_neigh_on_local_mac_change(zvni, zmac, 1,
- 0 /*es_change*/);
- return 0;
- }
-
- n->loc_seq = zmac->loc_seq;
-
- if (!neigh_on_hold) {
- ZEBRA_NEIGH_SET_ACTIVE(n);
- new_bgp_ready =
- zebra_vxlan_neigh_is_ready_for_bgp(n);
- zebra_vxlan_neigh_send_add_del_to_client(n,
- old_bgp_ready, new_bgp_ready);
- } else {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(" Neighbor on hold not sending");
- }
- return 0;
-}
-
-static int zvni_remote_neigh_update(zebra_vni_t *zvni,
- struct interface *ifp,
- struct ipaddr *ip,
- struct ethaddr *macaddr,
- uint16_t state)
-{
- char buf[ETHER_ADDR_STRLEN];
- char buf2[INET6_ADDRSTRLEN];
- zebra_neigh_t *n = NULL;
- zebra_mac_t *zmac = NULL;
-
- /* If the neighbor is unknown, there is no further action. */
- n = zvni_neigh_lookup(zvni, ip);
- if (!n)
- return 0;
-
- /* If a remote entry, see if it needs to be refreshed */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
-#ifdef GNU_LINUX
- if (state & NUD_STALE)
- zvni_rem_neigh_install(zvni, n, false /*was_static*/);
-#endif
- } else {
- /* We got a "remote" neighbor notification for an entry
- * we think is local. This can happen in a multihoming
- * scenario - but only if the MAC is already "remote".
- * Just mark our entry as "remote".
- */
- zmac = zvni_mac_lookup(zvni, macaddr);
- if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
- zlog_debug(
- "Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
- return -1;
- }
-
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
- SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
- ZEBRA_NEIGH_SET_ACTIVE(n);
- n->r_vtep_ip = zmac->fwd_info.r_vtep_ip;
- }
-
- return 0;
-}
-
-/*
- * Make hash key for MAC.
- */
-static unsigned int mac_hash_keymake(const void *p)
-{
- const zebra_mac_t *pmac = p;
- const void *pnt = (void *)pmac->macaddr.octet;
-
- return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
-}
-
-/*
- * Compare two MAC addresses.
- */
-static bool mac_cmp(const void *p1, const void *p2)
-{
- const zebra_mac_t *pmac1 = p1;
- const zebra_mac_t *pmac2 = p2;
-
- if (pmac1 == NULL && pmac2 == NULL)
- return true;
-
- if (pmac1 == NULL || pmac2 == NULL)
- return false;
-
- return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
- == 0);
-}
-
-/*
- * Callback to allocate MAC hash entry.
- */
-static void *zvni_mac_alloc(void *p)
-{
- const zebra_mac_t *tmp_mac = p;
- zebra_mac_t *mac;
-
- mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
- *mac = *tmp_mac;
-
- return ((void *)mac);
-}
-
-/*
- * Add MAC entry.
- */
-static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
-{
- zebra_mac_t tmp_mac;
- zebra_mac_t *mac = NULL;
-
- memset(&tmp_mac, 0, sizeof(zebra_mac_t));
- memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
- mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
- assert(mac);
-
- mac->zvni = zvni;
- mac->dad_mac_auto_recovery_timer = NULL;
-
- mac->neigh_list = list_new();
- mac->neigh_list->cmp = neigh_list_cmp;
-
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
- char buf[ETHER_ADDR_STRLEN];
-
- zlog_debug("%s: MAC %s flags 0x%x",
- __func__,
- prefix_mac2str(&mac->macaddr,
- buf, sizeof(buf)),
- mac->flags);
- }
- return mac;
-}
-
-/*
- * Delete MAC entry.
- */
-static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
-{
- zebra_mac_t *tmp_mac;
-
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
- char buf[ETHER_ADDR_STRLEN];
-
- zlog_debug("%s: MAC %s flags 0x%x",
- __func__,
- prefix_mac2str(&mac->macaddr,
- buf, sizeof(buf)),
- mac->flags);
- }
-
- /* force de-ref any ES entry linked to the MAC */
- zebra_evpn_es_mac_deref_entry(mac);
-
- /* Cancel proxy hold timer */
- zebra_vxlan_mac_stop_hold_timer(mac);
-
- /* Cancel auto recovery */
- THREAD_OFF(mac->dad_mac_auto_recovery_timer);
-
- list_delete(&mac->neigh_list);
-
- /* Free the VNI hash entry and allocated memory. */
- tmp_mac = hash_release(zvni->mac_table, mac);
- XFREE(MTYPE_MAC, tmp_mac);
-
- return 0;
-}
-
-static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx,
- zebra_mac_t *mac)
-{
- if ((wctx->flags & DEL_LOCAL_MAC) &&
- (mac->flags & ZEBRA_MAC_LOCAL))
- return true;
- else if ((wctx->flags & DEL_REMOTE_MAC) &&
- (mac->flags & ZEBRA_MAC_REMOTE))
- return true;
- else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) &&
- (mac->flags & ZEBRA_MAC_REMOTE) &&
- IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
- return true;
- else if ((wctx->flags & DEL_LOCAL_MAC) &&
- (mac->flags & ZEBRA_MAC_AUTO) &&
- !listcount(mac->neigh_list)) {
- if (IS_ZEBRA_DEBUG_VXLAN) {
- char buf[ETHER_ADDR_STRLEN];
-
- zlog_debug(
- "%s: Del MAC %s flags 0x%x", __func__,
- prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
- }
- wctx->uninstall = 0;
-
- return true;
- }
-
- return false;
-}
-
-/*
- * Free MAC hash entry (callback)
- */
-static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
-{
- struct mac_walk_ctx *wctx = arg;
- zebra_mac_t *mac = bucket->data;
-
- if (zvni_check_mac_del_from_db(wctx, mac)) {
- if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
- zvni_mac_send_del_to_client(wctx->zvni->vni,
- &mac->macaddr, mac->flags, false);
- }
- if (wctx->uninstall) {
- if (zebra_vxlan_mac_is_static(mac))
- zebra_vxlan_sync_mac_dp_install(mac,
- false /* set_inactive */,
- true /* force_clear_static */,
- __func__);
-
- if (mac->flags & ZEBRA_MAC_REMOTE)
- zvni_rem_mac_uninstall(wctx->zvni, mac);
- }
-
- zvni_mac_del(wctx->zvni, mac);
- }
-
- return;
-}
-
-/*
- * Delete all MAC entries for this VNI.
- */
-static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client,
- uint32_t flags)
-{
- struct mac_walk_ctx wctx;
-
- if (!zvni->mac_table)
- return;
-
- memset(&wctx, 0, sizeof(struct mac_walk_ctx));
- wctx.zvni = zvni;
- wctx.uninstall = uninstall;
- wctx.upd_client = upd_client;
- wctx.flags = flags;
-
- hash_iterate(zvni->mac_table, zvni_mac_del_hash_entry, &wctx);
-}
-
-/*
- * Look up MAC hash entry.
- */
-static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
-{
- zebra_mac_t tmp;
- zebra_mac_t *pmac;
-
- memset(&tmp, 0, sizeof(tmp));
- memcpy(&tmp.macaddr, mac, ETH_ALEN);
- pmac = hash_lookup(zvni->mac_table, &tmp);
-
- return pmac;
-}
-
-/*
- * Inform BGP about local MAC addition.
- */
-static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
- uint32_t mac_flags, uint32_t seq, struct zebra_evpn_es *es)
-{
- uint8_t flags = 0;
-
- if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
- /* host reachability has not been verified locally */
-
- /* if no ES peer is claiming reachability we can't advertise the
- * entry
- */
- if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- return 0;
-
- /* ES peers are claiming reachability; we will
- * advertise the entry but with a proxy flag
- */
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
- }
-
- if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
- SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
-
- return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
- seq, ZEBRA_NEIGH_ACTIVE, es,
- ZEBRA_MACIP_ADD);
-}
-
-/*
- * Inform BGP about local MAC deletion.
- */
-static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr,
- uint32_t flags, bool force)
-{
- if (!force) {
- if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) &&
- !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- /* the host was not advertised - nothing to delete */
- return 0;
- }
-
- return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
- 0 /* seq */, ZEBRA_NEIGH_ACTIVE, NULL,
- ZEBRA_MACIP_DEL);
-}
-
-/*
- * Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC
- * notifications, to see if they are of interest.
- */
-static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
- struct interface *br_if, vlanid_t vid)
-{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- zebra_vni_t *zvni;
- int found = 0;
-
- /* Determine if bridge is VLAN-aware or not */
- zif = br_if->info;
- assert(zif);
- br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
-
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return NULL;
-
- zvni = zvni_lookup(vxl->vni);
- return zvni;
-}
-
-/*
- * Map SVI and associated bridge to a VNI. This is invoked upon getting
- * neighbor notifications, to see if they are of interest.
- */
-static zebra_vni_t *zvni_from_svi(struct interface *ifp,
- struct interface *br_if)
-{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- vlanid_t vid = 0;
- zebra_vni_t *zvni;
- int found = 0;
-
- if (!br_if)
- return NULL;
-
- /* Make sure the linked interface is a bridge. */
- if (!IS_ZEBRA_IF_BRIDGE(br_if))
- return NULL;
-
- /* Determine if bridge is VLAN-aware or not */
- zif = br_if->info;
- assert(zif);
- br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
- if (bridge_vlan_aware) {
- struct zebra_l2info_vlan *vl;
-
- if (!IS_ZEBRA_IF_VLAN(ifp))
- return NULL;
-
- zif = ifp->info;
- assert(zif);
- vl = &zif->l2info.vl;
- vid = vl->vid;
- }
-
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return NULL;
-
- zvni = zvni_lookup(vxl->vni);
- return zvni;
-}
-
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
* of two cases:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
@@ -4042,7 +789,7 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
* (b) In the case of a VLAN-unaware bridge, the SVI is the bridge interface
* itself
*/
-static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
+struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
struct zebra_ns *zns;
struct route_node *rn;
@@ -4090,496 +837,30 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
return found ? tmp_if : NULL;
}
-/* Map to MAC-VLAN interface corresponding to specified SVI interface.
- */
-static struct interface *zvni_map_to_macvlan(struct interface *br_if,
- struct interface *svi_if)
-{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
- int found = 0;
-
- /* Defensive check, caller expected to invoke only with valid bridge. */
- if (!br_if)
- return NULL;
-
- if (!svi_if) {
- zlog_debug("svi_if is not passed.");
- return NULL;
- }
-
- /* Determine if bridge is VLAN-aware or not */
- zif = br_if->info;
- assert(zif);
-
- /* Identify corresponding VLAN interface. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- /* Check oper status of the SVI. */
- if (!tmp_if || !if_is_operative(tmp_if))
- continue;
- zif = tmp_if->info;
-
- if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
- continue;
-
- if (zif->link == svi_if) {
- found = 1;
- break;
- }
- }
-
- return found ? tmp_if : NULL;
-}
-
-
-/*
- * Install remote MAC into the forwarding plane.
- */
-static int zvni_rem_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac,
- bool was_static)
-{
- const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
- bool sticky;
- enum zebra_dplane_result res;
- const struct interface *br_ifp;
- vlanid_t vid;
- uint32_t nhg_id;
- struct in_addr vtep_ip;
-
- if (!(mac->flags & ZEBRA_MAC_REMOTE))
- return 0;
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
-
- br_ifp = zif->brslave_info.br_if;
- if (br_ifp == NULL)
- return -1;
-
- vxl = &zif->l2info.vxl;
-
- sticky = !!CHECK_FLAG(mac->flags,
- (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
-
- /* If nexthop group for the FDB entry is inactive (not programmed in
- * the dataplane) the MAC entry cannot be installed
- */
- if (mac->es) {
- if (!(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
- return -1;
- nhg_id = mac->es->nhg_id;
- vtep_ip.s_addr = 0;
- } else {
- nhg_id = 0;
- vtep_ip = mac->fwd_info.r_vtep_ip;
- }
-
- br_zif = (const struct zebra_if *)(br_ifp->info);
-
- if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
- else
- vid = 0;
-
- res = dplane_rem_mac_add(zvni->vxlan_if, br_ifp, vid,
- &mac->macaddr, vtep_ip, sticky,
- nhg_id, was_static);
- if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
- return 0;
- else
- return -1;
-}
-
-/*
- * Uninstall remote MAC from the forwarding plane.
- */
-static int zvni_rem_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac)
-{
- const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
- struct in_addr vtep_ip;
- const struct interface *ifp, *br_ifp;
- vlanid_t vid;
- enum zebra_dplane_result res;
-
- if (!(mac->flags & ZEBRA_MAC_REMOTE))
- return 0;
-
- if (!zvni->vxlan_if) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
- return -1;
- }
-
- zif = zvni->vxlan_if->info;
- if (!zif)
- return -1;
-
- br_ifp = zif->brslave_info.br_if;
- if (br_ifp == NULL)
- return -1;
-
- vxl = &zif->l2info.vxl;
-
- br_zif = (const struct zebra_if *)br_ifp->info;
-
- if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
- else
- vid = 0;
-
- ifp = zvni->vxlan_if;
- vtep_ip = mac->fwd_info.r_vtep_ip;
-
- res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
- if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
- return 0;
- else
- return -1;
-}
-
-/*
- * Install MAC hash entry - called upon access VLAN change.
- */
-static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_mac_t *mac;
- struct mac_walk_ctx *wctx = ctxt;
-
- mac = (zebra_mac_t *)bucket->data;
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
- zvni_rem_mac_install(wctx->zvni, mac, false);
-}
-
-/*
- * Count of remote neighbors referencing this MAC.
- */
-static int remote_neigh_count(zebra_mac_t *zmac)
-{
- zebra_neigh_t *n = NULL;
- struct listnode *node = NULL;
- int count = 0;
-
- for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
- count++;
- }
-
- return count;
-}
-
-/*
- * Decrement neighbor refcount of MAC; uninstall and free it if
- * appropriate.
- */
-static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
-{
- if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
- return;
-
- /* If all remote neighbors referencing a remote MAC go away,
- * we need to uninstall the MAC.
- */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
- remote_neigh_count(mac) == 0) {
- zvni_rem_mac_uninstall(zvni, mac);
- zebra_evpn_es_mac_deref_entry(mac);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- }
-
- /* If no neighbors, delete the MAC. */
- if (list_isempty(mac->neigh_list))
- zvni_mac_del(zvni, mac);
-}
-
-/*
- * Read and populate local MACs and neighbors corresponding to this VNI.
- */
-static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
-{
- struct zebra_ns *zns;
- struct zebra_if *zif;
- struct interface *vlan_if;
- struct zebra_l2info_vxlan *vxl;
- struct interface *vrr_if;
-
- zif = ifp->info;
- vxl = &zif->l2info.vxl;
- zns = zebra_ns_lookup(NS_DEFAULT);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u",
- ifp->name, ifp->ifindex, zvni->vni,
- zif->brslave_info.bridge_ifindex);
-
- macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
- if (vlan_if) {
-
- /* Add SVI MAC-IP */
- zvni_add_macip_for_intf(vlan_if, zvni);
-
- /* Add VRR MAC-IP - if any*/
- vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
- if (vrr_if)
- zvni_add_macip_for_intf(vrr_if, zvni);
-
- neigh_read_for_vlan(zns, vlan_if);
- }
-}
-
-/*
- * Hash function for VNI.
- */
-static unsigned int vni_hash_keymake(const void *p)
-{
- const zebra_vni_t *zvni = p;
-
- return (jhash_1word(zvni->vni, 0));
-}
-
-/*
- * Compare 2 VNI hash entries.
- */
-static bool vni_hash_cmp(const void *p1, const void *p2)
-{
- const zebra_vni_t *zvni1 = p1;
- const zebra_vni_t *zvni2 = p2;
-
- return (zvni1->vni == zvni2->vni);
-}
-
-int vni_list_cmp(void *p1, void *p2)
-{
- const zebra_vni_t *zvni1 = p1;
- const zebra_vni_t *zvni2 = p2;
-
- if (zvni1->vni == zvni2->vni)
- return 0;
- return (zvni1->vni < zvni2->vni) ? -1 : 1;
-}
-
-/*
- * Callback to allocate VNI hash entry.
- */
-static void *zvni_alloc(void *p)
-{
- const zebra_vni_t *tmp_vni = p;
- zebra_vni_t *zvni;
-
- zvni = XCALLOC(MTYPE_ZVNI, sizeof(zebra_vni_t));
- zvni->vni = tmp_vni->vni;
- return ((void *)zvni);
-}
-
-/*
- * Look up VNI hash entry.
- */
-zebra_vni_t *zvni_lookup(vni_t vni)
-{
- struct zebra_vrf *zvrf;
- zebra_vni_t tmp_vni;
- zebra_vni_t *zvni = NULL;
-
- zvrf = zebra_vrf_get_evpn();
- assert(zvrf);
- memset(&tmp_vni, 0, sizeof(zebra_vni_t));
- tmp_vni.vni = vni;
- zvni = hash_lookup(zvrf->vni_table, &tmp_vni);
-
- return zvni;
-}
-
-/*
- * Add VNI hash entry.
- */
-static zebra_vni_t *zvni_add(vni_t vni)
-{
- struct zebra_vrf *zvrf;
- zebra_vni_t tmp_zvni;
- zebra_vni_t *zvni = NULL;
-
- zvrf = zebra_vrf_get_evpn();
- assert(zvrf);
- memset(&tmp_zvni, 0, sizeof(zebra_vni_t));
- tmp_zvni.vni = vni;
- zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc);
- assert(zvni);
-
- zebra_evpn_vni_es_init(zvni);
-
- /* Create hash table for MAC */
- zvni->mac_table =
- hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table");
-
- /* Create hash table for neighbors */
- zvni->neigh_table = hash_create(neigh_hash_keymake, neigh_cmp,
- "Zebra VNI Neighbor Table");
-
- return zvni;
-}
-
-/* vni<=>vxlan_zif association */
-static void zvni_vxlan_if_set(zebra_vni_t *zvni, struct interface *ifp,
- bool set)
-{
- struct zebra_if *zif;
-
- if (set) {
- if (zvni->vxlan_if == ifp)
- return;
- zvni->vxlan_if = ifp;
- } else {
- if (!zvni->vxlan_if)
- return;
- zvni->vxlan_if = NULL;
- }
-
- if (ifp)
- zif = ifp->info;
- else
- zif = NULL;
-
- zebra_evpn_vxl_vni_set(zif, zvni, set);
-}
-
-/*
- * Delete VNI hash entry.
- */
-static int zvni_del(zebra_vni_t *zvni)
+static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn)
{
- struct zebra_vrf *zvrf;
- zebra_vni_t *tmp_zvni;
-
- zvrf = zebra_vrf_get_evpn();
- assert(zvrf);
-
- zvni_vxlan_if_set(zvni, zvni->vxlan_if, false /* set */);
+ zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */);
/* Remove references to the BUM mcast grp */
- zebra_vxlan_sg_deref(zvni->local_vtep_ip, zvni->mcast_grp);
-
- /* Free the neighbor hash table. */
- hash_free(zvni->neigh_table);
- zvni->neigh_table = NULL;
-
- /* Free the MAC hash table. */
- hash_free(zvni->mac_table);
- zvni->mac_table = NULL;
-
- zebra_evpn_vni_es_cleanup(zvni);
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip, zevpn->mcast_grp);
- /* Free the VNI hash entry and allocated memory. */
- tmp_zvni = hash_release(zvrf->vni_table, zvni);
- XFREE(MTYPE_ZVNI, tmp_zvni);
-
- return 0;
+ return zebra_evpn_del(zevpn);
}
-
-/*
- * Inform BGP about local VNI addition.
- */
-static int zvni_send_add_to_client(zebra_vni_t *zvni)
-{
- struct zserv *client;
- struct stream *s;
- int rc;
-
- client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
- /* BGP may not be running. */
- if (!client)
- return 0;
-
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
-
- zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
- stream_putl(s, zvni->vni);
- stream_put_in_addr(s, &zvni->local_vtep_ip);
- stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
- stream_put_in_addr(s, &zvni->mcast_grp);
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s", zvni->vni,
- inet_ntoa(zvni->local_vtep_ip),
- vrf_id_to_name(zvni->vrf_id),
- zebra_route_string(client->proto));
-
- client->vniadd_cnt++;
- rc = zserv_send_message(client, s);
-
- if (!(zvni->flags & ZVNI_READY_FOR_BGP)) {
- zvni->flags |= ZVNI_READY_FOR_BGP;
- /* once the VNI is sent the ES-EVIs can also be replayed
- * to BGP
- */
- zebra_evpn_vni_update_all_es(zvni);
- }
- return rc;
-}
-
-/*
- * Inform BGP about local VNI deletion.
- */
-static int zvni_send_del_to_client(zebra_vni_t *zvni)
-{
- struct zserv *client;
- struct stream *s;
-
- client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
- /* BGP may not be running. */
- if (!client)
- return 0;
-
- if (zvni->flags & ZVNI_READY_FOR_BGP) {
- zvni->flags &= ~ZVNI_READY_FOR_BGP;
- /* the ES-EVIs must be removed from BGP before the VNI is */
- zebra_evpn_vni_update_all_es(zvni);
- }
-
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
- stream_reset(s);
-
- zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id());
- stream_putl(s, zvni->vni);
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send VNI_DEL %u to %s", zvni->vni,
- zebra_route_string(client->proto));
-
- client->vnidel_cnt++;
- return zserv_send_message(client, s);
-}
-
/*
* Build the VNI hash table by going over the VxLAN interfaces. This
* is called when EVPN (advertise-all-vni) is enabled.
*/
-static void zvni_build_hash_table(void)
+static void zevpn_build_hash_table(void)
{
struct zebra_ns *zns;
struct route_node *rn;
struct interface *ifp;
- /* Walk VxLAN interfaces and create VNI hash. */
+ /* Walk VxLAN interfaces and create EVPN hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
vni_t vni;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
@@ -4636,11 +917,11 @@ static void zvni_build_hash_table(void)
ifp->name, ifp->ifindex, vni,
inet_ntoa(vxl->vtep_ip));
- /* VNI hash entry is expected to exist, if the BGP process is killed */
- zvni = zvni_lookup(vni);
- if (zvni) {
+ /* EVPN hash entry is expected to exist, if the BGP process is killed */
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn) {
zlog_debug(
- "VNI hash already present for IF %s(%u) L2-VNI %u",
+ "EVPN hash already present for IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
/*
@@ -4649,48 +930,49 @@ static void zvni_build_hash_table(void)
*/
if (if_is_operative(ifp) &&
zif->brslave_info.br_if)
- zvni_send_add_to_client(zvni);
+ zebra_evpn_send_add_to_client(zevpn);
/* Send Local MAC-entries to client */
- zvni_send_mac_to_client(zvni);
+ zebra_evpn_send_mac_list_to_client(zevpn);
/* Send Loval Neighbor entries to client */
- zvni_send_neigh_to_client(zvni);
+ zebra_evpn_send_neigh_to_client(zevpn);
} else {
- zvni = zvni_add(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_add(vni);
+ if (!zevpn) {
zlog_debug(
- "Failed to add VNI hash, IF %s(%u) L2-VNI %u",
+ "Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
return;
}
- if (zvni->local_vtep_ip.s_addr !=
+ if (zevpn->local_vtep_ip.s_addr !=
vxl->vtep_ip.s_addr ||
- zvni->mcast_grp.s_addr !=
+ zevpn->mcast_grp.s_addr !=
vxl->mcast_grp.s_addr) {
zebra_vxlan_sg_deref(
- zvni->local_vtep_ip,
- zvni->mcast_grp);
+ zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
zebra_vxlan_sg_ref(vxl->vtep_ip,
vxl->mcast_grp);
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->mcast_grp = vxl->mcast_grp;
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vxl->mcast_grp;
/* on local vtep-ip check if ES
* orig-ip needs to be updated
*/
- zebra_evpn_es_set_base_vni(zvni);
+ zebra_evpn_es_set_base_evpn(zevpn);
}
- zvni_vxlan_if_set(zvni, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ vlan_if = zvni_map_to_svi(
+ vxl->access_vlan,
+ zif->brslave_info.br_if);
if (vlan_if) {
- zvni->vrf_id = vlan_if->vrf_id;
+ zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(
vlan_if->vrf_id);
if (zl3vni)
listnode_add_sort(
- zl3vni->l2vnis, zvni);
+ zl3vni->l2vnis, zevpn);
}
/*
@@ -4699,182 +981,30 @@ static void zvni_build_hash_table(void)
*/
if (if_is_operative(ifp) &&
zif->brslave_info.br_if)
- zvni_send_add_to_client(zvni);
+ zebra_evpn_send_add_to_client(zevpn);
}
}
}
}
/*
- * See if remote VTEP matches with prefix.
+ * Cleanup EVPN/VTEP and update kernel
*/
-static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep)
+static void zebra_evpn_vxlan_cleanup_all(struct hash_bucket *bucket, void *arg)
{
- return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip));
-}
-
-/*
- * Locate remote VTEP in VNI hash table.
- */
-static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip)
-{
- zebra_vtep_t *zvtep;
-
- if (!zvni)
- return NULL;
-
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
- if (zvni_vtep_match(vtep_ip, zvtep))
- break;
- }
-
- return zvtep;
-}
-
-/*
- * Add remote VTEP to VNI hash table.
- */
-static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip,
- int flood_control)
-
-{
- zebra_vtep_t *zvtep;
-
- zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
-
- zvtep->vtep_ip = *vtep_ip;
- zvtep->flood_control = flood_control;
-
- if (zvni->vteps)
- zvni->vteps->prev = zvtep;
- zvtep->next = zvni->vteps;
- zvni->vteps = zvtep;
-
- return zvtep;
-}
-
-/*
- * Remove remote VTEP from VNI hash table.
- */
-static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
-{
- if (zvtep->next)
- zvtep->next->prev = zvtep->prev;
- if (zvtep->prev)
- zvtep->prev->next = zvtep->next;
- else
- zvni->vteps = zvtep->next;
-
- zvtep->prev = zvtep->next = NULL;
- XFREE(MTYPE_ZVNI_VTEP, zvtep);
-
- return 0;
-}
-
-/*
- * Delete all remote VTEPs for this VNI (upon VNI delete). Also
- * uninstall from kernel if asked to.
- */
-static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall)
-{
- zebra_vtep_t *zvtep, *zvtep_next;
-
- if (!zvni)
- return -1;
-
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next) {
- zvtep_next = zvtep->next;
- if (uninstall)
- zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
- zvni_vtep_del(zvni, zvtep);
- }
-
- return 0;
-}
-
-/*
- * Install remote VTEP into the kernel if the remote VTEP has asked
- * for head-end-replication.
- */
-static int zvni_vtep_install(zebra_vni_t *zvni, zebra_vtep_t *zvtep)
-{
- if (is_vxlan_flooding_head_end() &&
- (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) {
- if (ZEBRA_DPLANE_REQUEST_FAILURE ==
- dplane_vtep_add(zvni->vxlan_if,
- &zvtep->vtep_ip, zvni->vni))
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Uninstall remote VTEP from the kernel.
- */
-static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
-{
- if (!zvni->vxlan_if) {
- zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
- return -1;
- }
-
- if (ZEBRA_DPLANE_REQUEST_FAILURE ==
- dplane_vtep_delete(zvni->vxlan_if, vtep_ip, zvni->vni))
- return -1;
-
- return 0;
-}
-
-/*
- * Install or uninstall flood entries in the kernel corresponding to
- * remote VTEPs. This is invoked upon change to BUM handling.
- */
-static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket,
- void *zvrf)
-{
- zebra_vni_t *zvni;
- zebra_vtep_t *zvtep;
-
- zvni = (zebra_vni_t *)bucket->data;
- if (!zvni)
- return;
-
- for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
- if (is_vxlan_flooding_head_end())
- zvni_vtep_install(zvni, zvtep);
- else
- zvni_vtep_uninstall(zvni, &zvtep->vtep_ip);
- }
-}
-
-/*
- * Cleanup VNI/VTEP and update kernel
- */
-static void zvni_cleanup_all(struct hash_bucket *bucket, void *arg)
-{
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
- zvni = (zebra_vni_t *)bucket->data;
+ zevpn = (zebra_evpn_t *)bucket->data;
/* remove from l3-vni list */
if (zvrf->l3vni)
zl3vni = zl3vni_lookup(zvrf->l3vni);
if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zvni);
+ listnode_delete(zl3vni->l2vnis, zevpn);
- /* Free up all neighbors and MACs, if any. */
- zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
-
- /* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 1);
-
- /* Delete the hash entry. */
- zvni_del(zvni);
+ zebra_evpn_cleanup_all(bucket, arg);
}
/* cleanup L3VNI */
@@ -4947,7 +1077,7 @@ static void *zl3vni_rmac_alloc(void *p)
const zebra_mac_t *tmp_rmac = p;
zebra_mac_t *zrmac;
- zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
+ zrmac = XCALLOC(MTYPE_L3VNI_MAC, sizeof(zebra_mac_t));
*zrmac = *tmp_rmac;
return ((void *)zrmac);
@@ -4991,7 +1121,7 @@ static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
}
tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
- XFREE(MTYPE_MAC, tmp_rmac);
+ XFREE(MTYPE_L3VNI_MAC, tmp_rmac);
return 0;
}
@@ -5188,7 +1318,7 @@ static void *zl3vni_nh_alloc(void *p)
const zebra_neigh_t *tmp_n = p;
zebra_neigh_t *n;
- n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
+ n = XCALLOC(MTYPE_L3NEIGH, sizeof(zebra_neigh_t));
*n = *tmp_n;
return ((void *)n);
@@ -5234,7 +1364,7 @@ static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
}
tmp_n = hash_release(zl3vni->nh_table, n);
- XFREE(MTYPE_NEIGH, tmp_n);
+ XFREE(MTYPE_L3NEIGH, tmp_n);
return 0;
}
@@ -5450,15 +1580,13 @@ static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id)
zl3vni->svi_if = NULL;
zl3vni->vxlan_if = NULL;
zl3vni->l2vnis = list_new();
- zl3vni->l2vnis->cmp = vni_list_cmp;
+ zl3vni->l2vnis->cmp = zebra_evpn_list_cmp;
/* Create hash table for remote RMAC */
- zl3vni->rmac_table = hash_create(mac_hash_keymake, mac_cmp,
- "Zebra L3-VNI RMAC-Table");
+ zl3vni->rmac_table = zebra_mac_db_create("Zebra L3-VNI RMAC-Table");
/* Create hash table for neighbors */
- zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp,
- "Zebra L3-VNI next-hop table");
+ zl3vni->nh_table = zebra_neigh_db_create("Zebra L3-VNI next-hop table");
return zl3vni;
}
@@ -5554,7 +1682,8 @@ struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni)
if (!zif)
return NULL;
- return zvni_map_to_macvlan(zif->brslave_info.br_if, zl3vni->svi_if);
+ return zebra_evpn_map_to_macvlan(zif->brslave_info.br_if,
+ zl3vni->svi_if);
}
@@ -5767,13 +1896,13 @@ static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni)
zl3vni_send_del_to_client(zl3vni);
}
-static void zvni_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
+static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
{
- zebra_vni_t *zvni = (zebra_vni_t *)bucket->data;
+ zebra_evpn_t *zevpn = (zebra_evpn_t *)bucket->data;
zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt;
- if (zvni->vrf_id == zl3vni_vrf_id(zl3vni))
- listnode_add_sort(zl3vni->l2vnis, zvni);
+ if (zevpn->vrf_id == zl3vni_vrf_id(zl3vni))
+ listnode_add_sort(zl3vni->l2vnis, zevpn);
}
/*
@@ -5782,7 +1911,7 @@ static void zvni_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
int add)
{
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
/* There is a possibility that VNI notification was already received
* from kernel and we programmed it as L2-VNI
@@ -5794,28 +1923,27 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
*/
if (add) {
/* Locate hash entry */
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni);
- /* Delete VNI from BGP. */
- zvni_send_del_to_client(zvni);
+ /* Delete EVPN from BGP. */
+ zebra_evpn_send_del_to_client(zevpn);
- /* Free up all neighbors and MAC, if any. */
- zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+ zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC);
/* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 0);
+ zebra_evpn_vtep_del_all(zevpn, 0);
/* Delete the hash entry. */
- if (zvni_del(zvni)) {
+ if (zebra_evpn_vxlan_del(zevpn)) {
flog_err(EC_ZEBRA_VNI_DEL_FAILED,
- "Failed to del VNI hash %p, VNI %u", zvni,
- zvni->vni);
+ "Failed to del EVPN hash %p, VNI %u", zevpn,
+ zevpn->vni);
return -1;
}
} else {
@@ -5857,40 +1985,6 @@ static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx)
zl3vni_nh_del(zl3vni, n);
}
-static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
- uint16_t cmd)
-{
- struct zserv *client = NULL;
- struct stream *s = NULL;
- char buf[PREFIX_STRLEN];
-
- client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
- /* BGP may not be running. */
- if (!client)
- return 0;
-
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
-
- zclient_create_header(s, cmd, vrf_id);
- stream_put(s, p, sizeof(struct prefix));
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send ip prefix %s %s on vrf %s",
- prefix2str(p, buf, sizeof(buf)),
- (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
- vrf_id_to_name(vrf_id));
-
- if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
- client->prefixadd_cnt++;
- else
- client->prefixdel_cnt++;
-
- return zserv_send_message(client, s);
-}
-
/* re-add remote rmac if needed */
static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
struct ethaddr *rmac)
@@ -5910,1720 +2004,6 @@ static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
return 0;
}
-/**************************** SYNC MAC handling *****************************/
-/* if the mac has been added of a mac-route from the peer
- * or if it is being referenced by a neigh added by the
- * peer we cannot let it age out i.e. we set the static bit
- * in the dataplane
- */
-static inline bool zebra_vxlan_mac_is_static(zebra_mac_t *mac)
-{
- return ((mac->flags & ZEBRA_MAC_ALL_PEER_FLAGS) ||
- mac->sync_neigh_cnt);
-}
-
-/* mac needs to be locally active or active on an ES peer */
-static inline bool zebra_vxlan_mac_is_ready_for_bgp(uint32_t flags)
-{
- return (flags & ZEBRA_MAC_LOCAL) &&
- (!(flags & ZEBRA_MAC_LOCAL_INACTIVE) ||
- (flags & ZEBRA_MAC_ES_PEER_ACTIVE));
-}
-
-/* program sync mac flags in the dataplane */
-void zebra_vxlan_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
- bool force_clear_static, const char *caller)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- struct interface *ifp;
- bool sticky;
- bool set_static;
- zebra_vni_t *zvni = mac->zvni;
- vlanid_t vid;
- struct zebra_if *zif;
- struct interface *br_ifp;
-
- /* get the access vlan from the vxlan_device */
- zebra_vxlan_mac_get_access_info(mac,
- &ifp, &vid);
-
- if (!ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no access-port",
- caller,
- zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->flags,
- set_inactive ? "inactive " : "");
- return;
- }
-
- zif = ifp->info;
- br_ifp = zif->brslave_info.br_if;
- if (!br_ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("%s: dp-install sync-mac vni %u mac %s es %s 0x%x %sskipped, no br",
- caller,
- zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->flags,
- set_inactive ? "inactive " : "");
- return;
- }
-
- sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- if (force_clear_static)
- set_static = false;
- else
- set_static = zebra_vxlan_mac_is_static(mac);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("dp-install sync-mac vni %u mac %s es %s 0x%x %s%s",
- zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-", mac->flags,
- set_static ? "static " : "",
- set_inactive ? "inactive " : "");
-
- dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
- set_static, set_inactive);
-
-}
-
-static void zebra_vxlan_mac_send_add_del_to_client(zebra_mac_t *mac,
- bool old_bgp_ready, bool new_bgp_ready)
-{
- if (new_bgp_ready)
- zvni_mac_send_add_to_client(mac->zvni->vni,
- &mac->macaddr, mac->flags,
- mac->loc_seq, mac->es);
- else if (old_bgp_ready)
- zvni_mac_send_del_to_client(mac->zvni->vni,
- &mac->macaddr, mac->flags,
- true /* force */);
-}
-
-/* MAC hold timer is used to age out peer-active flag.
- *
- * During this wait time we expect the dataplane component or an
- * external neighmgr daemon to probe existing hosts to independently
- * establish their presence on the ES.
- */
-static int zebra_vxlan_mac_hold_exp_cb(struct thread *t)
-{
- zebra_mac_t *mac;
- bool old_bgp_ready;
- bool new_bgp_ready;
- bool old_static;
- bool new_static;
- char macbuf[ETHER_ADDR_STRLEN];
-
- mac = THREAD_ARG(t);
- /* the purpose of the hold timer is to age out the peer-active
- * flag
- */
- if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- return 0;
-
- old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- old_static = zebra_vxlan_mac_is_static(mac);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
- new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- new_static = zebra_vxlan_mac_is_static(mac);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold expired",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->flags);
-
- /* re-program the local mac in the dataplane if the mac is no
- * longer static
- */
- if (old_static != new_static)
- zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
-
- /* inform bgp if needed */
- if (old_bgp_ready != new_bgp_ready)
- zebra_vxlan_mac_send_add_del_to_client(mac,
- old_bgp_ready, new_bgp_ready);
-
- return 0;
-}
-
-static inline void zebra_vxlan_mac_start_hold_timer(zebra_mac_t *mac)
-{
- char macbuf[ETHER_ADDR_STRLEN];
-
- if (mac->hold_timer)
- return;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold started",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->flags);
- thread_add_timer(zrouter.master,
- zebra_vxlan_mac_hold_exp_cb,
- mac, zmh_info->mac_hold_time,
- &mac->hold_timer);
-}
-
-static inline void zebra_vxlan_mac_stop_hold_timer(zebra_mac_t *mac)
-{
- char macbuf[ETHER_ADDR_STRLEN];
-
- if (!mac->hold_timer)
- return;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac vni %u mac %s es %s 0x%x hold stopped",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr, macbuf,
- sizeof(macbuf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->flags);
- THREAD_OFF(mac->hold_timer);
-}
-
-static inline void zebra_vxlan_mac_clear_sync_info(zebra_mac_t *mac)
-{
- UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS);
- zebra_vxlan_mac_stop_hold_timer(mac);
-}
-
-static void zebra_vxlan_sync_mac_del(zebra_mac_t *mac)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- bool old_static;
- bool new_static;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac del vni %u mac %s es %s seq %d f 0x%x",
- mac->zvni->vni,
- prefix_mac2str(&mac->macaddr,
- macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-",
- mac->loc_seq,
- mac->flags);
- old_static = zebra_vxlan_mac_is_static(mac);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
- zebra_vxlan_mac_start_hold_timer(mac);
- new_static = zebra_vxlan_mac_is_static(mac);
-
- if (old_static != new_static)
- /* program the local mac in the kernel */
- zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
-}
-
-static inline bool zebra_vxlan_mac_is_bgp_seq_ok(zebra_vni_t *zvni,
- zebra_mac_t *mac, uint32_t seq, uint16_t ipa_len,
- struct ipaddr *ipaddr)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- uint32_t tmp_seq;
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
- tmp_seq = mac->loc_seq;
- else
- tmp_seq = mac->rem_seq;
-
- if (seq < tmp_seq) {
- /* if the mac was never advertised to bgp we must accept
- * whatever sequence number bgp sends
- * XXX - check with Vivek
- */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
- !zebra_vxlan_mac_is_ready_for_bgp(mac->flags)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-macip accept vni %u mac %s%s%s lower seq %u f 0x%x",
- zvni->vni,
- prefix_mac2str(&mac->macaddr,
- macbuf, sizeof(macbuf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr,
- ipbuf, sizeof(ipbuf)) : "",
- tmp_seq, mac->flags);
- return true;
- }
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-macip ignore vni %u mac %s%s%s as existing has higher seq %u f 0x%x",
- zvni->vni,
- prefix_mac2str(&mac->macaddr,
- macbuf, sizeof(macbuf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr,
- ipbuf, sizeof(ipbuf)) : "",
- tmp_seq, mac->flags);
- return false;
- }
-
- return true;
-}
-
-/* sync-path that is active on an ES peer */
-static zebra_mac_t *zebra_vxlan_proc_sync_mac_update(zebra_vni_t *zvni,
- struct ethaddr *macaddr, uint16_t ipa_len,
- struct ipaddr *ipaddr, uint8_t flags,
- uint32_t seq, esi_t *esi,
- struct sync_mac_ip_ctx *ctx)
-{
- zebra_mac_t *mac;
- bool inform_bgp = false;
- bool inform_dataplane = false;
- bool seq_change = false;
- bool es_change = false;
- uint32_t tmp_seq;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool old_local = false;
- bool old_bgp_ready;
- bool new_bgp_ready;
-
- mac = zvni_mac_lookup(zvni, macaddr);
- if (!mac) {
- /* if it is a new local path we need to inform both
- * the control protocol and the data-plane
- */
- inform_bgp = true;
- inform_dataplane = true;
- ctx->mac_created = true;
- ctx->mac_inactive = true;
-
- /* create the MAC and associate it with the dest ES */
- mac = zvni_mac_add(zvni, macaddr);
- zebra_evpn_es_mac_ref(mac, esi);
-
- /* local mac activated by an ES peer */
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- /* if mac-only route setup peer flags */
- if (!ipa_len) {
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
- else
- SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
- }
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
- old_bgp_ready = false;
- new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- } else {
- uint32_t old_flags;
- uint32_t new_flags;
- bool old_static;
- bool new_static;
- bool sticky;
- bool remote_gw;
-
- old_flags = mac->flags;
- sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
- remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
- if (sticky || remote_gw) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("Ignore sync-macip vni %u mac %s%s%s%s%s",
- zvni->vni,
- prefix_mac2str(macaddr,
- macbuf, sizeof(macbuf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf)) : "",
- sticky ? " sticky" : "",
- remote_gw ? " remote_gw" : "");
- ctx->ignore_macip = true;
- return NULL;
- }
- if (!zebra_vxlan_mac_is_bgp_seq_ok(zvni, mac, seq,
- ipa_len, ipaddr)) {
- ctx->ignore_macip = true;
- return NULL;
- }
-
- old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
- old_static = zebra_vxlan_mac_is_static(mac);
-
- /* re-build the mac flags */
- new_flags = 0;
- SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
- /* retain old local activity flag */
- if (old_flags & ZEBRA_MAC_LOCAL) {
- new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
- } else {
- new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
- ctx->mac_inactive = true;
- }
- if (ipa_len) {
- /* if mac-ip route do NOT update the peer flags
- * i.e. retain only flags as is
- */
- new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
- } else {
- /* if mac-only route update peer flags */
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
- SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
- /* if the mac was peer-active previously we
- * need to keep the flag and start the
- * holdtimer on it. the peer-active flag is
- * cleared on holdtimer expiry.
- */
- if (CHECK_FLAG(old_flags,
- ZEBRA_MAC_ES_PEER_ACTIVE)) {
- SET_FLAG(new_flags,
- ZEBRA_MAC_ES_PEER_ACTIVE);
- zebra_vxlan_mac_start_hold_timer(mac);
- }
- } else {
- SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
- /* stop hold timer if a peer has verified
- * reachability
- */
- zebra_vxlan_mac_stop_hold_timer(mac);
- }
- }
- mac->rem_seq = 0;
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- mac->flags = new_flags;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC &&
- (old_flags != new_flags))
- zlog_debug("sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
- zvni->vni,
- prefix_mac2str(macaddr,
- macbuf, sizeof(macbuf)),
- old_flags, mac->flags);
-
- /* update es */
- es_change = zebra_evpn_es_mac_ref(mac, esi);
- /* if mac dest change - inform both sides */
- if (es_change) {
- inform_bgp = true;
- inform_dataplane = true;
- ctx->mac_inactive = true;
- }
- /* if peer-flag is being set notify dataplane that the
- * entry must not be expired because of local inactivity
- */
- new_static = zebra_vxlan_mac_is_static(mac);
- if (old_static != new_static)
- inform_dataplane = true;
-
- old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(old_flags);
- new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- if (old_bgp_ready != new_bgp_ready)
- inform_bgp = true;
- }
-
-
- /* update sequence number; if that results in a new local sequence
- * inform bgp
- */
- tmp_seq = MAX(mac->loc_seq, seq);
- if (tmp_seq != mac->loc_seq) {
- mac->loc_seq = tmp_seq;
- seq_change = true;
- 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",
- ctx->mac_created ?
- "created" : "updated",
- zvni->vni,
- prefix_mac2str(macaddr,
- macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-",
- mac->loc_seq, mac->flags,
- inform_bgp ? " inform_bgp" : "",
- inform_dataplane ? " inform_dp" : "");
-
- if (inform_bgp)
- zebra_vxlan_mac_send_add_del_to_client(mac,
- old_bgp_ready, new_bgp_ready);
-
- /* neighs using the mac may need to be re-sent to
- * bgp with updated info
- */
- if (seq_change || es_change || !old_local)
- zvni_process_neigh_on_local_mac_change(zvni, mac,
- seq_change, es_change);
-
- if (inform_dataplane) {
- if (ipa_len)
- /* if the mac is being created as a part of MAC-IP
- * route wait for the neigh to be updated or
- * created before programming the mac
- */
- ctx->mac_dp_update_deferred = true;
- else
- /* program the local mac in the kernel. when the ES
- * change we need to force the dataplane to reset
- * the activity as we are yet to establish activity
- * locally
- */
- zebra_vxlan_sync_mac_dp_install(mac,
- ctx->mac_inactive,
- false /* force_clear_static */,
- __func__);
- }
-
- return mac;
-}
-
-/**************************** SYNC neigh handling **************************/
-static inline bool zebra_vxlan_neigh_is_static(zebra_neigh_t *neigh)
-{
- return !!(neigh->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS);
-}
-
-static inline bool zebra_vxlan_neigh_is_ready_for_bgp(zebra_neigh_t *n)
-{
- bool mac_ready;
- bool neigh_ready;
-
- mac_ready = !!(n->mac->flags & ZEBRA_MAC_LOCAL);
- neigh_ready = ((n->flags & ZEBRA_NEIGH_LOCAL) &&
- IS_ZEBRA_NEIGH_ACTIVE(n) &&
- (!(n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ||
- (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE))) ?
- true : false;
-
- return mac_ready && neigh_ready;
-}
-
-static void zebra_vxlan_sync_neigh_dp_install(zebra_neigh_t *n,
- bool set_inactive, bool force_clear_static, const char *caller)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- struct zebra_ns *zns;
- struct interface *ifp;
- bool set_static;
- bool set_router;
-
- zns = zebra_ns_lookup(NS_DEFAULT);
- ifp = if_lookup_by_index_per_ns(zns, n->ifindex);
- if (!ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("%s: dp-install sync-neigh vni %u ip %s mac %s if %d f 0x%x skipped",
- caller, n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->ifindex, n->flags);
- return;
- }
-
- if (force_clear_static)
- set_static = false;
- else
- set_static = zebra_vxlan_neigh_is_static(n);
-
- set_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
-
- /* XXX - this will change post integration with the new kernel */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
- set_inactive = true;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("%s: dp-install sync-neigh vni %u ip %s mac %s if %s(%d) f 0x%x%s%s%s",
- caller, n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- ifp->name, n->ifindex, n->flags,
- set_router ? " router":"",
- set_static ? " static":"",
- set_inactive ? " inactive":"");
- dplane_local_neigh_add(ifp, &n->ip,
- &n->emac, set_router, set_static, set_inactive);
-}
-
-static void zebra_vxlan_neigh_send_add_del_to_client(zebra_neigh_t *n,
- bool old_bgp_ready, bool new_bgp_ready)
-{
- if (new_bgp_ready)
- zvni_neigh_send_add_to_client(n->zvni->vni, &n->ip,
- &n->emac, n->mac, n->flags, n->loc_seq);
- else if (old_bgp_ready)
- zvni_neigh_send_del_to_client(n->zvni->vni, &n->ip,
- &n->emac, n->flags, n->state, true /*force*/);
-}
-
-/* if the static flag associated with the neigh changes we need
- * to update the sync-neigh references against the MAC
- * and inform the dataplane about the static flag changes.
- */
-static void zebra_vxlan_sync_neigh_static_chg(zebra_neigh_t *n,
- bool old_n_static, bool new_n_static,
- bool defer_n_dp, bool defer_mac_dp,
- const char *caller)
-{
- zebra_mac_t *mac = n->mac;
- bool old_mac_static;
- bool new_mac_static;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- if (old_n_static == new_n_static)
- return;
-
- /* update the neigh sync references in the dataplane. if
- * the neigh is in the middle of updates the caller can
- * request for a defer
- */
- if (!defer_n_dp)
- zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
- false /* force_clear_static */, __func__);
-
- if (!mac)
- return;
-
- /* update the mac sync ref cnt */
- old_mac_static = zebra_vxlan_mac_is_static(mac);
- if (new_n_static) {
- ++mac->sync_neigh_cnt;
- } else if (old_n_static) {
- if (mac->sync_neigh_cnt)
- --mac->sync_neigh_cnt;
- }
- new_mac_static = zebra_vxlan_mac_is_static(mac);
-
- /* update the mac sync references in the dataplane */
- if ((old_mac_static != new_mac_static) && !defer_mac_dp)
- zebra_vxlan_sync_mac_dp_install(mac,
- false /* set_inactive */,
- false /* force_clear_static */,
- __func__);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh ref-chg vni %u ip %s mac %s f 0x%x %d%s%s%s%s by %s",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags, mac->sync_neigh_cnt,
- old_n_static ? " old_n_static" : "",
- new_n_static ? " new_n_static" : "",
- old_mac_static ? " old_mac_static" : "",
- new_mac_static ? " new_mac_static" : "",
- caller);
-}
-
-/* Neigh hold timer is used to age out peer-active flag.
- *
- * During this wait time we expect the dataplane component or an
- * external neighmgr daemon to probe existing hosts to independently
- * establish their presence on the ES.
- */
-static int zebra_vxlan_neigh_hold_exp_cb(struct thread *t)
-{
- zebra_neigh_t *n;
- bool old_bgp_ready;
- bool new_bgp_ready;
- bool old_n_static;
- bool new_n_static;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- n = THREAD_ARG(t);
- /* the purpose of the hold timer is to age out the peer-active
- * flag
- */
- if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
- return 0;
-
- old_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
- old_n_static = zebra_vxlan_neigh_is_static(n);
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
- new_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
- new_n_static = zebra_vxlan_neigh_is_static(n);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold expired",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags);
-
- /* re-program the local neigh in the dataplane if the neigh is no
- * longer static
- */
- if (old_n_static != new_n_static)
- zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
- new_n_static, false /*defer_n_dp*/,
- false /*defer_mac_dp*/, __func__);
-
- /* inform bgp if needed */
- if (old_bgp_ready != new_bgp_ready)
- zebra_vxlan_neigh_send_add_del_to_client(n,
- old_bgp_ready, new_bgp_ready);
-
- return 0;
-}
-
-static inline void zebra_vxlan_neigh_start_hold_timer(zebra_neigh_t *n)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- if (n->hold_timer)
- return;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold start",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags);
- thread_add_timer(zrouter.master,
- zebra_vxlan_neigh_hold_exp_cb,
- n, zmh_info->neigh_hold_time,
- &n->hold_timer);
-}
-
-static inline void zebra_vxlan_neigh_stop_hold_timer(zebra_neigh_t *n)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- if (!n->hold_timer)
- return;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold stop",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags);
- THREAD_OFF(n->hold_timer);
-}
-
-static inline bool zebra_vxlan_neigh_clear_sync_info(zebra_neigh_t *n)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool old_n_static = false;
- bool new_n_static = false;
-
- if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x clear",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags);
-
- old_n_static = zebra_vxlan_neigh_is_static(n);
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_PEER_FLAGS);
- new_n_static = zebra_vxlan_neigh_is_static(n);
- if (old_n_static != new_n_static)
- zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
- new_n_static, true /*defer_dp)*/,
- false/*defer_mac_dp*/, __func__);
- }
- zebra_vxlan_neigh_stop_hold_timer(n);
-
- /* if the neigh static flag changed inform that a dp
- * re-install maybe needed
- */
- return old_n_static != new_n_static;
-}
-
-static void zebra_vxlan_local_neigh_deref_mac(zebra_neigh_t *n,
- bool send_mac_update)
-{
- zebra_mac_t *mac = n->mac;
- zebra_vni_t *zvni = n->zvni;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool old_static;
- bool new_static;
-
- n->mac = NULL;
- if (!mac)
- return;
-
- if ((n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) &&
- mac->sync_neigh_cnt){
- old_static = zebra_vxlan_mac_is_static(mac);
- --mac->sync_neigh_cnt;
- new_static = zebra_vxlan_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh deref mac vni %u ip %s mac %s ref %d",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf,
- sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- mac->sync_neigh_cnt);
- if ((old_static != new_static) && send_mac_update)
- /* program the local mac in the kernel */
- zebra_vxlan_sync_mac_dp_install(mac,
- false /* set_inactive */,
- false /* force_clear_static */,
- __func__);
- }
-
- listnode_delete(mac->neigh_list, n);
- zvni_deref_ip2mac(zvni, mac);
-}
-
-static void zebra_vxlan_local_neigh_ref_mac(zebra_neigh_t *n,
- struct ethaddr *macaddr, zebra_mac_t *mac,
- bool send_mac_update)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool old_static;
- bool new_static;
-
- memcpy(&n->emac, macaddr, ETH_ALEN);
- n->mac = mac;
-
- /* Link to new MAC */
- if (!mac)
- return;
-
- listnode_add_sort(mac->neigh_list, n);
- if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) {
- old_static = zebra_vxlan_mac_is_static(mac);
- ++mac->sync_neigh_cnt;
- new_static = zebra_vxlan_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh ref mac vni %u ip %s mac %s ref %d",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf,
- sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- mac->sync_neigh_cnt);
- if ((old_static != new_static) && send_mac_update)
- /* program the local mac in the kernel */
- zebra_vxlan_sync_mac_dp_install(mac,
- false /*set_inactive*/,
- false /*force_clear_static*/,
- __func__);
- }
-}
-
-static inline bool zebra_vxlan_neigh_is_bgp_seq_ok(zebra_vni_t *zvni,
- zebra_neigh_t *n, struct ethaddr *macaddr, uint32_t seq)
-{
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- uint32_t tmp_seq;
-
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
- tmp_seq = n->loc_seq;
- else
- tmp_seq = n->rem_seq;
-
- if (seq < tmp_seq) {
- /* if the neigh was never advertised to bgp we must accept
- * whatever sequence number bgp sends
- * XXX - check with Vivek
- */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) &&
- !zebra_vxlan_neigh_is_ready_for_bgp(n)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-macip accept vni %u mac %s IP %s lower seq %u f 0x%x",
- zvni->vni,
- prefix_mac2str(macaddr,
- macbuf, sizeof(macbuf)),
- ipaddr2str(&n->ip,
- ipbuf, sizeof(ipbuf)),
- tmp_seq, n->flags);
- return true;
- }
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-macip ignore vni %u mac %s IP %s as existing has higher seq %u f 0x%x",
- zvni->vni,
- prefix_mac2str(macaddr,
- macbuf, sizeof(macbuf)),
- ipaddr2str(&n->ip,
- ipbuf, sizeof(ipbuf)),
- tmp_seq, n->flags);
- return false;
- }
-
- return true;
-}
-
-static void zebra_vxlan_sync_neigh_del(zebra_neigh_t *n)
-{
- bool old_n_static;
- bool new_n_static;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh del vni %u ip %s mac %s f 0x%x",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- n->flags);
-
- old_n_static = zebra_vxlan_neigh_is_static(n);
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE))
- zebra_vxlan_neigh_start_hold_timer(n);
- new_n_static = zebra_vxlan_neigh_is_static(n);
-
- if (old_n_static != new_n_static)
- zebra_vxlan_sync_neigh_static_chg(n, old_n_static,
- new_n_static, false /*defer-dp*/,
- false /*defer_mac_dp*/, __func__);
-}
-
-static zebra_neigh_t *zebra_vxlan_proc_sync_neigh_update(zebra_vni_t *zvni,
- zebra_neigh_t *n, uint16_t ipa_len,
- struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
- esi_t *esi, struct sync_mac_ip_ctx *ctx)
-{
- struct interface *ifp = NULL;
- bool is_router;
- zebra_mac_t *mac = ctx->mac;
- uint32_t tmp_seq;
- bool old_router = false;
- bool old_bgp_ready = false;
- bool new_bgp_ready;
- bool inform_dataplane = false;
- bool inform_bgp = false;
- bool old_mac_static;
- bool new_mac_static;
- bool set_dp_inactive = false;
- struct zebra_if *zif;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool created;
- ifindex_t ifindex = 0;
-
- /* locate l3-svi */
- zif = zvni->vxlan_if->info;
- if (zif) {
- struct zebra_l2info_vxlan *vxl;
-
- vxl = &zif->l2info.vxl;
- ifp = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (ifp)
- ifindex = ifp->ifindex;
- }
-
- is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
- old_mac_static = zebra_vxlan_mac_is_static(mac);
-
- if (!n) {
- uint32_t n_flags = 0;
-
- /* New neighbor - create */
- SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL);
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- else
- SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
- SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
-
- n = zvni_neigh_add(zvni, ipaddr, &mac->macaddr, mac,
- n_flags);
- n->ifindex = ifindex;
- ZEBRA_NEIGH_SET_ACTIVE(n);
-
- created = true;
- inform_dataplane = true;
- inform_bgp = true;
- set_dp_inactive = true;
- } else {
- bool mac_change;
- uint32_t old_flags = n->flags;
- bool old_n_static;
- bool new_n_static;
-
- created = false;
- old_n_static = zebra_vxlan_neigh_is_static(n);
- old_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
- old_router = !!CHECK_FLAG(n->flags,
- ZEBRA_NEIGH_ROUTER_FLAG);
-
- mac_change = !!memcmp(&n->emac, &mac->macaddr, ETH_ALEN);
-
- /* deref and clear old info */
- if (mac_change) {
- if (old_bgp_ready) {
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, n->flags, n->state,
- false /*force*/);
- old_bgp_ready = false;
- }
- if (n->mac)
- zebra_vxlan_local_neigh_deref_mac(n,
- false /*send_mac_update*/);
- }
- /* clear old fwd info */
- n->rem_seq = 0;
- n->r_vtep_ip.s_addr = 0;
-
- /* setup new flags */
- n->flags = 0;
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- /* retain activity flag if the neigh was
- * previously local
- */
- if (old_flags & ZEBRA_NEIGH_LOCAL) {
- n->flags |= (old_flags & ZEBRA_NEIGH_LOCAL_INACTIVE);
- } else {
- inform_dataplane = true;
- set_dp_inactive = true;
- n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
- }
-
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- else
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
-
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY);
- /* if the neigh was peer-active previously we
- * need to keep the flag and start the
- * holdtimer on it. the peer-active flag is
- * cleared on holdtimer expiry.
- */
- if (CHECK_FLAG(old_flags,
- ZEBRA_NEIGH_ES_PEER_ACTIVE)) {
- SET_FLAG(n->flags,
- ZEBRA_NEIGH_ES_PEER_ACTIVE);
- zebra_vxlan_neigh_start_hold_timer(n);
- }
- } else {
- SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE);
- /* stop hold timer if a peer has verified
- * reachability
- */
- zebra_vxlan_neigh_stop_hold_timer(n);
- }
- ZEBRA_NEIGH_SET_ACTIVE(n);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH &&
- (old_flags != n->flags))
- zlog_debug("sync-neigh vni %u ip %s mac %s old_f 0x%x new_f 0x%x",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- old_flags, n->flags);
-
- new_n_static = zebra_vxlan_neigh_is_static(n);
- if (mac_change) {
- set_dp_inactive = true;
- n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE;
- inform_dataplane = true;
- zebra_vxlan_local_neigh_ref_mac(n, &mac->macaddr,
- mac, false /*send_mac_update*/);
- } else if (old_n_static != new_n_static) {
- inform_dataplane = true;
- /* if static flags have changed without a mac change
- * we need to create the correct sync-refs against
- * the existing mac
- */
- zebra_vxlan_sync_neigh_static_chg(n,
- old_n_static, new_n_static,
- true /*defer_dp*/, true /*defer_mac_dp*/,
- __func__);
- }
-
- /* Update the forwarding info. */
- if (n->ifindex != ifindex) {
- n->ifindex = ifindex;
- inform_dataplane = true;
- }
- }
-
- /* update the neigh seq. we don't bother with the mac seq as
- * sync_mac_update already took care of that
- */
- tmp_seq = MAX(n->loc_seq, seq);
- if (tmp_seq != n->loc_seq) {
- n->loc_seq = tmp_seq;
- inform_bgp = true;
- }
-
- /* Mark Router flag (R-bit) */
- if (is_router)
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
- else
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
-
- if (old_router != is_router)
- inform_dataplane = true;
-
- new_bgp_ready = zebra_vxlan_neigh_is_ready_for_bgp(n);
- if (old_bgp_ready != new_bgp_ready)
- inform_bgp = true;
-
- new_mac_static = zebra_vxlan_mac_is_static(mac);
- if ((old_mac_static != new_mac_static) ||
- ctx->mac_dp_update_deferred)
- zebra_vxlan_sync_mac_dp_install(mac,
- ctx->mac_inactive,
- false /* force_clear_static */,
- __func__);
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync-neigh %s vni %u ip %s mac %s if %s(%d) seq %d f 0x%x%s%s",
- created ?
- "created" : "updated",
- n->zvni->vni,
- ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)),
- prefix_mac2str(&n->emac, macbuf,
- sizeof(macbuf)),
- ifp ? ifp->name : "", ifindex,
- n->loc_seq, n->flags,
- inform_bgp ? " inform_bgp" : "",
- inform_dataplane ? " inform_dp" : "");
-
- if (inform_dataplane)
- zebra_vxlan_sync_neigh_dp_install(n, set_dp_inactive,
- false /* force_clear_static */, __func__);
-
- if (inform_bgp)
- zebra_vxlan_neigh_send_add_del_to_client(n,
- old_bgp_ready, new_bgp_ready);
-
- return n;
-}
-
-static void zebra_vxlan_process_sync_macip_add(zebra_vni_t *zvni,
- struct ethaddr *macaddr,
- uint16_t ipa_len,
- struct ipaddr *ipaddr,
- uint8_t flags,
- uint32_t seq,
- esi_t *esi)
-{
- struct sync_mac_ip_ctx ctx;
- char macbuf[ETHER_ADDR_STRLEN];
- char ipbuf[INET6_ADDRSTRLEN];
- bool sticky;
- bool remote_gw;
- zebra_neigh_t *n = NULL;
-
- sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- /* if sticky or remote-gw ignore updates from the peer */
- if (sticky || remote_gw) {
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH ||
- IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("Ignore sync-macip vni %u mac %s%s%s%s%s",
- zvni->vni,
- prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "",
- sticky ? " sticky" : "",
- remote_gw ? " remote_gw" : "");
- return;
- }
-
- if (ipa_len) {
- n = zvni_neigh_lookup(zvni, ipaddr);
- if (n &&
- !zebra_vxlan_neigh_is_bgp_seq_ok(zvni,
- n, macaddr, seq))
- return;
- }
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.mac = zebra_vxlan_proc_sync_mac_update(zvni, macaddr, ipa_len,
- ipaddr, flags, seq, esi, &ctx);
- if (ctx.ignore_macip || !ctx.mac || !ipa_len)
- return;
-
- zebra_vxlan_proc_sync_neigh_update(zvni, n, ipa_len,
- ipaddr, flags, seq, esi, &ctx);
-}
-
-/************************** remote mac-ip handling **************************/
-/* Process a remote MACIP add from BGP. */
-static void process_remote_macip_add(vni_t vni,
- struct ethaddr *macaddr,
- uint16_t ipa_len,
- struct ipaddr *ipaddr,
- uint8_t flags,
- uint32_t seq,
- struct in_addr vtep_ip,
- esi_t *esi)
-{
- zebra_vni_t *zvni;
- zebra_vtep_t *zvtep;
- zebra_mac_t *mac = NULL, *old_mac = NULL;
- zebra_neigh_t *n = NULL;
- int update_mac = 0, update_neigh = 0;
- char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
- struct interface *ifp = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_vrf *zvrf;
- uint32_t tmp_seq;
- bool sticky;
- bool remote_gw;
- bool is_router;
- bool do_dad = false;
- bool is_dup_detect = false;
- esi_t *old_esi;
- bool old_static = false;
-
- /* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni);
- return;
- }
-
- ifp = zvni->vxlan_if;
- if (ifp)
- zif = ifp->info;
- if (!ifp ||
- !if_is_operative(ifp) ||
- !zif ||
- !zif->brslave_info.br_if) {
- zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info",
- vni);
- return;
- }
-
- /* Type-2 routes from another PE can be interpreted as remote or
- * SYNC based on the destination ES -
- * SYNC - if ES is local
- * REMOTE - if ES is not local
- */
- if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) {
- zebra_vxlan_process_sync_macip_add(zvni, macaddr, ipa_len,
- ipaddr, flags, seq, esi);
- return;
- }
-
- /* The remote VTEP specified should normally exist, but it is
- * possible that when peering comes up, peer may advertise MACIP
- * routes before advertising type-3 routes.
- */
- if (vtep_ip.s_addr) {
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
- if (!zvtep) {
- zvtep = zvni_vtep_add(zvni, &vtep_ip,
- VXLAN_FLOOD_DISABLED);
- if (!zvtep) {
- flog_err(
- EC_ZEBRA_VTEP_ADD_FAILED,
- "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD",
- vni, zvni);
- return;
- }
-
- zvni_vtep_install(zvni, zvtep);
- }
- }
-
- sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
- remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
- is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-
- mac = zvni_mac_lookup(zvni, macaddr);
-
- /* Ignore if the mac is already present as a gateway mac */
- if (mac &&
- CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
- CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
- vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
- return;
- }
-
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf)
- return;
-
- old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
-
- /* check if the remote MAC is unknown or has a change.
- * If so, that needs to be updated first. Note that client could
- * install MAC and MACIP separately or just install the latter.
- */
- if (!mac
- || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
- || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
- || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
- || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
- || memcmp(old_esi, esi, sizeof(esi_t))
- || seq != mac->rem_seq)
- update_mac = 1;
-
- if (update_mac) {
- if (!mac) {
- mac = zvni_mac_add(zvni, macaddr);
- if (!mac) {
- zlog_warn(
- "Failed to add MAC %s VNI %u Remote VTEP %s",
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- vni, inet_ntoa(vtep_ip));
- return;
- }
-
- zebra_evpn_es_mac_ref(mac, esi);
-
- /* Is this MAC created for a MACIP? */
- 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
- * in transient situations (because {IP1,M1}
- * is a different route from {IP1,M2}). Check
- * 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",
- vni,
- prefix_mac2str(macaddr,
- buf, sizeof(buf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr,
- buf1, sizeof(buf1)) : "",
- tmp_seq, mac->flags);
- return;
- }
- }
-
- /* Check MAC's curent state is local (this is the case
- * where MAC has moved from L->R) and check previous
- * detection started via local learning.
- * RFC-7432: A PE/VTEP that detects a MAC mobility
- * event via local learning starts an M-second timer.
- *
- * VTEP-IP or seq. change alone is not considered
- * for dup. detection.
- *
- * MAC is already marked duplicate set dad, then
- * is_dup_detect will be set to not install the entry.
- */
- if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) &&
- mac->dad_count) ||
- CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
- do_dad = true;
-
- /* Remove local MAC from BGP. */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- /* force drop the sync flags */
- old_static = zebra_vxlan_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
- zvni->vni,
- prefix_mac2str(macaddr,
- buf, sizeof(buf)),
- mac->es ?
- mac->es->esi_str : "-",
- mac->loc_seq,
- mac->flags);
- zebra_vxlan_mac_clear_sync_info(mac);
- zvni_mac_send_del_to_client(zvni->vni, macaddr,
- mac->flags, false /* force */);
- }
-
- /* Set "auto" and "remote" forwarding info. */
- UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- mac->fwd_info.r_vtep_ip = vtep_ip;
-
- if (sticky)
- SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- else
- UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
-
- if (remote_gw)
- SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
- else
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
-
- zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac,
- mac->fwd_info.r_vtep_ip,
- do_dad, &is_dup_detect,
- false);
-
- if (!is_dup_detect) {
- zvni_process_neigh_on_remote_mac_add(zvni, mac);
- /* Install the entry. */
- zvni_rem_mac_install(zvni, mac, old_static);
- }
- }
-
- /* Update seq number. */
- mac->rem_seq = seq;
-
- /* If there is no IP, return after clearing AUTO flag of MAC. */
- if (!ipa_len) {
- UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- return;
- }
-
- /* Reset flag */
- do_dad = false;
- old_static = false;
-
- /* Check if the remote neighbor itself is unknown or has a
- * change. If so, create or update and then install the entry.
- */
- n = zvni_neigh_lookup(zvni, ipaddr);
- if (!n
- || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
- || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)
- || (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0)
- || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)
- || seq != n->rem_seq)
- update_neigh = 1;
-
- if (update_neigh) {
- if (!n) {
- n = zvni_neigh_add(zvni, ipaddr, macaddr, mac, 0);
- if (!n) {
- zlog_warn(
- "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s",
- ipaddr2str(ipaddr, buf1,
- sizeof(buf1)),
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- vni, inet_ntoa(vtep_ip));
- return;
- }
-
- } 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
- * in transient situations (because {IP1,M1}
- * is a different route from {IP1,M2}). Check
- * 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",
- vni,
- prefix_mac2str(macaddr,
- buf, sizeof(buf)),
- " IP ",
- ipaddr2str(ipaddr, buf1, sizeof(buf1)),
- n_type,
- tmp_seq);
- return;
- }
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- old_static = zebra_vxlan_neigh_is_static(n);
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("sync->remote neigh vni %u ip %s mac %s seq %d f0x%x",
- n->zvni->vni,
- ipaddr2str(&n->ip, buf1,
- sizeof(buf1)),
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- seq, n->flags);
- zebra_vxlan_neigh_clear_sync_info(n);
- if (IS_ZEBRA_NEIGH_ACTIVE(n))
- zvni_mac_send_del_to_client(zvni->vni,
- macaddr, mac->flags,
- false /*force*/);
- }
- if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) {
- /* update neigh list for macs */
- old_mac = zvni_mac_lookup(zvni, &n->emac);
- if (old_mac) {
- listnode_delete(old_mac->neigh_list, n);
- n->mac = NULL;
- zvni_deref_ip2mac(zvni, old_mac);
- }
- n->mac = mac;
- listnode_add_sort(mac->neigh_list, n);
- memcpy(&n->emac, macaddr, ETH_ALEN);
-
- /* Check Neigh's curent state is local
- * (this is the case where neigh/host has moved
- * from L->R) and check previous detction
- * started via local learning.
- *
- * RFC-7432: A PE/VTEP that detects a MAC
- * mobilit event via local learning starts
- * an M-second timer.
- * VTEP-IP or seq. change along is not
- * considered for dup. detection.
- *
- * Mobilty event scenario-B IP-MAC binding
- * changed.
- */
- if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE))
- && n->dad_count)
- do_dad = true;
-
- }
- }
-
- /* Set "remote" forwarding info. */
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS);
- n->r_vtep_ip = vtep_ip;
- SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
-
- /* Set router flag (R-bit) to this Neighbor entry */
- if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG))
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
- else
- UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
-
- /* Check old or new MAC detected as duplicate,
- * inherit duplicate flag to this neigh.
- */
- if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_mac,
- mac, n)) {
- flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
- "VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC",
- zvni->vni,
- prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- ipaddr2str(&n->ip, buf1, sizeof(buf1)));
- }
-
- /* Check duplicate address detection for IP */
- zebra_vxlan_dup_addr_detect_for_neigh(zvrf, n,
- n->r_vtep_ip,
- do_dad,
- &is_dup_detect,
- false);
- /* Install the entry. */
- if (!is_dup_detect)
- zvni_rem_neigh_install(zvni, n, old_static);
- }
-
- zvni_probe_neigh_on_mac_add(zvni, mac);
-
- /* Update seq number. */
- n->rem_seq = seq;
-}
-
-static void zebra_vxlan_rem_mac_del(zebra_vni_t *zvni,
- zebra_mac_t *mac)
-{
- zvni_process_neigh_on_remote_mac_del(zvni, mac);
- /* the remote sequence number in the auto mac entry
- * needs to be reset to 0 as the mac entry may have
- * been removed on all VTEPs (including
- * the originating one)
- */
- mac->rem_seq = 0;
-
- /* If all remote neighbors referencing a remote MAC
- * go away, we need to uninstall the MAC.
- */
- if (remote_neigh_count(mac) == 0) {
- zvni_rem_mac_uninstall(zvni, mac);
- zebra_evpn_es_mac_deref_entry(mac);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- }
-
- if (list_isempty(mac->neigh_list))
- zvni_mac_del(zvni, mac);
- else
- SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
-}
-
-/* Process a remote MACIP delete from BGP. */
-static void process_remote_macip_del(vni_t vni,
- struct ethaddr *macaddr,
- uint16_t ipa_len,
- struct ipaddr *ipaddr,
- struct in_addr vtep_ip)
-{
- zebra_vni_t *zvni;
- zebra_mac_t *mac = NULL;
- zebra_neigh_t *n = NULL;
- struct interface *ifp = NULL;
- struct zebra_if *zif = NULL;
- struct zebra_ns *zns;
- struct zebra_l2info_vxlan *vxl;
- struct zebra_vrf *zvrf;
- char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
-
- /* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni);
- return;
- }
-
- ifp = zvni->vxlan_if;
- if (ifp)
- zif = ifp->info;
- if (!ifp ||
- !if_is_operative(ifp) ||
- !zif ||
- !zif->brslave_info.br_if) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info",
- vni);
- return;
- }
- zns = zebra_ns_lookup(NS_DEFAULT);
- vxl = &zif->l2info.vxl;
-
- mac = zvni_mac_lookup(zvni, macaddr);
- if (ipa_len)
- n = zvni_neigh_lookup(zvni, ipaddr);
-
- if (n && !mac) {
- zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni);
- return;
- }
-
- /* If the remote mac or neighbor doesn't exist there is nothing
- * more to do. Otherwise, uninstall the entry and then remove it.
- */
- if (!mac && !n)
- return;
-
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
-
- /* Ignore the delete if this mac is a gateway mac-ip */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
- && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
- zlog_warn(
- "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC",
- vni,
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ipa_len ? " IP " : "",
- ipa_len ?
- ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "");
- return;
- }
-
- /* Uninstall remote neighbor or MAC. */
- if (n) {
- if (zvrf->dad_freeze &&
- CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) &&
- CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) &&
- (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) {
- struct interface *vlan_if;
-
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
- __func__,
- ipaddr2str(ipaddr, buf1, sizeof(buf1)),
- n->flags,
- vlan_if ? vlan_if->name : "Unknown");
- if (vlan_if)
- neigh_read_specific_ip(ipaddr, vlan_if);
- }
-
- /* When the MAC changes for an IP, it is possible the
- * client may update the new MAC before trying to delete the
- * "old" neighbor (as these are two different MACIP routes).
- * Do the delete only if the MAC matches.
- */
- if (!memcmp(n->emac.octet, macaddr->octet, ETH_ALEN)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- zebra_vxlan_sync_neigh_del(n);
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_neigh_uninstall(zvni, n);
- zvni_neigh_del(zvni, n);
- zvni_deref_ip2mac(zvni, mac);
- }
- }
- } else {
- /* DAD: when MAC is freeze state as remote learn event,
- * remote mac-ip delete event is received will result in freeze
- * entry removal, first fetch kernel for the same entry present
- * as LOCAL and reachable, avoid deleting this entry instead
- * use kerenel local entry to update during unfreeze time.
- */
- if (zvrf->dad_freeze &&
- CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) &&
- CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry",
- __func__,
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- mac->flags);
- macfdb_read_specific_mac(zns, zif->brslave_info.br_if,
- macaddr, vxl->access_vlan);
- }
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- if (!ipa_len)
- zebra_vxlan_sync_mac_del(mac);
- } else if (CHECK_FLAG(mac->flags, ZEBRA_NEIGH_REMOTE)) {
- zebra_vxlan_rem_mac_del(zvni, mac);
- }
- }
-}
-
-
/* Public functions */
int is_l3vni_for_prefix_routes_only(vni_t vni)
@@ -8017,22 +2397,22 @@ void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_neigh;
struct neigh_walk_ctx wctx;
json_object *json = NULL;
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_neigh = hashcount(zvni->neigh_table);
+ num_neigh = hashcount(zevpn->neigh_table);
if (!num_neigh)
return;
@@ -8044,21 +2424,22 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
* the maximum width.
*/
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.addr_width = 15;
wctx.json = json;
- hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
+ &wctx);
if (!use_json) {
vty_out(vty,
"Number of ARPs (local and remote) known for this VNI: %u\n",
num_neigh);
- zvni_print_neigh_hdr(vty, &wctx);
+ zebra_evpn_print_neigh_hdr(vty, &wctx);
} else
json_object_int_add(json, "numArpNd", num_neigh);
- hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
@@ -8085,9 +2466,9 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
args[1] = json;
args[2] = (void *)(ptrdiff_t)print_dup;
- hash_iterate(zvrf->vni_table,
+ hash_iterate(zvrf->evpn_table,
(void (*)(struct hash_bucket *,
- void *))zvni_print_neigh_hash_all_vni,
+ void *))zevpn_print_neigh_hash_all_evpn,
args);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8116,9 +2497,9 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty,
args[1] = json;
args[2] = (void *)(ptrdiff_t)print_dup;
- hash_iterate(zvrf->vni_table,
+ hash_iterate(zvrf->evpn_table,
(void (*)(struct hash_bucket *,
- void *))zvni_print_neigh_hash_all_vni_detail,
+ void *))zevpn_print_neigh_hash_all_evpn_detail,
args);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8134,21 +2515,21 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip, bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_neigh_t *n;
json_object *json = NULL;
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- n = zvni_neigh_lookup(zvni, ip);
+ n = zebra_evpn_neigh_lookup(zevpn, ip);
if (!n) {
if (!use_json)
vty_out(vty,
@@ -8159,7 +2540,7 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
if (use_json)
json = json_object_new_object();
- zvni_print_neigh(n, vty, json);
+ zebra_evpn_print_neigh(n, vty, json);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8176,22 +2557,22 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct in_addr vtep_ip,
bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_neigh;
struct neigh_walk_ctx wctx;
json_object *json = NULL;
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_neigh = hashcount(zvni->neigh_table);
+ num_neigh = hashcount(zevpn->neigh_table);
if (!num_neigh)
return;
@@ -8199,14 +2580,15 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
json = json_object_new_object();
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.addr_width = 15;
wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
wctx.json = json;
- hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
- hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
+ &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8224,7 +2606,7 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
vni_t vni,
bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_neigh;
struct neigh_walk_ctx wctx;
json_object *json = NULL;
@@ -8232,17 +2614,17 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_neigh = hashcount(zvni->neigh_table);
+ num_neigh = hashcount(zevpn->neigh_table);
if (!num_neigh)
return;
- num_neigh = num_dup_detected_neighs(zvni);
+ num_neigh = num_dup_detected_neighs(zevpn);
if (!num_neigh)
return;
@@ -8254,11 +2636,12 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
* the maximum width.
*/
memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.addr_width = 15;
wctx.json = json;
- hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_find_neigh_addr_width,
+ &wctx);
if (!use_json) {
vty_out(vty,
@@ -8270,7 +2653,8 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
} else
json_object_int_add(json, "numArpNd", num_neigh);
- hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash, &wctx);
+ hash_iterate(zevpn->neigh_table, zebra_evpn_print_dad_neigh_hash,
+ &wctx);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8285,7 +2669,7 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty,
void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_macs;
struct mac_walk_ctx wctx;
json_object *json = NULL;
@@ -8293,15 +2677,15 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_macs = num_valid_macs(zvni);
+ num_macs = num_valid_macs(zevpn);
if (!num_macs)
return;
@@ -8311,7 +2695,7 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
}
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.json = json_mac;
@@ -8327,7 +2711,7 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
} else
json_object_int_add(json, "numMacs", num_macs);
- hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, &wctx);
if (use_json) {
json_object_object_add(json, "macs", json_mac);
@@ -8358,7 +2742,7 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf,
wctx.vty = vty;
wctx.json = json;
wctx.print_dup = print_dup;
- hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
+ hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8389,7 +2773,7 @@ void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty,
wctx.vty = vty;
wctx.json = json;
wctx.print_dup = print_dup;
- hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni_detail,
+ hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn_detail,
&wctx);
if (use_json) {
@@ -8420,7 +2804,7 @@ void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
wctx.json = json;
- hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx);
+ hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -8436,22 +2820,22 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct ethaddr *macaddr,
bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_mac_t *mac;
json_object *json = NULL;
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- mac = zvni_mac_lookup(zvni, macaddr);
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
if (use_json)
vty_out(vty, "{}\n");
@@ -8465,7 +2849,7 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf,
if (use_json)
json = json_object_new_object();
- zvni_print_mac(mac, vty, json);
+ zebra_evpn_print_mac(mac, vty, json);
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
@@ -8478,7 +2862,7 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
struct zebra_vrf *zvrf,
vni_t vni, bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
struct mac_walk_ctx wctx;
uint32_t num_macs;
json_object *json = NULL;
@@ -8487,17 +2871,17 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_macs = num_valid_macs(zvni);
+ num_macs = num_valid_macs(zevpn);
if (!num_macs)
return;
- num_macs = num_dup_detected_macs(zvni);
+ num_macs = num_dup_detected_macs(zevpn);
if (!num_macs)
return;
@@ -8507,7 +2891,7 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
}
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.json = json_mac;
@@ -8520,7 +2904,7 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
} else
json_object_int_add(json, "numMacs", num_macs);
- hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, &wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_dad_mac_hash, &wctx);
if (use_json) {
json_object_object_add(json, "macs", json_mac);
@@ -8534,7 +2918,7 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty,
int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
struct ethaddr *macaddr)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_mac_t *mac;
struct listnode *node = NULL;
zebra_neigh_t *nbr = NULL;
@@ -8542,13 +2926,13 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
if (!is_evpn_enabled())
return 0;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_warn("VNI %u does not exist\n", vni);
return -1;
}
- mac = zvni_mac_lookup(zvni, macaddr);
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
zlog_warn("Requested MAC does not exist in VNI %u\n", vni);
return -1;
@@ -8573,8 +2957,8 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
ZEBRA_NEIGH_SET_INACTIVE(nbr);
else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
- zvni_rem_neigh_install(zvni, nbr,
- false /*was_static*/);
+ zebra_evpn_rem_neigh_install(
+ zevpn, nbr, false /*was_static*/);
}
UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
@@ -8597,21 +2981,20 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
/* Local: Notify Peer VTEPs, Remote: Install the entry */
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* Inform to BGP */
- if (zvni_mac_send_add_to_client(zvni->vni,
- &mac->macaddr,
- mac->flags,
- mac->loc_seq, mac->es))
+ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
+ mac->flags, mac->loc_seq,
+ mac->es))
return 0;
/* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
- 0 /*es_change*/);
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
+ 0 /*es_change*/);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- zvni_process_neigh_on_remote_mac_add(zvni, mac);
+ zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
/* Install the entry. */
- zvni_rem_mac_install(zvni, mac, false /* was_static */);
+ zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
}
return 0;
@@ -8620,7 +3003,7 @@ int zebra_vxlan_clear_dup_detect_vni_mac(struct zebra_vrf *zvrf, vni_t vni,
int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
struct ipaddr *ip)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_neigh_t *nbr;
zebra_mac_t *mac;
char buf[INET6_ADDRSTRLEN];
@@ -8629,13 +3012,13 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
if (!is_evpn_enabled())
return 0;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_debug("VNI %u does not exist\n", vni);
return -1;
}
- nbr = zvni_neigh_lookup(zvni, ip);
+ nbr = zebra_evpn_neigh_lookup(zevpn, ip);
if (!nbr) {
zlog_warn("Requested host IP does not exist in VNI %u\n", vni);
return -1;
@@ -8649,7 +3032,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
return -1;
}
- mac = zvni_mac_lookup(zvni, &nbr->emac);
+ mac = zebra_evpn_mac_lookup(zevpn, &nbr->emac);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
zlog_warn(
@@ -8670,21 +3053,21 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct zebra_vrf *zvrf, vni_t vni,
THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
- zvni_neigh_send_add_to_client(zvni->vni, ip,
- &nbr->emac, nbr->mac,
- nbr->flags, nbr->loc_seq);
+ zebra_evpn_neigh_send_add_to_client(zevpn->vni, ip, &nbr->emac,
+ nbr->mac, nbr->flags,
+ nbr->loc_seq);
} else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
+ zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/);
}
return 0;
}
-static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
+static void zevpn_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
{
struct mac_walk_ctx *wctx = ctxt;
zebra_mac_t *mac;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
struct listnode *node = NULL;
zebra_neigh_t *nbr = NULL;
@@ -8692,7 +3075,7 @@ static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
if (!mac)
return;
- zvni = wctx->zvni;
+ zevpn = wctx->zevpn;
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
return;
@@ -8719,88 +3102,50 @@ static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt)
/* Local: Notify Peer VTEPs, Remote: Install the entry */
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* Inform to BGP */
- if (zvni_mac_send_add_to_client(zvni->vni,
- &mac->macaddr,
- mac->flags, mac->loc_seq, mac->es))
+ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
+ mac->flags, mac->loc_seq,
+ mac->es))
return;
/* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
- 0 /*es_change*/);
+ zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
+ 0 /*es_change*/);
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- zvni_process_neigh_on_remote_mac_add(zvni, mac);
+ zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
/* Install the entry. */
- zvni_rem_mac_install(zvni, mac, false /* was_static */);
- }
-}
-
-static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt)
-{
- struct neigh_walk_ctx *wctx = ctxt;
- zebra_neigh_t *nbr;
- zebra_vni_t *zvni;
- char buf[INET6_ADDRSTRLEN];
-
- nbr = (zebra_neigh_t *)bucket->data;
- if (!nbr)
- return;
-
- zvni = wctx->zvni;
-
- if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE))
- return;
-
- if (IS_ZEBRA_DEBUG_VXLAN) {
- ipaddr2str(&nbr->ip, buf, sizeof(buf));
- zlog_debug("%s: clear neigh %s dup state, flags 0x%x seq %u",
- __func__, buf, nbr->flags, nbr->loc_seq);
- }
-
- UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
- nbr->dad_count = 0;
- nbr->detect_start_time.tv_sec = 0;
- nbr->detect_start_time.tv_usec = 0;
- nbr->dad_dup_detect_time = 0;
- THREAD_OFF(nbr->dad_ip_auto_recovery_timer);
-
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
- zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip,
- &nbr->emac, nbr->mac,
- nbr->flags, nbr->loc_seq);
- } else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
+ zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
}
}
-static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
+static void zevpn_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket,
void **args)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
struct zebra_vrf *zvrf;
struct mac_walk_ctx m_wctx;
struct neigh_walk_ctx n_wctx;
- zvni = (zebra_vni_t *)bucket->data;
- if (!zvni)
+ zevpn = (zebra_evpn_t *)bucket->data;
+ if (!zevpn)
return;
zvrf = (struct zebra_vrf *)args[0];
- if (hashcount(zvni->neigh_table)) {
+ if (hashcount(zevpn->neigh_table)) {
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
+ n_wctx.zevpn = zevpn;
n_wctx.zvrf = zvrf;
- hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
- &n_wctx);
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_clear_dup_neigh_hash, &n_wctx);
}
- if (num_valid_macs(zvni)) {
+ if (num_valid_macs(zevpn)) {
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
- m_wctx.zvni = zvni;
+ m_wctx.zevpn = zevpn;
m_wctx.zvrf = zvrf;
- hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
+ hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx);
}
}
@@ -8814,41 +3159,41 @@ int zebra_vxlan_clear_dup_detect_vni_all(struct zebra_vrf *zvrf)
args[0] = zvrf;
- hash_iterate(zvrf->vni_table,
+ hash_iterate(zvrf->evpn_table,
(void (*)(struct hash_bucket *, void *))
- zvni_clear_dup_detect_hash_vni_all, args);
+ zevpn_clear_dup_detect_hash_vni_all, args);
return 0;
}
int zebra_vxlan_clear_dup_detect_vni(struct zebra_vrf *zvrf, vni_t vni)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
struct mac_walk_ctx m_wctx;
struct neigh_walk_ctx n_wctx;
if (!is_evpn_enabled())
return 0;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_warn("VNI %u does not exist\n", vni);
- return -1;
+ return CMD_WARNING;
}
- if (hashcount(zvni->neigh_table)) {
+ if (hashcount(zevpn->neigh_table)) {
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
+ n_wctx.zevpn = zevpn;
n_wctx.zvrf = zvrf;
- hash_iterate(zvni->neigh_table, zvni_clear_dup_neigh_hash,
- &n_wctx);
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_clear_dup_neigh_hash, &n_wctx);
}
- if (num_valid_macs(zvni)) {
+ if (num_valid_macs(zevpn)) {
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
- m_wctx.zvni = zvni;
+ m_wctx.zevpn = zevpn;
m_wctx.zvrf = zvrf;
- hash_iterate(zvni->mac_table, zvni_clear_dup_mac_hash, &m_wctx);
+ hash_iterate(zevpn->mac_table, zevpn_clear_dup_mac_hash, &m_wctx);
}
return 0;
@@ -8861,7 +3206,7 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct in_addr vtep_ip,
bool use_json)
{
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
uint32_t num_macs;
struct mac_walk_ctx wctx;
json_object *json = NULL;
@@ -8869,15 +3214,15 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VNI %u does not exist\n", vni);
return;
}
- num_macs = num_valid_macs(zvni);
+ num_macs = num_valid_macs(zevpn);
if (!num_macs)
return;
@@ -8887,12 +3232,12 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
}
memset(&wctx, 0, sizeof(struct mac_walk_ctx));
- wctx.zvni = zvni;
+ wctx.zevpn = zevpn;
wctx.vty = vty;
wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP;
wctx.r_vtep_ip = vtep_ip;
wctx.json = json_mac;
- hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx);
+ hash_iterate(zevpn->mac_table, zebra_evpn_print_mac_hash, &wctx);
if (use_json) {
json_object_int_add(json, "numMacs", wctx.count);
@@ -8919,7 +3264,7 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
json_object *json = NULL;
void *args[2];
zebra_l3vni_t *zl3vni = NULL;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
if (!is_evpn_enabled())
return;
@@ -8934,9 +3279,9 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
if (zl3vni) {
zl3vni_print(zl3vni, (void *)args);
} else {
- zvni = zvni_lookup(vni);
- if (zvni)
- zvni_print(zvni, (void *)args);
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn)
+ zebra_evpn_print(zevpn, (void *)args);
else if (!json)
vty_out(vty, "%% VNI %u does not exist\n", vni);
}
@@ -8974,7 +3319,7 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
return;
num_l3vnis = hashcount(zrouter.l3vni_table);
- num_l2vnis = hashcount(zvrf->vni_table);
+ num_l2vnis = hashcount(zvrf->evpn_table);
num_vnis = num_l2vnis + num_l3vnis;
if (uj) {
@@ -9046,9 +3391,10 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
args[1] = json;
/* Display all L2-VNIs */
- hash_iterate(zvrf->vni_table,
- (void (*)(struct hash_bucket *, void *))zvni_print_hash,
- args);
+ hash_iterate(
+ zvrf->evpn_table,
+ (void (*)(struct hash_bucket *, void *))zebra_evpn_print_hash,
+ args);
/* Display all L3-VNIs */
hash_iterate(zrouter.l3vni_table,
@@ -9112,7 +3458,7 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf,
{
json_object *json_array = NULL;
struct zebra_ns *zns = NULL;
- struct zvni_evpn_show zes;
+ struct zebra_evpn_show zes;
if (!is_evpn_enabled())
return;
@@ -9130,10 +3476,10 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf,
zes.use_json = use_json;
/* Display all L2-VNIs */
- hash_iterate(
- zvrf->vni_table,
- (void (*)(struct hash_bucket *, void *))zvni_print_hash_detail,
- &zes);
+ hash_iterate(zvrf->evpn_table,
+ (void (*)(struct hash_bucket *,
+ void *))zebra_evpn_print_hash_detail,
+ &zes);
/* Display all L3-VNIs */
hash_iterate(zrouter.l3vni_table,
@@ -9160,14 +3506,8 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
struct ipaddr *ip)
{
char buf[INET6_ADDRSTRLEN];
- char buf2[ETHER_ADDR_STRLEN];
- zebra_neigh_t *n = NULL;
- zebra_vni_t *zvni = NULL;
- zebra_mac_t *zmac = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
- struct zebra_vrf *zvrf;
- bool old_bgp_ready;
- bool new_bgp_ready;
/* check if this is a remote neigh entry corresponding to remote
* next-hop
@@ -9179,111 +3519,29 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
*/
- zvni = zvni_from_svi(ifp, link_if);
- if (!zvni) {
+ zevpn = zebra_evpn_from_svi(ifp, link_if);
+ if (!zevpn) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "%s: Del neighbor %s VNI is not present for interface %s",
+ "%s: Del neighbor %s EVPN is not present for interface %s",
__func__, ipaddr2str(ip, buf, sizeof(buf)),
ifp->name);
return 0;
}
- if (!zvni->vxlan_if) {
+ if (!zevpn->vxlan_if) {
zlog_debug(
"VNI %u hash %p doesn't have intf upon local neighbor DEL",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
return -1;
}
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u",
ipaddr2str(ip, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, zvni->vni);
-
- /* If entry doesn't exist, nothing to do. */
- n = zvni_neigh_lookup(zvni, ip);
- if (!n)
- return 0;
-
- zmac = zvni_mac_lookup(zvni, &n->emac);
- if (!zmac) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Trying to del a neigh %s without a mac %s on VNI %u",
- ipaddr2str(ip, buf, sizeof(buf)),
- prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
- zvni->vni);
-
- return 0;
- }
-
- /* If it is a remote entry, the kernel has aged this out or someone has
- * deleted it, it needs to be re-installed as Quagga is the owner.
- */
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_rem_neigh_install(zvni, n, false /*was_static*/);
- return 0;
- }
-
- /* if this is a sync entry it cannot be dropped re-install it in
- * the dataplane
- */
- old_bgp_ready =
- zebra_vxlan_neigh_is_ready_for_bgp(n);
- if (zebra_vxlan_neigh_is_static(n)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
- zlog_debug("re-add sync neigh vni %u ip %s mac %s 0x%x",
- n->zvni->vni,
- ipaddr2str(&n->ip, buf, sizeof(buf)),
- prefix_mac2str(&n->emac, buf2,
- sizeof(buf2)),
- n->flags);
-
- if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE))
- SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE);
- /* inform-bgp about change in local-activity if any */
- new_bgp_ready =
- zebra_vxlan_neigh_is_ready_for_bgp(n);
- zebra_vxlan_neigh_send_add_del_to_client(n,
- old_bgp_ready, new_bgp_ready);
-
- /* re-install the entry in the kernel */
- zebra_vxlan_sync_neigh_dp_install(n, false /* set_inactive */,
- false /* force_clear_static */, __func__);
+ ifp->ifindex, zevpn->vni);
- return 0;
- }
-
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
- if (!zvrf) {
- zlog_debug("%s: VNI %u vrf lookup failed.", __func__,
- zvni->vni);
- return -1;
- }
-
- /* In case of feeze action, if local neigh is in duplicate state,
- * Mark the Neigh as inactive before sending delete request to BGPd,
- * If BGPd has remote entry, it will re-install
- */
- if (zvrf->dad_freeze &&
- CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
- ZEBRA_NEIGH_SET_INACTIVE(n);
-
- /* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
- &n->emac, n->flags, n->state,
- false /* force */);
-
- /* Delete this neighbor entry. */
- zvni_neigh_del(zvni, n);
-
- /* see if the AUTO mac needs to be deleted */
- if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO)
- && !listcount(zmac->neigh_list))
- zvni_mac_del(zvni, zmac);
-
- return 0;
+ return zebra_evpn_neigh_del_ip(zevpn, ip);
}
/*
@@ -9303,7 +3561,7 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
{
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* check if this is a remote neigh entry corresponding to remote
@@ -9316,8 +3574,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
/* We are only interested in neighbors on an SVI that resides on top
* of a VxLAN bridge.
*/
- zvni = zvni_from_svi(ifp, link_if);
- if (!zvni)
+ zevpn = zebra_evpn_from_svi(ifp, link_if);
+ if (!zevpn)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
@@ -9328,14 +3586,15 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
ifp->ifindex, state, is_ext ? "ext-learned " : "",
is_router ? "router " : "",
local_inactive ? "local_inactive " : "",
- zvni->vni);
+ zevpn->vni);
/* Is this about a local neighbor or a remote one? */
if (!is_ext)
- return zvni_local_neigh_update(zvni, ifp, ip, macaddr,
- is_router, local_inactive, dp_static);
+ return zebra_evpn_local_neigh_update(zevpn, ifp, ip, macaddr,
+ is_router, local_inactive,
+ dp_static);
- return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
+ return zebra_evpn_remote_neigh_update(zevpn, ifp, ip, macaddr, state);
}
static int32_t
@@ -9513,7 +3772,7 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
struct zebra_vrf *zvrf = NULL;
struct zebra_l2info_vxlan *vxl;
vni_t vni;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_vtep_t *zvtep = NULL;
zif = ifp->info;
@@ -9531,12 +3790,12 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
return -1;
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return 0;
/* If the remote vtep entry doesn't exists nothing to do */
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
+ zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
if (!zvtep)
return 0;
@@ -9545,7 +3804,7 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
"Del MAC for remote VTEP %s intf %s(%u) VNI %u - readd",
inet_ntoa(vtep_ip), ifp->name, ifp->ifindex, vni);
- zvni_vtep_install(zvni, zvtep);
+ zebra_evpn_vtep_install(zevpn, zvtep);
return 0;
}
@@ -9561,7 +3820,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
vni_t vni;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
@@ -9575,12 +3834,12 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
return 0;
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return 0;
/* If entry doesn't exist, nothing to do. */
- mac = zvni_mac_lookup(zvni, macaddr);
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac)
return 0;
@@ -9595,15 +3854,15 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
ifp->ifindex, vni, mac->flags);
/* Remove MAC from BGP. */
- zvni_mac_send_del_to_client(zvni->vni, macaddr,
- mac->flags, false /* force */);
+ zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags,
+ false /* force */);
/*
* 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)) {
- zvni_mac_del(zvni, mac);
+ zebra_evpn_mac_del(zevpn, mac);
} else {
UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
@@ -9625,7 +3884,7 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
vni_t vni;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
zebra_mac_t *mac = NULL;
char buf[ETHER_ADDR_STRLEN];
@@ -9645,12 +3904,12 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return 0;
/* If entry doesn't exist, nothing to do. */
- mac = zvni_mac_lookup(zvni, macaddr);
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac)
return 0;
@@ -9663,7 +3922,7 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, vni);
- zvni_rem_mac_install(zvni, mac, false /* was_static */);
+ zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
return 0;
}
@@ -9673,116 +3932,22 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
{
- zebra_vni_t *zvni;
- zebra_mac_t *mac;
- char buf[ETHER_ADDR_STRLEN];
- bool old_bgp_ready;
- bool new_bgp_ready;
+ zebra_evpn_t *zevpn;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
*/
- zvni = zvni_map_vlan(ifp, br_if, vid);
- if (!zvni)
+ zevpn = zebra_evpn_map_vlan(ifp, br_if, vid);
+ if (!zevpn)
return 0;
- if (!zvni->vxlan_if) {
+ if (!zevpn->vxlan_if) {
zlog_debug(
"VNI %u hash %p doesn't have intf upon local MAC DEL",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
return -1;
}
- /* If entry doesn't exist, nothing to do. */
- mac = zvni_mac_lookup(zvni, 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, vid, zvni->vni, mac->loc_seq,
- mac->flags, listcount(mac->neigh_list));
-
- old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- if (zebra_vxlan_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 %s es %s seq %d f 0x%x",
- zvni->vni,
- prefix_mac2str(macaddr,
- buf, sizeof(buf)),
- 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_vxlan_mac_is_ready_for_bgp(mac->flags);
- zebra_vxlan_mac_send_add_del_to_client(mac,
- old_bgp_ready, new_bgp_ready);
- }
-
- /* re-install the entry in the kernel */
- zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */,
- __func__);
-
- return 0;
- }
-
- /* Update all the neigh entries associated with this mac */
- zvni_process_neigh_on_local_mac_del(zvni, mac);
-
- /* Remove MAC from BGP. */
- zvni_mac_send_del_to_client(zvni->vni, 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)) {
- zvni_mac_del(zvni, 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 0;
-}
-
-/* update local fowarding info. return true if a dest-ES change
- * is detected
- */
-static bool zebra_vxlan_local_mac_update_fwd_info(zebra_mac_t *mac,
- struct interface *ifp, vlanid_t vid)
-{
- struct zebra_if *zif = ifp->info;
- bool es_change;
-
- memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
-
- es_change = zebra_evpn_es_mac_ref_entry(mac, zif->es_info.es);
-
- if (!mac->es) {
- /* if es is set fwd_info is not-relevant/taped-out */
- mac->fwd_info.local.ifindex = ifp->ifindex;
- mac->fwd_info.local.vid = vid;
- }
-
- return es_change;
+ return zebra_evpn_del_local_mac(zevpn, macaddr, ifp);
}
/*
@@ -9794,277 +3959,49 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
bool sticky, bool local_inactive,
bool dp_static)
{
- zebra_vni_t *zvni;
- zebra_mac_t *mac;
+ zebra_evpn_t *zevpn;
struct zebra_vrf *zvrf;
char buf[ETHER_ADDR_STRLEN];
- bool mac_sticky = false;
- bool inform_client = false;
- bool upd_neigh = false;
- bool is_dup_detect = false;
- struct in_addr vtep_ip = {.s_addr = 0};
- bool es_change = false;
- bool new_bgp_ready;
- /* assume inactive if not present or if not local */
- bool old_local_inactive = true;
- bool old_bgp_ready = false;
- bool inform_dataplane = false;
- bool new_static = false;
-
- if (ifp == NULL)
- return -1;
+
+ assert(ifp);
/* We are interested in MACs only on ports or (port, VLAN) that
- * map to a VNI.
+ * map to an EVPN.
*/
- zvni = zvni_map_vlan(ifp, br_if, vid);
- if (!zvni) {
+ zevpn = zebra_evpn_map_vlan(ifp, br_if, vid);
+ if (!zevpn) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- " Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
+ " Add/Update %sMAC %s intf %s(%u) VID %u, could not find EVPN",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid);
return 0;
}
- if (!zvni->vxlan_if) {
+ if (!zevpn->vxlan_if) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
" VNI %u hash %p doesn't have intf upon local MAC ADD",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
return -1;
}
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(" No Vrf found for vrf_id: %d",
- zvni->vxlan_if->vrf_id);
+ zevpn->vxlan_if->vrf_id);
return -1;
}
- /* Check if we need to create or update or it is a NO-OP. */
- mac = zvni_mac_lookup(zvni, macaddr);
- if (!mac) {
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s",
- sticky ? "sticky " : "",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid, zvni->vni,
- local_inactive ? " local-inactive" : "");
-
- mac = zvni_mac_add(zvni, macaddr);
- if (!mac) {
- flog_err(
- EC_ZEBRA_MAC_ADD_FAILED,
- "Failed to add MAC %s intf %s(%u) VID %u VNI %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid, zvni->vni);
- return -1;
- }
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
- ifp, vid);
- if (sticky)
- SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- inform_client = true;
- } else {
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
- sticky ? "sticky " : "",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid, zvni->vni,
- local_inactive ? "local-inactive " : "",
- mac->flags);
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- struct interface *old_ifp;
- vlanid_t old_vid;
- bool old_static;
-
- zebra_vxlan_mac_get_access_info(mac,
- &old_ifp, &old_vid);
- old_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(
- mac->flags);
- old_local_inactive = !!(mac->flags &
- ZEBRA_MAC_LOCAL_INACTIVE);
- old_static = zebra_vxlan_mac_is_static(mac);
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
- mac_sticky = true;
-
- /*
- * Update any changes and if changes are relevant to
- * BGP, note it.
- */
- if (mac_sticky == sticky
- && old_ifp == ifp
- && old_vid == vid
- && old_local_inactive == local_inactive
- && dp_static == old_static) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, entry exists and has not changed ",
- sticky ? "sticky " : "",
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- ifp->name, ifp->ifindex, vid,
- zvni->vni,
- local_inactive ?
- " local_inactive" : "");
- return 0;
- }
- if (mac_sticky != sticky) {
- if (sticky)
- SET_FLAG(mac->flags,
- ZEBRA_MAC_STICKY);
- else
- UNSET_FLAG(mac->flags,
- ZEBRA_MAC_STICKY);
- inform_client = true;
- }
-
- es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
- ifp, vid);
- /* If an es_change is detected we need to advertise
- * the route with a sequence that is one
- * greater. This is need to indicate a mac-move
- * to the ES peers
- */
- if (es_change) {
- mac->loc_seq = mac->loc_seq + 1;
- /* force drop the peer/sync info as it is
- * simply no longer relevant
- */
- if (CHECK_FLAG(mac->flags,
- ZEBRA_MAC_ALL_PEER_FLAGS)) {
- zebra_vxlan_mac_clear_sync_info(mac);
- new_static =
- zebra_vxlan_mac_is_static(mac);
- /* if we clear peer-flags we
- * also need to notify the dataplane
- * to drop the static flag
- */
- if (old_static != new_static)
- inform_dataplane = true;
- }
- }
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
- CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
- bool do_dad = false;
-
- /*
- * MAC has either moved or was "internally" created due
- * to a neighbor learn and is now actually learnt. If
- * it was learnt as a remote sticky MAC, this is an
- * operator error.
- */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
- flog_warn(
- EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
- "MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u",
- prefix_mac2str(macaddr, buf,
- sizeof(buf)),
- inet_ntoa(mac->fwd_info.r_vtep_ip),
- zvni->vni);
- return 0;
- }
-
- /* If an actual move, compute MAC's seq number */
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- mac->loc_seq = MAX(mac->rem_seq + 1,
- mac->loc_seq);
- vtep_ip = mac->fwd_info.r_vtep_ip;
- /* Trigger DAD for remote MAC */
- do_dad = true;
- }
-
- UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
- UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
- es_change = zebra_vxlan_local_mac_update_fwd_info(mac,
- ifp, vid);
- if (sticky)
- SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- else
- UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
- /*
- * We have to inform BGP of this MAC as well as process
- * all neighbors.
- */
- inform_client = true;
- upd_neigh = true;
-
- zebra_vxlan_dup_addr_detect_for_mac(zvrf, mac, vtep_ip,
- do_dad,
- &is_dup_detect,
- true);
- if (is_dup_detect) {
- inform_client = false;
- upd_neigh = false;
- }
- }
- }
-
- /* if the dataplane thinks the entry is sync but it is
- * not sync in zebra we need to re-install to fixup
- */
- if (dp_static) {
- new_static = zebra_vxlan_mac_is_static(mac);
- if (!new_static)
- inform_dataplane = true;
- }
-
- if (local_inactive)
- SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
- else
- UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
-
- new_bgp_ready = zebra_vxlan_mac_is_ready_for_bgp(mac->flags);
- /* if local-activity has changed we need update bgp
- * even if bgp already knows about the mac
- */
- if ((old_local_inactive != local_inactive) ||
- (new_bgp_ready != old_bgp_ready)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("local mac vni %u mac %s es %s seq %d f 0x%x%s",
- zvni->vni,
- prefix_mac2str(macaddr,
- buf, sizeof(buf)),
- mac->es ? mac->es->esi_str : "",
- mac->loc_seq,
- mac->flags,
- local_inactive ?
- " local-inactive" : "");
- inform_client = true;
- }
-
- if (es_change) {
- inform_client = true;
- upd_neigh = true;
- }
-
- /* Inform dataplane if required. */
- if (inform_dataplane)
- zebra_vxlan_sync_mac_dp_install(mac, false /* set_inactive */,
- false /* force_clear_static */, __func__);
-
- /* Inform BGP if required. */
- if (inform_client)
- zebra_vxlan_mac_send_add_del_to_client(mac,
- old_bgp_ready, new_bgp_ready);
-
- /* Process all neighbors associated with this MAC, if required. */
- if (upd_neigh)
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0, es_change);
-
- return 0;
+ return zebra_evpn_add_update_local_mac(zvrf, zevpn, ifp, macaddr, vid,
+ sticky, local_inactive,
+ dp_static);
}
/*
- * Handle message from client to delete a remote VTEP for a VNI.
+ * Handle message from client to delete a remote VTEP for an EVPN.
*/
void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
{
@@ -10072,7 +4009,7 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
unsigned short l = 0;
vni_t vni;
struct in_addr vtep_ip;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_vtep_t *zvtep;
struct interface *ifp;
struct zebra_if *zif;
@@ -10111,8 +4048,8 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Failed to locate VNI hash upon remote VTEP DEL, VNI %u",
@@ -10120,11 +4057,11 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
continue;
}
- ifp = zvni->vxlan_if;
+ ifp = zevpn->vxlan_if;
if (!ifp) {
zlog_debug(
"VNI %u hash %p doesn't have intf upon remote VTEP DEL",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
continue;
}
zif = ifp->info;
@@ -10139,12 +4076,12 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
* and
* then, the VTEP entry itself and remove it.
*/
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
+ zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
if (!zvtep)
continue;
- zvni_vtep_uninstall(zvni, &vtep_ip);
- zvni_vtep_del(zvni, zvtep);
+ zebra_evpn_vtep_uninstall(zevpn, &vtep_ip);
+ zebra_evpn_vtep_del(zevpn, zvtep);
}
stream_failure:
@@ -10152,7 +4089,7 @@ stream_failure:
}
/*
- * Handle message from client to add a remote VTEP for a VNI.
+ * Handle message from client to add a remote VTEP for an EVPN.
*/
void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
{
@@ -10160,7 +4097,7 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
unsigned short l = 0;
vni_t vni;
struct in_addr vtep_ip;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
struct interface *ifp;
struct zebra_if *zif;
int flood_control;
@@ -10195,21 +4132,21 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
flog_err(
EC_ZEBRA_VTEP_ADD_FAILED,
- "Failed to locate VNI hash upon remote VTEP ADD, VNI %u",
+ "Failed to locate EVPN hash upon remote VTEP ADD, VNI %u",
vni);
continue;
}
- ifp = zvni->vxlan_if;
+ ifp = zevpn->vxlan_if;
if (!ifp) {
flog_err(
EC_ZEBRA_VTEP_ADD_FAILED,
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
continue;
}
@@ -10219,7 +4156,7 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
continue;
- zvtep = zvni_vtep_find(zvni, &vtep_ip);
+ zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
if (zvtep) {
/* If the remote VTEP already exists check if
* the flood mode has changed
@@ -10231,18 +4168,20 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
* is no longer; get rid of the HER fdb
* entry installed before
*/
- zvni_vtep_uninstall(zvni, &vtep_ip);
+ zebra_evpn_vtep_uninstall(zevpn,
+ &vtep_ip);
zvtep->flood_control = flood_control;
- zvni_vtep_install(zvni, zvtep);
+ zebra_evpn_vtep_install(zevpn, zvtep);
}
} else {
- zvtep = zvni_vtep_add(zvni, &vtep_ip, flood_control);
+ zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip,
+ flood_control);
if (zvtep)
- zvni_vtep_install(zvni, zvtep);
+ zebra_evpn_vtep_install(zevpn, zvtep);
else
flog_err(EC_ZEBRA_VTEP_ADD_FAILED,
- "Failed to add remote VTEP, VNI %u zvni %p",
- vni, zvni);
+ "Failed to add remote VTEP, VNI %u zevpn %p",
+ vni, zevpn);
}
}
@@ -10263,7 +4202,7 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
{
struct ipaddr ip;
struct ethaddr macaddr;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
memset(&ip, 0, sizeof(struct ipaddr));
memset(&macaddr, 0, sizeof(struct ethaddr));
@@ -10307,14 +4246,15 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
svi_if_link = if_lookup_by_index_per_ns(
zebra_ns_lookup(NS_DEFAULT),
svi_if_zif->link_ifindex);
- zvni = zvni_from_svi(svi_if, svi_if_link);
+ zevpn = zebra_evpn_from_svi(svi_if,
+ svi_if_link);
}
} else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
/*
* If it is a vlan unaware bridge then svi is the bridge
* itself
*/
- zvni = zvni_from_svi(svi_if, svi_if);
+ zevpn = zebra_evpn_from_svi(svi_if, svi_if);
}
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_if *svi_if_zif =
@@ -10328,18 +4268,18 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
zebra_ns_lookup(NS_DEFAULT),
svi_if_zif->link_ifindex);
if (svi_if_link)
- zvni = zvni_from_svi(ifp, svi_if_link);
+ zevpn = zebra_evpn_from_svi(ifp, svi_if_link);
}
} else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
- zvni = zvni_from_svi(ifp, ifp);
+ zevpn = zebra_evpn_from_svi(ifp, ifp);
}
- if (!zvni)
+ if (!zevpn)
return 0;
- if (!zvni->vxlan_if) {
+ if (!zevpn->vxlan_if) {
zlog_debug("VNI %u hash %p doesn't have intf upon MACVLAN up",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
return -1;
}
@@ -10358,9 +4298,9 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
if (add)
- zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
+ zebra_evpn_gw_macip_add(ifp, zevpn, &macaddr, &ip);
else
- zvni_gw_macip_del(ifp, zvni, &ip);
+ zebra_evpn_gw_macip_del(ifp, zevpn, &ip);
return 0;
}
@@ -10370,7 +4310,7 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
* SVI can be associated to either L3-VNI or L2-VNI.
* For L2-VNI: At this point, this is a NOP since
* the kernel deletes the neighbor entries on this SVI (if any).
- * We only need to update the vrf corresponding to zvni.
+ * We only need to update the vrf corresponding to zevpn.
* For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete
* from bgp
*/
@@ -10387,17 +4327,17 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
/* remove association with svi-if */
zl3vni->svi_if = NULL;
} else {
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
- /* since we dont have svi corresponding to zvni, we associate it
+ /* since we dont have svi corresponding to zevpn, we associate it
* to default vrf. Note: the corresponding neigh entries on the
* SVI would have already been deleted */
- zvni = zvni_from_svi(ifp, link_if);
- if (zvni) {
- zvni->vrf_id = VRF_DEFAULT;
+ zevpn = zebra_evpn_from_svi(ifp, link_if);
+ if (zevpn) {
+ zevpn->vrf_id = VRF_DEFAULT;
/* update the tenant vrf in BGP */
- zvni_send_add_to_client(zvni);
+ zebra_evpn_send_add_to_client(zevpn);
}
}
return 0;
@@ -10413,7 +4353,7 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
*/
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
{
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
zl3vni = zl3vni_from_svi(ifp, link_if);
@@ -10430,31 +4370,31 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
/* process SVI up for l2-vni */
struct neigh_walk_ctx n_wctx;
- zvni = zvni_from_svi(ifp, link_if);
- if (!zvni)
+ zevpn = zebra_evpn_from_svi(ifp, link_if);
+ if (!zevpn)
return 0;
- if (!zvni->vxlan_if) {
+ if (!zevpn->vxlan_if) {
zlog_debug(
"VNI %u hash %p doesn't have intf upon SVI up",
- zvni->vni, zvni);
+ zevpn->vni, zevpn);
return -1;
}
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"SVI %s(%u) VNI %u VRF %s is UP, installing neighbors",
- ifp->name, ifp->ifindex, zvni->vni,
+ ifp->name, ifp->ifindex, zevpn->vni,
vrf_id_to_name(ifp->vrf_id));
/* update the vrf information for l2-vni and inform bgp */
- zvni->vrf_id = ifp->vrf_id;
- zvni_send_add_to_client(zvni);
+ zevpn->vrf_id = ifp->vrf_id;
+ zebra_evpn_send_add_to_client(zevpn);
/* Install any remote neighbors for this VNI. */
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
- hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
+ n_wctx.zevpn = zevpn;
+ hash_iterate(zevpn->neigh_table, zebra_evpn_install_neigh_hash,
&n_wctx);
}
@@ -10541,7 +4481,7 @@ int zebra_vxlan_if_down(struct interface *ifp)
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
zebra_l3vni_t *zl3vni = NULL;
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
@@ -10567,25 +4507,25 @@ int zebra_vxlan_if_down(struct interface *ifp)
ifp->ifindex, vni);
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_debug(
"Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
}
- assert(zvni->vxlan_if == ifp);
+ assert(zevpn->vxlan_if == ifp);
/* Delete this VNI from BGP. */
- zvni_send_del_to_client(zvni);
+ zebra_evpn_send_del_to_client(zevpn);
/* Free up all neighbors and MACs, if any. */
- zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
/* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 1);
+ zebra_evpn_vtep_del_all(zevpn, 1);
}
return 0;
}
@@ -10598,7 +4538,7 @@ int zebra_vxlan_if_up(struct interface *ifp)
vni_t vni;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* Check if EVPN is enabled. */
@@ -10636,29 +4576,29 @@ int zebra_vxlan_if_up(struct interface *ifp)
ifp->ifindex, vni);
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_debug(
- "Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
+ "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
}
- assert(zvni->vxlan_if == ifp);
+ assert(zevpn->vxlan_if == ifp);
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
- zvni->vrf_id = vlan_if->vrf_id;
+ zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
- listnode_add_sort(zl3vni->l2vnis, zvni);
+ listnode_add_sort(zl3vni->l2vnis, zevpn);
}
/* If part of a bridge, inform BGP about this VNI. */
/* Also, read and populate local MACs and neighbors. */
if (zif->brslave_info.br_if) {
- zvni_send_add_to_client(zvni);
- zvni_read_mac_neigh(zvni, ifp);
+ zebra_evpn_send_add_to_client(zevpn);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
}
}
@@ -10674,7 +4614,7 @@ int zebra_vxlan_if_del(struct interface *ifp)
vni_t vni;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* Check if EVPN is enabled. */
@@ -10707,8 +4647,8 @@ int zebra_vxlan_if_del(struct interface *ifp)
ifp->ifindex);
/* Locate hash entry; it is expected to exist. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_debug(
"Failed to locate VNI hash at del, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
@@ -10716,24 +4656,24 @@ int zebra_vxlan_if_del(struct interface *ifp)
}
/* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zvni);
+ listnode_delete(zl3vni->l2vnis, zevpn);
/* Delete VNI from BGP. */
- zvni_send_del_to_client(zvni);
+ zebra_evpn_send_del_to_client(zevpn);
/* Free up all neighbors and MAC, if any. */
- zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+ zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC);
/* Free up all remote VTEPs, if any. */
- zvni_vtep_del_all(zvni, 0);
+ zebra_evpn_vtep_del_all(zevpn, 0);
/* Delete the hash entry. */
- if (zvni_del(zvni)) {
+ if (zebra_evpn_vxlan_del(zevpn)) {
flog_err(EC_ZEBRA_VNI_DEL_FAILED,
- "Failed to del VNI hash %p, IF %s(%u) VNI %u",
- zvni, ifp->name, ifp->ifindex, zvni->vni);
+ "Failed to del EVPN hash %p, IF %s(%u) VNI %u",
+ zevpn, ifp->name, ifp->ifindex, zevpn->vni);
return -1;
}
}
@@ -10748,7 +4688,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
vni_t vni;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* Check if EVPN is enabled. */
@@ -10819,10 +4759,10 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
} else {
/* Update VNI hash. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
zlog_debug(
- "Failed to find L2-VNI hash on update, IF %s(%u) VNI %u",
+ "Failed to find EVPN hash on update, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
}
@@ -10839,10 +4779,10 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
&& (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
/* Delete from client, remove all remote VTEPs */
/* Also, free up all MACs and neighbors. */
- zvni_send_del_to_client(zvni);
- zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
- zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
- zvni_vtep_del_all(zvni, 1);
+ zebra_evpn_send_del_to_client(zevpn);
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+ zebra_evpn_vtep_del_all(zevpn, 1);
return 0;
}
@@ -10851,23 +4791,23 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
/* Remove all existing local neigh and MACs for this VNI
* (including from BGP)
*/
- zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
- zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
}
- if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zvni->local_vtep_ip,
- zvni->mcast_grp);
+ if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->mcast_grp = vxl->mcast_grp;
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vxl->mcast_grp;
/* on local vtep-ip check if ES orig-ip
* needs to be updated
*/
- zebra_evpn_es_set_base_vni(zvni);
+ zebra_evpn_es_set_base_evpn(zevpn);
}
- zvni_vxlan_if_set(zvni, ifp, true /* set */);
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
/* Take further actions needed.
* Note that if we are here, there is a change of interest.
*/
@@ -10880,7 +4820,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
& (ZEBRA_VXLIF_MASTER_CHANGE |
ZEBRA_VXLIF_LOCAL_IP_CHANGE |
ZEBRA_VXLIF_MCAST_GRP_CHANGE))
- zvni_send_add_to_client(zvni);
+ zebra_evpn_send_add_to_client(zevpn);
/* If there is a valid new master or a VLAN mapping change,
* read and populate local MACs and neighbors.
@@ -10888,22 +4828,22 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
* for this VNI (based on new VLAN).
*/
if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- zvni_read_mac_neigh(zvni, ifp);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
struct mac_walk_ctx m_wctx;
struct neigh_walk_ctx n_wctx;
- zvni_read_mac_neigh(zvni, ifp);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
- m_wctx.zvni = zvni;
- hash_iterate(zvni->mac_table, zvni_install_mac_hash,
- &m_wctx);
+ m_wctx.zevpn = zevpn;
+ hash_iterate(zevpn->mac_table,
+ zebra_evpn_install_mac_hash, &m_wctx);
memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
- n_wctx.zvni = zvni;
- hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
- &n_wctx);
+ n_wctx.zevpn = zevpn;
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_install_neigh_hash, &n_wctx);
}
}
@@ -10918,7 +4858,7 @@ int zebra_vxlan_if_add(struct interface *ifp)
vni_t vni;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
zebra_l3vni_t *zl3vni = NULL;
/* Check if EVPN is enabled. */
@@ -10958,39 +4898,39 @@ int zebra_vxlan_if_add(struct interface *ifp)
/* process if-add for l2-vni */
struct interface *vlan_if = NULL;
- /* Create or update VNI hash. */
- zvni = zvni_lookup(vni);
- if (!zvni) {
- zvni = zvni_add(vni);
- if (!zvni) {
+ /* Create or update EVPN hash. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zevpn = zebra_evpn_add(vni);
+ if (!zevpn) {
flog_err(
EC_ZEBRA_VNI_ADD_FAILED,
- "Failed to add VNI hash, IF %s(%u) VNI %u",
+ "Failed to add EVPN hash, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
}
}
- if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zvni->local_vtep_ip,
- zvni->mcast_grp);
+ if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zvni->local_vtep_ip = vxl->vtep_ip;
- zvni->mcast_grp = vxl->mcast_grp;
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vxl->mcast_grp;
/* on local vtep-ip check if ES orig-ip
* needs to be updated
*/
- zebra_evpn_es_set_base_vni(zvni);
+ zebra_evpn_es_set_base_evpn(zevpn);
}
- zvni_vxlan_if_set(zvni, ifp, true /* set */);
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
- zvni->vrf_id = vlan_if->vrf_id;
+ zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
- listnode_add_sort(zl3vni->l2vnis, zvni);
+ listnode_add_sort(zl3vni->l2vnis, zevpn);
}
if (IS_ZEBRA_DEBUG_VXLAN) {
@@ -11017,10 +4957,10 @@ int zebra_vxlan_if_add(struct interface *ifp)
return 0;
/* Inform BGP */
- zvni_send_add_to_client(zvni);
+ zebra_evpn_send_add_to_client(zevpn);
/* Read and populate local MACs and neighbors */
- zvni_read_mac_neigh(zvni, ifp);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
}
return 0;
@@ -11098,7 +5038,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
: "NIL");
/* formulate l2vni list */
- hash_iterate(zvrf_evpn->vni_table, zvni_add_to_l3vni_list,
+ hash_iterate(zvrf_evpn->evpn_table, zevpn_add_to_l3vni_list,
zl3vni);
if (is_l3vni_oper_up(zl3vni))
@@ -11228,7 +5168,7 @@ void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS)
/* Install or uninstall flood entries corresponding to
* remote VTEPs.
*/
- hash_iterate(zvrf->vni_table, zvni_handle_flooding_remote_vteps,
+ hash_iterate(zvrf->evpn_table, zebra_evpn_handle_flooding_remote_vteps,
zvrf);
stream_failure:
@@ -11244,7 +5184,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
struct stream *s;
int advertise;
vni_t vni = 0;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
struct interface *ifp = NULL;
if (!EVPN_ENABLED(zvrf)) {
@@ -11271,11 +5211,13 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
if (advertise) {
zvrf->advertise_svi_macip = advertise;
- hash_iterate(zvrf->vni_table,
- zvni_gw_macip_add_for_vni_hash, NULL);
+ hash_iterate(zvrf->evpn_table,
+ zebra_evpn_gw_macip_add_for_evpn_hash,
+ NULL);
} else {
- hash_iterate(zvrf->vni_table,
- zvni_svi_macip_del_for_vni_hash, NULL);
+ hash_iterate(zvrf->evpn_table,
+ zebra_evpn_svi_macip_del_for_evpn_hash,
+ NULL);
zvrf->advertise_svi_macip = advertise;
}
@@ -11284,27 +5226,27 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"EVPN SVI macip Adv %s on VNI %d , currently %s",
advertise ? "enabled" : "disabled", vni,
- advertise_svi_macip_enabled(zvni)
+ advertise_svi_macip_enabled(zevpn)
? "enabled"
: "disabled");
- if (zvni->advertise_svi_macip == advertise)
+ if (zevpn->advertise_svi_macip == advertise)
return;
/* Store flag even though SVI is not present.
* Once SVI comes up triggers self MAC-IP route add.
*/
- zvni->advertise_svi_macip = advertise;
+ zevpn->advertise_svi_macip = advertise;
- ifp = zvni->vxlan_if;
+ ifp = zevpn->vxlan_if;
if (!ifp)
return;
@@ -11322,10 +5264,10 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
if (advertise) {
/* Add primary SVI MAC-IP */
- zvni_add_macip_for_intf(vlan_if, zvni);
+ zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
} else {
/* Del primary SVI MAC-IP */
- zvni_del_macip_for_intf(vlan_if, zvni);
+ zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
}
}
@@ -11342,7 +5284,7 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
struct stream *s;
int advertise;
vni_t vni = 0;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan zl2_info;
@@ -11358,22 +5300,22 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
STREAM_GETC(s, advertise);
STREAM_GET(&vni, s, 3);
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return;
- if (zvni->advertise_subnet == advertise)
+ if (zevpn->advertise_subnet == advertise)
return;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s",
advertise ? "enabled" : "disabled", vni,
- zvni->advertise_subnet ? "enabled" : "disabled");
+ zevpn->advertise_subnet ? "enabled" : "disabled");
- zvni->advertise_subnet = advertise;
+ zevpn->advertise_subnet = advertise;
- ifp = zvni->vxlan_if;
+ ifp = zevpn->vxlan_if;
if (!ifp)
return;
@@ -11390,10 +5332,10 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
if (!vlan_if)
return;
- if (zvni->advertise_subnet)
- zvni_advertise_subnet(zvni, vlan_if, 1);
+ if (zevpn->advertise_subnet)
+ zebra_evpn_advertise_subnet(zevpn, vlan_if, 1);
else
- zvni_advertise_subnet(zvni, vlan_if, 0);
+ zebra_evpn_advertise_subnet(zevpn, vlan_if, 0);
stream_failure:
return;
@@ -11408,7 +5350,7 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
struct stream *s;
int advertise;
vni_t vni = 0;
- zebra_vni_t *zvni = NULL;
+ zebra_evpn_t *zevpn = NULL;
struct interface *ifp = NULL;
if (!EVPN_ENABLED(zvrf)) {
@@ -11434,12 +5376,14 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
zvrf->advertise_gw_macip = advertise;
- if (advertise_gw_macip_enabled(zvni))
- hash_iterate(zvrf->vni_table,
- zvni_gw_macip_add_for_vni_hash, NULL);
+ if (advertise_gw_macip_enabled(zevpn))
+ hash_iterate(zvrf->evpn_table,
+ zebra_evpn_gw_macip_add_for_evpn_hash,
+ NULL);
else
- hash_iterate(zvrf->vni_table,
- zvni_gw_macip_del_for_vni_hash, NULL);
+ hash_iterate(zvrf->evpn_table,
+ zebra_evpn_gw_macip_del_for_evpn_hash,
+ NULL);
} else {
struct zebra_if *zif = NULL;
@@ -11447,23 +5391,23 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
- zvni = zvni_lookup(vni);
- if (!zvni)
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
return;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"EVPN gateway macip Adv %s on VNI %d , currently %s",
advertise ? "enabled" : "disabled", vni,
- advertise_gw_macip_enabled(zvni) ? "enabled"
+ advertise_gw_macip_enabled(zevpn) ? "enabled"
: "disabled");
- if (zvni->advertise_gw_macip == advertise)
+ if (zevpn->advertise_gw_macip == advertise)
return;
- zvni->advertise_gw_macip = advertise;
+ zevpn->advertise_gw_macip = advertise;
- ifp = zvni->vxlan_if;
+ ifp = zevpn->vxlan_if;
if (!ifp)
return;
@@ -11480,22 +5424,22 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
if (!vlan_if)
return;
- if (advertise_gw_macip_enabled(zvni)) {
+ if (advertise_gw_macip_enabled(zevpn)) {
/* Add primary SVI MAC-IP */
- zvni_add_macip_for_intf(vlan_if, zvni);
+ zebra_evpn_add_macip_for_intf(vlan_if, zevpn);
/* Add VRR MAC-IP - if any*/
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
if (vrr_if)
- zvni_add_macip_for_intf(vrr_if, zvni);
+ zebra_evpn_add_macip_for_intf(vrr_if, zevpn);
} else {
/* Del primary MAC-IP */
- zvni_del_macip_for_intf(vlan_if, zvni);
+ zebra_evpn_del_macip_for_intf(vlan_if, zevpn);
/* Del VRR MAC-IP - if any*/
vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
if (vrr_if)
- zvni_del_macip_for_intf(vrr_if, zvni);
+ zebra_evpn_del_macip_for_intf(vrr_if, zevpn);
}
}
@@ -11547,12 +5491,12 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
/* Replay all ESs */
zebra_evpn_es_send_all_to_client(true /* add */);
- /* Build VNI hash table and inform BGP. */
- zvni_build_hash_table();
+ /* Build EVPN hash table and inform BGP. */
+ zevpn_build_hash_table();
/* Add all SVI (L3 GW) MACs to BGP*/
- hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
- NULL);
+ hash_iterate(zvrf->evpn_table,
+ zebra_evpn_gw_macip_add_for_evpn_hash, NULL);
/* Read the MAC FDB */
macfdb_read(zvrf->zns);
@@ -11560,10 +5504,11 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
/* Read neighbors */
neigh_read(zvrf->zns);
} else {
- /* Cleanup VTEPs for all VNIs - uninstall from
+ /* Cleanup VTEPs for all EVPNs - uninstall from
* kernel and free entries.
*/
- hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+ hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all,
+ zvrf);
/* Delete all ESs in BGP */
zebra_evpn_es_send_all_to_client(false /* add */);
@@ -11580,40 +5525,41 @@ stream_failure:
}
/*
- * Allocate VNI hash table for this VRF and do other initialization.
+ * Allocate EVPN hash table for this VRF and do other initialization.
* NOTE: Currently supported only for default VRF.
*/
void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
{
if (!zvrf)
return;
- zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp,
- "Zebra VRF VNI Table");
+ zvrf->evpn_table =
+ hash_create(zebra_evpn_hash_keymake, zebra_evpn_hash_cmp,
+ "Zebra VRF EVPN Table");
zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make,
zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table");
}
-/* Cleanup VNI info, but don't free the table. */
+/* Cleanup EVPN info, but don't free the table. */
void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
{
struct zebra_vrf *evpn_zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;
- hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+ hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
if (zvrf == evpn_zvrf)
zebra_evpn_es_cleanup();
}
-/* Close all VNI handling */
+/* Close all EVPN handling */
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
{
if (!zvrf)
return;
- hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
- hash_free(zvrf->vni_table);
+ hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
+ hash_free(zvrf->evpn_table);
}
/* init the l3vni table */
@@ -11644,130 +5590,6 @@ ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
return zl3vni->svi_if->ifindex;
}
-static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t)
-{
- struct zebra_vrf *zvrf = NULL;
- zebra_neigh_t *nbr = NULL;
- zebra_vni_t *zvni = NULL;
- char buf1[INET6_ADDRSTRLEN];
- char buf2[ETHER_ADDR_STRLEN];
-
- nbr = THREAD_ARG(t);
-
- /* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
- if (!zvrf)
- return 0;
-
- zvni = zvni_lookup(nbr->zvni->vni);
- if (!zvni)
- return 0;
-
- nbr = zvni_neigh_lookup(zvni, &nbr->ip);
- if (!nbr)
- return 0;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired",
- __func__,
- prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)),
- ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), nbr->flags,
- nbr->dad_count, zvni->vni);
-
- UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
- nbr->dad_count = 0;
- nbr->detect_start_time.tv_sec = 0;
- nbr->detect_start_time.tv_usec = 0;
- nbr->dad_dup_detect_time = 0;
- nbr->dad_ip_auto_recovery_timer = NULL;
- ZEBRA_NEIGH_SET_ACTIVE(nbr);
-
- /* Send to BGP */
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) {
- zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip, &nbr->emac,
- nbr->mac, nbr->flags, nbr->loc_seq);
- } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) {
- zvni_rem_neigh_install(zvni, nbr, false /*was_static*/);
- }
-
- return 0;
-}
-
-static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t)
-{
- struct zebra_vrf *zvrf = NULL;
- zebra_mac_t *mac = NULL;
- zebra_vni_t *zvni = NULL;
- struct listnode *node = NULL;
- zebra_neigh_t *nbr = NULL;
- char buf[ETHER_ADDR_STRLEN];
-
- mac = THREAD_ARG(t);
-
- /* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(mac->zvni->vrf_id);
- if (!zvrf)
- return 0;
-
- zvni = zvni_lookup(mac->zvni->vni);
- if (!zvni)
- return 0;
-
- mac = zvni_mac_lookup(zvni, &mac->macaddr);
- if (!mac)
- return 0;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "%s: duplicate addr mac %s flags 0x%x learn 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));
-
- /* Remove all IPs as duplicate associcated with this MAC */
- for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
- if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
- ZEBRA_NEIGH_SET_INACTIVE(nbr);
- else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
- zvni_rem_neigh_install(zvni, nbr,
- false /*was_static*/);
- }
-
- UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
- nbr->dad_count = 0;
- nbr->detect_start_time.tv_sec = 0;
- nbr->dad_dup_detect_time = 0;
- }
-
- UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
- mac->dad_count = 0;
- mac->detect_start_time.tv_sec = 0;
- mac->detect_start_time.tv_usec = 0;
- mac->dad_dup_detect_time = 0;
- mac->dad_mac_auto_recovery_timer = NULL;
-
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
- /* Inform to BGP */
- if (zvni_mac_send_add_to_client(zvni->vni, &mac->macaddr,
- mac->flags, mac->loc_seq, mac->es))
- return -1;
-
- /* Process all neighbors associated with this MAC. */
- zvni_process_neigh_on_local_mac_change(zvni, mac, 0,
- 0 /*es_change*/);
-
- } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
- zvni_process_neigh_on_remote_mac_add(zvni, mac);
-
- /* Install the entry. */
- zvni_rem_mac_install(zvni, mac, false /* was_static */);
- }
-
- return 0;
-}
-
/************************** vxlan SG cache management ************************/
/* Inform PIM about the mcast group */
static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
@@ -12019,87 +5841,6 @@ void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS)
hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_replay_send, NULL);
}
-/************************** EVPN BGP config management ************************/
-/* Notify Local MACs to the clienti, skips GW MAC */
-static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
- void *arg)
-{
- struct mac_walk_ctx *wctx = arg;
- zebra_mac_t *zmac = bucket->data;
-
- if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
- return;
-
- if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
- zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr,
- zmac->flags, zmac->loc_seq, zmac->es);
-}
-
-/* Iterator to Notify Local MACs of a L2VNI */
-static void zvni_send_mac_to_client(zebra_vni_t *zvni)
-{
- struct mac_walk_ctx wctx;
-
- if (!zvni->mac_table)
- return;
-
- memset(&wctx, 0, sizeof(struct mac_walk_ctx));
- wctx.zvni = zvni;
-
- hash_iterate(zvni->mac_table, zvni_send_mac_hash_entry_to_client,
- &wctx);
-}
-
-/* Notify Neighbor entries to the Client, skips the GW entry */
-static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket,
- void *arg)
-{
- struct mac_walk_ctx *wctx = arg;
- zebra_neigh_t *zn = bucket->data;
- zebra_mac_t *zmac = NULL;
-
- if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW))
- return;
-
- if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) &&
- IS_ZEBRA_NEIGH_ACTIVE(zn)) {
- zmac = zvni_mac_lookup(wctx->zvni, &zn->emac);
- if (!zmac)
- return;
-
- zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip,
- &zn->emac, zn->mac, zn->flags,
- zn->loc_seq);
- }
-}
-
-/* Iterator of a specific L2VNI */
-static void zvni_send_neigh_to_client(zebra_vni_t *zvni)
-{
- struct neigh_walk_ctx wctx;
-
- memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
- wctx.zvni = zvni;
-
- hash_iterate(zvni->neigh_table, zvni_send_neigh_hash_entry_to_client,
- &wctx);
-}
-
-static void zvni_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt)
-{
- zebra_vni_t *zvni = NULL;
-
- zvni = (zebra_vni_t *)bucket->data;
- zvni->advertise_gw_macip = 0;
- zvni->advertise_svi_macip = 0;
- zvni->advertise_subnet = 0;
-
- zvni_neigh_del_all(zvni, 1, 0,
- DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP);
- zvni_mac_del_all(zvni, 1, 0,
- DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP);
- zvni_vtep_del_all(zvni, 1);
-}
/* Cleanup EVPN configuration of a specific VRF */
static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf)
@@ -12111,7 +5852,7 @@ static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf)
zvrf->advertise_svi_macip = 0;
zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;
- hash_iterate(zvrf->vni_table, zvni_evpn_cfg_cleanup, NULL);
+ hash_iterate(zvrf->evpn_table, zebra_evpn_cfg_cleanup, NULL);
if (zvrf->l3vni)
zl3vni = zl3vni_lookup(zvrf->l3vni);
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index e2eae56873..9a88d98b81 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -29,6 +29,8 @@
#include "if.h"
#include "linklist.h"
#include "zebra_vxlan.h"
+#include "zebra_evpn.h"
+#include "zebra_evpn_mac.h"
#ifdef __cplusplus
extern "C" {
@@ -37,85 +39,8 @@ extern "C" {
#define ERR_STR_SZ 256
/* definitions */
-typedef struct zebra_vni_t_ zebra_vni_t;
-typedef struct zebra_vtep_t_ zebra_vtep_t;
-typedef struct zebra_mac_t_ zebra_mac_t;
-typedef struct zebra_neigh_t_ zebra_neigh_t;
typedef struct zebra_l3vni_t_ zebra_l3vni_t;
-/*
- * VTEP info
- *
- * Right now, this just has each remote VTEP's IP address.
- */
-struct zebra_vtep_t_ {
- /* Remote IP. */
- /* NOTE: Can only be IPv4 right now. */
- struct in_addr vtep_ip;
- /* Flood mode (one of enum vxlan_flood_control) based on the PMSI
- * tunnel type advertised by the remote VTEP
- */
- int flood_control;
-
- /* Links. */
- struct zebra_vtep_t_ *next;
- struct zebra_vtep_t_ *prev;
-};
-
-RB_HEAD(zebra_es_evi_rb_head, zebra_evpn_es_evi);
-RB_PROTOTYPE(zebra_es_evi_rb_head, zebra_evpn_es_evi, rb_node,
- zebra_es_evi_rb_cmp);
-
-/*
- * VNI hash table
- *
- * Contains information pertaining to a VNI:
- * - the list of remote VTEPs (with this VNI)
- */
-struct zebra_vni_t_ {
- /* VNI - key */
- vni_t vni;
-
- /* ES flags */
- uint32_t flags;
-#define ZVNI_READY_FOR_BGP (1 << 0) /* ready to be sent to BGP */
-
- /* Flag for advertising gw macip */
- uint8_t advertise_gw_macip;
-
- /* Flag for advertising svi macip */
- uint8_t advertise_svi_macip;
-
- /* Flag for advertising gw macip */
- uint8_t advertise_subnet;
-
- /* Corresponding VxLAN interface. */
- struct interface *vxlan_if;
-
- /* List of remote VTEPs */
- zebra_vtep_t *vteps;
-
- /* Local IP */
- struct in_addr local_vtep_ip;
-
- /* PIM-SM MDT group for BUM flooding */
- struct in_addr mcast_grp;
-
- /* tenant VRF, if any */
- vrf_id_t vrf_id;
-
- /* List of local or remote MAC */
- struct hash *mac_table;
-
- /* List of local or remote neighbors (MAC+IP) */
- struct hash *neigh_table;
-
- /* RB tree of ES-EVIs */
- struct zebra_es_evi_rb_head es_evi_rb_tree;
-
- /* List of local ESs */
- struct list *local_es_evi_list;
-};
/* L3 VNI hash table */
struct zebra_l3vni_t_ {
@@ -279,260 +204,11 @@ static inline void zl3vni_get_svi_rmac(zebra_l3vni_t *zl3vni,
memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN);
}
-struct host_rb_entry {
- RB_ENTRY(host_rb_entry) hl_entry;
-
- struct prefix p;
-};
-
-RB_HEAD(host_rb_tree_entry, host_rb_entry);
-RB_PROTOTYPE(host_rb_tree_entry, host_rb_entry, hl_entry,
- host_rb_entry_compare);
-/*
- * MAC hash table.
- *
- * This table contains the MAC addresses pertaining to this VNI.
- * This includes local MACs learnt on an attached VLAN that maps
- * to this VNI as well as remote MACs learnt and installed by BGP.
- * Local MACs will be known either on a VLAN sub-interface or
- * on (port, VLAN); however, it is sufficient for zebra to maintain
- * against the VNI i.e., it does not need to retain the local "port"
- * information. The correct VNI will be obtained as zebra maintains
- * the mapping (of VLAN to VNI).
- */
-struct zebra_mac_t_ {
- /* MAC address. */
- struct ethaddr macaddr;
-
- uint32_t flags;
-#define ZEBRA_MAC_LOCAL 0x01
-#define ZEBRA_MAC_REMOTE 0x02
-#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
-#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
-#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */
-#define ZEBRA_MAC_DEF_GW 0x20
-/* remote VTEP advertised MAC as default GW */
-#define ZEBRA_MAC_REMOTE_DEF_GW 0x40
-#define ZEBRA_MAC_DUPLICATE 0x80
-#define ZEBRA_MAC_FPM_SENT 0x100 /* whether or not this entry was sent. */
-/* MAC is locally active on an ethernet segment peer */
-#define ZEBRA_MAC_ES_PEER_ACTIVE 0x200
-/* MAC has been proxy-advertised by peers. This means we need to
- * keep the entry for forwarding but cannot advertise it
- */
-#define ZEBRA_MAC_ES_PEER_PROXY 0x400
-/* We have not been able to independently establish that the host is
- * local connected but one or more ES peers claims it is.
- * We will maintain the entry for forwarding purposes and continue
- * to advertise it as locally attached but with a "proxy" flag
- */
-#define ZEBRA_MAC_LOCAL_INACTIVE 0x800
-
-#define ZEBRA_MAC_ALL_LOCAL_FLAGS (ZEBRA_MAC_LOCAL |\
- ZEBRA_MAC_LOCAL_INACTIVE)
-#define ZEBRA_MAC_ALL_PEER_FLAGS (ZEBRA_MAC_ES_PEER_PROXY |\
- ZEBRA_MAC_ES_PEER_ACTIVE)
-
- /* back pointer to zvni */
- zebra_vni_t *zvni;
-
- /* Local or remote info. */
- union {
- struct {
- ifindex_t ifindex;
- vlanid_t vid;
- } local;
-
- struct in_addr r_vtep_ip;
- } fwd_info;
-
- /* Local or remote ES */
- struct zebra_evpn_es *es;
- /* memory used to link the mac to the es */
- struct listnode es_listnode;
-
- /* Mobility sequence numbers associated with this entry. */
- uint32_t rem_seq;
- uint32_t loc_seq;
-
- /* List of neigh associated with this mac */
- struct list *neigh_list;
-
- /* list of hosts pointing to this remote RMAC */
- struct host_rb_tree_entry host_rb;
-
- /* Duplicate mac detection */
- uint32_t dad_count;
-
- struct thread *dad_mac_auto_recovery_timer;
-
- struct timeval detect_start_time;
-
- time_t dad_dup_detect_time;
-
- /* used for ageing out the PEER_ACTIVE flag */
- struct thread *hold_timer;
-
- /* number of neigh entries (using this mac) that have
- * ZEBRA_MAC_ES_PEER_ACTIVE or ZEBRA_NEIGH_ES_PEER_PROXY
- */
- uint32_t sync_neigh_cnt;
-};
-
-/*
- * Context for MAC hash walk - used by callbacks.
- */
-struct mac_walk_ctx {
- zebra_vni_t *zvni; /* VNI hash */
- struct zebra_vrf *zvrf; /* VRF - for client notification. */
- int uninstall; /* uninstall from kernel? */
- int upd_client; /* uninstall from client? */
-
- uint32_t flags;
-#define DEL_LOCAL_MAC 0x1
-#define DEL_REMOTE_MAC 0x2
-#define DEL_ALL_MAC (DEL_LOCAL_MAC | DEL_REMOTE_MAC)
-#define DEL_REMOTE_MAC_FROM_VTEP 0x4
-#define SHOW_REMOTE_MAC_FROM_VTEP 0x8
-
- struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */
-
- struct vty *vty; /* Used by VTY handlers */
- uint32_t count; /* Used by VTY handlers */
- struct json_object *json; /* Used for JSON Output */
- bool print_dup; /* Used to print dup addr list */
-};
-
-struct rmac_walk_ctx {
- struct vty *vty;
- struct json_object *json;
-};
-
-/* temporary datastruct to pass info between the mac-update and
- * neigh-update while handling mac-ip routes
- */
-struct sync_mac_ip_ctx {
- bool ignore_macip;
- bool mac_created;
- bool mac_inactive;
- bool mac_dp_update_deferred;
- zebra_mac_t *mac;
-};
-
-#define IS_ZEBRA_NEIGH_ACTIVE(n) (n->state == ZEBRA_NEIGH_ACTIVE)
-
-#define IS_ZEBRA_NEIGH_INACTIVE(n) (n->state == ZEBRA_NEIGH_INACTIVE)
-
-#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE
-
-#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE
-
-/*
- * Neighbor hash table.
- *
- * This table contains the neighbors (IP to MAC bindings) pertaining to
- * this VNI. This includes local neighbors learnt on the attached VLAN
- * device that maps to this VNI as well as remote neighbors learnt and
- * installed by BGP.
- * Local neighbors will be known against the VLAN device (SVI); however,
- * it is sufficient for zebra to maintain against the VNI. The correct
- * VNI will be obtained as zebra maintains the mapping (of VLAN to VNI).
- */
-struct zebra_neigh_t_ {
- /* IP address. */
- struct ipaddr ip;
-
- /* MAC address. */
- struct ethaddr emac;
-
- /* Back pointer to MAC. Only applicable to hosts in a L2-VNI. */
- zebra_mac_t *mac;
-
- /* Underlying interface. */
- ifindex_t ifindex;
-
- zebra_vni_t *zvni;
-
- uint32_t flags;
-#define ZEBRA_NEIGH_LOCAL 0x01
-#define ZEBRA_NEIGH_REMOTE 0x02
-#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */
-#define ZEBRA_NEIGH_DEF_GW 0x08
-#define ZEBRA_NEIGH_ROUTER_FLAG 0x10
-#define ZEBRA_NEIGH_DUPLICATE 0x20
-#define ZEBRA_NEIGH_SVI_IP 0x40
-/* rxed from an ES peer */
-#define ZEBRA_NEIGH_ES_PEER_ACTIVE 0x80
-/* rxed from an ES peer as a proxy advertisement */
-#define ZEBRA_NEIGH_ES_PEER_PROXY 0x100
-/* We have not been able to independently establish that the host
- * is local connected
- */
-#define ZEBRA_NEIGH_LOCAL_INACTIVE 0x200
-#define ZEBRA_NEIGH_ALL_LOCAL_FLAGS (ZEBRA_NEIGH_LOCAL |\
- ZEBRA_NEIGH_LOCAL_INACTIVE)
-#define ZEBRA_NEIGH_ALL_PEER_FLAGS (ZEBRA_NEIGH_ES_PEER_PROXY |\
- ZEBRA_NEIGH_ES_PEER_ACTIVE)
-
- enum zebra_neigh_state state;
-
- /* Remote VTEP IP - applicable only for remote neighbors. */
- struct in_addr r_vtep_ip;
-
- /*
- * Mobility sequence numbers associated with this entry. The rem_seq
- * represents the sequence number from the client (BGP) for the most
- * recent add or update of this entry while the loc_seq represents
- * the sequence number informed (or to be informed) by zebra to BGP
- * for this entry.
- */
- uint32_t rem_seq;
- uint32_t loc_seq;
-
- /* list of hosts pointing to this remote NH entry */
- struct host_rb_tree_entry host_rb;
-
- /* Duplicate ip detection */
- uint32_t dad_count;
-
- struct thread *dad_ip_auto_recovery_timer;
-
- struct timeval detect_start_time;
-
- time_t dad_dup_detect_time;
-
- /* used for ageing out the PEER_ACTIVE flag */
- struct thread *hold_timer;
-};
-
-/*
- * Context for neighbor hash walk - used by callbacks.
- */
-struct neigh_walk_ctx {
- zebra_vni_t *zvni; /* VNI hash */
- struct zebra_vrf *zvrf; /* VRF - for client notification. */
- int uninstall; /* uninstall from kernel? */
- int upd_client; /* uninstall from client? */
-
- uint32_t flags;
-#define DEL_LOCAL_NEIGH 0x1
-#define DEL_REMOTE_NEIGH 0x2
-#define DEL_ALL_NEIGH (DEL_LOCAL_NEIGH | DEL_REMOTE_NEIGH)
-#define DEL_REMOTE_NEIGH_FROM_VTEP 0x4
-#define SHOW_REMOTE_NEIGH_FROM_VTEP 0x8
-
- struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */
-
- struct vty *vty; /* Used by VTY handlers */
- uint32_t count; /* Used by VTY handlers */
- uint8_t addr_width; /* Used by VTY handlers */
- struct json_object *json; /* Used for JSON Output */
-};
/* context for neigh hash walk - update l3vni and rmac */
struct neigh_l3info_walk_ctx {
- zebra_vni_t *zvni;
+ zebra_evpn_t *zevpn;
zebra_l3vni_t *zl3vni;
int add;
};
@@ -579,7 +255,7 @@ typedef struct zebra_vxlan_sg_ {
uint32_t ref_cnt;
} zebra_vxlan_sg_t;
-extern zebra_vni_t *zvni_lookup(vni_t vni);
+extern zebra_evpn_t *zevpn_lookup(vni_t vni);
extern void zebra_vxlan_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
bool force_clear_static, const char *caller);