summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--alpine/APKBUILD.in9
-rw-r--r--bgpd/bgp_attr.c4
-rw-r--r--bgpd/bgp_evpn.c1033
-rw-r--r--bgpd/bgp_evpn_mh.c18
-rw-r--r--bgpd/bgp_evpn_private.h121
-rw-r--r--bgpd/bgp_evpn_vty.c750
-rw-r--r--bgpd/bgp_evpn_vty.h6
-rw-r--r--bgpd/bgp_fsm.c7
-rw-r--r--bgpd/bgp_io.c9
-rw-r--r--bgpd/bgp_mplsvpn.c18
-rw-r--r--bgpd/bgp_packet.c28
-rw-r--r--bgpd/bgp_regex.h15
-rw-r--r--bgpd/bgp_route.c131
-rw-r--r--bgpd/bgp_route.h12
-rw-r--r--bgpd/bgp_routemap.c9
-rw-r--r--bgpd/bgp_vty.c22
-rw-r--r--bgpd/bgpd.h2
-rw-r--r--configure.ac12
-rw-r--r--debian/frr.install1
-rw-r--r--debian/frr.pam1
-rw-r--r--doc/user/bgp.rst4
-rw-r--r--doc/user/installation.rst7
-rw-r--r--doc/user/pathd.rst8
-rw-r--r--doc/user/zebra.rst30
-rw-r--r--docker/alpine/Dockerfile6
-rw-r--r--isisd/isis_route.c13
-rw-r--r--lib/command.h2
-rw-r--r--lib/frrstr.c9
-rw-r--r--lib/frrstr.h9
-rw-r--r--lib/ipaddr.h2
-rw-r--r--lib/srv6.c8
-rw-r--r--lib/srv6.h20
-rw-r--r--lib/vty.c9
-rw-r--r--lib/vty.h9
-rw-r--r--lib/zclient.c2
-rw-r--r--ospfd/ospf_lsa.c4
-rw-r--r--pathd/path_cli.c50
-rw-r--r--pathd/path_ted.c6
-rw-r--r--pathd/path_ted.h1
-rw-r--r--pathd/pathd.c180
-rw-r--r--pathd/pathd.h7
-rw-r--r--pimd/pim_iface.c4
-rw-r--r--pimd/pim_igmp_mtrace.c19
-rw-r--r--pimd/pim_nb_config.c3
-rw-r--r--pimd/pim_nht.c49
-rw-r--r--pimd/pim_nht.h7
-rw-r--r--pimd/pim_rpf.c10
-rw-r--r--redhat/frr.pam1
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--tests/topotests/srv6_locator_usid/__init__.py0
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_1.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_2.json8
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_3.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_4.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_5.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_6.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_7.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_8.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_1.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_2.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_3.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_4.json35
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_5.json36
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_6.json35
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_7.json19
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_8.json4
-rw-r--r--tests/topotests/srv6_locator_usid/r1/setup.sh2
-rw-r--r--tests/topotests/srv6_locator_usid/r1/sharpd.conf7
-rw-r--r--tests/topotests/srv6_locator_usid/r1/zebra.conf20
-rwxr-xr-xtests/topotests/srv6_locator_usid/test_srv6_locator_usid.py276
-rw-r--r--tools/etc/logrotate.d/frr (renamed from debian/frr.logrotate)0
-rwxr-xr-xtools/frrcommon.sh.in2
-rw-r--r--zebra/dplane_fpm_nl.c14
-rw-r--r--zebra/zapi_msg.c5
-rw-r--r--zebra/zebra_evpn.c67
-rw-r--r--zebra/zebra_evpn_mac.c159
-rw-r--r--zebra/zebra_evpn_mac.h33
-rw-r--r--zebra/zebra_evpn_mh.c6
-rw-r--r--zebra/zebra_evpn_neigh.c40
-rw-r--r--zebra/zebra_evpn_neigh.h2
-rw-r--r--zebra/zebra_srte.c17
-rw-r--r--zebra/zebra_srte.h1
-rw-r--r--zebra/zebra_srv6.c52
-rw-r--r--zebra/zebra_srv6.h3
-rw-r--r--zebra/zebra_srv6_vty.c38
-rw-r--r--zebra/zebra_vty.c26
-rw-r--r--zebra/zebra_vxlan.c14
-rw-r--r--zebra/zebra_vxlan.h3
89 files changed, 2988 insertions, 698 deletions
diff --git a/Makefile.am b/Makefile.am
index 8c7bde9d4c..44d2ab8e72 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -231,7 +231,7 @@ EXTRA_DIST += \
\
python/xrefstructs.json \
\
- redhat/frr.logrotate \
+ tools/etc/logrotate.d/frr \
redhat/frr.pam \
redhat/frr.spec \
\
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 51986de2dd..3aad9549b5 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -15,8 +15,8 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
libltdl libressl libssh2 libstdc++ libtool libuuid
linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
- ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
- perl pkgconf python3 python3-dev readline readline-dev sqlite-libs
+ ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre2
+ perl pkgconf python3 python3-dev readline readline-dev sqlite-libs pcre2-dev
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
py3-sphinx elfutils elfutils-dev libyang-dev"
checkdepends="pytest py-setuptools"
@@ -46,8 +46,9 @@ build() {
--enable-multipath=64 \
--enable-vty-group=frrvty \
--enable-user=$_user \
- --enable-group=$_user
- make
+ --enable-group=$_user \
+ --enable-pcre2posix
+ make -j $(nproc)
}
check() {
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b2d7bdcef4..b8010364a7 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -4506,7 +4506,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_put(s, &attr->srv6_l3vpn->sid,
sizeof(attr->srv6_l3vpn->sid)); /* sid */
stream_putc(s, 0); /* sid_flags */
- stream_putw(s, 0xffff); /* endpoint */
+ stream_putw(s,
+ attr->srv6_l3vpn
+ ->endpoint_behavior); /* endpoint */
stream_putc(s, 0); /* reserved */
stream_putc(
s,
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 0a97a8b7bc..eab70bfdaf 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -67,7 +67,6 @@ DEFINE_MTYPE_STATIC(BGPD, VRF_ROUTE_TARGET, "L3 Route Target");
/*
* Static function declarations
*/
-static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn);
static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
@@ -645,10 +644,14 @@ static void evpn_convert_nexthop_to_ipv6(struct attr *attr)
attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
}
-struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table, afi_t afi,
+/*
+ * Wrapper for node get in global table.
+ */
+struct bgp_dest *bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi,
safi_t safi,
const struct prefix_evpn *evp,
- struct prefix_rd *prd)
+ struct prefix_rd *prd,
+ const struct bgp_path_info *local_pi)
{
struct prefix_evpn global_p;
@@ -658,14 +661,38 @@ struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table, afi_t afi,
*/
evpn_type1_prefix_global_copy(&global_p, evp);
evp = &global_p;
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
+ local_pi) {
+ /*
+ * prefix in the global table needs MAC/IP, ensure they are
+ * present, using one's from local table's path_info.
+ */
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp,
+ evpn_type2_path_info_get_mac(local_pi),
+ NULL /* ip */);
+ }
+
+ evp = &global_p;
}
return bgp_afi_node_get(table, afi, safi, (struct prefix *)evp, prd);
}
-struct bgp_dest *bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi,
- safi_t safi,
- const struct prefix_evpn *evp,
- struct prefix_rd *prd)
+/*
+ * Wrapper for node lookup in global table.
+ */
+struct bgp_dest *
+bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
+ const struct prefix_evpn *evp,
+ struct prefix_rd *prd,
+ const struct bgp_path_info *local_pi)
{
struct prefix_evpn global_p;
@@ -675,21 +702,177 @@ struct bgp_dest *bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi,
*/
evpn_type1_prefix_global_copy(&global_p, evp);
evp = &global_p;
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
+ local_pi) {
+ /*
+ * prefix in the global table needs MAC/IP, ensure they are
+ * present, using one's from local table's path_info.
+ */
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &global_p, evp,
+ evpn_type2_path_info_get_mac(local_pi),
+ NULL /* ip */);
+ }
+
+ evp = &global_p;
}
return bgp_afi_node_lookup(table, afi, safi, (struct prefix *)evp, prd);
}
/*
+ * Wrapper for node get in VNI IP table.
+ */
+struct bgp_dest *bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) {
+ /* prefix in the global table doesn't include the VTEP-IP so
+ * we need to create a different copy for the VNI
+ */
+ evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
+ parent_pi->attr->nexthop);
+ evp = &vni_p;
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Only MAC-IP should go into this table, not mac-only */
+ assert(is_evpn_prefix_ipaddr_none(evp) == false);
+
+ /*
+ * prefix in the vni IP table doesn't include MAC so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
+ evp = &vni_p;
+ }
+ return bgp_node_get(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node lookup in VNI IP table.
+ */
+struct bgp_dest *
+bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE && parent_pi) {
+ /* prefix in the global table doesn't include the VTEP-IP so
+ * we need to create a different copy for the VNI
+ */
+ evpn_type1_prefix_vni_ip_copy(&vni_p, evp,
+ parent_pi->attr->nexthop);
+ evp = &vni_p;
+ } else if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Only MAC-IP should go into this table, not mac-only */
+ assert(is_evpn_prefix_ipaddr_none(evp) == false);
+
+ /*
+ * prefix in the vni IP table doesn't include MAC so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_ip_copy(&vni_p, evp);
+ evp = &vni_p;
+ }
+ return bgp_node_lookup(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node get in VNI MAC table.
+ */
+struct bgp_dest *
+bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ /* Only type-2 should ever go into this table */
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+
+ /*
+ * prefix in the vni MAC table doesn't include IP so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
+ evp = &vni_p;
+ return bgp_node_get(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node lookup in VNI MAC table.
+ */
+struct bgp_dest *
+bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi)
+{
+ struct prefix_evpn vni_p;
+
+ /* Only type-2 should ever go into this table */
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+
+ /*
+ * prefix in the vni MAC table doesn't include IP so
+ * we need to create a different copy of the prefix.
+ */
+ evpn_type2_prefix_vni_mac_copy(&vni_p, evp);
+ evp = &vni_p;
+ return bgp_node_lookup(table, (struct prefix *)evp);
+}
+
+/*
+ * Wrapper for node get in both VNI tables.
+ */
+struct bgp_dest *bgp_evpn_vni_node_get(struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi)
+{
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
+
+ return bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
+}
+
+/*
+ * Wrapper for node lookup in both VNI tables.
+ */
+struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi)
+{
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p,
+ parent_pi);
+
+ return bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
+}
+
+/*
* Add (update) or delete MACIP from zebra.
*/
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p,
+ const struct ethaddr *mac,
struct in_addr remote_vtep_ip, int add,
uint8_t flags, uint32_t seq, esi_t *esi)
{
struct stream *s;
uint16_t ipa_len;
static struct in_addr zero_remote_vtep_ip;
+ bool esi_valid;
/* Check socket. */
if (!zclient || zclient->sock < 0)
@@ -713,7 +896,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL,
bgp->vrf_id);
stream_putl(s, vpn->vni);
- stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN); /* Mac Addr */
+
+ if (mac) /* Mac Addr */
+ stream_put(s, &mac->octet, ETH_ALEN);
+ else
+ stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN);
+
/* IP address length and IP address, if any. */
if (is_evpn_prefix_ipaddr_none(p))
stream_putw(s, 0);
@@ -726,10 +914,13 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
/* If the ESI is valid that becomes the nexthop; tape out the
* VTEP-IP for that case
*/
- if (bgp_evpn_is_esi_valid(esi))
+ if (bgp_evpn_is_esi_valid(esi)) {
+ esi_valid = true;
stream_put_in_addr(s, &zero_remote_vtep_ip);
- else
+ } else {
+ esi_valid = false;
stream_put_in_addr(s, &remote_vtep_ip);
+ }
/* TX flags - MAC sticky status and/or gateway mac */
/* Also TX the sequence number of the best route. */
@@ -741,12 +932,20 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
stream_putw_at(s, 0, stream_get_endp(s));
- if (bgp_debug_zebra(NULL))
+ if (bgp_debug_zebra(NULL)) {
+ char esi_buf[ESI_STR_LEN];
+
+ if (esi_valid)
+ esi_to_str(esi, esi_buf, sizeof(esi_buf));
+ else
+ snprintf(esi_buf, sizeof(esi_buf), "-");
zlog_debug(
- "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4",
+ "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s",
add ? "ADD" : "DEL", vpn->vni,
- &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip,
- flags, seq, &remote_vtep_ip);
+ (mac ? mac : &p->prefix.macip_addr.mac),
+ &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip,
+ esi_buf);
+ }
frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip,
esi);
@@ -1080,8 +1279,13 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
}
ret = bgp_zebra_send_remote_macip(
- bgp, vpn, p, pi->attr->nexthop, 1, flags,
- seq, bgp_evpn_attr_get_esi(pi->attr));
+ bgp, vpn, p,
+ (is_evpn_prefix_ipaddr_none(p)
+ ? NULL /* MAC update */
+ : evpn_type2_path_info_get_mac(
+ pi) /* MAC-IP update */),
+ pi->attr->nexthop, 1, flags, seq,
+ bgp_evpn_attr_get_esi(pi->attr));
} else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE) {
ret = bgp_evpn_remote_es_evi_add(bgp, vpn, p);
} else {
@@ -1107,13 +1311,19 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
/* Uninstall EVPN route from zebra. */
static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p,
- struct in_addr remote_vtep_ip)
+ struct bgp_path_info *pi, bool is_sync)
{
int ret;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
- ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
- 0, 0, 0, NULL);
+ ret = bgp_zebra_send_remote_macip(
+ bgp, vpn, p,
+ (is_evpn_prefix_ipaddr_none(p)
+ ? NULL /* MAC update */
+ : evpn_type2_path_info_get_mac(
+ pi) /* MAC-IP update */),
+ (is_sync ? zero_vtep_ip : pi->attr->nexthop), 0, 0, 0,
+ NULL);
else if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p);
else
@@ -1156,9 +1366,10 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table is a 2-level tree (RD-level + Prefix-level) similar to
* L3VPN routes.
*/
- global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest),
- &vpn->prd);
+ global_dest = bgp_evpn_global_node_lookup(
+ bgp->rib[afi][safi], afi, safi,
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest),
+ &vpn->prd, old_local);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@@ -1271,7 +1482,7 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
bgp, vpn,
(const struct prefix_evpn *)bgp_dest_get_prefix(
dest),
- old_select->attr->nexthop);
+ old_select, false);
}
/* Clear any route change flags. */
@@ -1457,9 +1668,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
build_evpn_type5_route_extcomm(bgp_vrf, &attr);
/* get the route node in global table */
- dest = bgp_global_evpn_node_get(bgp_evpn->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)evp,
- &bgp_vrf->vrf_prd);
+ dest = bgp_evpn_global_node_get(bgp_evpn->rib[afi][safi], afi, safi,
+ evp, &bgp_vrf->vrf_prd, NULL);
assert(dest);
/* create or update the route entry within the route node */
@@ -1481,13 +1691,22 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
struct bgp_dest *dest, uint32_t loc_seq,
uint32_t *max_sync_seq, bool *active_on_peer,
- bool *peer_router, bool *proxy_from_peer)
+ bool *peer_router, bool *proxy_from_peer,
+ const struct ethaddr *mac)
{
struct bgp_path_info *tmp_pi;
struct bgp_path_info *second_best_path = NULL;
uint32_t tmp_mm_seq = 0;
esi_t *tmp_esi;
int paths_eq;
+ struct ethaddr *tmp_mac;
+ bool mac_cmp = false;
+ struct prefix_evpn *evp = (struct prefix_evpn *)&dest->p;
+
+
+ /* mac comparison is not needed for MAC-only routes */
+ if (mac && !is_evpn_prefix_ipaddr_none(evp))
+ mac_cmp = true;
/* find the best non-local path. a local path can only be present
* as best path
@@ -1498,6 +1717,13 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
!CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
continue;
+ /* ignore paths that have a different mac */
+ if (mac_cmp) {
+ tmp_mac = evpn_type2_path_info_get_mac(tmp_pi);
+ if (memcmp(mac, tmp_mac, sizeof(*mac)))
+ continue;
+ }
+
if (bgp_evpn_path_info_cmp(bgp, tmp_pi,
second_best_path, &paths_eq))
second_best_path = tmp_pi;
@@ -1542,7 +1768,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi,
static void update_evpn_route_entry_sync_info(struct bgp *bgp,
struct bgp_dest *dest,
struct attr *attr,
- uint32_t loc_seq, bool setup_sync)
+ uint32_t loc_seq, bool setup_sync,
+ const struct ethaddr *mac)
{
esi_t *esi;
struct prefix_evpn *evp =
@@ -1561,7 +1788,8 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
bgp_evpn_get_sync_info(bgp, esi, dest, loc_seq,
&max_sync_seq, &active_on_peer,
- &peer_router, &proxy_from_peer);
+ &peer_router, &proxy_from_peer,
+ mac);
attr->mm_sync_seqnum = max_sync_seq;
if (active_on_peer)
attr->es_flags |= ATTR_ES_PEER_ACTIVE;
@@ -1604,15 +1832,16 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp,
}
/*
- * Create or update EVPN route entry. This could be in the VNI route table
+ * Create or update EVPN route entry. This could be in the VNI route tables
* or the global route table.
*/
static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
afi_t afi, safi_t safi,
struct bgp_dest *dest, struct attr *attr,
- int add, struct bgp_path_info **pi,
- uint8_t flags, uint32_t seq, bool vpn_rt,
- bool *old_is_sync)
+ const struct ethaddr *mac,
+ const struct ipaddr *ip, int add,
+ struct bgp_path_info **pi, uint8_t flags,
+ uint32_t seq, bool vpn_rt, bool *old_is_sync)
{
struct bgp_path_info *tmp_pi;
struct bgp_path_info *local_pi;
@@ -1643,7 +1872,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* if a local path is being added with a non-zero esi look
* for SYNC paths from ES peers and bubble up the sync-info
*/
- update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt);
+ update_evpn_route_entry_sync_info(bgp, dest, attr, seq, vpn_rt, mac);
/* For non-GW MACs, update MAC mobility seq number, if needed. */
if (seq && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW))
@@ -1684,6 +1913,14 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
memcpy(&tmp_pi->extra->label, label, sizeof(label));
tmp_pi->extra->num_labels = num_labels;
+
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (mac)
+ evpn_type2_path_info_set_mac(tmp_pi, *mac);
+ else if (ip)
+ evpn_type2_path_info_set_ip(tmp_pi, *ip);
+ }
+
/* Mark route as self type-2 route */
if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP))
tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP;
@@ -1713,6 +1950,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
memcpy(&tmp_pi->extra->label, label, sizeof(label));
tmp_pi->extra->num_labels = num_labels;
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (mac)
+ evpn_type2_path_info_set_mac(tmp_pi,
+ *mac);
+ else if (ip)
+ evpn_type2_path_info_set_ip(tmp_pi,
+ *ip);
+ }
+
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr);
@@ -1832,6 +2078,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
safi_t safi = SAFI_EVPN;
int route_change;
bool old_is_sync = false;
+ bool mac_only = false;
memset(&attr, 0, sizeof(attr));
@@ -1891,14 +2138,20 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* Set up extended community. */
build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm);
- /* First, create (or fetch) route node within the VNI. */
- /* NOTE: There is no RD here. */
- dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
+ /* First, create (or fetch) route node within the VNI.
+ * NOTE: There is no RD here.
+ */
+ dest = bgp_evpn_vni_node_get(vpn, p, NULL);
+
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ mac_only = true;
/* Create or update route entry. */
- route_change = update_evpn_route_entry(bgp, vpn, afi, safi, dest, &attr,
- 1, &pi, flags, seq,
- true /* setup_sync */, &old_is_sync);
+ route_change = update_evpn_route_entry(
+ bgp, vpn, afi, safi, dest, &attr,
+ (mac_only ? NULL : &p->prefix.macip_addr.mac), NULL /* ip */, 1,
+ &pi, flags, seq, true /* setup_sync */, &old_is_sync);
assert(pi);
attr_new = pi->attr;
@@ -1936,7 +2189,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn, p, zero_vtep_ip);
+ evpn_zebra_uninstall(bgp, vpn, p, pi, true);
}
}
bgp_path_info_unlock(pi);
@@ -1951,12 +2204,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
if (route_change) {
struct bgp_path_info *global_pi;
- dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)p,
- &vpn->prd);
- update_evpn_route_entry(bgp, vpn, afi, safi, dest, attr_new, 1,
- &global_pi, flags, seq,
- false /* setup_sync */, NULL /* old_is_sync */);
+ dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ p, &vpn->prd, NULL);
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, dest, attr_new, NULL /* mac */,
+ NULL /* ip */, 1, &global_pi, flags, seq,
+ false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
bgp_process(bgp, dest, afi, safi);
@@ -2010,8 +2263,8 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp)
return 0;
/* locate the global route entry for this type-5 prefix */
- dest = bgp_global_evpn_node_lookup(bgp_evpn->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)evp, &bgp_vrf->vrf_prd);
+ dest = bgp_evpn_global_node_lookup(bgp_evpn->rib[afi][safi], afi, safi,
+ evp, &bgp_vrf->vrf_prd, NULL);
if (!dest)
return 0;
@@ -2037,9 +2290,9 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* First, locate the route node within the VNI. If it doesn't exist,
* there
* is nothing further to do.
+ * NOTE: There is no RD here.
*/
- /* NOTE: There is no RD here. */
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)p);
+ dest = bgp_evpn_vni_node_lookup(vpn, p, NULL);
if (!dest)
return 0;
@@ -2047,8 +2300,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table is a 2-level tree (RD-level + Prefix-level) similar to
* L3VPN routes.
*/
- global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)p, &vpn->prd);
+ global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi,
+ safi, p, &vpn->prd, NULL);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@@ -2087,8 +2340,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
int add_l3_ecomm = 0;
struct bgp_dest *global_dest;
struct bgp_path_info *global_pi;
- struct prefix_evpn *evp =
- (struct prefix_evpn *)bgp_dest_get_prefix(dest);
+ struct prefix_evpn evp;
int route_change;
bool old_is_sync = false;
@@ -2096,6 +2348,22 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
return;
/*
+ * VNI table MAC-IP prefixes don't have MAC so make sure it's set from
+ * path info here.
+ */
+ if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)&dest->p)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &evp, (struct prefix_evpn *)&dest->p, NULL /* mac */,
+ evpn_type2_path_info_get_ip(local_pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &evp, (struct prefix_evpn *)&dest->p,
+ evpn_type2_path_info_get_mac(local_pi), NULL /* ip */);
+ }
+
+ /*
* Build attribute per local route as the MAC mobility and
* some other values could differ for different routes. The
* attributes will be shared in the hash table.
@@ -2109,18 +2377,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
attr.es_flags = local_pi->attr->es_flags;
if (local_pi->attr->default_gw) {
attr.default_gw = 1;
- if (is_evpn_prefix_ipaddr_v6(evp))
+ if (is_evpn_prefix_ipaddr_v6(&evp))
attr.router_flag = 1;
}
memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t));
- bgp_evpn_get_rmac_nexthop(vpn, evp, &attr,
- local_pi->extra->af_flags);
+ bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, local_pi->extra->af_flags);
vni2label(vpn->vni, &(attr.label));
/* Add L3 VNI RTs and RMAC for non IPv6 link-local if
* using L3 VNI for type-2 routes also.
*/
add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok(
- vpn, evp,
+ vpn, &evp,
(attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL);
/* Set up extended community. */
@@ -2134,15 +2401,15 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
"VRF %s vni %u evp %pFX RMAC %pEA nexthop %pI4 esi %s esf 0x%x from %s",
vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id)
: " ",
- vpn->vni, evp, &attr.rmac, &attr.mp_nexthop_global_in,
+ vpn->vni, &evp, &attr.rmac, &attr.mp_nexthop_global_in,
esi_to_str(&attr.esi, buf3, sizeof(buf3)),
attr.es_flags, caller);
}
/* Update the route entry. */
route_change = update_evpn_route_entry(
- bgp, vpn, afi, safi, dest, &attr, 0, &pi, 0, seq,
- true /* setup_sync */, &old_is_sync);
+ bgp, vpn, afi, safi, dest, &attr, NULL /* mac */, NULL /* ip */,
+ 0, &pi, 0, seq, true /* setup_sync */, &old_is_sync);
assert(pi);
attr_new = pi->attr;
@@ -2177,8 +2444,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn,
- evp, zero_vtep_ip);
+ evpn_zebra_uninstall(bgp, vpn, &evp, pi, true);
}
}
@@ -2188,13 +2454,14 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
if (route_change) {
/* Update route in global routing table. */
- global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi,
- safi, evp, &vpn->prd);
+ global_dest = bgp_evpn_global_node_get(
+ bgp->rib[afi][safi], afi, safi, &evp, &vpn->prd, NULL);
assert(global_dest);
update_evpn_route_entry(
- bgp, vpn, afi, safi, global_dest, attr_new, 0,
- &global_pi, 0, mac_mobility_seqnum(attr_new),
- false /* setup_sync */, NULL /* old_is_sync */);
+ bgp, vpn, afi, safi, global_dest, attr_new,
+ NULL /* mac */, NULL /* ip */, 0, &global_pi, 0,
+ mac_mobility_seqnum(attr_new), false /* setup_sync */,
+ NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
bgp_process(bgp, global_dest, afi, safi);
@@ -2205,43 +2472,51 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
aspath_unintern(&attr.aspath);
}
+static void update_type2_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest)
+{
+ struct bgp_path_info *tmp_pi;
+
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return;
+
+ /* Identify local route. */
+ for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
+ tmp_pi = tmp_pi->next) {
+ if (tmp_pi->peer == bgp->peer_self &&
+ tmp_pi->type == ZEBRA_ROUTE_BGP &&
+ tmp_pi->sub_type == BGP_ROUTE_STATIC)
+ break;
+ }
+
+ if (!tmp_pi)
+ return;
+
+ bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi, __func__);
+}
+
/*
* Update all type-2 (MACIP) local routes for this VNI - these should also
* be scheduled for advertise to peers.
*/
-static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct bgp_dest *dest;
- struct bgp_path_info *tmp_pi;
- /* Walk this VNI's route table and update local type-2 routes. For any
- * routes updated, update corresponding entry in the global table too.
+ /* Walk this VNI's route MAC & IP table and update local type-2
+ * routes. For any routes updated, update corresponding entry in the
+ * global table too.
*/
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
- continue;
-
- /* Identify local route. */
- for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
- tmp_pi = tmp_pi->next) {
- if (tmp_pi->peer == bgp->peer_self
- && tmp_pi->type == ZEBRA_ROUTE_BGP
- && tmp_pi->sub_type == BGP_ROUTE_STATIC)
- break;
- }
-
- if (!tmp_pi)
- continue;
-
- bgp_evpn_update_type2_route_entry(bgp, vpn, dest, tmp_pi,
- __func__);
- }
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ update_type2_route(bgp, vpn, dest);
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ update_type2_route(bgp, vpn, dest);
}
/*
@@ -2282,55 +2557,65 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
}
}
+static void delete_vni_type2_route(struct bgp *bgp, struct bgp_dest *dest)
+{
+ struct bgp_path_info *pi;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return;
+
+ delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
+
+ /* Route entry in local table gets deleted immediately. */
+ if (pi)
+ bgp_path_info_reap(dest, pi);
+}
+
+static void delete_vni_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ struct bgp_dest *dest;
+
+ /* Next, walk this VNI's MAC & IP route table and delete local type-2
+ * routes.
+ */
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ delete_vni_type2_route(bgp, dest);
+
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ delete_vni_type2_route(bgp, dest);
+}
+
/*
* Delete all type-2 (MACIP) local routes for this VNI - from the global
* table as well as the per-VNI route table.
*/
-static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
- afi_t afi;
- safi_t safi;
- struct bgp_dest *dest;
- struct bgp_path_info *pi;
-
- afi = AFI_L2VPN;
- safi = SAFI_EVPN;
-
/* First, walk the global route table for this VNI's type-2 local
* routes.
* EVPN routes are a 2-level table, first get the RD table.
*/
delete_global_type2_routes(bgp, vpn);
-
- /* Next, walk this VNI's route table and delete local type-2 routes. */
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
- continue;
-
- delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
-
- /* Route entry in local table gets deleted immediately. */
- if (pi)
- bgp_path_info_reap(dest, pi);
- }
-
- return 0;
+ delete_vni_type2_routes(bgp, vpn);
}
/*
* Delete all routes in the per-VNI route table.
*/
-static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct bgp_dest *dest;
struct bgp_path_info *pi, *nextpi;
- /* Walk this VNI's route table and delete all routes. */
- for (dest = bgp_table_top(vpn->route_table); dest;
+ /* Walk this VNI's MAC & IP route table and delete all routes. */
+ for (dest = bgp_table_top(vpn->mac_table); dest;
dest = bgp_route_next(dest)) {
for (pi = bgp_dest_get_bgp_path_info(dest);
(pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
@@ -2340,7 +2625,14 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
}
}
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest)) {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
+ bgp_path_info_delete(dest, pi);
+ bgp_path_info_reap(dest, pi);
+ }
+ }
}
/* BUM traffic flood mode per-l2-vni */
@@ -2387,7 +2679,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return ret;
}
- return update_all_type2_routes(bgp, vpn);
+ update_all_type2_routes(bgp, vpn);
+ return 0;
}
/*
@@ -2404,9 +2697,7 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
/* Delete and withdraw locally learnt type-2 routes (MACIP)
* followed by type-3 routes (only one) - for this VNI.
*/
- ret = delete_all_type2_routes(bgp, vpn);
- if (ret)
- return ret;
+ delete_all_type2_routes(bgp, vpn);
build_evpn_type3_prefix(&p, vpn->originator_ip);
ret = delete_evpn_route(bgp, vpn, &p);
@@ -2414,7 +2705,8 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return ret;
/* Delete all routes from the per-VNI table. */
- return delete_all_vni_routes(bgp, vpn);
+ delete_all_vni_routes(bgp, vpn);
+ return 0;
}
/*
@@ -2495,6 +2787,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
pi->extra->num_labels = parent_pi->extra->num_labels;
pi->extra->igpmetric = parent_pi->extra->igpmetric;
}
+
bgp_path_info_add(dest, pi);
return pi;
@@ -2673,32 +2966,19 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/*
- * Install route entry into the VNI routing table and invoke route selection.
+ * Common handling for vni route tables install/selection.
*/
-static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- struct bgp_path_info *parent_pi)
+static int install_evpn_route_entry_in_vni_common(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ struct bgp_dest *dest, struct bgp_path_info *parent_pi)
{
- struct bgp_dest *dest;
struct bgp_path_info *pi;
struct bgp_path_info *local_pi;
struct attr *attr_new;
int ret;
- struct prefix_evpn ad_evp;
bool old_local_es = false;
bool new_local_es;
- /* EAD prefix in the global table doesn't include the VTEP-IP so
- * we need to create a different copy for the VNI
- */
- if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
- p = evpn_type1_prefix_vni_copy(&ad_evp, p,
- parent_pi->attr->nexthop);
-
- /* Create (or fetch) route within the VNI. */
- /* NOTE: There is no RD here. */
- dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
-
/* Check if route entry is already present. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->extra
@@ -2709,13 +2989,27 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
/* Create an info */
pi = bgp_create_evpn_bgp_path_info(parent_pi, dest,
parent_pi->attr);
+
+ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (is_evpn_type2_dest_ipaddr_none(dest))
+ evpn_type2_path_info_set_ip(
+ pi, p->prefix.macip_addr.ip);
+ else
+ evpn_type2_path_info_set_mac(
+ pi, p->prefix.macip_addr.mac);
+ }
+
new_local_es = bgp_evpn_attr_is_local_es(pi->attr);
} else {
- if (attrhash_cmp(pi->attr, parent_pi->attr)
- && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
- bgp_dest_unlock_node(dest);
+ /* Return early if attributes haven't changed
+ * and dest isn't flagged for removal.
+ * dest will be unlocked by either
+ * install_evpn_route_entry_in_vni_mac() or
+ * install_evpn_route_entry_in_vni_ip()
+ */
+ if (attrhash_cmp(pi->attr, parent_pi->attr) &&
+ !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
return 0;
- }
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(parent_pi->attr);
@@ -2766,12 +3060,160 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
if (local_pi && (old_local_es || new_local_es))
bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
__func__);
+
+ return ret;
+}
+
+/*
+ * Common handling for vni route tables uninstall/selection.
+ */
+static int uninstall_evpn_route_entry_in_vni_common(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ struct bgp_dest *dest, struct bgp_path_info *parent_pi)
+{
+ struct bgp_path_info *pi;
+ struct bgp_path_info *local_pi;
+ int ret;
+
+ /* Find matching route entry. */
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ if (pi->extra &&
+ (struct bgp_path_info *)pi->extra->parent == parent_pi)
+ break;
+
+ if (!pi)
+ return 0;
+
+ bgp_evpn_remote_ip_hash_del(vpn, pi);
+
+ /* Mark entry for deletion */
+ bgp_path_info_delete(dest, pi);
+
+ /* Perform route selection and update zebra, if required. */
+ ret = evpn_route_select_install(bgp, vpn, dest);
+
+ /* if the best path is a local path with a non-zero ES
+ * sync info against the local path may need to be updated
+ * when a remote path is deleted
+ */
+ local_pi = bgp_evpn_route_get_local_path(bgp, dest);
+ if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr))
+ bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
+ __func__);
+
+ return ret;
+}
+
+/*
+ * Install route entry into VNI IP table and invoke route selection.
+ */
+static int install_evpn_route_entry_in_vni_ip(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Ignore MAC Only Type-2 */
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return 0;
+
+ /* Create (or fetch) route within the VNI IP table. */
+ dest = bgp_evpn_vni_ip_node_get(vpn->ip_table, p, parent_pi);
+
+ ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+
+/*
+ * Install route entry into VNI MAC table and invoke route selection.
+ */
+static int install_evpn_route_entry_in_vni_mac(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Only type-2 routes go into this table */
+ if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return 0;
+
+ /* Create (or fetch) route within the VNI MAC table. */
+ dest = bgp_evpn_vni_mac_node_get(vpn->mac_table, p, parent_pi);
+
+ ret = install_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+
+/*
+ * Uninstall route entry from VNI IP table and invoke route selection.
+ */
+static int uninstall_evpn_route_entry_in_vni_ip(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Ignore MAC Only Type-2 */
+ if ((p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+ (is_evpn_prefix_ipaddr_none(p) == true))
+ return 0;
+
+ /* Locate route within the VNI IP table. */
+ dest = bgp_evpn_vni_ip_node_lookup(vpn->ip_table, p, parent_pi);
+ if (!dest)
+ return 0;
+
+ ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
bgp_dest_unlock_node(dest);
return ret;
}
/*
+ * Uninstall route entry from VNI IP table and invoke route selection.
+ */
+static int
+uninstall_evpn_route_entry_in_vni_mac(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret;
+ struct bgp_dest *dest;
+
+ /* Only type-2 routes go into this table */
+ if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+ return 0;
+
+ /* Locate route within the VNI MAC table. */
+ dest = bgp_evpn_vni_mac_node_lookup(vpn->mac_table, p, parent_pi);
+ if (!dest)
+ return 0;
+
+ ret = uninstall_evpn_route_entry_in_vni_common(bgp, vpn, p, dest,
+ parent_pi);
+
+ bgp_dest_unlock_node(dest);
+
+ return ret;
+}
+/*
* Uninstall route entry from the VRF routing table and send message
* to zebra, if appropriate.
*/
@@ -2849,62 +3291,79 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
}
/*
- * Uninstall route entry from the VNI routing table and send message
- * to zebra, if appropriate.
+ * Install route entry into the VNI routing tables.
+ */
+static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *parent_pi)
+{
+ int ret = 0;
+
+ if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s (%u): Installing EVPN %pFX route in VNI %u IP/MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ ret = install_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
+
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to install EVPN %pFX route in VNI %u MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ return ret;
+ }
+
+ ret = install_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
+
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to install EVPN %pFX route in VNI %u IP table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
+
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * Uninstall route entry from the VNI routing tables.
*/
static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
const struct prefix_evpn *p,
struct bgp_path_info *parent_pi)
{
- struct bgp_dest *dest;
- struct bgp_path_info *pi;
- struct bgp_path_info *local_pi;
- int ret;
- struct prefix_evpn ad_evp;
+ int ret = 0;
- /* EAD prefix in the global table doesn't include the VTEP-IP so
- * we need to create a different copy for the VNI
- */
- if (p->prefix.route_type == BGP_EVPN_AD_ROUTE)
- p = evpn_type1_prefix_vni_copy(&ad_evp, p,
- parent_pi->attr->nexthop);
+ if (bgp_debug_update(parent_pi->peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s (%u): Uninstalling EVPN %pFX route from VNI %u IP/MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- /* Locate route within the VNI. */
- /* NOTE: There is no RD here. */
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)p);
- if (!dest)
- return 0;
+ ret = uninstall_evpn_route_entry_in_vni_ip(bgp, vpn, p, parent_pi);
- /* Find matching route entry. */
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->extra
- && (struct bgp_path_info *)pi->extra->parent == parent_pi)
- break;
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u IP table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- if (!pi) {
- bgp_dest_unlock_node(dest);
- return 0;
+ return ret;
}
- bgp_evpn_remote_ip_hash_del(vpn, pi);
-
- /* Mark entry for deletion */
- bgp_path_info_delete(dest, pi);
-
- /* Perform route selection and update zebra, if required. */
- ret = evpn_route_select_install(bgp, vpn, dest);
+ ret = uninstall_evpn_route_entry_in_vni_mac(bgp, vpn, p, parent_pi);
- /* if the best path is a local path with a non-zero ES
- * sync info against the local path may need to be updated
- * when a remote path is deleted
- */
- local_pi = bgp_evpn_route_get_local_path(bgp, dest);
- if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr))
- bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi,
- __func__);
+ if (ret) {
+ flog_err(
+ EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to uninstall EVPN %pFX route from VNI %u MAC table",
+ vrf_id_to_name(bgp->vrf_id), bgp->vrf_id, p, vpn->vni);
- /* Unlock route node. */
- bgp_dest_unlock_node(dest);
+ return ret;
+ }
return ret;
}
@@ -3480,7 +3939,8 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
* we need to create a different copy for the VNI
*/
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE)
- evp = evpn_type1_prefix_vni_copy(&ad_evp, evp, attr->nexthop);
+ evp = evpn_type1_prefix_vni_ip_copy(&ad_evp, evp,
+ attr->nexthop);
ecom = bgp_attr_get_ecommunity(attr);
if (!ecom || !ecom->size)
@@ -3695,16 +4155,94 @@ static void withdraw_router_id_vrf(struct bgp *bgp_vrf)
delete_withdraw_vrf_routes(bgp_vrf);
}
+static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn,
+ struct bgp_dest *dest)
+{
+ struct bgp_dest *global_dest;
+ struct bgp_path_info *pi, *global_pi;
+ struct attr *attr;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+
+ struct prefix_evpn tmp_evp;
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ /*
+ * We have already processed type-3 routes.
+ * Process only type-1 and type-2 routes here.
+ */
+ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
+ return;
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP &&
+ pi->sub_type == BGP_ROUTE_STATIC)
+ break;
+ if (!pi)
+ return;
+
+ /*
+ * VNI table MAC-IP prefixes don't have MAC so make sure it's
+ * set from path info here.
+ */
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ &tmp_evp, evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ &tmp_evp, evp, evpn_type2_path_info_get_mac(pi),
+ NULL /* ip */);
+ }
+ } else {
+ memcpy(&tmp_evp, evp, sizeof(tmp_evp));
+ }
+
+ /* Create route in global routing table using this route entry's
+ * attribute.
+ */
+ attr = pi->attr;
+ global_dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ &tmp_evp, &vpn->prd, NULL);
+ assert(global_dest);
+
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /* Type-2 route */
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
+ NULL /* ip */, 1, &global_pi, 0,
+ mac_mobility_seqnum(attr), false /* setup_sync */,
+ NULL /* old_is_sync */);
+ } else {
+ /* Type-1 route */
+ struct bgp_evpn_es *es;
+ int route_changed = 0;
+
+ es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi);
+ bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, global_dest,
+ attr, &global_pi, &route_changed);
+ }
+
+ /* Schedule for processing and unlock node. */
+ bgp_process(bgp, global_dest, afi, safi);
+ bgp_dest_unlock_node(global_dest);
+}
+
/*
* Update and advertise local routes for a VNI. Invoked upon router-id
* change. Note that the processing is done only on the global route table
* using routes that already exist in the per-VNI table.
*/
-static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
+static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
{
struct prefix_evpn p;
struct bgp_dest *dest, *global_dest;
- struct bgp_path_info *pi, *global_pi;
+ struct bgp_path_info *pi;
struct attr *attr;
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
@@ -3718,9 +4256,9 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (bgp_evpn_vni_flood_mode_get(bgp, vpn)
== VXLAN_FLOOD_HEAD_END_REPL) {
build_evpn_type3_prefix(&p, vpn->originator_ip);
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest) /* unexpected */
- return 0;
+ return;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == bgp->peer_self &&
pi->type == ZEBRA_ROUTE_BGP
@@ -3728,76 +4266,33 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
break;
if (!pi) {
bgp_dest_unlock_node(dest);
- return 0;
+ return;
}
+
attr = pi->attr;
- global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi],
- afi, safi, &p, &vpn->prd);
- update_evpn_route_entry(bgp, vpn, afi, safi, global_dest, attr,
- 1, &pi, 0, mac_mobility_seqnum(attr),
- false /* setup_sync */, NULL /* old_is_sync */);
+ global_dest = bgp_evpn_global_node_get(
+ bgp->rib[afi][safi], afi, safi, &p, &vpn->prd, NULL);
+ update_evpn_route_entry(
+ bgp, vpn, afi, safi, global_dest, attr, NULL /* mac */,
+ NULL /* ip */, 1, &pi, 0, mac_mobility_seqnum(attr),
+ false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
bgp_process(bgp, global_dest, afi, safi);
bgp_dest_unlock_node(global_dest);
}
- /* Now, walk this VNI's route table and use the route and its attribute
- * to create and schedule route in global table.
+ /* Now, walk this VNI's MAC & IP route table and use the route and its
+ * attribute to create and schedule route in global table.
*/
- for (dest = bgp_table_top(vpn->route_table); dest;
- dest = bgp_route_next(dest)) {
- const struct prefix_evpn *evp =
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
-
- /*
- * We have already processed type-3 routes.
- * Process only type-1 and type-2 routes here.
- */
- if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
- && evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
- continue;
-
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
- if (pi->peer == bgp->peer_self
- && pi->type == ZEBRA_ROUTE_BGP
- && pi->sub_type == BGP_ROUTE_STATIC)
- break;
- if (!pi)
- continue;
-
- /* Create route in global routing table using this route entry's
- * attribute.
- */
- attr = pi->attr;
- global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- evp, &vpn->prd);
- assert(global_dest);
-
- if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
- /* Type-2 route */
- update_evpn_route_entry(
- bgp, vpn, afi, safi, global_dest, attr, 1,
- &global_pi, 0, mac_mobility_seqnum(attr),
- false /* setup_sync */, NULL /* old_is_sync */);
- } else {
- /* Type-1 route */
- struct bgp_evpn_es *es;
- int route_changed = 0;
-
- es = bgp_evpn_es_find(&evp->prefix.ead_addr.esi);
- bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi,
- global_dest, attr, &global_pi,
- &route_changed);
- }
-
- /* Schedule for processing and unlock node. */
- bgp_process(bgp, global_dest, afi, safi);
- bgp_dest_unlock_node(global_dest);
- }
+ for (dest = bgp_table_top(vpn->mac_table); dest;
+ dest = bgp_route_next(dest))
+ update_advertise_vni_route(bgp, vpn, dest);
- return 0;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
+ dest = bgp_route_next(dest))
+ update_advertise_vni_route(bgp, vpn, dest);
}
/*
@@ -3819,8 +4314,8 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
/* Remove type-3 route for this VNI from global table. */
build_evpn_type3_prefix(&p, vpn->originator_ip);
- global_dest = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)&p, &vpn->prd);
+ global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi,
+ safi, &p, &vpn->prd, NULL);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
@@ -5498,8 +5993,9 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
bf_assign_index(bm->rd_idspace, vpn->rd_id);
derive_rd_rt_for_vni(bgp, vpn);
- /* Initialize EVPN route table. */
- vpn->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
+ /* Initialize EVPN route tables. */
+ vpn->ip_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
+ vpn->mac_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
/* Add to hash */
(void)hash_get(bgp->vnihash, vpn, hash_alloc_intern);
@@ -5527,7 +6023,8 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
bgp_evpn_remote_ip_hash_destroy(vpn);
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
- bgp_table_unlock(vpn->route_table);
+ bgp_table_unlock(vpn->ip_table);
+ bgp_table_unlock(vpn->mac_table);
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
list_delete(&vpn->import_rtl);
list_delete(&vpn->export_rtl);
@@ -5653,7 +6150,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
delete_evpn_route(bgp, vpn, &p);
} else {
/* Re-instate the current remote best path if any */
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (dest) {
evpn_zebra_reinstall_best_route(bgp, vpn, dest);
bgp_dest_unlock_node(dest);
@@ -6661,7 +7158,7 @@ void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
bgp_evpn_remote_ip_hash_init(vpn);
- for (dest = bgp_table_top(vpn->route_table); dest;
+ for (dest = bgp_table_top(vpn->ip_table); dest;
dest = bgp_route_next(dest))
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
bgp_evpn_remote_ip_hash_add(vpn, pi);
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 1d40664aeb..2a5c5d7ec4 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -471,7 +471,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
struct prefix_rd *prd;
if (vpn) {
- rt_table = vpn->route_table;
+ rt_table = vpn->ip_table;
prd = &vpn->prd;
} else {
rt_table = es->route_table;
@@ -498,9 +498,8 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
/* Next, locate route node in the global EVPN routing table.
* Note that this table is a 2-level tree (RD-level + Prefix-level)
*/
- global_dest =
- bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
- (const struct prefix_evpn *)p, prd);
+ global_dest = bgp_evpn_global_node_lookup(bgp->rib[afi][safi], afi,
+ safi, p, prd, NULL);
if (global_dest) {
/* Delete route entry in the global EVPN table. */
@@ -675,8 +674,9 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp,
if (route_changed) {
struct bgp_path_info *global_pi;
- dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- p, &es->es_base_frag->prd);
+ dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ p, &es->es_base_frag->prd,
+ NULL);
bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
attr_new, &global_pi, &route_changed);
@@ -960,7 +960,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
/* First, create (or fetch) route node within the VNI. */
- dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
+ dest = bgp_node_get(vpn->ip_table, (struct prefix *)p);
/* Create or update route entry. */
ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
@@ -1015,8 +1015,8 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
if (route_changed) {
struct bgp_path_info *global_pi;
- dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
- p, global_rd);
+ dest = bgp_evpn_global_node_get(bgp->rib[afi][safi], afi, safi,
+ p, global_rd, NULL);
bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
attr_new, &global_pi, &route_changed);
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index fdbffa95dd..3f18e4e9f1 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -112,9 +112,10 @@ struct bgpevpn {
*/
struct hash *remote_ip_hash;
- /* Route table for EVPN routes for
+ /* Route tables for EVPN routes for
* this VNI. */
- struct bgp_table *route_table;
+ struct bgp_table *ip_table;
+ struct bgp_table *mac_table;
/* RB tree of ES-EVIs */
struct bgp_es_evi_rb_head es_evi_rb_tree;
@@ -543,10 +544,10 @@ static inline void evpn_type1_prefix_global_copy(struct prefix_evpn *global_p,
/* EAD prefix in the global table doesn't include the VTEP-IP so
* we need to create a different copy for the VNI
*/
-static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
- struct prefix_evpn *vni_p,
- const struct prefix_evpn *global_p,
- struct in_addr originator_ip)
+static inline struct prefix_evpn *
+evpn_type1_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p,
+ struct in_addr originator_ip)
{
memcpy(vni_p, global_p, sizeof(*vni_p));
vni_p->prefix.ead_addr.ip.ipa_type = IPADDR_V4;
@@ -555,6 +556,77 @@ static inline struct prefix_evpn *evpn_type1_prefix_vni_copy(
return vni_p;
}
+static inline void evpn_type2_prefix_global_copy(
+ struct prefix_evpn *global_p, const struct prefix_evpn *vni_p,
+ const struct ethaddr *mac, const struct ipaddr *ip)
+{
+ memcpy(global_p, vni_p, sizeof(*global_p));
+
+ if (mac)
+ global_p->prefix.macip_addr.mac = *mac;
+
+ if (ip)
+ global_p->prefix.macip_addr.ip = *ip;
+}
+
+static inline void
+evpn_type2_prefix_vni_ip_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p)
+{
+ memcpy(vni_p, global_p, sizeof(*vni_p));
+ memset(&vni_p->prefix.macip_addr.mac, 0, sizeof(struct ethaddr));
+}
+
+static inline void
+evpn_type2_prefix_vni_mac_copy(struct prefix_evpn *vni_p,
+ const struct prefix_evpn *global_p)
+{
+ memcpy(vni_p, global_p, sizeof(*vni_p));
+ memset(&vni_p->prefix.macip_addr.ip, 0, sizeof(struct ipaddr));
+}
+
+/* Get MAC of path_info prefix */
+static inline struct ethaddr *
+evpn_type2_path_info_get_mac(const struct bgp_path_info *local_pi)
+{
+ assert(local_pi->extra);
+ return &local_pi->extra->vni_info.mac;
+}
+
+/* Get IP of path_info prefix */
+static inline struct ipaddr *
+evpn_type2_path_info_get_ip(const struct bgp_path_info *local_pi)
+{
+ assert(local_pi->extra);
+ return &local_pi->extra->vni_info.ip;
+}
+
+/* Set MAC of path_info prefix */
+static inline void evpn_type2_path_info_set_mac(struct bgp_path_info *local_pi,
+ const struct ethaddr mac)
+{
+ assert(local_pi->extra);
+ local_pi->extra->vni_info.mac = mac;
+}
+
+/* Set IP of path_info prefix */
+static inline void evpn_type2_path_info_set_ip(struct bgp_path_info *local_pi,
+ const struct ipaddr ip)
+{
+ assert(local_pi->extra);
+ local_pi->extra->vni_info.ip = ip;
+}
+
+/* Is the IP empty for the RT's dest? */
+static inline bool is_evpn_type2_dest_ipaddr_none(const struct bgp_dest *dest)
+{
+ const struct prefix_evpn *evp =
+ (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
+
+ assert(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE);
+ return is_evpn_prefix_ipaddr_none(evp);
+}
+
static inline int evpn_default_originate_set(struct bgp *bgp, afi_t afi,
safi_t safi)
{
@@ -651,14 +723,39 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
int vni_list_cmp(void *p1, void *p2);
extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_dest *dest);
-extern struct bgp_dest *bgp_global_evpn_node_get(struct bgp_table *table,
- afi_t afi, safi_t safi,
- const struct prefix_evpn *evp,
- struct prefix_rd *prd);
extern struct bgp_dest *
-bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
+bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi,
+ const struct prefix_evpn *evp, struct prefix_rd *prd,
+ const struct bgp_path_info *local_pi);
+extern struct bgp_dest *
+bgp_evpn_global_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi,
+ const struct prefix_evpn *evp,
+ struct prefix_rd *prd,
+ const struct bgp_path_info *local_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_ip_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_ip_node_lookup(const struct bgp_table *const table,
const struct prefix_evpn *evp,
- struct prefix_rd *prd);
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_mac_node_get(struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_mac_node_lookup(const struct bgp_table *const table,
+ const struct prefix_evpn *evp,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_node_get(struct bgpevpn *vpn, const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi);
+extern struct bgp_dest *
+bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, const struct prefix_evpn *p,
+ const struct bgp_path_info *parent_pi);
+
+extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import);
extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp,
struct bgpevpn *vpn,
struct bgp_node *rn,
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 0f2ade8737..88c1329f48 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -57,6 +57,8 @@ struct vni_walk_ctx {
struct in_addr vtep_ip;
json_object *json;
int detail;
+ int type;
+ bool mac_table;
};
int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
@@ -517,7 +519,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json, "sviInterface",
ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
} else {
- vty_out(vty, "VNI: %d", vpn->vni);
+ vty_out(vty, "VNI: %u", vpn->vni);
if (is_vni_live(vpn))
vty_out(vty, " (known to the kernel)");
vty_out(vty, "\n");
@@ -735,7 +737,8 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
if (detail)
route_vty_out_detail(
- vty, bgp, rn, pi, AFI_L2VPN, SAFI_EVPN,
+ vty, bgp, rn, bgp_dest_get_prefix(rn),
+ pi, AFI_L2VPN, SAFI_EVPN,
RPKI_NOT_BEING_USED, json_path);
else
route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN,
@@ -770,9 +773,10 @@ static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
}
-static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
- struct vty *vty, struct in_addr vtep_ip,
- json_object *json, int detail)
+static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn,
+ struct vty *vty, int type, bool mac_table,
+ struct in_addr vtep_ip, json_object *json,
+ int detail)
{
struct bgp_dest *dest;
struct bgp_path_info *pi;
@@ -783,7 +787,11 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
prefix_cnt = path_cnt = 0;
- table = vpn->route_table;
+ if (mac_table)
+ table = vpn->mac_table;
+ else
+ table = vpn->ip_table;
+
tbl_ver = table->version;
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
const struct prefix_evpn *evp =
@@ -818,6 +826,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
* with code that already exists).
*/
for (; pi; pi = pi->next) {
+ struct prefix tmp_p;
json_object *json_path = NULL;
if (vtep_ip.s_addr != INADDR_ANY
@@ -825,16 +834,43 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
&(pi->attr->nexthop)))
continue;
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+ /*
+ * VNI IP/MAC table prefixes don't have MAC/IP
+ * respectively so make sure it's set from path
+ * info here.
+ */
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p,
+ evp, NULL /* mac */,
+ evpn_type2_path_info_get_ip(
+ pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p,
+ evp,
+ evpn_type2_path_info_get_mac(
+ pi),
+ NULL /* ip */);
+ }
+ } else
+ memcpy(&tmp_p, p, sizeof(tmp_p));
+
+
if (json)
json_path = json_object_new_array();
if (detail)
- route_vty_out_detail(vty, bgp, dest, pi,
+ route_vty_out_detail(vty, bgp, dest, &tmp_p, pi,
AFI_L2VPN, SAFI_EVPN,
RPKI_NOT_BEING_USED,
json_path);
+
else
- route_vty_out(vty, p, pi, 0, SAFI_EVPN,
+ route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN,
json_path, false);
if (json)
@@ -887,19 +923,55 @@ static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg)
json_object *json_vni = NULL;
char vni_str[VNI_STR_LEN];
- snprintf(vni_str, sizeof(vni_str), "%d", vpn->vni);
+ snprintf(vni_str, sizeof(vni_str), "%u", vpn->vni);
+ if (json) {
+ json_vni = json_object_new_object();
+ json_object_int_add(json_vni, "vni", vpn->vni);
+ } else {
+ vty_out(vty, "\nVNI: %u\n\n", vpn->vni);
+ }
+
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, wctx->type, wctx->mac_table,
+ wctx->vtep_ip, json_vni, wctx->detail);
+
+ if (json)
+ json_object_object_add(json, vni_str, json_vni);
+}
+
+static void show_vni_routes_all_hash(struct hash_bucket *bucket, void *arg)
+{
+ struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+ struct vni_walk_ctx *wctx = arg;
+ struct vty *vty = wctx->vty;
+ json_object *json = wctx->json;
+ json_object *json_vni = NULL;
+ json_object *json_vni_mac = NULL;
+ char vni_str[VNI_STR_LEN];
+
+ snprintf(vni_str, sizeof(vni_str), "%u", vpn->vni);
if (json) {
json_vni = json_object_new_object();
json_object_int_add(json_vni, "vni", vpn->vni);
} else {
- vty_out(vty, "\nVNI: %d\n\n", vpn->vni);
+ vty_out(vty, "\nVNI: %u\n\n", vpn->vni);
}
- show_vni_routes(wctx->bgp, vpn, 0, wctx->vty, wctx->vtep_ip, json_vni,
- wctx->detail);
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, false, wctx->vtep_ip,
+ json_vni, wctx->detail);
if (json)
json_object_object_add(json, vni_str, json_vni);
+
+ if (json)
+ json_vni_mac = json_object_new_object();
+ else
+ vty_out(vty, "\nVNI: %u MAC Table\n\n", vpn->vni);
+
+ show_vni_routes(wctx->bgp, vpn, wctx->vty, 0, true, wctx->vtep_ip,
+ json_vni_mac, wctx->detail);
+
+ if (json)
+ json_object_object_add(json_vni, "macTable", json_vni_mac);
}
static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
@@ -2322,9 +2394,9 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp,
/*
* Display EVPN routes for all VNIs - vty handler.
*/
-static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
- struct in_addr vtep_ip, json_object *json,
- int detail)
+static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, int type,
+ bool mac_table, struct in_addr vtep_ip,
+ json_object *json, int detail)
{
uint32_t num_vnis;
struct vni_walk_ctx wctx;
@@ -2335,6 +2407,8 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
memset(&wctx, 0, sizeof(wctx));
wctx.bgp = bgp;
wctx.vty = vty;
+ wctx.type = type;
+ wctx.mac_table = mac_table;
wctx.vtep_ip = vtep_ip;
wctx.json = json;
wctx.detail = detail;
@@ -2344,6 +2418,32 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp,
}
/*
+ * Display EVPN routes for all VNIs & all types - vty handler.
+ */
+static void evpn_show_routes_vni_all_type_all(struct vty *vty, struct bgp *bgp,
+ struct in_addr vtep_ip,
+ json_object *json, int detail)
+{
+ uint32_t num_vnis;
+ struct vni_walk_ctx wctx;
+
+ num_vnis = hashcount(bgp->vnihash);
+ if (!num_vnis)
+ return;
+
+ memset(&wctx, 0, sizeof(struct vni_walk_ctx));
+ wctx.bgp = bgp;
+ wctx.vty = vty;
+ wctx.vtep_ip = vtep_ip;
+ wctx.json = json;
+ wctx.detail = detail;
+ hash_iterate(bgp->vnihash,
+ (void (*)(struct hash_bucket *,
+ void *))show_vni_routes_all_hash,
+ &wctx);
+}
+
+/*
* Display EVPN routes for a VNI -- for specific type-3 route (vty handler).
*/
static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
@@ -2371,7 +2471,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
/* See if route exists. */
build_evpn_type3_prefix(&p, orig_ip);
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
if (!json)
vty_out(vty, "%% Network not in table\n");
@@ -2386,7 +2486,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
json_paths = json_object_new_array();
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json);
+ route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
+ NULL, afi, safi, json);
/* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
@@ -2395,8 +2496,9 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
if (json)
json_path = json_object_new_array();
- route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path);
+ route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest),
+ pi, afi, safi, RPKI_NOT_BEING_USED,
+ json_path);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2427,12 +2529,15 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
{
struct bgpevpn *vpn;
struct prefix_evpn p;
+ struct prefix_evpn tmp_p;
struct bgp_dest *dest;
struct bgp_path_info *pi;
uint32_t path_cnt = 0;
afi_t afi;
safi_t safi;
json_object *json_paths = NULL;
+ struct ethaddr empty_mac = {};
+ const struct prefix_evpn *evp;
afi = AFI_L2VPN;
safi = SAFI_EVPN;
@@ -2445,9 +2550,10 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
return;
}
+ build_evpn_type2_prefix(&p, mac ? mac : &empty_mac, ip);
+
/* See if route exists. Look for both non-sticky and sticky. */
- build_evpn_type2_prefix(&p, mac, ip);
- dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+ dest = bgp_evpn_vni_node_lookup(vpn, &p, NULL);
if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
if (!json)
vty_out(vty, "%% Network not in table\n");
@@ -2458,21 +2564,68 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
return;
}
+ /*
+ * MAC is per-path, we have to walk the path_info's and look for it
+ * first here.
+ */
+ if (ip && mac) {
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+ if (memcmp(mac, evpn_type2_path_info_get_mac(pi),
+ sizeof(*mac)) == 0)
+ break;
+ }
+
+ if (!pi) {
+ if (!json)
+ vty_out(vty, "%% Network not in table\n");
+ return;
+ }
+ }
+
if (json)
json_paths = json_object_new_array();
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, dest, NULL, afi, safi, json);
+ route_vty_out_detail_header(vty, bgp, dest, (struct prefix *)&p, NULL,
+ afi, safi, json);
+
+ evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
/* Display each path for this prefix. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
json_object *json_path = NULL;
+ /* skip non-matching MACs */
+ if (ip && mac &&
+ memcmp(mac, evpn_type2_path_info_get_mac(pi),
+ sizeof(*mac)) != 0)
+ continue;
+
if (json)
json_path = json_object_new_array();
- route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path);
+ /*
+ * VNI table MAC-IP prefixes don't have MAC so
+ * make sure it's set from path info
+ * here.
+ */
+ if (is_evpn_prefix_ipaddr_none(evp)) {
+ /* VNI MAC -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p, evp,
+ NULL /* mac */,
+ evpn_type2_path_info_get_ip(pi));
+ } else {
+ /* VNI IP -> Global */
+ evpn_type2_prefix_global_copy(
+ (struct prefix_evpn *)&tmp_p, evp,
+ evpn_type2_path_info_get_mac(pi),
+ NULL /* ip */);
+ }
+
+ route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p,
+ pi, afi, safi, RPKI_NOT_BEING_USED,
+ json_path);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2516,8 +2669,8 @@ static void evpn_show_routes_esi(struct vty *vty, struct bgp *bgp,
* If the vtep_ip is non zero, only routes behind that vtep are shown
*/
static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
- int type, struct in_addr vtep_ip,
- json_object *json)
+ int type, bool mac_table,
+ struct in_addr vtep_ip, json_object *json)
{
struct bgpevpn *vpn;
@@ -2530,7 +2683,7 @@ static void evpn_show_routes_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
}
/* Walk this VNI's route table and display appropriate routes. */
- show_vni_routes(bgp, vpn, type, vty, vtep_ip, json, 0);
+ show_vni_routes(bgp, vpn, vty, type, mac_table, vtep_ip, json, 0);
}
/*
@@ -2568,7 +2721,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
}
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, dest, prd, afi, safi, json);
+ route_vty_out_detail_header(vty, bgp, dest, bgp_dest_get_prefix(dest),
+ prd, afi, safi, json);
if (json)
json_paths = json_object_new_array();
@@ -2580,8 +2734,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
if (json)
json_path = json_object_new_array();
- route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path);
+ route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest),
+ pi, afi, safi, RPKI_NOT_BEING_USED,
+ json_path);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2673,8 +2828,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
}
/* Prefix and num paths displayed once per prefix. */
- route_vty_out_detail_header(vty, bgp, dest, prd, afi,
- safi, json_prefix);
+ route_vty_out_detail_header(
+ vty, bgp, dest, bgp_dest_get_prefix(dest), prd,
+ afi, safi, json_prefix);
prefix_cnt++;
}
@@ -2689,8 +2845,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json)
json_path = json_object_new_array();
- route_vty_out_detail(vty, bgp, dest, pi, afi, safi,
- RPKI_NOT_BEING_USED, json_path);
+ route_vty_out_detail(
+ vty, bgp, dest, bgp_dest_get_prefix(dest), pi,
+ afi, safi, RPKI_NOT_BEING_USED, json_path);
if (json)
json_object_array_add(json_paths, json_path);
@@ -2807,7 +2964,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
} else
/* Prefix and num paths displayed once per prefix. */
route_vty_out_detail_header(
- vty, bgp, dest, (struct prefix_rd *)rd_destp,
+ vty, bgp, dest, p, (struct prefix_rd *)rd_destp,
AFI_L2VPN, SAFI_EVPN, json_prefix);
/* For EVPN, the prefix is displayed for each path (to
@@ -2822,7 +2979,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
if (json)
json_path = json_object_new_array();
- route_vty_out_detail(vty, bgp, dest, pi, AFI_L2VPN,
+ route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN,
SAFI_EVPN, RPKI_NOT_BEING_USED,
json_path);
@@ -2960,6 +3117,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
if (detail)
route_vty_out_detail_header(
vty, bgp, dest,
+ bgp_dest_get_prefix(dest),
(struct prefix_rd *)rd_destp, AFI_L2VPN,
SAFI_EVPN, json_prefix);
@@ -2979,9 +3137,10 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
if (detail) {
route_vty_out_detail(
- vty, bgp, dest, pi, AFI_L2VPN,
- SAFI_EVPN, RPKI_NOT_BEING_USED,
- json_path);
+ vty, bgp, dest,
+ bgp_dest_get_prefix(dest), pi,
+ AFI_L2VPN, SAFI_EVPN,
+ RPKI_NOT_BEING_USED, json_path);
} else
route_vty_out(vty, p, pi, 0, SAFI_EVPN,
json_path, false);
@@ -3297,7 +3456,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
struct ecommunity *ecom;
if (is_vni_configured(vpn)) {
- vty_out(vty, " vni %d\n", vpn->vni);
+ vty_out(vty, " vni %u\n", vpn->vni);
if (is_rd_configured(vpn))
vty_out(vty, " rd %pRD\n", &vpn->prd);
@@ -4562,28 +4721,32 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
as_type, as, show_flags);
}
+static int bgp_evpn_cli_parse_type_cmp(int *type, const char *type_str)
+{
+ if ((strncmp(type_str, "ma", 2) == 0) || (strmatch(type_str, "2")))
+ *type = BGP_EVPN_MAC_IP_ROUTE;
+ else if ((strncmp(type_str, "mu", 2) == 0) || (strmatch(type_str, "3")))
+ *type = BGP_EVPN_IMET_ROUTE;
+ else if ((strncmp(type_str, "es", 2) == 0) || (strmatch(type_str, "4")))
+ *type = BGP_EVPN_ES_ROUTE;
+ else if ((strncmp(type_str, "ea", 2) == 0) || (strmatch(type_str, "1")))
+ *type = BGP_EVPN_AD_ROUTE;
+ else if ((strncmp(type_str, "p", 1) == 0) || (strmatch(type_str, "5")))
+ *type = BGP_EVPN_IP_PREFIX_ROUTE;
+ else
+ return -1;
+
+ return 0;
+}
+
int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc)
{
int type_idx = 0;
if (argv_find(argv, argc, "type", &type_idx)) {
/* Specific type is requested */
- if ((strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "2")))
- *type = BGP_EVPN_MAC_IP_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "3")))
- *type = BGP_EVPN_IMET_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "4")))
- *type = BGP_EVPN_ES_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "ea", 2) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "1")))
- *type = BGP_EVPN_AD_ROUTE;
- else if ((strncmp(argv[type_idx + 1]->arg, "p", 1) == 0)
- || (strmatch(argv[type_idx + 1]->arg, "5")))
- *type = BGP_EVPN_IP_PREFIX_ROUTE;
- else
+ if (bgp_evpn_cli_parse_type_cmp(type,
+ argv[type_idx + 1]->arg) != 0)
return -1;
}
@@ -4881,7 +5044,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd,
}
}
- evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json);
+ evpn_show_routes_vni(vty, bgp, vni, type, false, vtep_ip, json);
if (uj)
vty_json(vty, json);
@@ -5063,7 +5226,464 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
}
}
- evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da);
+ evpn_show_routes_vni_all(vty, bgp, 0, false, vtep_ip, json, da);
+
+ if (uj) {
+ vty_json(vty, json);
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN ALL routing tables - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all,
+ show_bgp_vni_all_cmd,
+ "show bgp vni all [vtep A.B.C.D$addr] [detail$detail] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all_type_all(vty, bgp, addr, json, !!detail);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN EAD routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_ead,
+ show_bgp_vni_all_ead_cmd,
+ "show bgp vni all type <1|ead> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_AD_ROUTE, false, addr, json,
+ !!detail);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_macip_mac,
+ show_bgp_vni_all_macip_mac_cmd,
+ "show bgp vni all type <2|macip> mac [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, true, addr,
+ json, !!detail);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN IP routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_macip_ip,
+ show_bgp_vni_all_macip_ip_cmd,
+ "show bgp vni all type <2|macip> ip [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "IP Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_MAC_IP_ROUTE, false, addr,
+ json, !!detail);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN Multicast routing table - for all VNIs.
+ */
+DEFPY(show_bgp_vni_all_imet,
+ show_bgp_vni_all_imet_cmd,
+ "show bgp vni all type <3|multicast> [vtep A.B.C.D$addr] [<detail$detail|json$uj>]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_ALL_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ DETAIL_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni_all(vty, bgp, BGP_EVPN_IMET_ROUTE, false, addr,
+ json, !!detail);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN ALL routing tables - for select VNI
+ */
+DEFPY(show_bgp_vni,
+ show_bgp_vni_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+ json_object *json_mac = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj) {
+ json = json_object_new_object();
+ json_mac = json_object_new_object();
+ }
+
+ evpn_show_routes_vni(vty, bgp, vni, 0, false, addr, json);
+
+ if (!uj)
+ vty_out(vty, "\n\nMAC Table:\n\n");
+
+ evpn_show_routes_vni(vty, bgp, vni, 0, true, addr, json_mac);
+
+ if (uj) {
+ json_object_object_add(json, "macTable", json_mac);
+ vty_json(vty, json);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN EAD routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_ead,
+ show_bgp_vni_ead_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <1|ead> [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ EVPN_TYPE_1_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_AD_ROUTE, false, addr,
+ json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC-IP MAC routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_macip_mac,
+ show_bgp_vni_macip_mac_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, true, addr,
+ json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MAC-IP IP routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_macip_ip,
+ show_bgp_vni_macip_ip_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> ip [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "IP Table\n"
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_MAC_IP_ROUTE, false, addr,
+ json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN Multicast routing table - for select VNI
+ */
+DEFPY(show_bgp_vni_imet,
+ show_bgp_vni_imet_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <3|multicast> [vtep A.B.C.D$addr] [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ EVPN_TYPE_3_HELP_STR
+ VTEP_HELP_STR
+ VTEP_IP_HELP_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_routes_vni(vty, bgp, vni, BGP_EVPN_IMET_ROUTE, false, addr,
+ json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MACIP MAC routing table - for select VNI & MAC
+ */
+DEFPY(show_bgp_vni_macip_mac_addr,
+ show_bgp_vni_macip_mac_addr_cmd,
+ "show bgp vni "CMD_VNI_RANGE"$vni type <2|macip> mac X:X:X:X:X:X [json$uj]",
+ SHOW_STR
+ BGP_STR
+ VNI_HELP_STR
+ VNI_NUM_HELP_STR
+ EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ EVPN_TYPE_2_HELP_STR
+ "MAC Table\n"
+ MAC_STR
+ JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ evpn_show_route_vni_macip(vty, bgp, vni, &mac->eth_addr, NULL, json);
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VNI EVPN MACIP IP routing table - for select VNI & IP
+ */
+DEFPY(show_bgp_vni_macip_ip_addr, show_bgp_vni_macip_ip_addr_cmd,
+ "show bgp vni " CMD_VNI_RANGE
+ "$vni type <2|macip> ip <A.B.C.D|X:X::X:X> [json$uj]",
+ SHOW_STR BGP_STR VNI_HELP_STR VNI_NUM_HELP_STR EVPN_TYPE_HELP_STR
+ EVPN_TYPE_2_HELP_STR EVPN_TYPE_2_HELP_STR
+ "IP Table\n" IP_ADDR_STR IP6_ADDR_STR JSON_STR)
+{
+ struct bgp *bgp;
+ json_object *json = NULL;
+ struct ipaddr ip_addr = {.ipa_type = IPADDR_NONE};
+
+ bgp = bgp_get_evpn();
+ if (!bgp)
+ return CMD_WARNING;
+
+ /* check if we need json output */
+ if (uj)
+ json = json_object_new_object();
+
+ if (sockunion_family(ip) == AF_INET) {
+ ip_addr.ipa_type = IPADDR_V4;
+ ip_addr.ipaddr_v4.s_addr = sockunion2ip(ip);
+ } else {
+ ip_addr.ipa_type = IPADDR_V6;
+ memcpy(&ip_addr.ipaddr_v6, &ip->sin6.sin6_addr,
+ sizeof(struct in6_addr));
+ }
+ evpn_show_route_vni_macip(vty, bgp, vni, NULL, &ip_addr, json);
if (uj)
vty_json(vty, json);
@@ -6755,6 +7375,20 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
+ /* "show bgp vni" commands. */
+ install_element(VIEW_NODE, &show_bgp_vni_all_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_ead_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_macip_mac_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_macip_ip_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_all_imet_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_ead_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_mac_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_ip_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_imet_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_mac_addr_cmd);
+ install_element(VIEW_NODE, &show_bgp_vni_macip_ip_addr_cmd);
+
/* "show bgp evpn" commands. */
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h
index 137365ddbf..6b17a83b74 100644
--- a/bgpd/bgp_evpn_vty.h
+++ b/bgpd/bgp_evpn_vty.h
@@ -27,6 +27,12 @@ extern void bgp_ethernetvpn_init(void);
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
#define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
+#define VNI_HELP_STR "VXLAN Network Identifier\n"
+#define VNI_NUM_HELP_STR "VNI number\n"
+#define VNI_ALL_HELP_STR "All VNIs\n"
+#define DETAIL_HELP_STR "Print Detailed Output\n"
+#define VTEP_HELP_STR "Remote VTEP\n"
+#define VTEP_IP_HELP_STR "Remote VTEP IP address\n"
extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc,
int *oly_idx,
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 01c61615a3..f110005e49 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -634,7 +634,8 @@ const char *const peer_down_str[] = {"",
"AS Set config change",
"Waiting for peer OPEN",
"Reached received prefix count",
- "Socket Error"};
+ "Socket Error",
+ "Admin. shutdown (RTT)"};
static void bgp_graceful_restart_timer_off(struct peer *peer)
{
@@ -1832,7 +1833,9 @@ int bgp_start(struct peer *peer)
flog_err(EC_BGP_FSM,
"%s [FSM] Trying to start suppressed peer - this is never supposed to happen!",
peer->host);
- if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index ce8ce96a0d..49ae9816a3 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -280,10 +280,11 @@ static void bgp_process_reads(struct thread *thread)
case -ENOMEM:
ibuf_full = true;
if (!ibuf_full_logged) {
- flog_warn(
- EC_BGP_UPDATE_RCV,
- "%s [Warning] Peer Input-Queue is full: limit (%u)",
- peer->host, bm->inq_limit);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s [Event] Peer Input-Queue is full: limit (%u)",
+ peer->host, bm->inq_limit);
+
ibuf_full_logged = true;
}
break;
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 9a25450afa..18cb90763c 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -1554,13 +1554,22 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
+ struct srv6_locator_chunk *locator =
+ from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
- static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ afi == AFI_IP
+ ? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT4)
+ : (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT6);
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->vpn_policy[afi]
.tovpn_sid_locator->block_bits_length;
@@ -1587,12 +1596,17 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
.tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
} else if (from_bgp->tovpn_sid_locator) {
+ struct srv6_locator_chunk *locator =
+ from_bgp->tovpn_sid_locator;
encode_label(from_bgp->tovpn_sid_transpose_label, &label);
static_attr.srv6_l3vpn =
XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
- static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT46;
static_attr.srv6_l3vpn->loc_block_len =
from_bgp->tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 72d6a92317..f3ca3bba0a 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1011,9 +1011,12 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
if (code == BGP_NOTIFY_CEASE) {
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
+ else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+ } else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
} else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
@@ -1749,15 +1752,24 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
/* If the peer's RTT is higher than expected, shutdown
* the peer automatically.
*/
- if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN)
- && peer->rtt > peer->rtt_expected) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN))
+ return Receive_KEEPALIVE_message;
+ if (peer->rtt > peer->rtt_expected) {
peer->rtt_keepalive_rcv++;
if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) {
- zlog_warn(
- "%s shutdown due to high round-trip-time (%dms > %dms)",
- peer->host, peer->rtt, peer->rtt_expected);
+ char rtt_shutdown_reason[BUFSIZ] = {};
+
+ snprintfrr(
+ rtt_shutdown_reason,
+ sizeof(rtt_shutdown_reason),
+ "shutdown due to high round-trip-time (%dms > %dms, hit %u times)",
+ peer->rtt, peer->rtt_expected,
+ peer->rtt_keepalive_rcv);
+ zlog_warn("%s %s", peer->host, rtt_shutdown_reason);
+ SET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ peer_tx_shutdown_message_set(peer, rtt_shutdown_reason);
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
}
} else {
diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h
index 43ebb9ac91..e07b7f911b 100644
--- a/bgpd/bgp_regex.h
+++ b/bgpd/bgp_regex.h
@@ -18,19 +18,24 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _QUAGGA_BGP_REGEX_H
-#define _QUAGGA_BGP_REGEX_H
+#ifndef _FRR_BGP_REGEX_H
+#define _FRR_BGP_REGEX_H
#include <zebra.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
extern void bgp_regex_free(regex_t *regex);
extern regex_t *bgp_regcomp(const char *str);
extern int bgp_regexec(regex_t *regex, struct aspath *aspath);
-#endif /* _QUAGGA_BGP_REGEX_H */
+#endif /* _FRR_BGP_REGEX_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 130a0b4abd..6eb1a556b1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4044,6 +4044,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
int vnc_implicit_withdraw = 0;
#endif
int same_attr = 0;
+ const struct prefix *bgp_nht_param_prefix;
/* Special case for BGP-LU - map LU safi to ordinary unicast safi */
if (orig_safi == SAFI_LABELED_UNICAST)
@@ -4111,6 +4112,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (aspath_get_last_as(attr->aspath) == bgp->as)
do_loop_check = 0;
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+ bgp_nht_param_prefix = NULL;
+ else
+ bgp_nht_param_prefix = p;
+
/* AS path loop check. */
if (do_loop_check) {
if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
@@ -4621,8 +4627,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi,
safi, pi, NULL, connected,
- p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, pi,
BGP_PATH_VALID);
else {
@@ -4784,8 +4790,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
nh_afi = BGP_ATTR_NH_AFI(afi, new->attr);
if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, safi, new, NULL,
- connected, p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ connected, bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
else {
if (BGP_DEBUG(nht, NHT)) {
@@ -10209,12 +10215,14 @@ static void route_vty_out_detail_es_info(struct vty *vty,
}
void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
- struct bgp_path_info *path, afi_t afi, safi_t safi,
+ const struct prefix *p, struct bgp_path_info *path,
+ afi_t afi, safi_t safi,
enum rpki_states rpki_curr_state,
json_object *json_paths)
{
char buf[INET6_ADDRSTRLEN];
char buf1[BUFSIZ];
+ char tag_buf[30];
struct attr *attr = path->attr;
time_t tbuf;
json_object *json_bestpath = NULL;
@@ -10245,6 +10253,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
uint32_t bos = 0;
uint32_t exp = 0;
mpls_label_t label = MPLS_INVALID_LABEL;
+ tag_buf[0] = '\0';
if (json_paths) {
json_path = json_object_new_object();
@@ -10254,13 +10263,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (safi == SAFI_EVPN) {
if (!json_paths)
- vty_out(vty, " Route %pRN", bn);
+ vty_out(vty, " Route %pFX", p);
}
if (path->extra) {
- char tag_buf[30];
-
- tag_buf[0] = '\0';
if (path->extra && path->extra->num_labels) {
bgp_evpn_label2str(path->extra->label,
path->extra->num_labels, tag_buf,
@@ -10279,44 +10285,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}
}
-
- if (path->extra && path->extra->parent && !json_paths) {
- struct bgp_path_info *parent_ri;
- struct bgp_dest *dest, *pdest;
-
- parent_ri = (struct bgp_path_info *)path->extra->parent;
- dest = parent_ri->net;
- if (dest && dest->pdest) {
- pdest = dest->pdest;
- if (is_pi_family_evpn(parent_ri)) {
- vty_out(vty,
- " Imported from %pRD:%pFX, VNI %s",
- (struct prefix_rd *)
- bgp_dest_get_prefix(
- pdest),
- (struct prefix_evpn *)
- bgp_dest_get_prefix(
- dest),
- tag_buf);
- if (attr->es_flags & ATTR_ES_L3_NHG)
- vty_out(vty, ", L3NHG %s",
- (attr->es_flags
- & ATTR_ES_L3_NHG_ACTIVE)
- ? "active"
- : "inactive");
- vty_out(vty, "\n");
-
- } else
- vty_out(vty,
- " Imported from %pRD:%pFX\n",
- (struct prefix_rd *)
- bgp_dest_get_prefix(
- pdest),
- (struct prefix_evpn *)
- bgp_dest_get_prefix(
- dest));
- }
- }
}
if (safi == SAFI_EVPN
@@ -10336,6 +10304,41 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (safi == SAFI_EVPN && !json_path)
vty_out(vty, "\n");
+
+ if (path->extra && path->extra->parent && !json_paths) {
+ struct bgp_path_info *parent_ri;
+ struct bgp_dest *dest, *pdest;
+
+ parent_ri = (struct bgp_path_info *)path->extra->parent;
+ dest = parent_ri->net;
+ if (dest && dest->pdest) {
+ pdest = dest->pdest;
+ if (is_pi_family_evpn(parent_ri)) {
+ vty_out(vty,
+ " Imported from %pRD:%pFX, VNI %s",
+ (struct prefix_rd *)bgp_dest_get_prefix(
+ pdest),
+ (struct prefix_evpn *)
+ bgp_dest_get_prefix(dest),
+ tag_buf);
+ if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG))
+ vty_out(vty, ", L3NHG %s",
+ CHECK_FLAG(
+ attr->es_flags,
+ ATTR_ES_L3_NHG_ACTIVE)
+ ? "active"
+ : "inactive");
+ vty_out(vty, "\n");
+
+ } else
+ vty_out(vty, " Imported from %pRD:%pFX\n",
+ (struct prefix_rd *)bgp_dest_get_prefix(
+ pdest),
+ (struct prefix_evpn *)
+ bgp_dest_get_prefix(dest));
+ }
+ }
+
/* Line1 display AS-path, Aggregator */
if (attr->aspath) {
if (json_paths) {
@@ -10415,10 +10418,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Line2 display Next-hop, Neighbor, Router-id */
/* Display the nexthop */
- const struct prefix *bn_p = bgp_dest_get_prefix(bn);
- if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET ||
- bn_p->family == AF_EVPN) &&
+ if ((p->family == AF_INET || p->family == AF_ETHERNET ||
+ p->family == AF_EVPN) &&
(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN ||
!BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
@@ -10531,7 +10533,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* This path was originated locally */
if (path->peer == bgp->peer_self) {
- if (safi == SAFI_EVPN || (bn_p->family == AF_INET &&
+ if (safi == SAFI_EVPN || (p->family == AF_INET &&
!BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr))) {
if (json_paths)
json_object_string_add(json_peer, "peerId",
@@ -11555,8 +11557,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
prd = bgp_rd_from_dest(dest, safi);
route_vty_out_detail_header(
- vty, bgp, dest, prd, table->afi,
- safi, jtemp);
+ vty, bgp, dest,
+ bgp_dest_get_prefix(dest), prd,
+ table->afi, safi, jtemp);
json_object_array_add(json_paths, jtemp);
@@ -11582,7 +11585,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
else {
if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL))
route_vty_out_detail(
- vty, bgp, dest, pi,
+ vty, bgp, dest,
+ bgp_dest_get_prefix(dest), pi,
family2afi(dest_p->family),
safi, RPKI_NOT_BEING_USED,
json_paths);
@@ -11803,12 +11807,11 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
/* Header of detailed BGP route information */
void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
- struct bgp_dest *dest,
- const struct prefix_rd *prd,
- afi_t afi, safi_t safi, json_object *json)
+ struct bgp_dest *dest, const struct prefix *p,
+ const struct prefix_rd *prd, afi_t afi,
+ safi_t safi, json_object *json)
{
struct bgp_path_info *pi;
- const struct prefix *p;
struct peer *peer;
struct listnode *node, *nnode;
char buf1[RD_ADDRSTRLEN];
@@ -11838,7 +11841,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
mpls_lse_decode(dest->local_label, &label, &ttl, &exp, &bos);
- p = bgp_dest_get_prefix(dest);
has_valid_label = bgp_is_valid_label(&label);
if (safi == SAFI_EVPN) {
@@ -12046,8 +12048,9 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
if (header) {
route_vty_out_detail_header(
- vty, bgp, bgp_node, pfx_rd,
- AFI_IP, safi, json_header);
+ vty, bgp, bgp_node,
+ bgp_dest_get_prefix(bgp_node), pfx_rd, AFI_IP,
+ safi, json_header);
header = 0;
}
(*display)++;
@@ -12058,8 +12061,10 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
|| (pathtype == BGP_PATH_SHOW_MULTIPATH
&& (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH)
|| CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))))
- route_vty_out_detail(vty, bgp, bgp_node, pi, AFI_IP,
- safi, rpki_curr_state, json_paths);
+ route_vty_out_detail(vty, bgp, bgp_node,
+ bgp_dest_get_prefix(bgp_node), pi,
+ AFI_IP, safi, rpki_curr_state,
+ json_paths);
}
if (json && json_paths) {
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index c85551634a..3fa58c0dfb 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -214,9 +214,14 @@ struct bgp_path_info_extra {
} vnc;
#endif
- /* For imported routes into a VNI (or VRF), this points to the parent.
+ /*
+ * For imported routes into a VNI (or VRF)
*/
- void *parent;
+ void *parent; /* parent from global table */
+ union {
+ struct ethaddr mac; /* MAC set here for VNI IP table */
+ struct ipaddr ip; /* IP set here for VNI MAC table */
+ } vni_info;
/*
* Some tunnelish parameters follow. Maybe consolidate into an
@@ -849,10 +854,11 @@ extern bool bgp_zebra_has_route_changed(struct bgp_path_info *selected);
extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
struct bgp_dest *dest,
+ const struct prefix *p,
const struct prefix_rd *prd, afi_t afi,
safi_t safi, json_object *json);
extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
- struct bgp_dest *bn,
+ struct bgp_dest *bn, const struct prefix *p,
struct bgp_path_info *path, afi_t afi,
safi_t safi, enum rpki_states,
json_object *json_paths);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index aff09206e4..b736e6c38a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -30,11 +30,16 @@
#include "log.h"
#include "frrlua.h"
#include "frrscript.h"
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "buffer.h"
#include "sockunion.h"
#include "hash.h"
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 1f66080e93..6f0bd5eded 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -5272,8 +5272,10 @@ static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
return CMD_WARNING_CONFIG_FAILED;
}
- if (!set && flag == PEER_FLAG_SHUTDOWN)
+ if (!set && flag == PEER_FLAG_SHUTDOWN) {
peer_tx_shutdown_message_unset(peer);
+ UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ }
if (set)
ret = peer_flag_set(peer, flag);
@@ -14565,9 +14567,18 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
if (use_json) {
json_object_int_add(json_neigh, "connectRetryTimer",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
json_object_int_add(json_neigh, "estimatedRttInMsecs",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) {
+ json_object_int_add(json_neigh,
+ "shutdownRttInMsecs",
+ p->rtt_expected);
+ json_object_int_add(json_neigh,
+ "shutdownRttAfterCount",
+ p->rtt_keepalive_rcv);
+ }
+ }
if (p->t_start)
json_object_int_add(
json_neigh, "nextStartTimerDueInMsecs",
@@ -14602,9 +14613,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
} else {
vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
vty_out(vty, "Estimated round trip time: %d ms\n",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN))
+ vty_out(vty,
+ "Shutdown when RTT > %dms, count > %u\n",
+ p->rtt_expected, p->rtt_keepalive_rcv);
+ }
if (p->t_start)
vty_out(vty, "Next start timer due in %ld seconds\n",
thread_timer_remain_second(p->t_start));
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index b3fce07344..8a0ec5ad2d 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1524,6 +1524,7 @@ struct peer {
/* LLGR aware peer */
#define PEER_STATUS_LLGR_WAIT (1U << 11)
#define PEER_STATUS_REFRESH_PENDING (1U << 12) /* refresh request from peer */
+#define PEER_STATUS_RTT_SHUTDOWN (1U << 13) /* In shutdown state due to RTT */
/* Configured timer values. */
_Atomic uint32_t holdtime;
@@ -1737,6 +1738,7 @@ struct peer {
#define PEER_DOWN_WAITING_OPEN 32U /* Waiting for open to succeed */
#define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */
#define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */
+#define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */
/*
* Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason
diff --git a/configure.ac b/configure.ac
index 1a481ecd79..97c8ca451b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -712,6 +712,8 @@ AC_ARG_ENABLE([cpu-time],
AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering]))
AC_ARG_ENABLE([pcreposix],
AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
+AC_ARG_ENABLE([pcre2posix],
+ AS_HELP_STRING([--enable-pcre2posix], [enable using PCRE2 Posix libs for regex functions]))
AC_ARG_ENABLE([fpm],
AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
AC_ARG_ENABLE([werror],
@@ -1659,6 +1661,16 @@ if test "$enable_pcreposix" = "yes"; then
fi
AC_SUBST([HAVE_LIBPCREPOSIX])
+dnl ---------------------------
+dnl check system has PCRE2 regexp
+dnl ---------------------------
+if test "$enable_pcre2posix" = "yes"; then
+ AC_CHECK_LIB([pcre2-posix], [regexec], [], [
+ AC_MSG_ERROR([--enable-pcre2posix given but unable to find libpcre2-posix])
+ ])
+fi
+AC_SUBST([HAVE_LIBPCRE2_POSIX])
+
dnl ##########################################################################
dnl test "$enable_clippy_only" != "yes"
fi
diff --git a/debian/frr.install b/debian/frr.install
index 48263222f8..044b484984 100644
--- a/debian/frr.install
+++ b/debian/frr.install
@@ -1,6 +1,7 @@
debian/frr.conf usr/lib/tmpfiles.d
etc/
tools/etc/frr/frr.conf etc/frr/
+tools/etc/logrotate.d/frr etc/logrotate.d/
tools/frr-reload usr/lib/frr/
usr/bin/mtracebis
usr/bin/vtysh
diff --git a/debian/frr.pam b/debian/frr.pam
index 2b106d43bc..737b88953b 100644
--- a/debian/frr.pam
+++ b/debian/frr.pam
@@ -1,3 +1,4 @@
# Any user may call vtysh but only those belonging to the group frrvty can
# actually connect to the socket and use the program.
auth sufficient pam_permit.so
+account sufficient pam_rootok.so
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 7083b19b90..44349976f6 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -4135,6 +4135,10 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
EVPN prefixes can also be filtered by EVPN route type.
+.. clicmd:: show bgp vni <all|VNI> [vtep VTEP] [type <ead|1|macip|2|multicast|3>] [<detail|json>]
+
+ Display per-VNI EVPN routing table in bgp. Filter route-type, vtep, or VNI.
+
.. clicmd:: show bgp [afi] [safi] [all] summary [json]
Show a bgp peer summary for the specified address family, and subsequent
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index ba35facf2a..8f89c6c4f8 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -368,6 +368,13 @@ options from the list below.
Turn on the usage of PCRE Posix libs for regex functionality.
+.. option:: --enable-pcre2posix
+
+ Turn on the usage of PCRE2 Posix libs for regex functionality.
+
+ PCRE2 versions <= 10.31 work a bit differently. We suggest using at least
+ >= 10.36.
+
.. option:: --enable-rpath
Set hardcoded rpaths in the executable [default=yes].
diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst
index f0b76f10b7..ec107fbe47 100644
--- a/doc/user/pathd.rst
+++ b/doc/user/pathd.rst
@@ -175,7 +175,7 @@ controller and obtain those by means of the PCEP protocol.
.. image:: images/pathd_initiated_multi.png
Starting
-=============
+========
Default configuration file for *pathd* is :file:`pathd.conf`. The typical
location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf.
@@ -480,6 +480,12 @@ Configuration Commands
Specify a peer and its precedence in a PCC definition.
+Debugging
+---------
+
+.. clicmd:: debug pathd policy
+
+ Enable or disable Pathd policy information.
Introspection Commands
----------------------
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 0a843b9283..db43266d68 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -810,6 +810,36 @@ and this section also helps that case.
!
...
+.. clicmd:: behavior usid
+
+ Specify the SRv6 locator as a Micro-segment (uSID) locator. When a locator is
+ specified as a uSID locator, all the SRv6 SIDs allocated from the locator by the routing
+ protocols are bound to the SRv6 uSID behaviors. For example, if you configure BGP to use
+ a locator specified as a uSID locator, BGP instantiates and advertises SRv6 uSID behaviors
+ (e.g., ``uDT4`` / ``uDT6`` / ``uDT46``) instead of classic SRv6 behaviors
+ (e.g., ``End.DT4`` / ``End.DT6`` / ``End.DT46``).
+
+::
+
+ router# configure terminal
+ router(config)# segment-routinig
+ router(config-sr)# srv6
+ router(config-srv6)# locators
+ router(config-srv6-locators)# locator loc1
+ router(config-srv6-locator)# prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
+ router(config-srv6-locator)# behavior usid
+
+ router(config-srv6-locator)# show run
+ ...
+ segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48
+ behavior usid
+ !
+ ...
+
.. _multicast-rib-commands:
Multicast RIB Commands
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index b9278dbb88..238a7fc409 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Create a basic stage set up to build APKs
-FROM alpine:3.15 as alpine-builder
+FROM alpine:3.16 as alpine-builder
RUN apk add \
--update-cache \
abuild \
@@ -13,7 +13,7 @@ RUN apk add \
RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n'
# This stage builds a dist tarball from the source
-FROM alpine:3.15 as source-builder
+FROM alpine:3.16 as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
@@ -48,7 +48,7 @@ RUN cd /dist \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:3.15
+FROM alpine:3.16
RUN mkdir -p /pkgs/apk
COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index 4fdb11b211..c7dc9b7c44 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -485,6 +485,9 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
+ if (area == NULL)
+ return;
+
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
@@ -492,9 +495,8 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
isis_route_remove_previous_sid(area, prefix, route_info);
/* Install route. */
- if (area)
- isis_zebra_route_add_route(area->isis, prefix, src_p,
- route_info);
+ isis_zebra_route_add_route(area->isis, prefix, src_p,
+ route_info);
/* Install/reinstall Prefix-SID label. */
if (route_info->sr.present)
isis_zebra_prefix_sid_install(area, prefix, route_info,
@@ -509,9 +511,8 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
isis_zebra_prefix_sid_uninstall(
area, prefix, route_info, &route_info->sr);
/* Uninstall route. */
- if (area)
- isis_zebra_route_del_route(area->isis, prefix, src_p,
- route_info);
+ isis_zebra_route_del_route(area->isis, prefix, src_p,
+ route_info);
hook_call(isis_route_update_hook, area, prefix, route_info);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
diff --git a/lib/command.h b/lib/command.h
index 31e5cad23f..0f9715e81c 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -383,6 +383,8 @@ struct cmd_node {
#define SHOW_STR "Show running system information\n"
#define IP_STR "IP information\n"
#define IPV6_STR "IPv6 information\n"
+#define IP_ADDR_STR "IPv4 Address\n"
+#define IP6_ADDR_STR "IPv6 Address\n"
#define SRTE_STR "SR-TE information\n"
#define SRTE_COLOR_STR "SR-TE Color information\n"
#define NO_STR "Negate a command or set its defaults\n"
diff --git a/lib/frrstr.c b/lib/frrstr.c
index 1b98b224cc..d66c6f8c16 100644
--- a/lib/frrstr.c
+++ b/lib/frrstr.c
@@ -23,11 +23,16 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "frrstr.h"
#include "memory.h"
diff --git a/lib/frrstr.h b/lib/frrstr.h
index d52d6a4482..f0066d0fc5 100644
--- a/lib/frrstr.h
+++ b/lib/frrstr.h
@@ -23,11 +23,16 @@
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdbool.h>
#include "vector.h"
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index d7ab358afe..43b3028200 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -61,6 +61,8 @@ struct ipaddr {
#define IPADDRSZ(p) \
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
+#define IPADDR_STRING_SIZE 46
+
static inline int ipaddr_family(const struct ipaddr *ip)
{
switch (ip->ipa_type) {
diff --git a/lib/srv6.c b/lib/srv6.c
index 1c2c8913d5..5cd82080f5 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -241,6 +241,10 @@ json_object *srv6_locator_json(const struct srv6_locator *loc)
json_object_int_add(jo_root, "argumentBitsLength",
loc->argument_bits_length);
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set status_up */
json_object_boolean_add(jo_root, "statusUp",
loc->status_up);
@@ -286,6 +290,10 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc)
json_object_int_add(jo_root, "argumentBitsLength",
loc->argument_bits_length);
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set algonum */
json_object_int_add(jo_root, "algoNum", loc->algonum);
diff --git a/lib/srv6.h b/lib/srv6.h
index 18d5bdebc2..acfb0631cc 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -92,6 +92,9 @@ struct srv6_locator {
bool status_up;
struct list *chunks;
+ uint8_t flags;
+#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(srv6_locator);
@@ -116,6 +119,23 @@ struct srv6_locator_chunk {
uint8_t proto;
uint16_t instance;
uint32_t session_id;
+
+ uint8_t flags;
+};
+
+/*
+ * SRv6 Endpoint Behavior codepoints, as defined by IANA in
+ * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml
+ */
+enum srv6_endpoint_behavior_codepoint {
+ SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040,
+ SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF,
};
struct nexthop_srv6 {
diff --git a/lib/vty.c b/lib/vty.c
index d524ae53cb..5fe8d82473 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -24,11 +24,16 @@
#include <lib/version.h>
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdio.h>
#include "linklist.h"
diff --git a/lib/vty.h b/lib/vty.h
index 430579c5a8..0b3fd2443f 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -22,11 +22,16 @@
#define _ZEBRA_VTY_H
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "thread.h"
#include "log.h"
diff --git a/lib/zclient.c b/lib/zclient.c
index 2517773dc4..fd6eb7db0d 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1088,6 +1088,7 @@ int zapi_srv6_locator_chunk_encode(struct stream *s,
stream_putc(s, c->node_bits_length);
stream_putc(s, c->function_bits_length);
stream_putc(s, c->argument_bits_length);
+ stream_putc(s, c->flags);
return 0;
}
@@ -1109,6 +1110,7 @@ int zapi_srv6_locator_chunk_decode(struct stream *s,
STREAM_GETC(s, c->node_bits_length);
STREAM_GETC(s, c->function_bits_length);
STREAM_GETC(s, c->argument_bits_length);
+ STREAM_GETC(s, c->flags);
return 0;
stream_failure:
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 4fb3a33568..a67b6c6c19 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2205,7 +2205,7 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
*/
if (ospf->router_id.s_addr == INADDR_ANY) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
&ei->p.prefix);
@@ -2214,7 +2214,7 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
/* Create new AS-external-LSA instance. */
if ((new = ospf_external_lsa_new(ospf, ei, NULL)) == NULL) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: Could not originate AS-external-LSA",
&ei->p.prefix);
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index a6540cc84a..b88453c68f 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -126,7 +126,7 @@ DEFPY(show_srte_policy,
ttable_rowseps(tt, 0, BOTTOM, true, '-');
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
@@ -173,7 +173,7 @@ DEFPY(show_srte_policy_detail,
vty_out(vty, "\n");
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
struct srte_candidate *candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
char *segment_list_info;
static char undefined_info[] = "(undefined)";
@@ -1091,8 +1091,25 @@ DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
"pathd module debugging\n")
{
+ vty_out(vty, "Path debugging status:\n");
+
cmd_show_lib_debugs(vty);
/* nothing to do here */
+ path_ted_show_debugging(vty);
+ path_policy_show_debugging(vty);
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
+ NO_STR DEBUG_STR
+ "path debugging\n"
+ "policy debugging\n")
+{
+ uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool no_debug = no;
+
+ DEBUG_MODE_SET(&path_policy_debug, mode, !no);
+ DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug);
return CMD_SUCCESS;
}
@@ -1291,8 +1308,34 @@ int config_write_segment_routing(struct vty *vty)
return 1;
}
+static int path_policy_cli_debug_config_write(struct vty *vty)
+{
+ if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) {
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug,
+ PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, "debug pathd policy\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int path_policy_cli_debug_set_all(uint32_t flags, bool set)
+{
+ DEBUG_FLAGS_SET(&path_policy_debug, flags, set);
+
+ /* If all modes have been turned off, don't preserve options. */
+ if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL))
+ DEBUG_CLEAR(&path_policy_debug);
+
+ return 0;
+}
+
void path_cli_init(void)
{
+ hook_register(nb_client_debug_config_write,
+ path_policy_cli_debug_config_write);
+ hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all);
+
install_node(&segment_routing_node);
install_node(&sr_traffic_eng_node);
install_node(&srte_segment_list_node);
@@ -1308,6 +1351,9 @@ void path_cli_init(void)
install_element(ENABLE_NODE, &show_srte_policy_cmd);
install_element(ENABLE_NODE, &show_srte_policy_detail_cmd);
+ install_element(ENABLE_NODE, &debug_path_policy_cmd);
+ install_element(CONFIG_NODE, &debug_path_policy_cmd);
+
install_element(CONFIG_NODE, &segment_routing_cmd);
install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
diff --git a/pathd/path_ted.c b/pathd/path_ted.c
index 68748af53e..5fc8a1f032 100644
--- a/pathd/path_ted.c
+++ b/pathd/path_ted.c
@@ -488,6 +488,12 @@ int path_ted_cli_debug_config_write(struct vty *vty)
return 0;
}
+void path_ted_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
+ vty_out(vty, " Path TED debugging is on\n");
+}
+
int path_ted_cli_debug_set_all(uint32_t flags, bool set)
{
DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
diff --git a/pathd/path_ted.h b/pathd/path_ted.h
index c6897b1520..5a0c8eecd3 100644
--- a/pathd/path_ted.h
+++ b/pathd/path_ted.h
@@ -101,6 +101,7 @@ int path_ted_segment_list_refresh(void);
/* TED configuration functions */
uint32_t path_ted_config_write(struct vty *vty);
+void path_ted_show_debugging(struct vty *vty);
/* TED util functions */
/* clang-format off */
diff --git a/pathd/pathd.c b/pathd/pathd.c
index e9d7cc6fc7..167c88aeab 100644
--- a/pathd/pathd.c
+++ b/pathd/pathd.c
@@ -23,6 +23,8 @@
#include "lib_errors.h"
#include "network.h"
#include "libfrr.h"
+#include <debug.h>
+#include <hook.h>
#include "pathd/pathd.h"
#include "pathd/path_zebra.h"
@@ -44,6 +46,17 @@ DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
(candidate));
+struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG(fmt, ...) \
+ do { \
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, \
+ PATH_POLICY_DEBUG_BASIC)) \
+ DEBUGD(&path_policy_debug, "policy: " fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+
static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
static void trigger_pathd_candidate_created_timer(struct thread *thread);
static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
@@ -97,6 +110,20 @@ RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
+static void srte_policy_status_log(struct srte_policy *policy)
+{
+ char endpoint[ENDPOINT_STR_LENGTH];
+
+ ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+ if (policy->status == SRTE_POLICY_STATUS_DOWN) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is DOWN", endpoint,
+ policy->color);
+ } else if (policy->status == SRTE_POLICY_STATUS_UP) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is UP", endpoint,
+ policy->color);
+ }
+}
+
/**
* Adds a segment list to pathd.
*
@@ -531,6 +558,10 @@ void srte_apply_changes(void)
RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
+ if (policy->status != SRTE_POLICY_STATUS_DOWN) {
+ policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
+ }
srte_policy_del(policy);
continue;
}
@@ -565,7 +596,7 @@ void srte_policy_apply_changes(struct srte_policy *policy)
struct srte_candidate *candidate, *safe;
struct srte_candidate *old_best_candidate;
struct srte_candidate *new_best_candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
@@ -574,8 +605,7 @@ void srte_policy_apply_changes(struct srte_policy *policy)
new_best_candidate = srte_policy_best_candidate(policy);
if (new_best_candidate != old_best_candidate) {
- /* TODO: add debug guard. */
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): best candidate changed from %s to %s",
endpoint, policy->color,
old_best_candidate ? old_best_candidate->name : "none",
@@ -617,10 +647,10 @@ void srte_policy_apply_changes(struct srte_policy *policy)
F_SEGMENT_LIST_MODIFIED);
if (candidate_changed || segment_list_changed) {
- /* TODO: add debug guard. */
- zlog_debug("SR-TE(%s, %u): best candidate %s changed",
- endpoint, policy->color,
- new_best_candidate->name);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): best candidate %s changed",
+ endpoint, policy->color,
+ new_best_candidate->name);
path_zebra_add_sr_policy(
policy, new_best_candidate->lsp->segment_list);
@@ -722,10 +752,10 @@ void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
float bandwidth, bool required)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
endpoint, policy->color, candidate->name,
required ? "required " : "", bandwidth);
@@ -750,11 +780,13 @@ void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
- endpoint, policy->color, candidate->name,
- required ? "required" : "", bandwidth);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
+ endpoint, policy->color, candidate->name,
+ required ? "required" : "", bandwidth);
SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
lsp->bandwidth = bandwidth;
@@ -770,10 +802,11 @@ void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
- endpoint, policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s config bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
candidate->bandwidth = 0;
@@ -792,10 +825,11 @@ void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
- policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s lsp bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
@@ -820,9 +854,10 @@ void srte_candidate_set_metric(struct srte_candidate *candidate,
bool is_computed)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
@@ -854,9 +889,10 @@ void srte_lsp_set_metric(struct srte_lsp *lsp,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
@@ -889,11 +925,13 @@ void srte_candidate_unset_metric(struct srte_candidate *candidate,
enum srte_candidate_metric_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&candidate->metrics[type - 1]);
srte_lsp_unset_metric(candidate->lsp, type);
@@ -913,11 +951,13 @@ void srte_lsp_unset_metric(struct srte_lsp *lsp,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&lsp->metrics[type - 1]);
}
@@ -941,16 +981,18 @@ void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
enum objfun_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
candidate->objfun = type;
SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
- zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
- endpoint, policy->color, candidate->name,
- required ? "required " : "", objfun_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %sobjective function set to %s",
+ endpoint, policy->color, candidate->name,
+ required ? "required " : "", objfun_type_name(type));
}
/**
@@ -961,14 +1003,15 @@ void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
void srte_candidate_unset_objfun(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->objfun = OBJFUN_UNDEFINED;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s objective functions preferences unset",
endpoint, policy->color, candidate->name);
}
@@ -1013,7 +1056,8 @@ void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
uint32_t filter)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
@@ -1021,7 +1065,7 @@ void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
SET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = filter;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
endpoint, policy->color, candidate->name,
filter_type_name(type), filter);
@@ -1038,7 +1082,8 @@ void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
enum affinity_filter_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
@@ -1046,9 +1091,10 @@ void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = 0;
- zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
- endpoint, policy->color, candidate->name,
- filter_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s affinity filter %s unset",
+ endpoint, policy->color, candidate->name,
+ filter_type_name(type));
}
/**
@@ -1093,10 +1139,11 @@ srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
void srte_candidate_status_update(struct srte_candidate *candidate, int status)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
- policy->color, status);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): zebra updated status to %d", endpoint,
+ policy->color, status);
switch (status) {
case ZEBRA_SR_POLICY_DOWN:
switch (policy->status) {
@@ -1109,9 +1156,8 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status)
case SRTE_POLICY_STATUS_DOWN:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
break;
}
break;
@@ -1120,9 +1166,8 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status)
case SRTE_POLICY_STATUS_UP:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_UP;
+ srte_policy_status_log(policy);
break;
}
break;
@@ -1148,19 +1193,20 @@ void srte_candidate_unset_segment_list(const char *originator, bool force)
return;
}
- zlog_debug("Unset segment lists for originator %s", originator);
+ PATH_POLICY_DEBUG("Unset segment lists for originator %s", originator);
/* Iterate the policies, then iterate each policy's candidate path
* to check the candidate path's segment list originator */
struct srte_policy *policy;
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- zlog_debug("Unset segment lists checking policy %s",
- policy->name);
+ PATH_POLICY_DEBUG("Unset segment lists checking policy %s",
+ policy->name);
struct srte_candidate *candidate;
RB_FOREACH (candidate, srte_candidate_head,
&policy->candidate_paths) {
- zlog_debug("Unset segment lists checking candidate %s",
- candidate->name);
+ PATH_POLICY_DEBUG(
+ "Unset segment lists checking candidate %s",
+ candidate->name);
if (candidate->lsp == NULL) {
continue;
}
@@ -1190,8 +1236,8 @@ void srte_candidate_unset_segment_list(const char *originator, bool force)
sizeof(segment_list->originator))
== 0
|| force) {
- zlog_debug("Unset segment list %s",
- segment_list->name);
+ PATH_POLICY_DEBUG("Unset segment list %s",
+ segment_list->name);
SET_FLAG(segment_list->flags,
F_SEGMENT_LIST_DELETED);
SET_FLAG(candidate->flags,
@@ -1222,6 +1268,12 @@ const char *srte_origin2str(enum srte_protocol_origin origin)
}
}
+void path_policy_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, " Path policy debugging is on\n");
+}
+
void pathd_shutdown(void)
{
path_ted_teardown();
@@ -1347,8 +1399,9 @@ int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
@@ -1377,8 +1430,9 @@ int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
@@ -1406,8 +1460,8 @@ int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
ted_sid);
} else {
- zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__,
- ted_sid);
+ PATH_TED_DEBUG("%s:SL: Success query F : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
diff --git a/pathd/pathd.h b/pathd/pathd.h
index 81d7aa9105..bb2e63c04b 100644
--- a/pathd/pathd.h
+++ b/pathd/pathd.h
@@ -43,6 +43,10 @@ enum srte_protocol_origin {
SRTE_ORIGIN_LOCAL = 3,
};
+extern struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG_BASIC 0x01
+
enum srte_policy_status {
SRTE_POLICY_STATUS_UNKNOWN = 0,
SRTE_POLICY_STATUS_DOWN = 1,
@@ -326,6 +330,8 @@ struct srte_candidate {
RB_HEAD(srte_candidate_head, srte_candidate);
RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
+#define ENDPOINT_STR_LENGTH IPADDR_STRING_SIZE
+
struct srte_policy {
RB_ENTRY(srte_policy) entry;
@@ -444,6 +450,7 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status);
void srte_candidate_unset_segment_list(const char *originator, bool force);
const char *srte_origin2str(enum srte_protocol_origin origin);
void pathd_shutdown(void);
+void path_policy_show_debugging(struct vty *vty);
/* path_cli.c */
void path_cli_init(void);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 6f272f0085..db9156b04b 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -689,7 +689,7 @@ static void pim_if_addr_del_pim(struct connected *ifc)
{
struct pim_interface *pim_ifp = ifc->ifp->info;
- if (ifc->address->family != AF_INET) {
+ if (ifc->address->family != PIM_AF) {
/* non-IPv4 address */
return;
}
@@ -843,7 +843,7 @@ void pim_if_addr_del_all(struct interface *ifp)
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
- if (p->family != AF_INET)
+ if (p->family != PIM_AF)
continue;
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
index 1a90b46dec..259c34c819 100644
--- a/pimd/pim_igmp_mtrace.c
+++ b/pimd/pim_igmp_mtrace.c
@@ -365,19 +365,9 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
if (ip_hdr->ip_ttl-- <= 1)
return -1;
- ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
-
- fd = pim_socket_raw(IPPROTO_RAW);
-
- if (fd < 0)
- return -1;
-
- pim_socket_ip_hdr(fd);
-
if (interface == NULL) {
memset(&nexthop, 0, sizeof(nexthop));
if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
- close(fd);
if (PIM_DEBUG_MTRACE)
zlog_debug(
"Dropping mtrace packet, no route to destination");
@@ -389,6 +379,15 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
if_out = interface;
}
+ ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
+
+ fd = pim_socket_raw(IPPROTO_RAW);
+
+ if (fd < 0)
+ return -1;
+
+ pim_socket_ip_hdr(fd);
+
ret = pim_socket_bind(fd, if_out);
if (ret < 0) {
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 12f8ffedfe..c4ff912cde 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -24,6 +24,7 @@
#include "lib/northbound_cli.h"
#include "pim_igmpv3.h"
#include "pim_neighbor.h"
+#include "pim_nht.h"
#include "pim_pim.h"
#include "pim_mlag.h"
#include "pim_bfd.h"
@@ -146,6 +147,7 @@ static int pim_cmd_interface_add(struct interface *ifp)
pim_ifp->pim_enable = true;
pim_if_addr_add_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
@@ -171,6 +173,7 @@ static int pim_cmd_interface_delete(struct interface *ifp)
if (!pim_ifp->gm_enable) {
pim_if_addr_del_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_delete(ifp);
}
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index f9a9aeb1b0..a33da64568 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -469,6 +469,40 @@ static int pim_update_upstream_nh(struct pim_instance *pim,
return 0;
}
+static int pim_upstream_nh_if_update_helper(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct pim_nexthop_cache *pnc = bucket->data;
+ struct pnc_hash_walk_data *pwd = arg;
+ struct pim_instance *pim = pwd->pim;
+ struct interface *ifp = pwd->ifp;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ if (ifp != if_lookup_by_index(first_ifindex, pim->vrf->vrf_id))
+ continue;
+
+ if (pnc->upstream_hash->count) {
+ pim_update_upstream_nh(pim, pnc);
+ break;
+ }
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp)
+{
+ struct pnc_hash_walk_data pwd;
+
+ pwd.pim = pim;
+ pwd.ifp = ifp;
+
+ hash_walk(pim->rpf_hash, pim_upstream_nh_if_update_helper, &pwd);
+}
+
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
{
uint32_t hash_val;
@@ -495,6 +529,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
uint32_t i, num_nbrs = 0;
+ struct pim_interface *pim_ifp;
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
@@ -611,10 +646,13 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
nh_iter++;
continue;
}
- if (!ifp->info) {
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (nh_iter == mod_val)
@@ -882,6 +920,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
uint32_t num_nbrs = 0;
+ struct pim_interface *pim_ifp;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
@@ -964,10 +1003,12 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (i == mod_val)
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
index 240e61d98f..f487a21ba4 100644
--- a/pimd/pim_nht.h
+++ b/pimd/pim_nht.h
@@ -53,6 +53,11 @@ struct pim_nexthop_cache {
uint32_t bsr_count;
};
+struct pnc_hash_walk_data {
+ struct pim_instance *pim;
+ struct interface *ifp;
+};
+
int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS);
int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp,
@@ -77,5 +82,5 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr);
/* RPF(bsr_addr) == src_ip%src_ifp? */
bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip);
-
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp);
#endif
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index f5834029a5..d237a73126 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -61,6 +61,7 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
ifindex_t first_ifindex = 0;
int found = 0;
int i = 0;
+ struct pim_interface *pim_ifp;
#if PIM_IPV == 4
/*
@@ -118,15 +119,16 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_ZEBRA)
zlog_debug(
- "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
+ "%s: pim not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
__func__, ifp->name, first_ifindex,
&addr);
i++;
- } else if (neighbor_needed
- && !pim_if_connected_to_source(ifp, addr)) {
+ } else if (neighbor_needed &&
+ !pim_if_connected_to_source(ifp, addr)) {
nbr = pim_neighbor_find(ifp,
nexthop_tab[i].nexthop_addr);
if (PIM_DEBUG_PIM_TRACE_DETAIL)
diff --git a/redhat/frr.pam b/redhat/frr.pam
index 5cef5d9d74..17a62f1999 100644
--- a/redhat/frr.pam
+++ b/redhat/frr.pam
@@ -5,6 +5,7 @@
# Only allow root (and possibly wheel) to use this because enable access
# is unrestricted.
auth sufficient pam_rootok.so
+account sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 8f469d2a07..afe75e1f26 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -469,7 +469,7 @@ ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr
install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr/frr.conf.template
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
-install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
+install -m644 %{zeb_src}/tools/etc/logrotate.d/frr %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
%if 0%{?rhel} > 7 || 0%{?fedora} > 29
diff --git a/tests/topotests/srv6_locator_usid/__init__.py b/tests/topotests/srv6_locator_usid/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/__init__.py
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_1.json b/tests/topotests/srv6_locator_usid/expected_chunks_1.json
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_1.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_2.json b/tests/topotests/srv6_locator_usid/expected_chunks_2.json
new file mode 100644
index 0000000000..304d73807c
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_2.json
@@ -0,0 +1,8 @@
+[
+ {
+ "name": "loc1",
+ "chunks": [
+ "fc00:0:1::/48"
+ ]
+ }
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_3.json b/tests/topotests/srv6_locator_usid/expected_chunks_3.json
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_3.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_4.json b/tests/topotests/srv6_locator_usid/expected_chunks_4.json
new file mode 100644
index 0000000000..fe51488c70
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_4.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_5.json b/tests/topotests/srv6_locator_usid/expected_chunks_5.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_5.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_6.json b/tests/topotests/srv6_locator_usid/expected_chunks_6.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_6.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_7.json b/tests/topotests/srv6_locator_usid/expected_chunks_7.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_7.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_8.json b/tests/topotests/srv6_locator_usid/expected_chunks_8.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_8.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_1.json b/tests/topotests/srv6_locator_usid/expected_locators_1.json
new file mode 100644
index 0000000000..c0eeacc09a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_1.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_2.json b/tests/topotests/srv6_locator_usid/expected_locators_2.json
new file mode 100644
index 0000000000..38a6739d64
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_2.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "sharp"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_3.json b/tests/topotests/srv6_locator_usid/expected_locators_3.json
new file mode 100644
index 0000000000..c0eeacc09a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_3.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_4.json b/tests/topotests/srv6_locator_usid/expected_locators_4.json
new file mode 100644
index 0000000000..b1528ff111
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_4.json
@@ -0,0 +1,35 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_5.json b/tests/topotests/srv6_locator_usid/expected_locators_5.json
new file mode 100644
index 0000000000..b6acc238a7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_5.json
@@ -0,0 +1,36 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_6.json b/tests/topotests/srv6_locator_usid/expected_locators_6.json
new file mode 100644
index 0000000000..b1528ff111
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_6.json
@@ -0,0 +1,35 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_7.json b/tests/topotests/srv6_locator_usid/expected_locators_7.json
new file mode 100644
index 0000000000..e965e02170
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_7.json
@@ -0,0 +1,19 @@
+{
+ "locators":[
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "statusUp": true,
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "chunks":[
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_8.json b/tests/topotests/srv6_locator_usid/expected_locators_8.json
new file mode 100644
index 0000000000..6e1b993ca8
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_8.json
@@ -0,0 +1,4 @@
+{
+ "locators":[
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/r1/setup.sh b/tests/topotests/srv6_locator_usid/r1/setup.sh
new file mode 100644
index 0000000000..36ed713f24
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/setup.sh
@@ -0,0 +1,2 @@
+ip link add dummy0 type dummy
+ip link set dummy0 up
diff --git a/tests/topotests/srv6_locator_usid/r1/sharpd.conf b/tests/topotests/srv6_locator_usid/r1/sharpd.conf
new file mode 100644
index 0000000000..d46085935c
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/sharpd.conf
@@ -0,0 +1,7 @@
+hostname r1
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file sharpd.log debugging
+!
diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf
new file mode 100644
index 0000000000..78ef1e9d40
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf
@@ -0,0 +1,20 @@
+hostname r1
+!
+! debug zebra events
+! debug zebra rib detailed
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file zebra.log debugging
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ behavior usid
+ !
+ !
+ !
+!
diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
new file mode 100755
index 0000000000..37fd736d2b
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, University of Rome Tor Vergata
+# Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
+#
+# 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_srv6_locator_usid.py:
+Test for SRv6 Locator uSID on zebra
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd]
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def setup_module(mod):
+ tgen = Topogen({None: "r1"}, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(
+ CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_SHARP, os.path.join(
+ CWD, "{}/sharpd.conf".format(rname))
+ )
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def _check_srv6_locator(router, expected_locator_file):
+ logger.info("checking zebra locator status")
+ output = json.loads(
+ router.vtysh_cmd("show segment-routing srv6 locator json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
+ return topotest.json_cmp(output, expected)
+
+
+def _check_sharpd_chunk(router, expected_chunk_file):
+ logger.info("checking sharpd locator chunk status")
+ output = json.loads(
+ router.vtysh_cmd("show sharp segment-routing srv6 json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
+ return topotest.json_cmp(output, expected)
+
+
+def check_srv6_locator(router, expected_file):
+ func = functools.partial(_check_srv6_locator, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def check_sharpd_chunk(router, expected_file):
+ func = functools.partial(_check_sharpd_chunk, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def test_srv6_usid_locator_configuration():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Verify SRv6 Locators instantiated from config file")
+ check_srv6_locator(router, "expected_locators_1.json")
+ check_sharpd_chunk(router, "expected_chunks_1.json")
+
+
+def test_srv6_usid_locator_get_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Get chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_2.json")
+ check_sharpd_chunk(router, "expected_chunks_2.json")
+
+
+def test_srv6_usid_locator_release_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Release chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_3.json")
+ check_sharpd_chunk(router, "expected_chunks_3.json")
+
+
+def test_srv6_usid_locator_create_locator():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Create an additional SRv6 Locator")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ """
+ )
+ check_srv6_locator(router, "expected_locators_4.json")
+ check_sharpd_chunk(router, "expected_chunks_4.json")
+
+
+def test_srv6_usid_locator_set_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_5.json")
+ check_sharpd_chunk(router, "expected_chunks_5.json")
+
+
+def test_srv6_usid_locator_unset_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Clear Micro-segment (uSID) Locator flag for loc2")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ no behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_6.json")
+ check_sharpd_chunk(router, "expected_chunks_6.json")
+
+
+def test_srv6_usid_locator_delete():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Delete locator loc1 and verify that the chunk is released automatically"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ no locator loc1
+ """
+ )
+ check_srv6_locator(router, "expected_locators_7.json")
+ check_sharpd_chunk(router, "expected_chunks_7.json")
+
+
+def test_srv6_usid_locator_delete_all():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Delete all the SRv6 configuration")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ no srv6
+ """
+ )
+ check_srv6_locator(router, "expected_locators_8.json")
+ check_sharpd_chunk(router, "expected_chunks_8.json")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/debian/frr.logrotate b/tools/etc/logrotate.d/frr
index 735af6539b..735af6539b 100644
--- a/debian/frr.logrotate
+++ b/tools/etc/logrotate.d/frr
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 61f1abb378..3c16c27c6d 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -335,7 +335,7 @@ if [ -z "$FRR_PATHSPACE" ]; then
load_old_config "/etc/sysconfig/frr"
fi
-if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
+if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare -a'; then
log_warning_msg "watchfrr_options contains a bash array value." \
"The configured value is intentionally ignored since it is likely wrong." \
"Please remove or fix the setting."
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index d07c4c6332..c5e1c113cb 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -98,6 +98,7 @@ struct fpm_nl_ctx {
struct thread *t_read;
struct thread *t_write;
struct thread *t_event;
+ struct thread *t_nhg;
struct thread *t_dequeue;
/* zebra events. */
@@ -271,7 +272,7 @@ DEFUN(fpm_use_nhg, fpm_use_nhg_cmd,
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
@@ -287,7 +288,7 @@ DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd,
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
@@ -1275,7 +1276,7 @@ static void fpm_process_queue(struct thread *t)
static void fpm_process_event(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
- int event = THREAD_VAL(t);
+ enum fpm_nl_events event = THREAD_VAL(t);
switch (event) {
case FNE_DISABLE:
@@ -1328,11 +1329,6 @@ static void fpm_process_event(struct thread *t)
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: LSP walk finished", __func__);
break;
-
- default:
- if (IS_ZEBRA_DEBUG_FPM)
- zlog_debug("%s: unhandled event %d", __func__, event);
- break;
}
}
@@ -1372,6 +1368,8 @@ static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
THREAD_OFF(fnc->t_ribwalk);
THREAD_OFF(fnc->t_rmacreset);
THREAD_OFF(fnc->t_rmacwalk);
+ THREAD_OFF(fnc->t_event);
+ THREAD_OFF(fnc->t_nhg);
thread_cancel_async(fnc->fthread->master, &fnc->t_read, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_write, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_connect, NULL);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index a3db53f296..130fb972db 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2606,8 +2606,10 @@ static void zread_sr_policy_set(ZAPI_HANDLER_ARGS)
return;
policy = zebra_sr_policy_find(zp.color, &zp.endpoint);
- if (!policy)
+ if (!policy) {
policy = zebra_sr_policy_add(zp.color, &zp.endpoint, zp.name);
+ policy->sock = client->sock;
+ }
/* TODO: per-VRF list of SR-TE policies. */
policy->zvrf = zvrf;
@@ -2710,6 +2712,7 @@ int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
chunk.keep = 0;
chunk.proto = client->proto;
chunk.instance = client->instance;
+ chunk.flags = loc->flags;
zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id);
zapi_srv6_locator_chunk_encode(s, &chunk);
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 168f0b2ce6..f207477445 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -1327,11 +1327,11 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
uint8_t flags, uint32_t seq,
const esi_t *esi)
{
- struct sync_mac_ip_ctx ctx;
char ipbuf[INET6_ADDRSTRLEN];
bool sticky;
bool remote_gw;
struct zebra_neigh *n = NULL;
+ struct zebra_mac *mac = NULL;
sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
@@ -1352,22 +1352,30 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
return;
}
- if (ipa_len) {
+ if (!ipa_len) {
+ /* MAC update */
+ (void)zebra_evpn_proc_sync_mac_update(zevpn, macaddr, ipa_len,
+ ipaddr, flags, seq, esi);
+ } else {
+ /* MAC-IP update */
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr,
+ ipa_len, ipaddr,
+ flags, seq, esi);
+ }
+ if (!mac)
+ return;
+
n = zebra_evpn_neigh_lookup(zevpn, ipaddr);
if (n
&& !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq,
true))
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);
+ zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr,
+ flags, seq, esi, mac);
+ }
}
/************************** remote mac-ip handling **************************/
@@ -1452,14 +1460,30 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
}
zvrf = zebra_vrf_get_evpn();
- if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len,
- ipaddr, &mac, vtep_ip, flags, seq,
- esi)
- != 0)
+ if (!zvrf)
return;
- zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip,
- flags, seq);
+ if (!ipa_len) {
+ /* MAC update */
+ zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, vtep_ip,
+ flags, seq, esi);
+ } else {
+ /* MAC-IP update
+ * Add auto MAC if it doesn't exist.
+ */
+ mac = zebra_evpn_mac_lookup(zevpn, macaddr);
+ if (!mac) {
+ mac = zebra_evpn_mac_add_auto(zevpn, macaddr);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Neigh %pIA: MAC %pEA not found, Auto MAC created",
+ ipaddr, macaddr);
+ }
+
+ zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac,
+ vtep_ip, flags, seq);
+ }
}
/* Process a remote MACIP delete from BGP. */
@@ -1504,7 +1528,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
if (n && !mac) {
zlog_warn(
- "Failed to locate MAC %pEA for neigh %pIA VNI %u upon remote MACIP DEL",
+ "Failed to locate MAC %pEA for Neigh %pIA VNI %u upon remote MACIP DEL",
macaddr, ipaddr, vni);
return;
}
@@ -1512,8 +1536,13 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
/* 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)
+ if (!mac && !n) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Failed to locate MAC %pEA & Neigh %pIA VNI %u upon remote MACIP DEL",
+ macaddr, ipaddr, vni);
return;
+ }
zvrf = zevpn->vxlan_if->vrf->info;
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index cbdc17653b..218184ad0d 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -1179,6 +1179,25 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
return 0;
}
+/*
+ * Add Auto MAC entry.
+ */
+struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
+ const struct ethaddr *macaddr)
+{
+ struct zebra_mac *mac;
+
+ mac = zebra_evpn_mac_add(zevpn, macaddr);
+ if (!mac)
+ return NULL;
+
+ zebra_evpn_mac_clear_fwd_info(mac);
+ memset(&mac->flags, 0, sizeof(uint32_t));
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+
+ return mac;
+}
+
static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
struct zebra_mac *mac)
{
@@ -1592,43 +1611,44 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
struct zebra_mac *mac,
- uint32_t seq, uint16_t ipa_len,
- const struct ipaddr *ipaddr,
- bool sync)
+ uint32_t seq, bool sync)
{
- char ipbuf[INET6_ADDRSTRLEN];
+ char mac_buf[MAC_BUF_SIZE];
uint32_t tmp_seq;
const char *n_type;
+ bool is_local = false;
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
tmp_seq = mac->loc_seq;
n_type = "local";
+ is_local = true;
} else {
tmp_seq = mac->rem_seq;
n_type = "remote";
}
if (seq < tmp_seq) {
+
+ if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
+ sync ? "sync" : "rem", zevpn->vni,
+ n_type, &mac->macaddr, tmp_seq,
+ mac->flags);
+ return true;
+ }
+
/* if the mac was never advertised to bgp we must accept
* whatever sequence number bgp sends
- * 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
- || IS_ZEBRA_DEBUG_VXLAN) {
- char mac_buf[MAC_BUF_SIZE];
-
+ if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
+ IS_ZEBRA_DEBUG_VXLAN) {
zlog_debug(
- "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
+ "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
sync ? "sync" : "rem", zevpn->vni,
- n_type,
- &mac->macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf))
- : "",
- tmp_seq,
+ n_type, &mac->macaddr, tmp_seq,
zebra_evpn_zebra_mac_flag_dump(
mac, mac_buf, sizeof(mac_buf)));
}
@@ -1637,30 +1657,26 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
}
if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
- char mac_buf[MAC_BUF_SIZE];
-
zlog_debug(
- "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
+ "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
sync ? "sync" : "rem", zevpn->vni, n_type,
- &mac->macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf))
- : "",
- tmp_seq,
+ &mac->macaddr, tmp_seq,
zebra_evpn_zebra_mac_flag_dump(
mac, mac_buf, sizeof(mac_buf)));
}
+
return false;
}
return true;
}
-struct zebra_mac *zebra_evpn_proc_sync_mac_update(
- struct zebra_evpn *zevpn, const struct ethaddr *macaddr,
- uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
- uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx)
+struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
+ const struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ const struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ const esi_t *esi)
{
struct zebra_mac *mac;
bool inform_bgp = false;
@@ -1672,6 +1688,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
bool old_local = false;
bool old_bgp_ready;
bool new_bgp_ready;
+ bool created = false;
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
@@ -1680,8 +1697,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
*/
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);
@@ -1699,6 +1714,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
old_bgp_ready = false;
new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
+ created = true;
} else {
uint32_t old_flags;
uint32_t new_flags;
@@ -1723,14 +1739,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
: "",
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, true)) {
- ctx->ignore_macip = true;
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
return NULL;
- }
old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
old_static = zebra_evpn_mac_is_static(mac);
@@ -1739,12 +1751,11 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
new_flags = 0;
SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
/* retain old local activity flag */
- if (old_flags & ZEBRA_MAC_LOCAL) {
+ if (old_flags & ZEBRA_MAC_LOCAL)
new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
- } else {
+ 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
@@ -1797,7 +1808,6 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
if (es_change) {
inform_bgp = true;
inform_dataplane = true;
- ctx->mac_inactive = true;
}
/* if peer-flag is being set notify dataplane that the
@@ -1828,8 +1838,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
char mac_buf[MAC_BUF_SIZE];
zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
- ctx->mac_created ? "created" : "updated",
- zevpn->vni, macaddr,
+ created ? "created" : "updated", zevpn->vni, macaddr,
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
sizeof(mac_buf)),
@@ -1848,22 +1857,15 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(
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__);
+ if (inform_dataplane && !ipa_len) {
+ /* 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, false /* set_inactive */,
+ false /* force_clear_static */,
+ __func__);
}
return mac;
@@ -1987,13 +1989,12 @@ void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
zebra_evpn_print_mac_hash_detail(bucket, ctxt);
}
-int zebra_evpn_mac_remote_macip_add(
- struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
- const struct ethaddr *macaddr, uint16_t ipa_len,
- const struct ipaddr *ipaddr, struct zebra_mac **macp,
- struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi)
+int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
+ struct zebra_vrf *zvrf,
+ const struct ethaddr *macaddr,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, const esi_t *esi)
{
- char buf1[INET6_ADDRSTRLEN];
bool sticky;
bool remote_gw;
int update_mac = 0;
@@ -2015,11 +2016,8 @@ int zebra_evpn_mac_remote_macip_add(
&& CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
- zevpn->vni, macaddr,
- ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
- : "");
+ "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
+ zevpn->vni, macaddr);
return -1;
}
@@ -2040,10 +2038,6 @@ int zebra_evpn_mac_remote_macip_add(
if (!mac) {
mac = zebra_evpn_mac_add(zevpn, macaddr);
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 {
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
@@ -2053,8 +2047,8 @@ int zebra_evpn_mac_remote_macip_add(
* the sequence number and ignore this update
* if appropriate.
*/
- if (!zebra_evpn_mac_is_bgp_seq_ok(
- zevpn, mac, seq, ipa_len, ipaddr, false))
+ if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
+ false))
return -1;
old_es_present = !!mac->es;
@@ -2138,12 +2132,7 @@ int zebra_evpn_mac_remote_macip_add(
/* 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;
+ UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
return 0;
}
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index b727ac1f98..9b4ea2b79e 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -176,17 +176,6 @@ struct rmac_walk_ctx {
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;
- struct zebra_mac *mac;
-};
-
/**************************** 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
@@ -232,6 +221,8 @@ struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevi,
const struct ethaddr *mac);
struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevi,
const struct ethaddr *macaddr);
+struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevi,
+ const struct ethaddr *macaddr);
int zebra_evpn_mac_del(struct zebra_evpn *zevi, struct zebra_mac *mac);
int zebra_evpn_macip_send_msg_to_client(uint32_t id,
const struct ethaddr *macaddr,
@@ -255,20 +246,22 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
uint32_t flags, bool force);
void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevi);
-struct zebra_mac *zebra_evpn_proc_sync_mac_update(
- struct zebra_evpn *zevi, const struct ethaddr *macaddr,
- uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
- uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx);
+struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevi,
+ const struct ethaddr *macaddr,
+ uint16_t ipa_len,
+ const struct ipaddr *ipaddr,
+ uint8_t flags, uint32_t seq,
+ const esi_t *esi);
void zebra_evpn_sync_mac_del(struct zebra_mac *mac);
void zebra_evpn_rem_mac_del(struct zebra_evpn *zevi, struct zebra_mac *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 zebra_evpn_mac_remote_macip_add(
- struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
- const struct ethaddr *macaddr, uint16_t ipa_len,
- const struct ipaddr *ipaddr, struct zebra_mac **macp,
- struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi);
+int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
+ struct zebra_vrf *zvrf,
+ const struct ethaddr *macaddr,
+ struct in_addr vtep_ip, uint8_t flags,
+ uint32_t seq, const esi_t *esi);
int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
struct zebra_evpn *zevpn,
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 98120accfd..01ea9c5b9c 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -2759,6 +2759,12 @@ bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
if (zif->zif_type == ZEBRA_IF_BOND)
return true;
+ /* relax the checks to allow config to be applied in zebra
+ * before interface is rxed from the kernel
+ */
+ if (zif->ifp->ifindex == IFINDEX_INTERNAL)
+ return true;
+
/* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
return false;
}
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 6d90a603f7..684720bb4d 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -501,22 +501,33 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn,
{
uint32_t tmp_seq;
const char *n_type;
+ bool is_local = false;
if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
tmp_seq = n->loc_seq;
n_type = "local";
+ is_local = true;
} else {
tmp_seq = n->rem_seq;
n_type = "remote";
}
if (seq < tmp_seq) {
+ if (is_local && !zebra_evpn_neigh_is_ready_for_bgp(n)) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH ||
+ IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s-macip not ready vni %u %s mac %pEA IP %pIA lower seq %u f 0x%x",
+ sync ? "sync" : "remote", zevpn->vni,
+ n_type, macaddr, &n->ip, tmp_seq,
+ n->flags);
+ return true;
+ }
+
/* 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_local && zebra_vxlan_get_accept_bgp_seq()) {
if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
|| IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@@ -615,11 +626,10 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n)
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
- const esi_t *esi, struct sync_mac_ip_ctx *ctx)
+ const esi_t *esi, struct zebra_mac *mac)
{
struct interface *ifp = NULL;
bool is_router;
- struct zebra_mac *mac = ctx->mac;
uint32_t tmp_seq;
bool old_router = false;
bool old_bgp_ready = false;
@@ -780,8 +790,8 @@ struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
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,
+ if (old_mac_static != new_mac_static)
+ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
false /* force_clear_static */,
__func__);
@@ -1275,10 +1285,12 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u",
macaddr, ip, zevpn->vni);
- zmac = zebra_evpn_mac_add(zevpn, macaddr);
- zebra_evpn_mac_clear_fwd_info(zmac);
- memset(&zmac->flags, 0, sizeof(uint32_t));
- SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO);
+ zmac = zebra_evpn_mac_add_auto(zevpn, macaddr);
+ if (!zmac) {
+ zlog_debug("Failed to add MAC %pEA VNI %u", macaddr,
+ zevpn->vni);
+ return -1;
+ }
} else {
if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
/*
@@ -2233,6 +2245,12 @@ void zebra_evpn_neigh_remote_uninstall(struct zebra_evpn *zevpn,
zebra_evpn_neigh_del(zevpn, n);
zebra_evpn_deref_ip2mac(zevpn, mac);
}
+ } else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "%s: IP %pIA MAC %pEA (flags 0x%x) found doesn't match MAC %pEA, ignoring Neigh DEL",
+ __func__, ipaddr, &n->emac, n->flags,
+ &mac->macaddr);
}
}
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
index c779109e0a..9271817440 100644
--- a/zebra/zebra_evpn_neigh.h
+++ b/zebra/zebra_evpn_neigh.h
@@ -231,7 +231,7 @@ void zebra_evpn_sync_neigh_del(struct zebra_neigh *n);
struct zebra_neigh *zebra_evpn_proc_sync_neigh_update(
struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len,
const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq,
- const esi_t *esi, struct sync_mac_ip_ctx *ctx);
+ const esi_t *esi, struct zebra_mac *mac);
void zebra_evpn_neigh_del_all(struct zebra_evpn *zevpn, int uninstall,
int upd_client, uint32_t flags);
struct zebra_neigh *zebra_evpn_neigh_lookup(struct zebra_evpn *zevpn,
diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c
index c0f18dd091..7d95607fcf 100644
--- a/zebra/zebra_srte.c
+++ b/zebra/zebra_srte.c
@@ -384,6 +384,23 @@ int zebra_sr_policy_label_update(mpls_label_t label,
return 0;
}
+static int zebra_srte_client_close_cleanup(struct zserv *client)
+{
+ int sock = client->sock;
+ struct zebra_sr_policy *policy;
+
+ if (!sock)
+ return 0;
+
+ RB_FOREACH (policy, zebra_sr_policy_instance_head,
+ &zebra_sr_policy_instances) {
+ if (policy->sock == sock)
+ zebra_sr_policy_del(policy);
+ }
+ return 1;
+}
+
void zebra_srte_init(void)
{
+ hook_register(zserv_client_close, zebra_srte_client_close_cleanup);
}
diff --git a/zebra/zebra_srte.h b/zebra/zebra_srte.h
index fe77809446..dff2f595fd 100644
--- a/zebra/zebra_srte.h
+++ b/zebra/zebra_srte.h
@@ -45,6 +45,7 @@ struct zebra_sr_policy {
struct zapi_srte_tunnel segment_list;
struct zebra_lsp *lsp;
struct zebra_vrf *zvrf;
+ int sock;
};
RB_HEAD(zebra_sr_policy_instance_head, zebra_sr_policy);
RB_PROTOTYPE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index 36506cacc7..d61e4f8045 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -177,6 +177,58 @@ struct srv6_locator *zebra_srv6_locator_lookup(const char *name)
return NULL;
}
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ /*
+ * Notify new locator info to zclients.
+ *
+ * The srv6 locators and their prefixes are managed by zserv(zebra).
+ * And an actual configuration the srv6 sid in the srv6 locator is done
+ * by zclient(bgpd, isisd, etc). The configuration of each locator
+ * allocation and specify it by zserv and zclient should be
+ * asynchronous. For that, zclient should be received the event via
+ * ZAPI when a srv6 locator is added on zebra.
+ * Basically, in SRv6, adding/removing SRv6 locators is performed less
+ * frequently than adding rib entries, so a broad to all zclients will
+ * not degrade the overall performance of FRRouting.
+ */
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_zebra_srv6_locator_add(client, locator);
+}
+
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
+{
+ struct listnode *n;
+ struct srv6_locator_chunk *c;
+ struct zserv *client;
+
+ /*
+ * Notify deleted locator info to zclients if needed.
+ *
+ * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
+ * uses it for its own purpose. For example, in the case of BGP L3VPN,
+ * the SID assigned to vpn unicast rib will be given.
+ * And when the locator is deleted by zserv(zebra), those SIDs need to
+ * be withdrawn. The zclient must initiate the withdrawal of the SIDs
+ * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
+ * owner of each chunk.
+ */
+ for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
+ if (c->proto == ZEBRA_ROUTE_SYSTEM)
+ continue;
+ client = zserv_find_client(c->proto, c->instance);
+ if (!client) {
+ zlog_warn("Not found zclient(proto=%u, instance=%u).",
+ c->proto, c->instance);
+ continue;
+ }
+ zsend_zebra_srv6_locator_delete(client, locator);
+ }
+}
+
struct zebra_srv6 *zebra_srv6_get_default(void)
{
static struct zebra_srv6 srv6;
diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h
index 84fcc305bc..f320b9ca0f 100644
--- a/zebra/zebra_srv6.h
+++ b/zebra/zebra_srv6.h
@@ -61,6 +61,9 @@ extern void zebra_srv6_locator_add(struct srv6_locator *locator);
extern void zebra_srv6_locator_delete(struct srv6_locator *locator);
extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name);
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator);
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator);
+
extern void zebra_srv6_init(void);
extern struct zebra_srv6 *zebra_srv6_get_default(void);
extern bool zebra_srv6_is_enable(void);
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index e6810bdc56..1221365d4d 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -172,6 +172,9 @@ DEFUN (show_srv6_locator_detail,
vty_out(vty, "Argument-Bit-Len: %u\n",
locator->argument_bits_length);
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, "Behavior: uSID\n");
+
vty_out(vty, "Chunks:\n");
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
chunk)) {
@@ -369,6 +372,38 @@ DEFPY (locator_prefix,
return CMD_SUCCESS;
}
+DEFPY (locator_behavior,
+ locator_behavior_cmd,
+ "[no] behavior usid",
+ NO_STR
+ "Configure SRv6 behavior\n"
+ "Specify SRv6 behavior uSID\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_locator, locator);
+
+ if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already unset, nothing to do */
+ return CMD_SUCCESS;
+
+ if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already set, nothing to do */
+ return CMD_SUCCESS;
+
+ /* Remove old locator from zclients */
+ zebra_notify_srv6_locator_delete(locator);
+
+ /* Set/Unset the SRV6_LOCATOR_USID */
+ if (no)
+ UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+ else
+ SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+
+ /* Notify the new locator to zclients */
+ zebra_notify_srv6_locator_add(locator);
+
+ return CMD_SUCCESS;
+}
+
static int zebra_sr_config(struct vty *vty)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
@@ -399,6 +434,8 @@ static int zebra_sr_config(struct vty *vty)
if (locator->argument_bits_length)
vty_out(vty, " arg-len %u",
locator->argument_bits_length);
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, " behavior usid");
vty_out(vty, "\n");
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
@@ -435,6 +472,7 @@ void zebra_srv6_vty_init(void)
/* Command for configuration */
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
+ install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
/* Command for operation */
install_element(VIEW_NODE, &show_srv6_locator_cmd);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 40b400f104..6561ac95fa 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -3747,6 +3747,27 @@ DEFPY (clear_evpn_dup_addr,
return ret;
}
+DEFPY_HIDDEN (evpn_accept_bgp_seq,
+ evpn_accept_bgp_seq_cmd,
+ "evpn accept-bgp-seq",
+ "EVPN\n"
+ "Accept all sequence numbers from BGP\n")
+{
+ zebra_vxlan_set_accept_bgp_seq(true);
+ return CMD_SUCCESS;
+}
+
+DEFPY_HIDDEN (no_evpn_accept_bgp_seq,
+ no_evpn_accept_bgp_seq_cmd,
+ "no evpn accept-bgp-seq",
+ NO_STR
+ "EVPN\n"
+ "Accept all sequence numbers from BGP\n")
+{
+ zebra_vxlan_set_accept_bgp_seq(false);
+ return CMD_SUCCESS;
+}
+
/* Static ip route configuration write function. */
static int zebra_ip_config(struct vty *vty)
{
@@ -3952,6 +3973,9 @@ static int config_write_protocol(struct vty *vty)
zebra_pbr_config_write(vty);
+ if (!zebra_vxlan_get_accept_bgp_seq())
+ vty_out(vty, "no evpn accept-bgp-seq\n");
+
/* Include nexthop-group config */
if (!zebra_nhg_kernel_nexthops_enabled())
vty_out(vty, "no zebra nexthop kernel enable\n");
@@ -4589,6 +4613,8 @@ void zebra_vty_init(void)
install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd);
install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd);
+ install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd);
+ install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd);
install_element(VIEW_NODE, &show_neigh_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 34cce71cd7..f1c7debe11 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -69,6 +69,9 @@ DEFINE_HOOK(zebra_rmac_update,
const char *reason),
(rmac, zl3vni, delete, reason));
+/* config knobs */
+static bool accept_bgp_seq = true;
+
/* static function declarations */
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
void **args);
@@ -6284,6 +6287,17 @@ extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx)
return;
}
+/* Config knob for accepting lower sequence numbers */
+void zebra_vxlan_set_accept_bgp_seq(bool set)
+{
+ accept_bgp_seq = set;
+}
+
+bool zebra_vxlan_get_accept_bgp_seq(void)
+{
+ return accept_bgp_seq;
+}
+
/* Cleanup BGP EVPN configuration upon client disconnect */
extern void zebra_evpn_init(void)
{
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 757c65d185..121e5633d6 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -225,6 +225,9 @@ extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct ethaddr *macaddr,
vlanid_t vid);
+extern void zebra_vxlan_set_accept_bgp_seq(bool set);
+extern bool zebra_vxlan_get_accept_bgp_seq(void);
+
#ifdef __cplusplus
}
#endif