summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/neighbour.c67
-rw-r--r--bgpd/bgp_addpath.h6
-rw-r--r--bgpd/bgp_aspath.h8
-rw-r--r--bgpd/bgp_attr.c12
-rw-r--r--bgpd/bgp_attr.h5
-rw-r--r--bgpd/bgp_filter.c20
-rw-r--r--bgpd/bgp_filter.h6
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--bgpd/bgp_mpath.c12
-rw-r--r--bgpd/bgp_mplsvpn.c12
-rw-r--r--bgpd/bgp_nht.c55
-rw-r--r--bgpd/bgp_open.c88
-rw-r--r--bgpd/bgp_open.h2
-rw-r--r--bgpd/bgp_packet.c128
-rw-r--r--bgpd/bgp_route.c28
-rw-r--r--bgpd/bgp_routemap.c38
-rw-r--r--bgpd/bgp_routemap_nb.c11
-rw-r--r--bgpd/bgp_routemap_nb.h17
-rw-r--r--bgpd/bgp_routemap_nb_config.c134
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c6
-rw-r--r--bgpd/bgp_updgrp.c7
-rw-r--r--bgpd/bgp_updgrp_adv.c34
-rw-r--r--bgpd/bgp_vty.c203
-rw-r--r--bgpd/bgp_zebra.c28
-rw-r--r--bgpd/bgpd.c5
-rw-r--r--bgpd/bgpd.h13
-rw-r--r--doc/user/bgp.rst36
-rw-r--r--doc/user/isisd.rst6
-rw-r--r--fpm/fpm.proto145
-rw-r--r--fpm/fpm_pb.h400
-rw-r--r--isisd/isis_spf.c118
-rw-r--r--isisd/isis_sr.c26
-rw-r--r--lib/affinitymap_northbound.c3
-rw-r--r--lib/base64.c9
-rw-r--r--lib/base64.h1
-rw-r--r--lib/filter.c3
-rw-r--r--lib/filter.h1
-rw-r--r--lib/filter_nb.c171
-rw-r--r--lib/mgmt_fe_client.c30
-rw-r--r--lib/mgmt_fe_client.h3
-rw-r--r--lib/northbound.c32
-rw-r--r--lib/routemap.c29
-rw-r--r--ospfd/ospf_ldp_sync.c2
-rw-r--r--ospfd/ospf_ri.c15
-rw-r--r--ospfd/ospf_te.c4
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/__init__.py0
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r1/frr.conf13
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r2/frr.conf37
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r3/frr.conf16
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r4/frr.conf16
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r5/frr.conf16
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r6/frr.conf16
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/r7/frr.conf13
-rw-r--r--tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py128
-rw-r--r--tests/topotests/bgp_evpn_mh/test_evpn_mh.py25
-rw-r--r--tests/topotests/bgp_evpn_route_map_match/r1/frr.conf16
-rw-r--r--tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py6
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json2
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json2
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py104
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf5
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf9
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf61
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf32
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf50
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf4
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf29
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf50
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf6
-rw-r--r--tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf29
-rwxr-xr-xtests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py169
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf6
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py229
-rw-r--r--tests/topotests/lib/checkping.py12
-rwxr-xr-xtests/topotests/lib/fe_client.py2
-rw-r--r--tests/topotests/mgmt_config/test_regression.py20
-rw-r--r--tests/topotests/nb_config/r1/frr.conf6
-rw-r--r--tests/topotests/nb_config/test_nb_config.py69
-rw-r--r--yang/frr-bgp-route-map.yang6
-rw-r--r--zebra/dpdk/zebra_dplane_dpdk.c51
-rw-r--r--zebra/zebra_evpn.c140
-rw-r--r--zebra/zebra_nb.c16
-rw-r--r--zebra/zebra_nb.h6
-rw-r--r--zebra/zebra_nb_config.c75
-rw-r--r--zebra/zebra_vxlan.c4
102 files changed, 2917 insertions, 614 deletions
diff --git a/babeld/neighbour.c b/babeld/neighbour.c
index 51e595a84b..65e613cc8b 100644
--- a/babeld/neighbour.c
+++ b/babeld/neighbour.c
@@ -34,15 +34,13 @@ find_neighbour_nocreate(const unsigned char *address, struct interface *ifp)
{
struct neighbour *neigh;
FOR_ALL_NEIGHBOURS(neigh) {
- if(memcmp(address, neigh->address, 16) == 0 &&
- neigh->ifp == ifp)
+ if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp)
return neigh;
}
return NULL;
}
-void
-flush_neighbour(struct neighbour *neigh)
+void flush_neighbour(struct neighbour *neigh)
{
debugf(BABEL_DEBUG_COMMON,"Flushing neighbour %s (reach 0x%04x)",
format_address(neigh->address), neigh->reach);
@@ -102,8 +100,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
}
/* Recompute a neighbour's rxcost. Return true if anything changed. */
-int
-update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
+int update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
{
int missed_hellos;
int rc = 0;
@@ -160,26 +157,26 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
if(hello >= 0) {
neigh->hello_seqno = hello;
neigh->reach >>= 1;
- neigh->reach |= 0x8000;
- if((neigh->reach & 0xFC00) != 0xFC00)
+ SET_FLAG(neigh->reach, 0x8000);
+ if(CHECK_FLAG(neigh->reach, 0xFC00) != 0xFC00)
rc = 1;
}
/* Make sure to give neighbours some feedback early after association */
- if((neigh->reach & 0xBF00) == 0x8000) {
+ if(CHECK_FLAG(neigh->reach, 0xBF00) == 0x8000) {
/* A new neighbour */
send_hello(neigh->ifp);
} else {
/* Don't send hellos, in order to avoid a positive feedback loop. */
- int a = (neigh->reach & 0xC000);
- int b = (neigh->reach & 0x3000);
+ int a = CHECK_FLAG(neigh->reach, 0xC000);
+ int b = CHECK_FLAG(neigh->reach, 0x3000);
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
/* Reachability is either 1100 or 0011 */
send_self_update(neigh->ifp);
}
}
- if((neigh->reach & 0xFC00) == 0xC000) {
+ if(CHECK_FLAG(neigh->reach, 0xFC00) == 0xC000) {
/* This is a newish neighbour, let's request a full route dump.
We ought to avoid this when the network is dense */
send_unicast_request(neigh, NULL, 0);
@@ -188,8 +185,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
return rc;
}
-static int
-reset_txcost(struct neighbour *neigh)
+static int reset_txcost(struct neighbour *neigh)
{
unsigned delay;
@@ -199,9 +195,8 @@ reset_txcost(struct neighbour *neigh)
return 0;
/* If we're losing a lot of packets, we probably lost an IHU too */
- if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 ||
- (neigh->ihu_interval > 0 &&
- delay >= neigh->ihu_interval * 10U * 10U)) {
+ if (delay >= 180000 || CHECK_FLAG(neigh->reach, 0xFFF0) == 0 ||
+ (neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) {
neigh->txcost = INFINITY;
neigh->ihu_time = babel_now;
return 1;
@@ -210,14 +205,12 @@ reset_txcost(struct neighbour *neigh)
return 0;
}
-unsigned
-neighbour_txcost(struct neighbour *neigh)
+unsigned neighbour_txcost(struct neighbour *neigh)
{
return neigh->txcost;
}
-unsigned
-check_neighbours(void)
+unsigned check_neighbours(void)
{
struct neighbour *neigh;
int changed, rc;
@@ -253,21 +246,20 @@ check_neighbours(void)
return msecs;
}
-unsigned
-neighbour_rxcost(struct neighbour *neigh)
+unsigned neighbour_rxcost(struct neighbour *neigh)
{
unsigned delay;
unsigned short reach = neigh->reach;
delay = timeval_minus_msec(&babel_now, &neigh->hello_time);
- if((reach & 0xFFF0) == 0 || delay >= 180000) {
+ if(CHECK_FLAG(reach, 0xFFF0) == 0 || delay >= 180000) {
return INFINITY;
- } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) {
+ } else if (CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)) {
int sreach =
- ((reach & 0x8000) >> 2) +
- ((reach & 0x4000) >> 1) +
- (reach & 0x3FFF);
+ (CHECK_FLAG(reach, 0x8000) >> 2) +
+ (CHECK_FLAG(reach, 0x4000) >> 1) +
+ CHECK_FLAG(reach, 0x3FFF);
/* 0 <= sreach <= 0x7FFF */
int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1);
/* cost >= interface->cost */
@@ -276,19 +268,18 @@ neighbour_rxcost(struct neighbour *neigh)
return MIN(cost, INFINITY);
} else {
/* To lose one hello is a misfortune, to lose two is carelessness. */
- if((reach & 0xC000) == 0xC000)
+ if (CHECK_FLAG(reach, 0xC000) == 0xC000)
return babel_get_if_nfo(neigh->ifp)->cost;
- else if((reach & 0xC000) == 0)
+ else if (CHECK_FLAG(reach, 0xC000) == 0)
return INFINITY;
- else if((reach & 0x2000))
+ else if (CHECK_FLAG(reach, 0x2000))
return babel_get_if_nfo(neigh->ifp)->cost;
else
return INFINITY;
}
}
-unsigned
-neighbour_rttcost(struct neighbour *neigh)
+unsigned neighbour_rttcost(struct neighbour *neigh)
{
struct interface *ifp = neigh->ifp;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
@@ -304,15 +295,14 @@ neighbour_rttcost(struct neighbour *neigh)
(unsigned long long)babel_ifp->max_rtt_penalty *
(neigh->rtt - babel_ifp->rtt_min) /
(babel_ifp->rtt_max - babel_ifp->rtt_min);
- assert((tmp & 0x7FFFFFFF) == tmp);
+ assert(CHECK_FLAG(tmp, 0x7FFFFFFF) == tmp);
return tmp;
} else {
return babel_ifp->max_rtt_penalty;
}
}
-unsigned
-neighbour_cost(struct neighbour *neigh)
+unsigned neighbour_cost(struct neighbour *neigh)
{
unsigned a, b, cost;
@@ -328,7 +318,7 @@ neighbour_cost(struct neighbour *neigh)
if(b >= INFINITY)
return INFINITY;
- if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ)
+ if (!CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)
|| (a < 256 && b < 256)) {
cost = a;
} else {
@@ -347,8 +337,7 @@ neighbour_cost(struct neighbour *neigh)
return MIN(cost, INFINITY);
}
-int
-valid_rtt(struct neighbour *neigh)
+int valid_rtt(struct neighbour *neigh)
{
return (timeval_minus_msec(&babel_now, &neigh->rtt_time) < 180000) ? 1 : 0;
}
diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h
index d562000e30..b19e63c946 100644
--- a/bgpd/bgp_addpath.h
+++ b/bgpd/bgp_addpath.h
@@ -21,6 +21,12 @@ struct bgp_addpath_capability {
uint8_t flags;
};
+struct bgp_paths_limit_capability {
+ uint16_t afi;
+ uint8_t safi;
+ uint16_t paths_limit;
+};
+
#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index ebfc7d087d..2a831c3a55 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -65,6 +65,14 @@ struct aspath {
#define ASPATH_STR_DEFAULT_LEN 32
+/* `set as-path exclude ASn' */
+struct aspath_exclude {
+ struct aspath *aspath;
+ bool exclude_all;
+ char *exclude_aspath_acl_name;
+ struct as_list *exclude_aspath_acl;
+};
+
/* Prototypes. */
extern void aspath_init(void);
extern void aspath_finish(void);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index edfbc6c835..0dec8ea4e4 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2347,6 +2347,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
@@ -2364,6 +2370,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
if (attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index d78f04c6dd..5386f24a0b 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -158,6 +158,8 @@ struct attr {
uint8_t nh_flags;
#define BGP_ATTR_NH_VALID 0x01
+#define BGP_ATTR_NH_IF_OPERSTATE 0x02
+#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */
/* Path origin attribute */
uint8_t origin;
@@ -254,9 +256,6 @@ struct attr {
/* MP Nexthop length */
uint8_t mp_nexthop_len;
- /* MP Nexthop preference */
- uint8_t mp_nexthop_prefer_global;
-
/* Static MAC for EVPN */
uint8_t sticky;
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index ad541b67ad..a85117965a 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -205,8 +205,17 @@ static struct as_list *as_list_new(void)
static void as_list_free(struct as_list *aslist)
{
- XFREE(MTYPE_AS_STR, aslist->name);
- XFREE(MTYPE_AS_LIST, aslist);
+ struct aspath_exclude_list *cur_bp = aslist->exclude_list;
+ struct aspath_exclude_list *next_bp = NULL;
+
+ while (cur_bp) {
+ next_bp = cur_bp->next;
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp);
+ cur_bp = next_bp;
+ }
+
+ XFREE (MTYPE_AS_STR, aslist->name);
+ XFREE (MTYPE_AS_LIST, aslist);
}
/* Insert new AS list to list of as_list. Each as_list is sorted by
@@ -290,6 +299,7 @@ static void as_list_delete(struct as_list *aslist)
{
struct as_list_list *list;
struct as_filter *filter, *next;
+ struct aspath_exclude_list *cur_bp;
for (filter = aslist->head; filter; filter = next) {
next = filter->next;
@@ -308,6 +318,12 @@ static void as_list_delete(struct as_list *aslist)
else
list->head = aslist->next;
+ cur_bp = aslist->exclude_list;
+ while (cur_bp) {
+ cur_bp->bp_as_excl->exclude_aspath_acl = NULL;
+ cur_bp = cur_bp->next;
+ }
+
as_list_free(aslist);
}
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index 1890fd3d96..2d9f07ce84 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -25,6 +25,11 @@ struct as_filter {
int64_t seq;
};
+struct aspath_exclude_list {
+ struct aspath_exclude_list *next;
+ struct aspath_exclude *bp_as_excl;
+};
+
/* AS path filter list. */
struct as_list {
char *name;
@@ -34,6 +39,7 @@ struct as_list {
struct as_filter *head;
struct as_filter *tail;
+ struct aspath_exclude_list *exclude_list;
};
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 234dbb0715..657c7e22d7 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi];
peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi];
peer->llgr[afi][safi] = from_peer->llgr[afi][safi];
+ peer->addpath_paths_limit[afi][safi] =
+ from_peer->addpath_paths_limit[afi][safi];
}
if (bgp_getsockname(peer) < 0) {
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index c773c21fb7..296e64003d 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -129,15 +129,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
&bpi2->attr->mp_nexthop_global);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- addr1 = (bpi1->attr->mp_nexthop_prefer_global)
+ addr1 = (CHECK_FLAG(bpi1->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi1->attr->mp_nexthop_global
: bpi1->attr->mp_nexthop_local;
- addr2 = (bpi2->attr->mp_nexthop_prefer_global)
+ addr2 = (CHECK_FLAG(bpi2->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi2->attr->mp_nexthop_global
: bpi2->attr->mp_nexthop_local;
- if (!bpi1->attr->mp_nexthop_prefer_global
- && !bpi2->attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(bpi1->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL) &&
+ !CHECK_FLAG(bpi2->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
compare = !bgp_interface_same(
bpi1->peer->ifp,
bpi2->peer->ifp);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index cd5cf5be54..91bc3b1a88 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -2093,8 +2093,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
struct bgp_path_info *bpi;
int origin_local = 0;
struct bgp *src_vrf;
- struct interface *ifp;
+ struct interface *ifp = NULL;
char rd_buf[RD_ADDRSTRLEN];
+
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
@@ -2260,6 +2261,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
break;
}
+ if (!ifp && static_attr.nh_ifindex)
+ ifp = if_lookup_by_index(static_attr.nh_ifindex,
+ src_vrf->vrf_id);
+
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+
/*
* route map handling
*/
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index e2c103bb52..884fabf077 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
struct bgp_path_info *path)
{
+ return (bnc && (bnc->nexthop_num > 0 &&
+ (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
+ bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
+ bgp_isvalid_nexthop_for_mplsovergre(bnc, path))));
+}
+
+static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc,
+ struct bgp_path_info *path)
+{
+ if (bgp_zebra_num_connects() == 0)
+ return 1;
+
+ if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) {
+ /* In the case of SRv6-VPN, we need to track the reachability to the
+ * SID (in other words, IPv6 address). We check that the SID is
+ * available in the BGP update; then if it is available, we check
+ * for the nexthop reachability.
+ */
+ if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc)))
+ return 1;
+ return 0;
+ }
/*
- * - In the case of MPLS-VPN, the label is learned from LDP or other
+ * In the case of MPLS-VPN, the label is learned from LDP or other
* protocols, and nexthop tracking is enabled for the label.
* The value is recorded as BGP_NEXTHOP_LABELED_VALID.
- * - In the case of SRv6-VPN, we need to track the reachability to the
- * SID (in other words, IPv6 address). As in MPLS, we need to record
- * the value as BGP_NEXTHOP_SID_VALID. However, this function is
- * currently not implemented, and this function assumes that all
- * Transit routes for SRv6-VPN are valid.
* - Otherwise check for mpls-gre acceptance
*/
- return (bgp_zebra_num_connects() == 0 ||
- (bnc && (bnc->nexthop_num > 0 &&
- (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
- CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
- bnc->bgp->srv6_enabled ||
- bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
- bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
+ return bgp_isvalid_nexthop_for_mpls(bnc, path);
}
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
@@ -496,7 +508,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
else if (safi == SAFI_UNICAST && pi &&
pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra &&
pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop)
- return bgp_isvalid_nexthop_for_mpls(bnc, pi);
+ return bgp_isvalid_nexthop_for_l3vpn(bnc, pi);
else if (safi == SAFI_MPLS_VPN && pi &&
pi->sub_type != BGP_ROUTE_IMPORTED)
/* avoid not redistributing mpls vpn routes */
@@ -1045,8 +1057,11 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
break;
case AFI_IP6:
p->family = AF_INET6;
-
- if (is_bgp_static) {
+ if (pi->attr && pi->attr->srv6_l3vpn) {
+ IPV6_ADDR_COPY(&(p->u.prefix6),
+ &(pi->attr->srv6_l3vpn->sid));
+ p->prefixlen = IPV6_MAX_BITLEN;
+ } else if (is_bgp_static) {
p->u.prefix6 = p_orig->u.prefix6;
p->prefixlen = p_orig->prefixlen;
} else {
@@ -1065,7 +1080,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
else if (pi->attr->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- if (pi->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(pi->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
p->u.prefix6 =
pi->attr->mp_nexthop_global;
else
@@ -1294,8 +1310,9 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
&& (path->attr->evpn_overlay.type
!= OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
- bgp_isvalid_nexthop_for_mpls(bnc, path) ? true
- : false;
+ bgp_isvalid_nexthop_for_l3vpn(bnc, path)
+ ? true
+ : false;
} else if (safi == SAFI_MPLS_VPN &&
path->sub_type != BGP_ROUTE_IMPORTED) {
/* avoid not redistributing mpls vpn routes */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 43a59e2448..aa1d81362b 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -42,6 +42,7 @@ const struct message capcode_str[] = {
{ CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" },
{ CAPABILITY_CODE_ROLE, "Role" },
{ CAPABILITY_CODE_SOFT_VERSION, "Software Version" },
+ { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" },
{ 0 }
};
@@ -61,6 +62,7 @@ static const size_t cap_minsizes[] = {
[CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
[CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,
[CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN,
+ [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN,
};
/* value the capability must be a multiple of.
@@ -83,6 +85,7 @@ static const size_t cap_modsizes[] = {
[CAPABILITY_CODE_LLGR] = 1,
[CAPABILITY_CODE_ROLE] = 1,
[CAPABILITY_CODE_SOFT_VERSION] = 1,
+ [CAPABILITY_CODE_PATHS_LIMIT] = 5,
};
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
@@ -739,6 +742,62 @@ static int bgp_capability_addpath(struct peer *peer,
return 0;
}
+static int bgp_capability_paths_limit(struct peer *peer,
+ struct capability_header *hdr)
+{
+ struct stream *s = BGP_INPUT(peer);
+ size_t end = stream_get_getp(s) + hdr->length;
+
+ if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "Paths-Limit: Received invalid length %d, non-multiple of %d",
+ hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN);
+ return -1;
+ }
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_DATA,
+ "Paths-Limit: Received Paths-Limit capability without Add-Path capability");
+ return -1;
+ }
+
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+
+ while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi = stream_getw(s);
+ iana_safi_t pkt_safi = stream_getc(s);
+ uint16_t paths_limit = stream_getw(s);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u",
+ peer->host,
+ lookup_msg(capcode_str, hdr->code, NULL),
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi), paths_limit);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ continue;
+ } else if (!peer->afc[afi][safi]) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ continue;
+ }
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV);
+ peer->addpath_paths_limit[afi][safi].receive = paths_limit;
+ }
+
+ return 0;
+}
+
static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
{
struct stream *s = BGP_INPUT(peer);
@@ -1012,6 +1071,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_EXT_MESSAGE:
case CAPABILITY_CODE_ROLE:
case CAPABILITY_CODE_SOFT_VERSION:
+ case CAPABILITY_CODE_PATHS_LIMIT:
/* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code]) {
zlog_info(
@@ -1113,6 +1173,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_SOFT_VERSION:
ret = bgp_capability_software_version(peer, &caphdr);
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ ret = bgp_capability_paths_limit(peer, &caphdr);
+ break;
default:
if (caphdr.code > 128) {
/* We don't send Notification for unknown vendor
@@ -1874,6 +1937,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
}
}
+ /* Paths-Limit capability */
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV);
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ afi_safi_count) +
+ 2)
+ : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ afi_safi_count) +
+ 2);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putw(s, peer->addpath_paths_limit[afi][safi].send);
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV);
+ }
+
/* ORF capability. */
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(peer->af_flags[afi][safi],
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 34f4b7619e..a01e49ceba 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -53,6 +53,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
#define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */
#define CAPABILITY_CODE_ROLE 9 /* Role Capability */
+#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */
/* Capability Length */
#define CAPABILITY_CODE_MP_LEN 4
@@ -61,6 +62,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */
#define CAPABILITY_CODE_AS4_LEN 4
#define CAPABILITY_CODE_ADDPATH_LEN 4
+#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5
#define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
#define CAPABILITY_CODE_MIN_FQDN_LEN 2
#define CAPABILITY_CODE_ENHANCED_LEN 0
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9d484d901a..da352a8441 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1224,7 +1224,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
if (!peer_established(peer->connection))
return;
- if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) ||
!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
return;
@@ -1462,6 +1462,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi2str(pkt_safi));
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ addpath_afi_safi_count++;
+ }
+
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ addpath_afi_safi_count);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
+ &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putw(s,
+ peer->addpath_paths_limit[afi][safi].send);
+
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u",
+ peer,
+ action == CAPABILITY_ACTION_SET
+ ? "Advertising"
+ : "Removing",
+ capability, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi),
+ peer->addpath_paths_limit[afi][safi]
+ .send);
+ }
+
+ break;
case CAPABILITY_CODE_ORF:
/* Convert AFI, SAFI to values for packet. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
@@ -3170,6 +3213,85 @@ ignore:
}
}
+static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
+ struct capability_header *hdr,
+ struct peer *peer)
+{
+ uint8_t *data = pnt + 3;
+ uint8_t *end = data + hdr->length;
+ size_t len = end - data;
+ afi_t afi;
+ safi_t safi;
+
+ if (action == CAPABILITY_ACTION_SET) {
+ if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "Paths-Limit: Received invalid length %zu, non-multiple of %d",
+ len, CAPABILITY_CODE_PATHS_LIMIT_LEN);
+ return;
+ }
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_DATA,
+ "Paths-Limit: Received Paths-Limit capability without Add-Path capability");
+ goto ignore;
+ }
+
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+
+ while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi;
+ iana_safi_t pkt_safi;
+ struct bgp_paths_limit_capability bpl = {};
+
+ memcpy(&bpl, data, sizeof(bpl));
+ pkt_afi = ntohs(bpl.afi);
+ pkt_safi = safi_int2iana(bpl.safi);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u",
+ peer->host,
+ lookup_msg(capcode_str, hdr->code,
+ NULL),
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi),
+ bpl.paths_limit);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi,
+ &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host,
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ goto ignore;
+ } else if (!peer->afc[afi][safi]) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host,
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ goto ignore;
+ }
+
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV);
+ peer->addpath_paths_limit[afi][safi].receive =
+ bpl.paths_limit;
+ignore:
+ data += CAPABILITY_CODE_PATHS_LIMIT_LEN;
+ }
+ } else {
+ FOREACH_AFI_SAFI (afi, safi)
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV);
+
+ UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+ }
+}
+
static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
@@ -3723,6 +3845,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ADDPATH:
bgp_dynamic_capability_addpath(pnt, action, hdr, peer);
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ bgp_dynamic_capability_paths_limit(pnt, action, hdr,
+ peer);
+ break;
case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index f0c5de074d..c61ffbd558 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -8569,6 +8569,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
afi_t afi;
route_map_result_t ret;
struct bgp_redist *red;
+ struct interface *ifp;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) ||
bgp->peer_self == NULL)
@@ -8628,6 +8629,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
}
attr.nh_type = nhtype;
attr.nh_ifindex = ifindex;
+ ifp = if_lookup_by_index(ifindex, bgp->vrf_id);
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
attr.med = metric;
attr.distance = distance;
@@ -9317,9 +9323,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
"link-local");
if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
- &attr->mp_nexthop_local)
- != 0)
- && !attr->mp_nexthop_prefer_global)
+ &attr->mp_nexthop_local) !=
+ 0) &&
+ !CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
else
@@ -9331,10 +9338,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
} else {
/* Display LL if LL/Global both in table unless
* prefer-global is set */
- if (((attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- && !attr->mp_nexthop_prefer_global)
- || (path->peer->conf_if)) {
+ if (((attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) &&
+ !CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) ||
+ (path->peer->conf_if)) {
if (path->peer->conf_if) {
len = vty_out(vty, "%s",
path->peer->conf_if);
@@ -10582,7 +10590,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object_boolean_true_add(json_nexthop_ll,
"accessible");
- if (!attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(json_nexthop_ll,
"used");
else
@@ -10592,7 +10601,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, " (%s) %s\n",
inet_ntop(AF_INET6, &attr->mp_nexthop_local,
buf, INET6_ADDRSTRLEN),
- attr->mp_nexthop_prefer_global
+ CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)
? "(prefer-global)"
: "(used)");
}
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 36e04c5e68..a091b67680 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -2323,17 +2323,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
route_set_aspath_prepend_free,
};
-/* `set as-path exclude ASn' */
-struct aspath_exclude {
- struct aspath *aspath;
- bool exclude_all;
- char *exclude_aspath_acl_name;
- struct as_list *exclude_aspath_acl;
-};
-
static void *route_aspath_exclude_compile(const char *arg)
{
struct aspath_exclude *ase;
+ struct aspath_exclude_list *ael;
const char *str = arg;
static const char asp_acl[] = "as-path-access-list";
@@ -2348,16 +2341,41 @@ static void *route_aspath_exclude_compile(const char *arg)
ase->exclude_aspath_acl = as_list_lookup(str);
} else
ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL));
+
+ if (ase->exclude_aspath_acl) {
+ ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
+ sizeof(struct aspath_exclude_list));
+ ael->bp_as_excl = ase;
+ ael->next = ase->exclude_aspath_acl->exclude_list;
+ ase->exclude_aspath_acl->exclude_list = ael;
+ }
+
return ase;
}
static void route_aspath_exclude_free(void *rule)
{
struct aspath_exclude *ase = rule;
+ struct aspath_exclude_list *cur_ael = NULL;
+ struct aspath_exclude_list *prev_ael = NULL;
aspath_free(ase->aspath);
if (ase->exclude_aspath_acl_name)
XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
+ if (ase->exclude_aspath_acl)
+ cur_ael = ase->exclude_aspath_acl->exclude_list;
+ while (cur_ael) {
+ if (cur_ael->bp_as_excl == ase) {
+ if (prev_ael)
+ prev_ael->next = cur_ael->next;
+ else
+ ase->exclude_aspath_acl->exclude_list = NULL;
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael);
+ break;
+ }
+ prev_ael = cur_ael;
+ cur_ael = cur_ael->next;
+ }
XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
}
@@ -3935,11 +3953,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
/* Set next hop preference to global */
- path->attr->mp_nexthop_prefer_global = true;
+ SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
} else {
- path->attr->mp_nexthop_prefer_global = false;
+ UNSET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
}
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index abebfe5155..096502aaa9 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -147,6 +147,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list",
.cbs = {
+ .create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create,
+ .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy,
.apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish,
}
},
@@ -154,7 +156,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name",
.cbs = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify,
- .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy,
}
},
{
@@ -356,6 +357,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator",
.cbs = {
+ .create = lib_route_map_entry_set_action_rmap_set_action_aggregator_create,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy,
.apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish,
}
},
@@ -363,14 +366,12 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy,
}
},
{
@@ -390,6 +391,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
{
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb",
.cbs = {
+ .create = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy,
.apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish,
}
},
@@ -397,7 +400,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy,
}
},
{
@@ -418,7 +420,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify,
- .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy,
}
},
{
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index 28e4188026..d7f0cea30e 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -60,9 +60,12 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod
int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify(
@@ -127,24 +130,28 @@ int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(s
int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create(
+ struct nb_cb_create_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy(
+ struct nb_cb_destroy_args *args);
void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args);
-int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify(
struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy(
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index d6fcb6b8dc..c1d6ee12e1 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -1121,6 +1121,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des
/*
* XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list
*/
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_match_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void
lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(
struct nb_cb_apply_finish_args *args)
@@ -1211,23 +1232,6 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam
return NB_OK;
}
-int
-lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
- }
-
- return NB_OK;
-
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any
@@ -1253,9 +1257,8 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- break;
case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
+ break;
}
return NB_OK;
@@ -1287,9 +1290,8 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
- break;
case NB_EV_APPLY:
- return lib_route_map_entry_match_destroy(args);
+ break;
}
return NB_OK;
@@ -2735,6 +2737,27 @@ lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(
* xpath =
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator
*/
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(
struct nb_cb_apply_finish_args *args)
{
@@ -2799,22 +2822,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_set_destroy(args);
- }
-
- return NB_OK;
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address
@@ -2834,22 +2841,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_mod
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- return lib_route_map_entry_set_destroy(args);
- }
-
- return NB_OK;
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name
@@ -2918,6 +2909,27 @@ lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb
*/
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create(
+ struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
void
lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
struct nb_cb_apply_finish_args *args)
@@ -2973,13 +2985,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_set_destroy(args);
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth
@@ -2995,7 +3000,7 @@ int
lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(
struct nb_cb_destroy_args *args)
{
- return lib_route_map_entry_set_destroy(args);
+ return NB_OK;
}
/*
@@ -3061,13 +3066,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec
return NB_OK;
}
-int
-lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(
- struct nb_cb_destroy_args *args)
-{
- return lib_route_map_entry_set_destroy(args);
-}
-
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index 0c8ed33d43..70369104a2 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -853,7 +853,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
return SNMP_INTEGER(2);
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- if (path->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
return SNMP_INTEGER(2);
else
return SNMP_INTEGER(4);
@@ -867,7 +868,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global);
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- if (path->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
return SNMP_IP6ADDRESS(
path->attr->mp_nexthop_global);
else
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index d13515af6f..c522865eba 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -145,6 +145,8 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
dst->addpath_best_selected[afi][safi] =
src->addpath_best_selected[afi][safi];
+ dst->addpath_paths_limit[afi][safi] =
+ src->addpath_paths_limit[afi][safi];
dst->local_as = src->local_as;
dst->change_local_as = src->change_local_as;
dst->shared_network = src->shared_network;
@@ -348,6 +350,8 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
key = jhash_1word(peer->addpath_best_selected[afi][safi], key);
+ key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key);
+ key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key);
key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
key);
@@ -461,6 +465,9 @@ static unsigned int updgrp_hash_key_make(const void *p)
PEER_UPDGRP_AF_CAP_FLAGS),
peer->v_routeadv, peer->change_local_as,
peer->as_path_loop_detection);
+ zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)",
+ peer, peer->addpath_paths_limit[afi][safi].send,
+ peer->addpath_paths_limit[afi][safi].receive);
zlog_debug(
"%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
peer, peer->max_packet_size, peer->pmax_out[afi][safi],
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 7ecebe3020..cc039e3e11 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -97,13 +97,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
enum bgp_path_selection_reason reason;
char pfx_buf[PREFIX2STR_BUFFER] = {};
int paths_eq = 0;
- int best_path_count = 0;
struct list *list = list_new();
struct bgp_path_info *pi = NULL;
+ uint16_t paths_count = 0;
+ uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive;
if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) {
- while (best_path_count++ <
- peer->addpath_best_selected[afi][safi]) {
+ paths_limit =
+ paths_limit
+ ? MIN(paths_limit,
+ peer->addpath_best_selected[afi][safi])
+ : peer->addpath_best_selected[afi][safi];
+
+ while (paths_count++ < paths_limit) {
struct bgp_path_info *exist = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
@@ -139,8 +145,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
subgroup_process_announce_selected(
subgrp, NULL, dest, afi, safi, id);
} else {
- subgroup_process_announce_selected(subgrp, pi, dest,
- afi, safi, id);
+ /* No Paths-Limit involved */
+ if (!paths_limit) {
+ subgroup_process_announce_selected(subgrp, pi,
+ dest, afi,
+ safi, id);
+ continue;
+ }
+
+ /* If we have Paths-Limit capability, we MUST
+ * not send more than the number of paths expected
+ * by the peer.
+ */
+ if (paths_count++ < paths_limit)
+ subgroup_process_announce_selected(subgrp, pi,
+ dest, afi,
+ safi, id);
+ else
+ subgroup_process_announce_selected(subgrp, NULL,
+ dest, afi,
+ safi, id);
}
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 31524e2221..efc71bc8a7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9198,6 +9198,63 @@ DEFPY(
return CMD_SUCCESS;
}
+DEFPY (neighbor_addpath_paths_limit,
+ neighbor_addpath_paths_limit_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit (1-65535)$paths_limit",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Paths Limit for Addpath to receive from the peer\n"
+ "Maximum number of paths\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = peer_af_flag_set_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
+
+ peer->addpath_paths_limit[afi][safi].send = paths_limit;
+
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
+ CAPABILITY_ACTION_SET);
+
+ return ret;
+}
+
+DEFPY (no_neighbor_addpath_paths_limit,
+ no_neighbor_addpath_paths_limit_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit [(1-65535)]",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Paths Limit for Addpath to receive from the peer\n"
+ "Maximum number of paths\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
+
+ peer->addpath_paths_limit[afi][safi].send = 0;
+
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
+ CAPABILITY_ACTION_UNSET);
+
+ return ret;
+}
+
DEFPY(
no_neighbor_aspath_loop_detection,
no_neighbor_aspath_loop_detection_cmd,
@@ -14146,6 +14203,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_add);
}
+ /* Paths-Limit */
+ if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
+ json_object *json_add = NULL;
+ const char *print_store;
+
+ json_add = json_object_new_object();
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ json_object *json_sub = NULL;
+
+ json_sub = json_object_new_object();
+ print_store = get_afi_safi_str(afi, safi,
+ true);
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) &&
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "advertisedAndReceived");
+ json_object_int_add(
+ json_sub,
+ "advertisedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+ json_object_int_add(
+ json_sub,
+ "receivedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+ } else if (CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "advertised");
+ json_object_int_add(
+ json_sub,
+ "advertisedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+ } else if (CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "received");
+ json_object_int_add(
+ json_sub,
+ "receivedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+ }
+ }
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV))
+ json_object_object_add(json_add,
+ print_store,
+ json_sub);
+ else
+ json_object_free(json_sub);
+ }
+
+ json_object_object_add(json_cap, "pathsLimit",
+ json_add);
+ }
+
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@@ -14599,6 +14736,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
+ /* Paths-Limit */
+ if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
+ vty_out(vty, " Paths-Limit:\n");
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ vty_out(vty, " %s: ",
+ get_afi_safi_str(afi,
+ safi,
+ false));
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV))
+ vty_out(vty,
+ "advertised (%u)",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV))
+ vty_out(vty,
+ "%sreceived (%u)",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV)
+ ? " and "
+ : "",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+
+ vty_out(vty, "\n");
+ }
+ }
+ }
+
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@@ -18383,6 +18561,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX))
vty_out(vty, " neighbor %s disable-addpath-rx\n", addr);
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT))
+ vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr,
+ peer->addpath_paths_limit[afi][safi].send);
+
/* ORF capability. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi,
@@ -20544,6 +20727,26 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE,
&no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ /* "neighbor addpath-rx-paths-limit" commands.*/
+ install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
+
/* "neighbor sender-as-path-loop-detection" commands. */
install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd);
install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 1172514e52..26194f8601 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -235,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_up(ifp);
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -282,6 +290,14 @@ static int bgp_ifp_down(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_down(ifp);
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -927,7 +943,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex)
|| path->attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
/* Check if route-map is set to prefer global over link-local */
- if (path->attr->mp_nexthop_prefer_global) {
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
nexthop = &path->attr->mp_nexthop_global;
if (IN6_IS_ADDR_LINKLOCAL(nexthop))
*ifindex = path->attr->nh_ifindex;
@@ -3144,6 +3161,15 @@ static int bgp_ifp_create(struct interface *ifp)
bgp_update_interface_nbrs(bgp, ifp, ifp);
hook_call(bgp_vrf_status_changed, bgp, ifp);
+
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 8fc52652a2..e7712f0f3e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1527,6 +1527,8 @@ struct peer *peer_new(struct bgp *bgp)
PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
peer->addpath_best_selected[afi][safi] = 0;
+ peer->addpath_paths_limit[afi][safi].receive = 0;
+ peer->addpath_paths_limit[afi][safi].send = 0;
peer->soo[afi][safi] = NULL;
}
@@ -1620,6 +1622,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
peer_dst->addpath_type[afi][safi] =
peer_src->addpath_type[afi][safi];
+ peer_dst->addpath_paths_limit[afi][safi] =
+ peer_src->addpath_paths_limit[afi][safi];
}
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
@@ -4614,6 +4618,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_SOO, 0, peer_change_reset},
{PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
{PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out},
+ {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none},
{0, 0, 0}};
/* Proper action set. */
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0f69095323..cf333e07cc 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1140,6 +1140,11 @@ struct llgr_info {
uint8_t flags;
};
+struct addpath_paths_limit {
+ uint16_t send;
+ uint16_t receive;
+};
+
struct peer_connection {
struct peer *peer;
@@ -1333,6 +1338,8 @@ struct peer {
#define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */
#define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27)
#define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28)
+#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29)
+#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30)
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
@@ -1351,6 +1358,8 @@ struct peer {
#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
#define PEER_CAP_LLGR_AF_ADV (1U << 15)
#define PEER_CAP_LLGR_AF_RCV (1U << 16)
+#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17)
+#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18)
/* Global configuration flags. */
/*
@@ -1528,6 +1537,7 @@ struct peer {
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27)
#define PEER_FLAG_SOO (1ULL << 28)
#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
+#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1845,6 +1855,9 @@ struct peer {
/* Add-Path Best selected paths number to advertise */
uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX];
+ /* Add-Path Paths-Limit */
+ struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 53dc551ca3..9ae9508b02 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1780,6 +1780,17 @@ Configuring Peers
Do not accept additional paths from this neighbor.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-rx-paths-limit (1-65535)
+
+ Limit the maximum number of paths a BGP speaker can receive from a peer, optimizing
+ the transmission of BGP routes by selectively relaying pertinent routes instead of
+ the entire set.
+
+ If this command is configured, the sender will only send the number of paths specified
+ in PATHS-LIMIT capability.
+
+ To exchange this limit, both peers must support the PATHS-LIMIT capability.
+
.. clicmd:: neighbor PEER ttl-security hops NUMBER
This command enforces Generalized TTL Security Mechanism (GTSM), as
@@ -3196,6 +3207,31 @@ L3VPN SRv6
Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must
be set in zebra, but user can set it in any order.
+L3VPN SRv6 SID reachability
+---------------------------
+
+In the context of IPv4 L3VPN over SRv6 specific usecase, 2001:db8:12::2
+is the peer IPv6 address of r2, and 2001:db8:2:2:: is the SRv6 SID
+advertised by router r2 for prefix P. On r1, the SID reachability is
+checked in order to install the prefix P. The below output indicates
+that the 2001:db8:2:2:: prefix is valid.
+
+
+.. code-block:: frr
+
+ r1# show bgp nexthop detail
+ Current BGP nexthop cache:
+ 2001:db8:2:2:: valid [IGP metric 0], #paths 4
+ gate 2001:db8:12::2, if eth0
+ Last update: Tue Nov 14 10:36:28 2023
+ Paths:
+ 1/1 192.168.2.0/24 VRF vrf10 flags 0x4018
+ 1/3 192.168.2.0/24 RD 65002:10 VRF default flags 0x418
+ 2001:db8:12::2 valid [IGP metric 0], #paths 0, peer 2001:db8:12::2
+ if eth0
+ Last update: Tue Nov 14 10:36:26 2023
+ Paths:
+
General configuration
^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index d37dfa64c6..6e4e42b811 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -320,12 +320,12 @@ Showing ISIS information
Show the ISIS database globally, for a specific LSP id without or with
details.
-.. clicmd:: show isis topology [level-1|level-2] [algorithm (128-255)]
+.. clicmd:: show isis topology [level-1|level-2] [algorithm [(128-255)]]
Show topology IS-IS paths to Intermediate Systems, globally, in area
(level-1) or domain (level-2).
-.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] [algorithm (128-255)]
+.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] [algorithm [(128-255)]]
Show the ISIS routing table, as determined by the most recent SPF
calculation.
@@ -435,7 +435,7 @@ Known limitations:
clear the Node flag that is set by default for Prefix-SIDs associated to
loopback addresses. This option is necessary to configure Anycast-SIDs.
-.. clicmd:: show isis segment-routing node [algorithm (128-255)]
+.. clicmd:: show isis segment-routing node [algorithm [(128-255)]]
Show detailed information about all learned Segment Routing Nodes.
diff --git a/fpm/fpm.proto b/fpm/fpm.proto
index 9f0917feae..beaa5d635c 100644
--- a/fpm/fpm.proto
+++ b/fpm/fpm.proto
@@ -6,6 +6,9 @@
//
// @author Avneesh Sachdev <avneesh@sproute.com>
//
+// Portions:
+// Copyright (C) 2024 Carmine Scarpitta (for SRv6)
+//
// 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
@@ -72,6 +75,141 @@ message AddRoute {
required int32 metric = 8;
repeated Nexthop nexthops = 9;
+
+ /* Source Address of outer encapsulating IPv6 header */
+ optional qpb.Ipv6Address srv6_encap_source_address = 10;
+ /* SRv6 SID for VPN use cases */
+ optional qpb.Ipv6Address srv6_vpn_sid = 11;
+}
+
+/* SID Format - as per RFC 8986 section #3.1 */
+message SRv6SIDFormat
+{
+ /* Locator block length */
+ required uint32 locator_block_length = 1;
+ /* Locator node length */
+ required uint32 locator_node_length = 2;
+ /* Function length */
+ required uint32 function_length = 3;
+ /* Argument length */
+ required uint32 argument_length = 4;
+}
+
+/* SRv6 Local SID */
+message SRv6LocalSID
+{
+ /* SRv6 SID value */
+ required qpb.Ipv6Address sid = 1;
+
+ /* SID Format - as per RFC 8986 section #3.1 */
+ optional SRv6SIDFormat sid_format = 2;
+
+ /* SRv6 Endpoint Behavior associated with the SID */
+ oneof end_behavior
+ {
+ /* Endpoint */
+ End end = 3;
+ /* Endpoint with L3 cross-connect */
+ EndX end_x = 4;
+ /* Endpoint with specific IPv6 table lookup */
+ EndT end_t = 5;
+ /* Endpoint with decapsulation and IPv6 cross-connect */
+ EndDX6 end_dx6 = 7;
+ /* Endpoint with decapsulation and IPv4 cross-connect */
+ EndDX4 end_dx4 = 8;
+ /* Endpoint with decapsulation and specific IPv6 table lookup */
+ EndDT6 end_dt6 = 9;
+ /* Endpoint with decapsulation and specific IPv4 table lookup */
+ EndDT4 end_dt4 = 10;
+ /* Endpoint with decapsulation and specific IP table lookup */
+ EndDT46 end_dt46 = 11;
+ /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */
+ UN un = 12;
+ /* End.X behavior with NEXT-CSID, PSP and USD flavors */
+ UA ua = 13;
+ /* End.DT6 behavior with NEXT-CSID flavor */
+ UDT6 udt6 = 14;
+ /* End.DT4 behavior with NEXT-CSID flavor */
+ UDT4 udt4 = 15;
+ /* End.DT46 behavior with NEXT-CSID flavor */
+ UDT46 udt46 = 16;
+ }
+
+ /* Endpoint */
+ message End
+ {
+ }
+
+ /* Endpoint with L3 cross-connect */
+ message EndX
+ {
+ required Nexthop nexthop = 1;
+ }
+
+ /* Endpoint with specific IPv6 table lookup */
+ message EndT
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* Endpoint with decapsulation and IPv6 cross-connect */
+ message EndDX6
+ {
+ required Nexthop nexthop = 1;
+ }
+
+ /* Endpoint with decapsulation and IPv4 cross-connect */
+ message EndDX4
+ {
+ required Nexthop nexthop = 1;
+ }
+
+ /* Endpoint with decapsulation and specific IPv6 table lookup */
+ message EndDT6
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* Endpoint with decapsulation and specific IPv4 table lookup */
+ message EndDT4
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* Endpoint with decapsulation and specific IP table lookup */
+ message EndDT46
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */
+ message UN
+ {
+ }
+
+ /* End.X behavior with NEXT-CSID, PSP and USD flavors */
+ message UA
+ {
+ required Nexthop nexthop = 1;
+ }
+
+ /* End.DT6 behavior with NEXT-CSID flavor */
+ message UDT6
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* End.DT4 behavior with NEXT-CSID flavor */
+ message UDT4
+ {
+ required uint32 vrf_id = 1;
+ }
+
+ /* End.DT46 behavior with NEXT-CSID flavor */
+ message UDT46
+ {
+ required uint32 vrf_id = 1;
+ }
}
//
@@ -82,10 +220,17 @@ message Message {
UNKNOWN_MSG = 0;
ADD_ROUTE = 1;
DELETE_ROUTE = 2;
+ /* Install an SRv6 Local SID */
+ ADD_SRV6_LOCALSID = 3;
+ /* Remove an SRv6 Local SID */
+ DELETE_SRV6_LOCALSID = 4;
};
optional Type type = 1;
optional AddRoute add_route = 2;
optional DeleteRoute delete_route = 3;
+
+ /* SRv6 Local SID */
+ optional SRv6LocalSID srv6_localsid = 4;
}
diff --git a/fpm/fpm_pb.h b/fpm/fpm_pb.h
index 7e39054d19..23d7e43993 100644
--- a/fpm/fpm_pb.h
+++ b/fpm/fpm_pb.h
@@ -5,6 +5,9 @@
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
+ *
+ * Portions:
+ * Copyright (C) 2024 Carmine Scarpitta (for SRv6)
*/
/*
@@ -15,6 +18,7 @@
#define _FPM_PB_H
#include "lib/route_types.h"
+#include "lib/vrf.h"
#include "qpb/qpb.h"
#include "fpm/fpm.pb-c.h"
@@ -42,4 +46,400 @@ static inline Fpm__RouteKey *fpm__route_key__create(qpb_allocator_t *allocator,
return key;
}
+/*
+ * fpm__nexthop__create
+ */
+#define fpm_nexthop_create fpm__nexthop__create
+static inline Fpm__Nexthop *
+fpm__nexthop__create(qpb_allocator_t *allocator, struct nexthop *nh)
+{
+ Fpm__Nexthop *nexthop;
+ uint8_t family;
+
+ nexthop = QPB_ALLOC(allocator, typeof(*nexthop));
+ if (!nexthop)
+ return NULL;
+
+ fpm__nexthop__init(nexthop);
+
+ if (nh->type == NEXTHOP_TYPE_IPV4 ||
+ nh->type == NEXTHOP_TYPE_IPV4_IFINDEX)
+ family = AF_INET;
+ else if (nh->type == NEXTHOP_TYPE_IPV6 ||
+ nh->type == NEXTHOP_TYPE_IPV6_IFINDEX)
+ family = AF_INET6;
+ else
+ return NULL;
+
+ nexthop->if_id = qpb__if_identifier__create(allocator, nh->ifindex);
+ if (!nexthop->if_id)
+ return NULL;
+
+ nexthop->address = qpb__l3_address__create(allocator, &nh->gate, family);
+ if (!nexthop->address)
+ return NULL;
+
+
+ return nexthop;
+}
+
+/*
+ * fpm__nexthop__get
+ *
+ * Read out information from a protobuf nexthop structure.
+ */
+#define fpm_nexthop_get fpm__nexthop__get
+static inline int fpm__nexthop__get(const Fpm__Nexthop *nh,
+ struct nexthop *nexthop)
+{
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ uint32_t ifindex;
+ char *ifname;
+
+ if (!nh)
+ return 0;
+
+ if (!qpb_if_identifier_get(nh->if_id, &ifindex, &ifname))
+ return 0;
+
+ if (nh->address) {
+ if (nh->address->v4) {
+ memset(&ipv4, 0, sizeof(ipv4));
+ if (!qpb__ipv4_address__get(nh->address->v4, &ipv4))
+ return 0;
+
+ nexthop->vrf_id = VRF_DEFAULT;
+ nexthop->type = NEXTHOP_TYPE_IPV4;
+ nexthop->gate.ipv4 = ipv4;
+ if (ifindex) {
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ nexthop->ifindex = ifindex;
+ }
+ return 1;
+ }
+
+ if (nh->address->v6) {
+ memset(&ipv6, 0, sizeof(ipv6));
+ if (!qpb__ipv6_address__get(nh->address->v6, &ipv6))
+ return 0;
+ nexthop->vrf_id = VRF_DEFAULT;
+ nexthop->type = NEXTHOP_TYPE_IPV6;
+ nexthop->gate.ipv6 = ipv6;
+ if (ifindex) {
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ nexthop->ifindex = ifindex;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * fpm__srv6_sid_format__create
+ */
+#define fpm_srv6_sid_format_create fpm__srv6_sid_format__create
+static inline Fpm__SRv6SIDFormat *
+fpm__srv6_sid_format__create(qpb_allocator_t *allocator,
+ uint8_t locator_block_length,
+ uint8_t locator_node_length,
+ uint8_t function_length, uint8_t argument_length)
+{
+ Fpm__SRv6SIDFormat *sid_format;
+
+ sid_format = QPB_ALLOC(allocator, typeof(*sid_format));
+ if (!sid_format)
+ return NULL;
+ fpm__srv6_sidformat__init(sid_format);
+
+ sid_format->locator_block_length = locator_block_length;
+ sid_format->locator_node_length = locator_node_length;
+ sid_format->function_length = function_length;
+ sid_format->argument_length = argument_length;
+
+ return sid_format;
+}
+
+/*
+ * fpm__srv6_local_sid_end_behavior__create
+ */
+#define fpm_srv6_local_sid_end_behavior_create \
+ fpm__srv6_local_sid_end_behavior__create
+static inline Fpm__SRv6LocalSID__End *
+fpm__srv6_local_sid_end_behavior__create(qpb_allocator_t *allocator)
+{
+ Fpm__SRv6LocalSID__End *end;
+
+ end = QPB_ALLOC(allocator, typeof(*end));
+ if (!end)
+ return NULL;
+
+ fpm__srv6_local_sid__end__init(end);
+
+ return end;
+}
+
+/*
+ * fpm__srv6_local_sid_end_x_behavior__create
+ */
+#define fpm_srv6_local_sid_end_x_behavior_create \
+ fpm__srv6_local_sid_end_x_behavior__create
+static inline Fpm__SRv6LocalSID__EndX *
+fpm__srv6_local_sid_end_x_behavior__create(qpb_allocator_t *allocator,
+ struct nexthop *nexthop)
+{
+ Fpm__SRv6LocalSID__EndX *end_x;
+
+ end_x = QPB_ALLOC(allocator, typeof(*end_x));
+ if (!end_x)
+ return NULL;
+
+ fpm__srv6_local_sid__end_x__init(end_x);
+
+ end_x->nexthop = fpm_nexthop_create(allocator, nexthop);
+
+ return end_x;
+}
+
+/*
+ * fpm__srv6_local_sid_end_t_behavior__create
+ */
+#define fpm_srv6_local_sid_end_t_behavior_create \
+ fpm__srv6_local_sid_end_t_behavior__create
+static inline Fpm__SRv6LocalSID__EndT *
+fpm__srv6_local_sid_end_t_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__EndT *end_t;
+
+ end_t = QPB_ALLOC(allocator, typeof(*end_t));
+ if (!end_t)
+ return NULL;
+
+ fpm__srv6_local_sid__end_t__init(end_t);
+
+ end_t->vrf_id = vrf_id;
+
+ return end_t;
+}
+
+/*
+ * fpm__srv6_local_sid_end_dx6_behavior__create
+ */
+#define fpm_srv6_local_sid_end_dx6_behavior_create \
+ fpm__srv6_local_sid_end_dx6_behavior__create
+static inline Fpm__SRv6LocalSID__EndDX6 *
+fpm__srv6_local_sid_end_dx6_behavior__create(qpb_allocator_t *allocator,
+ struct nexthop *nexthop)
+{
+ Fpm__SRv6LocalSID__EndDX6 *end_dx6;
+
+ end_dx6 = QPB_ALLOC(allocator, typeof(*end_dx6));
+ if (!end_dx6)
+ return NULL;
+
+ fpm__srv6_local_sid__end_dx6__init(end_dx6);
+
+ end_dx6->nexthop = fpm_nexthop_create(allocator, nexthop);
+
+ return end_dx6;
+}
+
+/*
+ * fpm__srv6_local_sid_end_dx4_behavior__create
+ */
+#define fpm_srv6_local_sid_end_dx4_behavior_create \
+ fpm__srv6_local_sid_end_dx4_behavior__create
+static inline Fpm__SRv6LocalSID__EndDX4 *
+fpm__srv6_local_sid_end_dx4_behavior__create(qpb_allocator_t *allocator,
+ struct nexthop *nexthop)
+{
+ Fpm__SRv6LocalSID__EndDX4 *end_dx4;
+
+ end_dx4 = QPB_ALLOC(allocator, typeof(*end_dx4));
+ if (!end_dx4)
+ return NULL;
+
+ fpm__srv6_local_sid__end_dx4__init(end_dx4);
+
+ end_dx4->nexthop = fpm_nexthop_create(allocator, nexthop);
+
+ return end_dx4;
+}
+
+/*
+ * fpm__srv6_local_sid_end_dt6_behavior__create
+ */
+#define fpm_srv6_local_sid_end_dt6_behavior_create \
+ fpm__srv6_local_sid_end_dt6_behavior__create
+static inline Fpm__SRv6LocalSID__EndDT6 *
+fpm__srv6_local_sid_end_dt6_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__EndDT6 *end_dt6;
+
+ end_dt6 = QPB_ALLOC(allocator, typeof(*end_dt6));
+ if (!end_dt6)
+ return NULL;
+
+ fpm__srv6_local_sid__end_dt6__init(end_dt6);
+
+ end_dt6->vrf_id = vrf_id;
+
+ return end_dt6;
+}
+
+/*
+ * fpm__srv6_local_sid_end_dt4_behavior__create
+ */
+#define fpm_srv6_local_sid_end_dt4_behavior_create \
+ fpm__srv6_local_sid_end_dt4_behavior__create
+static inline Fpm__SRv6LocalSID__EndDT4 *
+fpm__srv6_local_sid_end_dt4_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__EndDT4 *end_dt4;
+
+ end_dt4 = QPB_ALLOC(allocator, typeof(*end_dt4));
+ if (!end_dt4)
+ return NULL;
+
+ fpm__srv6_local_sid__end_dt4__init(end_dt4);
+
+ end_dt4->vrf_id = vrf_id;
+
+ return end_dt4;
+}
+
+/*
+ * fpm__srv6_local_sid_end_dt46_behavior__create
+ */
+#define fpm_srv6_local_sid_end_dt46_behavior_create \
+ fpm__srv6_local_sid_end_dt46_behavior__create
+static inline Fpm__SRv6LocalSID__EndDT46 *
+fpm__srv6_local_sid_end_dt46_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__EndDT46 *end_dt46;
+
+ end_dt46 = QPB_ALLOC(allocator, typeof(*end_dt46));
+ if (!end_dt46)
+ return NULL;
+
+ fpm__srv6_local_sid__end_dt46__init(end_dt46);
+
+ end_dt46->vrf_id = vrf_id;
+
+ return end_dt46;
+}
+
+/*
+ * fpm__srv6_local_sid_un_behavior__create
+ */
+#define fpm_srv6_local_sid_un_behavior_create \
+ fpm__srv6_local_sid_un_behavior__create
+static inline Fpm__SRv6LocalSID__UN *
+fpm__srv6_local_sid_un_behavior__create(qpb_allocator_t *allocator)
+{
+ Fpm__SRv6LocalSID__UN *un;
+
+ un = QPB_ALLOC(allocator, typeof(*un));
+ if (!un)
+ return NULL;
+
+ fpm__srv6_local_sid__un__init(un);
+
+ return un;
+}
+
+/*
+ * fpm__srv6_local_sid_ua_behavior__create
+ */
+#define fpm_srv6_local_sid_ua_behavior_create \
+ fpm__srv6_local_sid_ua_behavior__create
+static inline Fpm__SRv6LocalSID__UA *
+fpm__srv6_local_sid_ua_behavior__create(qpb_allocator_t *allocator,
+ struct nexthop *nexthop)
+{
+ Fpm__SRv6LocalSID__UA *ua;
+
+ ua = QPB_ALLOC(allocator, typeof(*ua));
+ if (!ua)
+ return NULL;
+
+ fpm__srv6_local_sid__ua__init(ua);
+
+ ua->nexthop = fpm_nexthop_create(allocator, nexthop);
+
+ return ua;
+}
+
+/*
+ * fpm__srv6_local_sid_udt6_behavior__create
+ */
+#define fpm_srv6_local_sid_udt6_behavior_create \
+ fpm__srv6_local_sid_udt6_behavior__create
+static inline Fpm__SRv6LocalSID__UDT6 *
+fpm__srv6_local_sid_udt6_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__UDT6 *udt6;
+
+ udt6 = QPB_ALLOC(allocator, typeof(*udt6));
+ if (!udt6)
+ return NULL;
+
+ fpm__srv6_local_sid__udt6__init(udt6);
+
+ udt6->vrf_id = vrf_id;
+
+ return udt6;
+}
+
+/*
+ * fpm__srv6_local_sid_udt4_behavior__create
+ */
+#define fpm_srv6_local_sid_udt4_behavior_create \
+ fpm__srv6_local_sid_udt4_behavior__create
+static inline Fpm__SRv6LocalSID__UDT4 *
+fpm__srv6_local_sid_udt4_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__UDT4 *udt4;
+
+ udt4 = QPB_ALLOC(allocator, typeof(*udt4));
+ if (!udt4)
+ return NULL;
+
+ fpm__srv6_local_sid__udt4__init(udt4);
+
+ udt4->vrf_id = vrf_id;
+
+ return udt4;
+}
+
+/*
+ * fpm__srv6_local_sid_udt46_behavior__create
+ */
+#define fpm_srv6_local_sid_udt46_behavior_create \
+ fpm__srv6_local_sid_udt46_behavior__create
+static inline Fpm__SRv6LocalSID__UDT46 *
+fpm__srv6_local_sid_udt46_behavior__create(qpb_allocator_t *allocator,
+ vrf_id_t vrf_id)
+{
+ Fpm__SRv6LocalSID__UDT46 *udt46;
+
+ udt46 = QPB_ALLOC(allocator, typeof(*udt46));
+ if (!udt46)
+ return NULL;
+
+ fpm__srv6_local_sid__udt46__init(udt46);
+
+ udt46->vrf_id = vrf_id;
+
+ return udt46;
+}
+
#endif
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 7a4b45a0de..36986a19c5 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -2424,7 +2424,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
" [vrf <NAME|all>] topology"
#ifndef FABRICD
" [<level-1|level-2>]"
- " [algorithm (128-255)]"
+ " [algorithm [(128-255)]]"
#endif /* ifndef FABRICD */
,
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
@@ -2443,8 +2443,10 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
struct isis *isis = NULL;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
+ bool all_algorithm = false;
int idx_vrf = 0;
- uint8_t algorithm = SR_ALGORITHM_SPF;
+ uint16_t algorithm = SR_ALGORITHM_SPF;
+
#ifndef FABRICD
int idx = 0;
@@ -2453,8 +2455,12 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
levels = ISIS_LEVEL1;
if (argv_find(argv, argc, "level-2", &idx))
levels = ISIS_LEVEL2;
- if (argv_find(argv, argc, "algorithm", &idx))
- algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10);
+ if (argv_find(argv, argc, "algorithm", &idx)) {
+ if (argv_find(argv, argc, "(128-255)", &idx))
+ algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10);
+ else
+ all_algorithm = true;
+ }
#endif /* ifndef FABRICD */
if (!im) {
@@ -2465,14 +2471,34 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
if (vrf_name) {
if (all_vrf) {
- for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
- show_isis_topology_common(vty, levels, isis,
- algorithm);
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+ if (all_algorithm) {
+ for (algorithm = SR_ALGORITHM_FLEX_MIN;
+ algorithm <= SR_ALGORITHM_FLEX_MAX;
+ algorithm++)
+ show_isis_topology_common(
+ vty, levels, isis,
+ (uint8_t)algorithm);
+ } else {
+ show_isis_topology_common(
+ vty, levels, isis,
+ (uint8_t)algorithm);
+ }
+ }
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
- if (isis != NULL)
- show_isis_topology_common(vty, levels, isis, algorithm);
+ if (isis == NULL)
+ return CMD_SUCCESS;
+ if (all_algorithm) {
+ for (algorithm = SR_ALGORITHM_FLEX_MIN;
+ algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) {
+ show_isis_topology_common(vty, levels, isis,
+ (uint8_t)algorithm);
+ }
+ } else
+ show_isis_topology_common(vty, levels, isis,
+ (uint8_t)algorithm);
}
return CMD_SUCCESS;
@@ -2912,6 +2938,7 @@ static void show_isis_route_common(struct vty *vty, int levels,
jstr = json_object_new_string(
area->area_tag ? area->area_tag : "null");
json_object_object_add(*json, "area", jstr);
+ json_object_int_add(*json, "algorithm", algo);
} else {
vty_out(vty, "Area %s:",
area->area_tag ? area->area_tag : "null");
@@ -3011,6 +3038,39 @@ static void show_isis_route_common(struct vty *vty, int levels,
}
}
+static void show_isis_route_all_algos(struct vty *vty, int levels,
+ struct isis *isis, bool prefix_sid,
+ bool backup, json_object **json)
+{
+ uint16_t algo;
+
+ json_object *json_algo = NULL, *json_algos = NULL;
+
+ if (json) {
+ *json = json_object_new_object();
+ json_algos = json_object_new_array();
+ }
+
+ for (algo = SR_ALGORITHM_FLEX_MIN; algo <= SR_ALGORITHM_FLEX_MAX;
+ algo++) {
+ show_isis_route_common(vty, levels, isis, prefix_sid, backup,
+ (uint8_t)algo, json ? &json_algo : NULL);
+ if (!json)
+ continue;
+ if (json_object_object_length(json_algo) == 0) {
+ json_object_free(json_algo);
+ continue;
+ }
+ json_object_object_add(json_algo, "algorithm",
+ json_object_new_int(algo));
+ json_object_array_add(json_algos, json_algo);
+ }
+
+ if (json)
+ json_object_object_add(*json, "algorithms", json_algos);
+}
+
+
DEFUN(show_isis_route, show_isis_route_cmd,
"show " PROTO_NAME
" [vrf <NAME|all>] route"
@@ -3019,7 +3079,7 @@ DEFUN(show_isis_route, show_isis_route_cmd,
#endif /* ifndef FABRICD */
" [<prefix-sid|backup>]"
#ifndef FABRICD
- " [algorithm (128-255)]"
+ " [algorithm [(128-255)]]"
#endif /* ifndef FABRICD */
" [json$uj]",
SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
@@ -3041,6 +3101,7 @@ DEFUN(show_isis_route, show_isis_route_cmd,
struct listnode *node;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
+ bool all_algorithm = false;
bool prefix_sid = false;
bool backup = false;
bool uj = use_json(argc, argv);
@@ -3067,8 +3128,13 @@ DEFUN(show_isis_route, show_isis_route_cmd,
backup = true;
#ifndef FABRICD
- if (argv_find(argv, argc, "algorithm", &idx))
- algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10);
+ if (argv_find(argv, argc, "algorithm", &idx)) {
+ if (argv_find(argv, argc, "(128-255)", &idx))
+ algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL,
+ 10);
+ else
+ all_algorithm = true;
+ }
#endif /* ifndef FABRICD */
if (uj)
@@ -3077,9 +3143,19 @@ DEFUN(show_isis_route, show_isis_route_cmd,
if (vrf_name) {
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
- show_isis_route_common(
- vty, levels, isis, prefix_sid, backup,
- algorithm, uj ? &json_vrf : NULL);
+ if (all_algorithm)
+ show_isis_route_all_algos(vty, levels,
+ isis,
+ prefix_sid,
+ backup,
+ uj ? &json_vrf
+ : NULL);
+ else
+ show_isis_route_common(vty, levels,
+ isis, prefix_sid,
+ backup, algorithm,
+ uj ? &json_vrf
+ : NULL);
if (uj) {
json_object_object_add(
json_vrf, "vrf_id",
@@ -3092,9 +3168,15 @@ DEFUN(show_isis_route, show_isis_route_cmd,
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis != NULL) {
- show_isis_route_common(vty, levels, isis, prefix_sid,
- backup, algorithm,
- uj ? &json_vrf : NULL);
+ if (all_algorithm)
+ show_isis_route_all_algos(vty, levels, isis,
+ prefix_sid, backup,
+ uj ? &json_vrf : NULL);
+ else
+ show_isis_route_common(vty, levels, isis,
+ prefix_sid, backup,
+ algorithm,
+ uj ? &json_vrf : NULL);
if (uj) {
json_object_object_add(
json_vrf, "vrf_id",
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index 1d69dbbbfa..e8354fdf92 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -1074,7 +1074,7 @@ DEFUN(show_sr_node, show_sr_node_cmd,
"show " PROTO_NAME
" segment-routing node"
#ifndef FABRICD
- " [algorithm (128-255)]"
+ " [algorithm [(128-255)]]"
#endif /* ifndef FABRICD */
,
SHOW_STR PROTO_HELP
@@ -1088,13 +1088,18 @@ DEFUN(show_sr_node, show_sr_node_cmd,
{
struct listnode *node, *inode;
struct isis_area *area;
- uint8_t algorithm = SR_ALGORITHM_SPF;
+ uint16_t algorithm = SR_ALGORITHM_SPF;
+ bool all_algorithm = false;
struct isis *isis;
#ifndef FABRICD
int idx = 0;
- if (argv_find(argv, argc, "algorithm", &idx))
- algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10);
+ if (argv_find(argv, argc, "algorithm", &idx)) {
+ if (argv_find(argv, argc, "(128-255)", &idx))
+ algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10);
+ else
+ all_algorithm = true;
+ }
#endif /* ifndef FABRICD */
for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
@@ -1106,8 +1111,17 @@ DEFUN(show_sr_node, show_sr_node_cmd,
continue;
}
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
- level++)
- show_node(vty, area, level, algorithm);
+ level++) {
+ if (all_algorithm) {
+ for (algorithm = SR_ALGORITHM_FLEX_MIN;
+ algorithm <= SR_ALGORITHM_FLEX_MAX;
+ algorithm++)
+ show_node(vty, area, level,
+ (uint8_t)algorithm);
+ } else
+ show_node(vty, area, level,
+ (uint8_t)algorithm);
+ }
}
}
diff --git a/lib/affinitymap_northbound.c b/lib/affinitymap_northbound.c
index 8e84d36f2f..003e0c11b9 100644
--- a/lib/affinitymap_northbound.c
+++ b/lib/affinitymap_northbound.c
@@ -94,7 +94,8 @@ const struct frr_yang_module_info frr_affinity_map_info = {
.cbs = {
.create = lib_affinity_map_create,
.destroy = lib_affinity_map_destroy,
- }
+ },
+ .priority = NB_DFLT_PRIORITY - 1,
},
{
.xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map/value",
diff --git a/lib/base64.c b/lib/base64.c
index ee2e838c01..00dd35ffb5 100644
--- a/lib/base64.c
+++ b/lib/base64.c
@@ -11,7 +11,6 @@
#include "base64.h"
#include "compiler.h"
-static const int CHARS_PER_LINE = 72;
static const char *ENCODING =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -19,7 +18,6 @@ void base64_init_encodestate(struct base64_encodestate *state_in)
{
state_in->step = step_A;
state_in->result = 0;
- state_in->stepcount = 0;
}
char base64_encode_value(char value_in)
@@ -76,12 +74,6 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out,
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
-
- ++(state_in->stepcount);
- if (state_in->stepcount == CHARS_PER_LINE/4) {
- *codechar++ = '\n';
- state_in->stepcount = 0;
- }
}
}
/* control should not reach here */
@@ -105,7 +97,6 @@ int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
case step_A:
break;
}
- *codechar++ = '\n';
return codechar - code_out;
}
diff --git a/lib/base64.h b/lib/base64.h
index 839f92aa7c..9bf4ace82f 100644
--- a/lib/base64.h
+++ b/lib/base64.h
@@ -14,7 +14,6 @@ enum base64_encodestep {
struct base64_encodestate {
enum base64_encodestep step;
char result;
- int stepcount;
};
void base64_init_encodestate(struct base64_encodestate *state_in);
diff --git a/lib/filter.c b/lib/filter.c
index a0adff0e35..5a0790f8bf 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -410,7 +410,10 @@ void access_list_filter_add(struct access_list *access,
filter->prev = access->tail;
access->tail = filter;
}
+}
+void access_list_filter_update(struct access_list *access)
+{
/* Run hook function. */
if (access->master->add_hook)
(*access->master->add_hook)(access);
diff --git a/lib/filter.h b/lib/filter.h
index bd9e22d384..4fa482ba4e 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -128,6 +128,7 @@ struct filter *filter_new(void);
void access_list_filter_add(struct access_list *access, struct filter *filter);
void access_list_filter_delete(struct access_list *access,
struct filter *filter);
+void access_list_filter_update(struct access_list *access);
int64_t filter_new_seq_get(struct access_list *access);
extern const struct frr_yang_module_info frr_filter_info;
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index eba4e421c0..39042d39ab 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -17,23 +17,6 @@
#include "lib/plist_int.h"
#include "lib/routemap.h"
-/* Helper function. */
-static void acl_notify_route_map(struct access_list *acl, int route_map_event)
-{
- switch (route_map_event) {
- case RMAP_EVENT_FILTER_ADDED:
- if (acl->master->add_hook)
- (*acl->master->add_hook)(acl);
- break;
- case RMAP_EVENT_FILTER_DELETED:
- if (acl->master->delete_hook)
- (*acl->master->delete_hook)(acl);
- break;
- }
-
- route_map_notify_dependencies(acl->name, route_map_event);
-}
-
static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
{
int type = yang_dnode_get_enum(args->dnode, "../../type");
@@ -153,9 +136,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -174,9 +154,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
ple->le = yang_dnode_get_uint8(args->dnode, NULL);
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -195,9 +172,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
ple->ge = 0;
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -216,9 +190,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
ple->le = 0;
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -575,6 +546,15 @@ static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
}
+static void
+lib_access_list_entry_apply_finish(struct nb_cb_apply_finish_args *args)
+{
+ struct filter *f;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ access_list_filter_update(f->acl);
+}
+
/*
* XPath: /frr-filter:lib/access-list/entry/action
*/
@@ -594,8 +574,6 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
else
f->type = FILTER_DENY;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -629,8 +607,6 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -647,8 +623,6 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
-
return NB_OK;
}
@@ -681,8 +655,6 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
fz->exact = yang_dnode_get_bool(args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -699,8 +671,6 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->exact = 0;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
-
return NB_OK;
}
@@ -733,8 +703,6 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -751,7 +719,29 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
fc = &f->u.cfilter;
cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry/network
+ */
+static int lib_access_list_entry_network_create(struct nb_cb_create_args *args)
+{
+ /* Nothing to do here, everything is done in children callbacks */
+ return NB_OK;
+}
+
+static int lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
return NB_OK;
}
@@ -784,8 +774,6 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args)
fc = &f->u.cfilter;
yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -817,8 +805,6 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args)
fc = &f->u.cfilter;
yang_dnode_get_ipv4(&fc->addr_mask, args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -851,8 +837,6 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
fc->addr.s_addr = INADDR_ANY;
fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -869,8 +853,6 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
fc = &f->u.cfilter;
cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
-
return NB_OK;
}
@@ -903,8 +885,6 @@ static int lib_access_list_entry_destination_host_modify(
yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -922,7 +902,32 @@ static int lib_access_list_entry_destination_host_destroy(
fc->extended = 0;
cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-filter:lib/access-list/entry/destination-network
+ */
+static int
+lib_access_list_entry_destination_network_create(struct nb_cb_create_args *args)
+{
+ /* Nothing to do here, everything is done in children callbacks */
+ return NB_OK;
+}
+
+static int lib_access_list_entry_destination_network_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct filter_cisco *fc;
+ struct filter *f;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ f = nb_running_get_entry(args->dnode, NULL, true);
+ fc = &f->u.cfilter;
+ fc->extended = 0;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
return NB_OK;
}
@@ -955,8 +960,6 @@ static int lib_access_list_entry_destination_network_address_modify(
fc->extended = 1;
yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -988,8 +991,6 @@ static int lib_access_list_entry_destination_network_mask_modify(
fc->extended = 1;
yang_dnode_get_ipv4(&fc->mask_mask, args->dnode, NULL);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -1022,8 +1023,6 @@ static int lib_access_list_entry_destination_any_create(
fc->mask.s_addr = INADDR_ANY;
fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -1041,8 +1040,6 @@ static int lib_access_list_entry_destination_any_destroy(
fc->extended = 0;
cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
-
return NB_OK;
}
@@ -1089,8 +1086,6 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
break;
}
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
-
return NB_OK;
}
@@ -1106,8 +1101,6 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->prefix.family = AF_UNSPEC;
- acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
-
return NB_OK;
}
@@ -1224,6 +1217,22 @@ static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
return NB_OK;
}
+static void
+lib_prefix_list_entry_apply_finish(struct nb_cb_apply_finish_args *args)
+{
+ struct prefix_list_entry *ple;
+
+ ple = nb_running_get_entry(args->dnode, NULL, true);
+
+ /*
+ * Finish prefix entry update procedure. The procedure is started in
+ * children callbacks. `prefix_list_entry_update_start` can be called
+ * multiple times if multiple children are modified, but it is actually
+ * executed only once because of the protection by `ple->installed`.
+ */
+ prefix_list_entry_update_finish(ple);
+}
+
/*
* XPath: /frr-filter:lib/prefix-list/entry/action
*/
@@ -1246,9 +1255,6 @@ static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
else
ple->type = PREFIX_DENY;
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -1276,10 +1282,6 @@ static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args)
prefix_copy(&ple->prefix, &p);
}
-
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -1297,9 +1299,6 @@ static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args)
memset(&ple->prefix, 0, sizeof(ple->prefix));
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -1547,9 +1546,6 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
break;
}
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -1567,9 +1563,6 @@ static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
ple->any = false;
- /* Finish prefix entry update procedure. */
- prefix_list_entry_update_finish(ple);
-
return NB_OK;
}
@@ -1597,6 +1590,7 @@ const struct frr_yang_module_info frr_filter_info = {
.cbs = {
.create = lib_access_list_entry_create,
.destroy = lib_access_list_entry_destroy,
+ .apply_finish = lib_access_list_entry_apply_finish,
.cli_cmp = access_list_cmp,
.cli_show = access_list_show,
}
@@ -1629,6 +1623,13 @@ const struct frr_yang_module_info frr_filter_info = {
}
},
{
+ .xpath = "/frr-filter:lib/access-list/entry/network",
+ .cbs = {
+ .create = lib_access_list_entry_network_create,
+ .destroy = lib_access_list_entry_network_destroy,
+ }
+ },
+ {
.xpath = "/frr-filter:lib/access-list/entry/network/address",
.cbs = {
.modify = lib_access_list_entry_network_address_modify,
@@ -1655,6 +1656,13 @@ const struct frr_yang_module_info frr_filter_info = {
}
},
{
+ .xpath = "/frr-filter:lib/access-list/entry/destination-network",
+ .cbs = {
+ .create = lib_access_list_entry_destination_network_create,
+ .destroy = lib_access_list_entry_destination_network_destroy,
+ }
+ },
+ {
.xpath = "/frr-filter:lib/access-list/entry/destination-network/address",
.cbs = {
.modify = lib_access_list_entry_destination_network_address_modify,
@@ -1721,6 +1729,7 @@ const struct frr_yang_module_info frr_filter_info = {
.cbs = {
.create = lib_prefix_list_entry_create,
.destroy = lib_prefix_list_entry_destroy,
+ .apply_finish = lib_prefix_list_entry_apply_finish,
.cli_cmp = prefix_list_cmp,
.cli_show = prefix_list_show,
}
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index bfdecedc4e..a107582bea 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -510,14 +510,11 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
debug_fe_client("Got native message for session-id %" PRIu64,
msg->refer_id);
- if (msg->code != MGMT_MSG_CODE_NOTIFY) {
- session = mgmt_fe_find_session_by_session_id(client,
- msg->refer_id);
- if (!session || !session->client) {
- log_err_fe_client("No session for received native msg session-id %" PRIu64,
- msg->refer_id);
- return;
- }
+ session = mgmt_fe_find_session_by_session_id(client, msg->refer_id);
+ if (!session || !session->client) {
+ log_err_fe_client("No session for received native msg session-id %" PRIu64,
+ msg->refer_id);
+ return;
}
switch (msg->code) {
@@ -558,6 +555,9 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
tree_msg->partial_error);
break;
case MGMT_MSG_CODE_NOTIFY:
+ if (!session->client->cbs.async_notification)
+ return;
+
notify_msg = (typeof(notify_msg))msg;
if (msg_len < sizeof(*notify_msg)) {
log_err_fe_client("Corrupt notify-data msg recv");
@@ -579,15 +579,13 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
notify_msg->result_type);
return;
}
- FOREACH_SESSION_IN_LIST (client, session) {
- if (!session->client->cbs.async_notification)
- continue;
- session->client->cbs
- .async_notification(client, client->user_data,
- session->client_id,
- session->user_ctx, data);
- }
+ session->client->cbs.async_notification(client,
+ client->user_data,
+ session->client_id,
+ msg->refer_id,
+ session->user_ctx, data);
+
if (notify_msg->result_type != LYD_JSON)
darr_free(data);
break;
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index 7af1270071..eee4594e17 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -117,7 +117,8 @@ struct mgmt_fe_client_cbs {
/* Called with asynchronous notifications from backends */
int (*async_notification)(struct mgmt_fe_client *client,
uintptr_t user_data, uint64_t client_id,
- uintptr_t session_ctx, const char *result);
+ uint64_t session_id, uintptr_t session_ctx,
+ const char *result);
/* Called when new native error is returned */
int (*error_notify)(struct mgmt_fe_client *client, uintptr_t user_data,
diff --git a/lib/northbound.c b/lib/northbound.c
index a3d91e56af..25ea658bc4 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -157,7 +157,7 @@ void nb_nodes_delete(void)
struct nb_node *nb_node_find(const char *path)
{
const struct lysc_node *snode;
- uint32_t llopts;
+ uint32_t llopts = 0;
/*
* Use libyang to find the schema node associated to the path and get
@@ -165,8 +165,6 @@ struct nb_node *nb_node_find(const char *path)
* disable logging temporarily to avoid libyang from logging an error
* message when the node is not found.
*/
- llopts = ly_log_options(LY_LOSTORE);
- llopts &= ~LY_LOLOG;
ly_temp_log_options(&llopts);
snode = yang_find_snode(ly_native_ctx, path, 0);
@@ -391,13 +389,29 @@ void nb_config_replace(struct nb_config *config_dst,
static inline int nb_config_cb_compare(const struct nb_config_cb *a,
const struct nb_config_cb *b)
{
- /* Sort by priority first. */
- if (a->nb_node->priority < b->nb_node->priority)
+ bool a_destroy = a->operation == NB_CB_DESTROY;
+ bool b_destroy = b->operation == NB_CB_DESTROY;
+
+ /*
+ * Sort by operation first. All "destroys" must come first, to correctly
+ * process the change of a "case" inside a "choice". The old "case" must
+ * be deleted before the new "case" is created.
+ */
+ if (a_destroy && !b_destroy)
return -1;
- if (a->nb_node->priority > b->nb_node->priority)
+ if (!a_destroy && b_destroy)
return 1;
/*
+ * Then sort by priority. If the operation is "destroy", reverse the
+ * order, so that the dependants are deleted before the dependencies.
+ */
+ if (a->nb_node->priority < b->nb_node->priority)
+ return !a_destroy ? -1 : 1;
+ if (a->nb_node->priority > b->nb_node->priority)
+ return !a_destroy ? 1 : -1;
+
+ /*
* Preserve the order of the configuration changes as told by libyang.
*/
if (a->seq < b->seq)
@@ -1811,6 +1825,7 @@ nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const struct nb_node *nb_node,
struct nb_config_cb *cb;
cb = XCALLOC(MTYPE_TMP, sizeof(*cb));
+ cb->operation = NB_CB_APPLY_FINISH;
cb->nb_node = nb_node;
cb->dnode = dnode;
RB_INSERT(nb_config_cbs, cbs, cb);
@@ -1825,6 +1840,7 @@ nb_apply_finish_cb_find(struct nb_config_cbs *cbs,
{
struct nb_config_cb s;
+ s.operation = NB_CB_APPLY_FINISH;
s.seq = 0;
s.nb_node = nb_node;
s.dnode = dnode;
@@ -1922,6 +1938,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
return false;
break;
case LYS_CONTAINER:
+ if (snode->parent && snode->parent->nodetype == LYS_CASE)
+ return true;
scontainer = (struct lysc_node_container *)snode;
if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE))
return false;
@@ -1976,6 +1994,8 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
return false;
break;
case LYS_CONTAINER:
+ if (snode->parent && snode->parent->nodetype == LYS_CASE)
+ return true;
scontainer = (struct lysc_node_container *)snode;
if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE))
return false;
diff --git a/lib/routemap.c b/lib/routemap.c
index 6b3f81b4d4..ea917ebd8c 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -2548,7 +2548,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
struct route_map_index *index = NULL;
struct route_map_rule *set = NULL;
bool skip_match_clause = false;
- struct prefix conv;
if (recursion > RMAP_RECURSION_LIMIT) {
if (map)
@@ -2571,31 +2570,14 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
map->applied++;
- /*
- * Handling for matching evpn_routes in the prefix table.
- *
- * We convert type2/5 prefix to ipv4/6 prefix to do longest
- * prefix matching on.
- */
if (prefix->family == AF_EVPN) {
- if (evpn_prefix2prefix(prefix, &conv) != 0) {
- if (unlikely(CHECK_FLAG(rmap_debug,
- DEBUG_ROUTEMAP_DETAIL)))
- zlog_debug(
- "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup",
- prefix);
- } else {
- if (unlikely(CHECK_FLAG(rmap_debug,
- DEBUG_ROUTEMAP_DETAIL)))
- zlog_debug(
- "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup",
- prefix, &conv);
-
- prefix = &conv;
- }
+ index = map->head;
+ } else {
+ skip_match_clause = true;
+ index = route_map_get_index(map, prefix, match_object,
+ &match_ret);
}
- index = route_map_get_index(map, prefix, match_object, &match_ret);
if (index) {
index->applied++;
if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)))
@@ -2619,7 +2601,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
ret = RMAP_DENYMATCH;
goto route_map_apply_end;
}
- skip_match_clause = true;
for (; index; index = index->next) {
if (!skip_match_clause) {
diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c
index 4aab880d22..d1ef85c9a6 100644
--- a/ospfd/ospf_ldp_sync.c
+++ b/ospfd/ospf_ldp_sync.c
@@ -774,7 +774,7 @@ DEFPY (no_ospf_mpls_ldp_sync,
"Disable MPLS LDP-IGP Sync\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
- ospf_ldp_sync_gbl_exit(ospf, false);
+ ospf_ldp_sync_gbl_exit(ospf, true);
return CMD_SUCCESS;
}
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index 99326b41b3..dbe44f7be4 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1784,11 +1784,10 @@ static void ospf_router_info_schedule(enum lsa_opcode opcode)
DEFUN (router_info,
router_info_area_cmd,
- "router-info <as|area [A.B.C.D]>",
+ "router-info <as|area>",
OSPF_RI_STR
"Enable the Router Information functionality with AS flooding scope\n"
- "Enable the Router Information functionality with Area flooding scope\n"
- "OSPF area ID in IP format (deprecated)\n")
+ "Enable the Router Information functionality with Area flooding scope\n")
{
int idx_mode = 1;
uint8_t scope;
@@ -1844,6 +1843,15 @@ DEFUN (router_info,
return CMD_SUCCESS;
}
+#if CONFDATE > 20240809
+CPP_NOTICE("Drop deprecated router_info_area_id_cmd")
+#endif
+ALIAS_HIDDEN (router_info,
+ router_info_area_id_cmd,
+ "router-info area A.B.C.D",
+ OSPF_RI_STR
+ "Enable the Router Information functionality with Area flooding scope\n"
+ "OSPF area ID in IP format (deprecated)\n")
DEFUN (no_router_info,
no_router_info_cmd,
@@ -2239,6 +2247,7 @@ static void ospf_router_info_register_vty(void)
install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd);
install_element(OSPF_NODE, &router_info_area_cmd);
+ install_element(OSPF_NODE, &router_info_area_id_cmd);
install_element(OSPF_NODE, &no_router_info_cmd);
install_element(OSPF_NODE, &pce_address_cmd);
install_element(OSPF_NODE, &no_pce_address_cmd);
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index a55a37a907..359dc1f5d4 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -2246,6 +2246,10 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa)
}
/* Get corresponding Edge from Link State Data Base */
+ if (IPV4_NET0(attr.standard.local.s_addr) && !attr.standard.local_id) {
+ ote_debug(" |- Found no TE Link local address/ID. Abort!");
+ return -1;
+ }
edge = get_edge(ted, attr.adv, attr.standard.local);
old = edge->attributes;
diff --git a/tests/topotests/bgp_addpath_paths_limit/__init__.py b/tests/topotests/bgp_addpath_paths_limit/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/__init__.py
diff --git a/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf
new file mode 100644
index 0000000000..65beb7f286
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf
@@ -0,0 +1,13 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65001
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers connect 5
+ address-family ipv4 unicast
+ neighbor 192.168.1.2 addpath-rx-paths-limit 2
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf
new file mode 100644
index 0000000000..796b4d0ba7
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf
@@ -0,0 +1,37 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.2/24
+!
+int r2-eth2
+ ip address 192.168.7.2/24
+!
+router bgp 65002
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.7.7 remote-as external
+ neighbor 192.168.7.7 timers connect 5
+ neighbor 192.168.2.3 remote-as external
+ neighbor 192.168.2.3 timers connect 5
+ neighbor 192.168.2.3 weight 3
+ neighbor 192.168.2.4 remote-as external
+ neighbor 192.168.2.4 timers connect 5
+ neighbor 192.168.2.4 weight 4
+ neighbor 192.168.2.5 remote-as external
+ neighbor 192.168.2.5 timers connect 5
+ neighbor 192.168.2.5 weight 5
+ neighbor 192.168.2.6 remote-as external
+ neighbor 192.168.2.6 timers connect 5
+ neighbor 192.168.2.6 weight 6
+ address-family ipv4 unicast
+ neighbor 192.168.1.1 addpath-tx-all-paths
+ neighbor 192.168.1.1 prefix-list announce out
+ neighbor 192.168.7.7 addpath-tx-all-paths
+ neighbor 192.168.7.7 prefix-list announce out
+ exit-address-family
+!
+ip prefix-list announce seq 5 permit 172.16.16.254/32
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf
new file mode 100644
index 0000000000..4d834d3113
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf
@@ -0,0 +1,16 @@
+!
+int lo
+ ip address 172.16.16.254/32
+!
+int r3-eth0
+ ip address 192.168.2.3/24
+!
+router bgp 65003
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers connect 5
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf
new file mode 100644
index 0000000000..01e0aa99d3
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf
@@ -0,0 +1,16 @@
+!
+int lo
+ ip address 172.16.16.254/32
+!
+int r4-eth0
+ ip address 192.168.2.4/24
+!
+router bgp 65004
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers connect 5
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf
new file mode 100644
index 0000000000..02bb847987
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf
@@ -0,0 +1,16 @@
+!
+int lo
+ ip address 172.16.16.254/32
+!
+int r5-eth0
+ ip address 192.168.2.5/24
+!
+router bgp 65005
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers connect 5
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf
new file mode 100644
index 0000000000..39fdbcce32
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf
@@ -0,0 +1,16 @@
+!
+int lo
+ ip address 172.16.16.254/32
+!
+int r6-eth0
+ ip address 192.168.2.6/24
+!
+router bgp 65006
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers connect 5
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf
new file mode 100644
index 0000000000..8c44566b2f
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf
@@ -0,0 +1,13 @@
+!
+int r7-eth0
+ ip address 192.168.7.7/24
+!
+router bgp 65007
+ timers bgp 3 10
+ no bgp ebgp-requires-policy
+ neighbor 192.168.7.2 remote-as external
+ neighbor 192.168.7.2 timers connect 5
+ address-family ipv4 unicast
+ neighbor 192.168.7.2 addpath-rx-paths-limit 3
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py
new file mode 100644
index 0000000000..b7a1cfbb27
--- /dev/null
+++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2024 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Test if Paths-Limit capability works as expected.
+"""
+
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 8):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+ switch.add_link(tgen.gears["r5"])
+ switch.add_link(tgen.gears["r6"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r7"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_addpath_paths_limit():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+ r7 = tgen.gears["r7"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.7.7": {
+ "neighborCapabilities": {
+ "pathsLimit": {
+ "ipv4Unicast": {
+ "advertisedAndReceived": True,
+ "advertisedPathsLimit": 0,
+ "receivedPathsLimit": 3,
+ }
+ }
+ }
+ },
+ "192.168.1.1": {
+ "neighborCapabilities": {
+ "pathsLimit": {
+ "ipv4Unicast": {
+ "advertisedAndReceived": True,
+ "advertisedPathsLimit": 0,
+ "receivedPathsLimit": 2,
+ }
+ }
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge initially"
+
+ def _bgp_check_received_routes(router, expected):
+ output = json.loads(
+ router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.254/32 json")
+ )
+
+ if "paths" not in output:
+ return "No paths received"
+
+ return topotest.json_cmp(len(output["paths"]), expected)
+
+ test_func = functools.partial(_bgp_check_received_routes, r1, 2)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Received routes count is not as expected"
+
+ test_func = functools.partial(_bgp_check_received_routes, r7, 3)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Received routes count is not as expected"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
index 945c0383e7..7d8ddac4c8 100644
--- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
+++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py
@@ -389,13 +389,6 @@ def setup_module(module):
tors.append("torm22")
config_tors(tgen, tors)
- hosts = []
- hosts.append("hostd11")
- hosts.append("hostd12")
- hosts.append("hostd21")
- hosts.append("hostd22")
- config_hosts(tgen, hosts)
-
# tgen.mininet_cli()
# This is a sample of configuration loading.
router_list = tgen.routers()
@@ -410,6 +403,13 @@ def setup_module(module):
TopoRouter.RD_BGP, os.path.join(CWD, "{}/evpn.conf".format(rname))
)
tgen.start_router()
+
+ hosts = []
+ hosts.append("hostd11")
+ hosts.append("hostd12")
+ hosts.append("hostd21")
+ hosts.append("hostd22")
+ config_hosts(tgen, hosts)
# tgen.mininet_cli()
@@ -634,6 +634,7 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None):
out = dut.vtysh_cmd("show evpn mac vni %d mac %s json" % (vni, mac))
+ tmp_esi = None
mac_js = json.loads(out)
for mac, info in mac_js.items():
tmp_esi = info.get("esi", "")
@@ -642,7 +643,15 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None):
if tmp_esi == esi and tmp_m_type == m_type and intf == intf:
return None
- return "invalid vni %d mac %s out %s" % (vni, mac, mac_js)
+ return "invalid vni %d mac %s expected esi %s, %s m_type %s and intf %s out %s" % (
+ vni,
+ mac,
+ tmp_esi,
+ esi,
+ m_type,
+ intf,
+ mac_js,
+ )
def test_evpn_mac():
diff --git a/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf
index 33353a61f1..4347052c5e 100644
--- a/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf
+++ b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf
@@ -1,5 +1,8 @@
!
!debug bgp neighbor
+!debug route-map detail
+!
+vni 10
!
int lo
ip address 10.10.10.1/32
@@ -9,22 +12,33 @@ int r1-eth1
!
router bgp 65001
no bgp ebgp-requires-policy
+ no bgp network import-check
neighbor 192.168.1.2 remote-as external
neighbor 192.168.1.2 timers 1 3
neighbor 192.168.1.2 timers connect 1
!
address-family ipv4 unicast
redistribute connected
+ network 10.10.10.10/32
exit-address-family
!
address-family l2vpn evpn
neighbor 192.168.1.2 activate
neighbor 192.168.1.2 route-map r2 out
advertise-all-vni
+ advertise ipv4 unicast
exit-address-family
!
route-map r2 deny 10
match evpn route-type macip
!
-route-map r2 permit 20
+route-map r2 deny 20
+ match ip address prefix-list pl
+ match evpn route-type prefix
+!
+route-map r2 permit 30
+!
+ip prefix-list pl seq 5 permit 192.168.1.0/24
+ip prefix-list pl seq 10 permit 10.10.10.1/32
+ip prefix-list pl seq 15 permit 10.10.10.2/32
!
diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py
index 18e25d5674..5781684a88 100644
--- a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py
+++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py
@@ -83,8 +83,8 @@ def test_bgp_evpn_route_map_match_route_type():
)
expected = {
"advertisedRoutes": {
- "10.10.10.1:2": {
- "[3]:[0]:[32]:[10.10.10.1]": {
+ "10.10.10.1:1": {
+ "[5]:[0]:[32]:[10.10.10.10]": {
"valid": True,
}
},
@@ -102,7 +102,7 @@ def test_bgp_evpn_route_map_match_route_type():
_bgp_converge,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
- assert result is None, "MAC-IP EVPN routes should not be advertised"
+ assert result is None, "Filtered EVPN routes should not be advertised"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json
index 98ae92ce55..45d00c6fa6 100644
--- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json
@@ -1,7 +1,7 @@
{
"vni":101,
"type":"L2",
- "vrf":"default",
+ "tenantVrf":"default",
"vxlanInterface":"vxlan0",
"vtepIp":"10.10.10.10",
"mcastGroup":"0.0.0.0",
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json
index 5c059786b2..f480b567ae 100644
--- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json
@@ -1,7 +1,7 @@
{
"vni":101,
"type":"L2",
- "vrf":"default",
+ "tenantVrf":"default",
"vxlanInterface":"vxlan0",
"vtepIp":"10.30.30.30",
"mcastGroup":"0.0.0.0",
diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
index a0cd89f064..d373a749fe 100644
--- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
+++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
@@ -62,23 +62,48 @@ def teardown_module(mod):
tgen.stop_topology()
+expected_1 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65002"}],
+ "172.16.255.32/32": [{"path": ""}],
+ }
+}
+
+expected_2 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": ""}],
+ "172.16.255.32/32": [{"path": ""}],
+ }
+}
+
+expected_3 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65003"}],
+ "172.16.255.32/32": [{"path": "65003"}],
+ }
+}
+
+expected_4 = {
+ "routes": {
+ "172.16.255.31/32": [{"path": "65002 65003"}],
+ "172.16.255.32/32": [{"path": "65002 65003"}],
+ }
+}
+
+
+def bgp_converge(router, expected):
+ output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
+
+ return topotest.json_cmp(output, expected)
+
+
def test_bgp_set_aspath_exclude():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": "65002"}],
- "172.16.255.32/32": [{"path": ""}],
- }
- }
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(_bgp_converge, tgen.gears["r1"])
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with route-map"
@@ -102,19 +127,7 @@ conf
"""
)
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": ""}],
- "172.16.255.32/32": [{"path": ""}],
- }
- }
-
- def _bgp_regexp_1(router):
- output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
-
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"])
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map"
@@ -127,19 +140,46 @@ conf
"""
)
- expected = {
- "routes": {
- "172.16.255.31/32": [{"path": "65003"}],
- "172.16.255.32/32": [{"path": "65003"}],
- }
- }
-
- test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"])
+ # tgen.mininet_cli()
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map"
+def test_no_bgp_set_aspath_exclude_access_list():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rname = "r1"
+ r1 = tgen.gears[rname]
+
+ r1.vtysh_cmd(
+ """
+conf
+ no bgp as-path access-list SECOND permit 2
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, "Failed removing bgp as-path access-list"
+
+ r1.vtysh_cmd(
+ """
+clear bgp *
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, "Failed to renegotiate with peers"
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf
new file mode 100644
index 0000000000..bcf5a0499f
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf
@@ -0,0 +1,4 @@
+!
+ip route 0.0.0.0/0 192.168.1.254
+ipv6 route ::/0 2001:1::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf
new file mode 100644
index 0000000000..0615cf9a95
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf
@@ -0,0 +1,6 @@
+hostname c11
+!
+interface eth0
+ ip address 192.168.1.1/24
+ ipv6 address 2001:1::1/64
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf
new file mode 100644
index 0000000000..bcf5a0499f
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf
@@ -0,0 +1,4 @@
+!
+ip route 0.0.0.0/0 192.168.1.254
+ipv6 route ::/0 2001:1::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf
new file mode 100644
index 0000000000..18985aa383
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf
@@ -0,0 +1,6 @@
+hostname c12
+!
+interface eth0
+ ip address 192.168.1.1/24
+ ipv6 address 2001:1::1/64
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf
new file mode 100644
index 0000000000..608e60060e
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf
@@ -0,0 +1,4 @@
+!
+ip route 0.0.0.0/0 192.168.2.254
+ipv6 route ::/0 2001:2::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf
new file mode 100644
index 0000000000..b8b70ac965
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf
@@ -0,0 +1,6 @@
+hostname c21
+!
+interface eth0
+ ip address 192.168.2.1/24
+ ipv6 address 2001:2::1/64
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf
new file mode 100644
index 0000000000..277aae998c
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf
@@ -0,0 +1,5 @@
+
+!
+ip route 0.0.0.0/0 192.168.2.254
+ipv6 route ::/0 2001:2::ffff
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf
new file mode 100644
index 0000000000..cc764cc35c
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf
@@ -0,0 +1,9 @@
+hostname c22
+!
+interface eth0
+ ip address 192.168.2.1/24
+ ipv6 address 2001:2::1/64
+!
+ip route 0.0.0.0/0 192.168.2.254
+ipv6 route ::/0 2001:2::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf
new file mode 100644
index 0000000000..0c88575abd
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf
@@ -0,0 +1,4 @@
+!
+ip route 0.0.0.0/0 192.168.3.254
+ipv6 route ::/0 2001:3::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf
new file mode 100644
index 0000000000..3f75641ea7
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf
@@ -0,0 +1,6 @@
+hostname c31
+!
+interface eth0
+ ip address 192.168.3.1/24
+ ipv6 address 2001:3::1/64
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf
new file mode 100644
index 0000000000..0c88575abd
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf
@@ -0,0 +1,4 @@
+!
+ip route 0.0.0.0/0 192.168.3.254
+ipv6 route ::/0 2001:3::ffff
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf
new file mode 100644
index 0000000000..c06a7d19f5
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf
@@ -0,0 +1,6 @@
+hostname c32
+!
+interface eth0
+ ip address 192.168.3.1/24
+ ipv6 address 2001:3::1/64
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf
new file mode 100644
index 0000000000..573dbe0951
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf
@@ -0,0 +1,61 @@
+frr defaults traditional
+!
+hostname r1
+password zebra
+!
+log commands
+!
+router bgp 65001
+ bgp router-id 192.0.2.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001:db8:12::2 remote-as 65002
+ neighbor 2001:db8:12::2 timers 3 10
+ neighbor 2001:db8:12::2 timers connect 1
+ neighbor 2001:db8:12::2 capability extended-nexthop
+ neighbor 2001:db8:13::3 remote-as 65001
+ neighbor 2001:db8:13::3 timers 3 10
+ neighbor 2001:db8:13::3 timers connect 1
+ neighbor 2001:db8:13::3 capability extended-nexthop
+ !
+ segment-routing srv6
+ locator default
+ !
+ address-family ipv4 vpn
+ neighbor 2001:db8:12::2 activate
+ neighbor 2001:db8:13::3 activate
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf10
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 1
+ rd vpn export 65001:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf20
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 2
+ rd vpn export 65001:20
+ rt vpn both 0:20
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+interface eth0
+ mpls bgp forwarding
+!
+interface eth1
+ mpls bgp forwarding
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf
new file mode 100644
index 0000000000..49b64fd7af
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf
@@ -0,0 +1,4 @@
+!
+ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
+ipv6 route 2001:db8:3:3::/64 2001:db8:13::3
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf
new file mode 100644
index 0000000000..79dbf95593
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf
@@ -0,0 +1,32 @@
+log file zebra.log
+!
+hostname r1
+!
+interface lo
+ ipv6 address 2001:db8:1:1::1/128
+!
+interface eth0
+ ipv6 address 2001:db8:12::1/64
+!
+interface eth1
+ ipv6 address 2001:db8:13::1/64
+!
+interface eth2 vrf vrf10
+ ip address 192.168.1.254/24
+!
+interface eth3 vrf vrf20
+ ip address 192.168.1.254/24
+!
+segment-routing
+ srv6
+ locators
+ locator default
+ prefix 2001:db8:1:1::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf
new file mode 100644
index 0000000000..723d6fca2f
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf
@@ -0,0 +1,50 @@
+frr defaults traditional
+!
+hostname r2
+password zebra
+!
+log commands
+!
+router bgp 65002
+ bgp router-id 192.0.2.2
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001:db8:12::1 remote-as 65001
+ neighbor 2001:db8:12::1 timers 3 10
+ neighbor 2001:db8:12::1 timers connect 1
+ neighbor 2001:db8:12::1 capability extended-nexthop
+ !
+ segment-routing srv6
+ locator default
+ !
+ address-family ipv4 vpn
+ neighbor 2001:db8:12::1 activate
+ exit-address-family
+ !
+!
+router bgp 65002 vrf vrf10
+ bgp router-id 192.0.2.2
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 1
+ rd vpn export 65002:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65002 vrf vrf20
+ bgp router-id 192.0.2.2
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 2
+ rd vpn export 65002:20
+ rt vpn both 0:20
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf
new file mode 100644
index 0000000000..8d80c1ead2
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf
@@ -0,0 +1,4 @@
+!
+ipv6 route 2001:db8:1:1::/64 2001:db8:12::1
+ipv6 route 2001:db8:3:3::/64 2001:db8:12::1
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf
new file mode 100644
index 0000000000..09a65b989c
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf
@@ -0,0 +1,29 @@
+log file zebra.log
+!
+hostname r2
+!
+interface lo
+ ipv6 address 2001:db8:2:2::1/128
+!
+interface eth0
+ ipv6 address 2001:db8:12::2/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.2.254/24
+!
+interface eth2 vrf vrf20
+ ip address 192.168.2.254/24
+!
+segment-routing
+ srv6
+ locators
+ locator default
+ prefix 2001:db8:2:2::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf
new file mode 100644
index 0000000000..c412cb6d29
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf
@@ -0,0 +1,50 @@
+frr defaults traditional
+!
+hostname r2
+password zebra
+!
+log commands
+!
+router bgp 65001
+ bgp router-id 192.0.2.3
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001:db8:13::1 remote-as 65001
+ neighbor 2001:db8:13::1 timers 3 10
+ neighbor 2001:db8:13::1 timers connect 1
+ neighbor 2001:db8:13::1 capability extended-nexthop
+ !
+ segment-routing srv6
+ locator default
+ !
+ address-family ipv4 vpn
+ neighbor 2001:db8:13::1 activate
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf10
+ bgp router-id 192.0.2.3
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 1
+ rd vpn export 65001:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf20
+ bgp router-id 192.0.2.2
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export 2
+ rd vpn export 65001:20
+ rt vpn both 0:20
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf
new file mode 100644
index 0000000000..9d672d51ba
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf
@@ -0,0 +1,6 @@
+!
+ipv6 route 2001:db8:12::/64 2001:db8:13::1
+!
+ipv6 route 2001:db8:1:1::/64 2001:db8:13::1
+ipv6 route 2001:db8:2:2::/64 2001:db8:13::1
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf
new file mode 100644
index 0000000000..a20cb76a74
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf
@@ -0,0 +1,29 @@
+log file zebra.log
+!
+hostname r2
+!
+interface lo
+ ipv6 address 2001:db8:3:3::1/128
+!
+interface eth0
+ ipv6 address 2001:db8:13::3/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.3.254/24
+!
+interface eth2 vrf vrf20
+ ip address 192.168.3.254/24
+!
+segment-routing
+ srv6
+ locators
+ locator default
+ prefix 2001:db8:3:3::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py
new file mode 100755
index 0000000000..92315bce04
--- /dev/null
+++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2023 by 6WIND
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+from lib.checkping import check_ping
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+ tgen.add_router("r3")
+
+ tgen.add_router("c11")
+ tgen.add_router("c12")
+ tgen.add_router("c21")
+ tgen.add_router("c22")
+ tgen.add_router("c31")
+ tgen.add_router("c32")
+
+ tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0")
+ tgen.add_link(tgen.gears["r1"], tgen.gears["r3"], "eth1", "eth0")
+ tgen.add_link(tgen.gears["r1"], tgen.gears["c11"], "eth2", "eth0")
+ tgen.add_link(tgen.gears["r1"], tgen.gears["c12"], "eth3", "eth0")
+ tgen.add_link(tgen.gears["r2"], tgen.gears["c21"], "eth1", "eth0")
+ tgen.add_link(tgen.gears["r2"], tgen.gears["c22"], "eth2", "eth0")
+ tgen.add_link(tgen.gears["r3"], tgen.gears["c31"], "eth1", "eth0")
+ tgen.add_link(tgen.gears["r3"], tgen.gears["c32"], "eth2", "eth0")
+
+
+def setup_module(mod):
+ result = required_linux_kernel_version("5.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r1"].run("ip link set vrf10 up")
+ tgen.gears["r1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r1"].run("ip link set vrf20 up")
+ tgen.gears["r1"].run("ip link set eth2 master vrf10")
+ tgen.gears["r1"].run("ip link set eth3 master vrf20")
+
+ tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r2"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r2"].run("ip link set vrf10 up")
+ tgen.gears["r2"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r2"].run("ip link set vrf20 up")
+ tgen.gears["r2"].run("ip link set eth1 master vrf10")
+ tgen.gears["r2"].run("ip link set eth2 master vrf20")
+
+ tgen.gears["r3"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r3"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r3"].run("ip link set vrf10 up")
+ tgen.gears["r3"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r3"].run("ip link set vrf20 up")
+ tgen.gears["r3"].run("ip link set eth1 master vrf10")
+ tgen.gears["r3"].run("ip link set eth2 master vrf20")
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_ping():
+ tgen = get_topogen()
+
+ check_ping("c11", "192.168.2.1", True, 10, 1)
+ check_ping("c11", "192.168.3.1", True, 10, 1)
+ check_ping("c12", "192.168.2.1", True, 10, 1)
+ check_ping("c12", "192.168.3.1", True, 10, 1)
+ check_ping("c21", "192.168.3.1", True, 10, 1)
+ check_ping("c22", "192.168.3.1", True, 10, 1)
+
+
+def test_sid_unreachable_nht():
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ no ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
+ """
+ )
+ check_ping("c11", "192.168.2.1", False, 10, 1)
+
+
+def test_sid_reachable_again_nht():
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ ipv6 route 2001:db8:2:2::/64 2001:db8:12::2
+ """
+ )
+ check_ping("c11", "192.168.2.1", True, 10, 1)
+
+
+def test_sid_unreachable_bgp_update():
+ get_topogen().gears["r2"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ no segment-routing srv6
+ exit
+ router bgp 65002 vrf vrf10
+ address-family ipv4 unicast
+ no sid vpn export 1
+ """
+ )
+ check_ping("c11", "192.168.2.1", False, 10, 1)
+
+
+def test_sid_reachable_again_bgp_update():
+ get_topogen().gears["r2"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ segment-routing srv6
+ locator default
+ exit
+ exit
+ router bgp 65002 vrf vrf10
+ address-family ipv4 unicast
+ sid vpn export 1
+ """
+ )
+ check_ping("c11", "192.168.2.1", True, 10, 1)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
index f52f56b0e0..397f7938d2 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
@@ -12,7 +12,7 @@ router bgp 99 vrf DONNA
address-family ipv4 unicast
redistribute connected
import vrf EVA
- import vrf NOTEXISTING
+ import vrf ZITA
import vrf default
!
!
@@ -21,10 +21,10 @@ router bgp 99 vrf EVA
address-family ipv4 unicast
redistribute connected
import vrf DONNA
- import vrf NOTEXISTING
+ import vrf ZITA
!
!
-router bgp 99 vrf NOTEXISTING
+router bgp 99 vrf ZITA
no bgp ebgp-requires-policy
no bgp network import-check
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
index ef813e9541..013ddfece9 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
@@ -24,7 +24,7 @@ sys.path.append(os.path.join(CWD, "../"))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
-
+from lib.checkping import check_ping
pytestmark = [pytest.mark.bgpd]
@@ -126,11 +126,13 @@ def test_vrf_route_leak_donna():
"172.16.101.0/24": [
{
"protocol": "bgp",
+ "selected": None,
"nexthops": [
{
- "interfaceIndex": 0,
+ "fib": None,
"interfaceName": "unknown",
"vrf": "Unknown",
+ "active": None,
},
],
},
@@ -196,11 +198,13 @@ def test_vrf_route_leak_eva():
"172.16.101.0/24": [
{
"protocol": "bgp",
+ "selected": None,
"nexthops": [
{
- "interfaceIndex": 0,
+ "fib": None,
"interfaceName": "unknown",
"vrf": "Unknown",
+ "active": None,
},
],
},
@@ -214,7 +218,7 @@ def test_vrf_route_leak_eva():
assert result, "BGP VRF EVA check failed:\n{}".format(diff)
-def test_vrf_route_leak_donna():
+def test_vrf_route_leak_default():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
@@ -223,37 +227,31 @@ def test_vrf_route_leak_donna():
r1 = tgen.gears["r1"]
- # Test DONNA VRF.
+ # Test default VRF.
expect = {
"10.0.0.0/24": [
{
- "protocol": "connected",
- }
- ],
- "10.0.1.0/24": [
- {
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
- "interfaceName": "EVA",
- "vrf": "EVA",
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
"active": True,
},
],
},
],
- "10.0.2.0/24": [{"protocol": "connected"}],
- "10.0.3.0/24": [
+ "10.0.2.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
- "interfaceName": "EVA",
- "vrf": "EVA",
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
"active": True,
},
],
@@ -261,26 +259,73 @@ def test_vrf_route_leak_donna():
],
"10.0.4.0/24": [
{
+ "protocol": "connected",
+ }
+ ],
+ }
+
+ test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF default check failed:\n{}".format(diff)
+
+
+def test_ping():
+ "Simple ping tests"
+
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Ping from default to DONNA")
+ check_ping("r1", "10.0.0.1", True, 10, 0.5, source_addr="10.0.4.1")
+
+
+def test_vrf_route_leak_donna_after_eva_down():
+ logger.info("Ensure that route states change after EVA interface goes down")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+configure
+interface EVA
+ shutdown
+"""
+ )
+
+ # Test DONNA VRF.
+ expect = {
+ "10.0.1.0/24": [
+ {
"protocol": "bgp",
- "selected": True,
+ "selected": None,
"nexthops": [
{
- "fib": True,
- "interfaceName": "lo",
- "vrf": "default",
- "active": True,
+ "fib": None,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": None,
},
],
},
],
- "172.16.101.0/24": [
+ "10.0.3.0/24": [
{
"protocol": "bgp",
+ "selected": None,
"nexthops": [
{
- "interfaceIndex": 0,
- "interfaceName": "unknown",
- "vrf": "Unknown",
+ "fib": None,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": None,
},
],
},
@@ -294,135 +339,157 @@ def test_vrf_route_leak_donna():
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
-def test_vrf_route_leak_eva():
- logger.info("Ensure that routes are leaked back and forth")
+def test_vrf_route_leak_donna_after_eva_up():
+ logger.info("Ensure that route states change after EVA interface goes up")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+configure
+interface EVA
+ no shutdown
+"""
+ )
- # Test EVA VRF.
+ # Test DONNA VRF.
expect = {
- "10.0.0.0/24": [
+ "10.0.1.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
- "interfaceName": "DONNA",
- "vrf": "DONNA",
+ "interfaceName": "EVA",
+ "vrf": "EVA",
"active": True,
},
],
},
],
- "10.0.1.0/24": [
- {
- "protocol": "connected",
- }
- ],
- "10.0.2.0/24": [
+ "10.0.3.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
- "interfaceName": "DONNA",
- "vrf": "DONNA",
+ "interfaceName": "EVA",
+ "vrf": "EVA",
"active": True,
},
],
},
],
- "10.0.3.0/24": [
- {
- "protocol": "connected",
- }
- ],
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
+
+def test_vrf_route_leak_donna_add_vrf_zita():
+ logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r1.cmd("ip link add ZITA type vrf table 1003")
+
+ # Test DONNA VRF.
+ expect = {
"172.16.101.0/24": [
{
"protocol": "bgp",
+ "selected": None,
"nexthops": [
{
- "interfaceIndex": 0,
- "interfaceName": "unknown",
- "vrf": "Unknown",
+ "fib": None,
+ "interfaceName": "ZITA",
+ "vrf": "ZITA",
+ "active": None,
},
],
},
],
}
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
-def test_vrf_route_leak_default():
- logger.info("Ensure that routes are leaked back and forth")
+def test_vrf_route_leak_donna_set_zita_up():
+ logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated")
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ """
+configure
+interface ZITA
+ no shutdown
+"""
+ )
- # Test default VRF.
+ # Test DONNA VRF.
expect = {
- "10.0.0.0/24": [
- {
- "protocol": "bgp",
- "selected": True,
- "nexthops": [
- {
- "fib": True,
- "interfaceName": "DONNA",
- "vrf": "DONNA",
- "active": True,
- },
- ],
- },
- ],
- "10.0.2.0/24": [
+ "172.16.101.0/24": [
{
"protocol": "bgp",
"selected": True,
"nexthops": [
{
"fib": True,
- "interfaceName": "DONNA",
- "vrf": "DONNA",
+ "interfaceName": "ZITA",
+ "vrf": "ZITA",
"active": True,
},
],
},
],
- "10.0.4.0/24": [
- {
- "protocol": "connected",
- }
- ],
}
- test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
- assert result, "BGP VRF default check failed:\n{}".format(diff)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
-def test_ping():
- "Simple ping tests"
-
+def test_vrf_route_leak_donna_delete_vrf_zita():
+ logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted")
tgen = get_topogen()
-
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
+ r1.cmd("ip link delete ZITA")
- logger.info("Ping from default to DONNA")
- output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1")
- assert " 0% packet loss" in output, "Ping default->DONNA FAILED"
+ # Test DONNA VRF.
+ expect = {
+ "172.16.101.0/24": None,
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
def test_memory_leak():
diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py
index aaa6164dd4..5500807fab 100644
--- a/tests/topotests/lib/checkping.py
+++ b/tests/topotests/lib/checkping.py
@@ -8,7 +8,7 @@ from lib.topolog import logger
from lib import topotest
-def check_ping(name, dest_addr, expect_connected, count, wait):
+def check_ping(name, dest_addr, expect_connected, count, wait, source_addr=None):
"""
Assert that ping to dest_addr is expected
* 'name': the router to set the ping from
@@ -18,9 +18,13 @@ def check_ping(name, dest_addr, expect_connected, count, wait):
* 'wait': how long ping should wait to receive all replies
"""
- def _check(name, dest_addr, match):
+ def _check(name, dest_addr, source_addr, match):
tgen = get_topogen()
- output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr))
+ cmd = "ping {}".format(dest_addr)
+ if source_addr:
+ cmd += " -I {}".format(source_addr)
+ cmd += " -c 1 -w 1"
+ output = tgen.gears[name].run(cmd)
logger.info(output)
if match not in output:
return "ping fail"
@@ -28,6 +32,6 @@ def check_ping(name, dest_addr, expect_connected, count, wait):
match = ", {} packet loss".format("0%" if expect_connected else "100%")
logger.info("[+] check {} {} {}".format(name, dest_addr, match))
tgen = get_topogen()
- func = functools.partial(_check, name, dest_addr, match)
+ func = functools.partial(_check, name, dest_addr, source_addr, match)
success, result = topotest.run_and_expect(func, None, count=count, wait=wait)
assert result is None, "Failed"
diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py
index 07059ccf3a..a47544633b 100755
--- a/tests/topotests/lib/fe_client.py
+++ b/tests/topotests/lib/fe_client.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
# SPDX-License-Identifier: GPL-2.0-or-later
#
diff --git a/tests/topotests/mgmt_config/test_regression.py b/tests/topotests/mgmt_config/test_regression.py
index 70f38d2ec7..928151a23a 100644
--- a/tests/topotests/mgmt_config/test_regression.py
+++ b/tests/topotests/mgmt_config/test_regression.py
@@ -51,3 +51,23 @@ def test_regression_issue_13920(tgen):
)
output = r1.net.checkRouterCores()
assert not output.strip()
+
+
+def test_regression_pullreq_15423(tgen):
+ r1 = tgen.gears["r1"]
+ r1.vtysh_multicmd(
+ """
+ conf t
+ access-list test seq 1 permit ip any 10.10.10.0 0.0.0.255
+ """
+ )
+
+ output = r1.vtysh_multicmd(
+ """
+ conf terminal file-lock
+ mgmt delete-config /frr-filter:lib/access-list[name='test'][type='ipv4']/entry[sequence='1']/destination-network
+ mgmt commit apply
+ end
+ """
+ )
+ assert "No changes found" not in output
diff --git a/tests/topotests/nb_config/r1/frr.conf b/tests/topotests/nb_config/r1/frr.conf
new file mode 100644
index 0000000000..677ec0b86d
--- /dev/null
+++ b/tests/topotests/nb_config/r1/frr.conf
@@ -0,0 +1,6 @@
+log timestamp precision 6
+log file frr.log
+
+interface r1-eth0
+ ip address 1.1.1.1/24
+exit
diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py
new file mode 100644
index 0000000000..f699a4e20e
--- /dev/null
+++ b/tests/topotests/nb_config/test_nb_config.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# February 24 2024, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2024, LabN Consulting, L.L.C.
+#
+"""
+Test Northbound Config Operations
+"""
+import json
+import os
+
+import pytest
+from lib.topogen import Topogen
+from lib.topotest import json_cmp
+
+pytestmark = [pytest.mark.mgmtd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {
+ "s1": ("r1",)
+ }
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def test_access_list_config_ordering(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ output = r1.vtysh_multicmd([
+ "conf t",
+ "access-list test seq 1 permit host 10.0.0.1"])
+ output = r1.vtysh_cmd("show ip access-list test json")
+ got = json.loads(output)
+ expected = json.loads('{"ZEBRA":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}')
+ result = json_cmp(got, expected)
+ assert result is None
+
+ #
+ # If the northbound mis-orders the create/delete then this test fails.
+ # https://github.com/FRRouting/frr/pull/15423/commits/38b85e0c2bc555b8827dbd2cb6515b6febf548b4
+ #
+ output = r1.vtysh_multicmd([
+ "conf t",
+ "access-list test seq 1 permit 10.0.0.0/8"])
+ output = r1.vtysh_cmd("show ip access-list test json")
+ got = json.loads(output)
+ expected = json.loads('{"ZEBRA":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}')
+ result = json_cmp(got, expected)
+ assert result is None
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index c50c51389e..c679f3b911 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -379,6 +379,7 @@ identity set-extcommunity-color {
grouping extcommunity-non-transitive-types {
leaf two-octet-as-specific {
type boolean;
+ default false;
description
"Non-Transitive Two-Octet AS-Specific Extended Community";
}
@@ -769,6 +770,7 @@ identity set-extcommunity-color {
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity')";
container comm-list {
leaf comm-list-name {
+ mandatory true;
type bgp-filter:bgp-list-name;
}
@@ -872,11 +874,13 @@ identity set-extcommunity-color {
description
"Value of the ext-community.";
leaf lb-type {
+ mandatory true;
type frr-bgp-route-map:extcommunity-lb-type;
}
leaf bandwidth {
when "../lb-type = 'explicit-bandwidth'";
+ mandatory true;
type uint16 {
range "1..25600";
}
@@ -1108,12 +1112,14 @@ identity set-extcommunity-color {
container aggregator {
leaf aggregator-asn {
type asn-type;
+ mandatory true;
description
"ASN of the aggregator";
}
leaf aggregator-address {
type inet:ipv4-address;
+ mandatory true;
description
"IPv4 address of the aggregator";
}
diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c
index 4c32044251..7a5388c57b 100644
--- a/zebra/dpdk/zebra_dplane_dpdk.c
+++ b/zebra/dpdk/zebra_dplane_dpdk.c
@@ -105,8 +105,7 @@ static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg)
ifp = if_lookup_by_name_vrf(rule->ifname, vrf);
if (ifp)
- zd_dpdk_flow_stat_show(vty, ifp->ifindex,
- zaction->dp_flow_ptr);
+ zd_dpdk_flow_stat_show(vty, ifp->ifindex, zaction->dp_flow_ptr);
}
return HASHWALK_CONTINUE;
}
@@ -153,8 +152,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
zlog_debug(
"PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n",
- dplane_ctx_rule_get_ifname(ctx), seq, pri,
- unique, in_ifindex);
+ dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, in_ifindex);
return;
}
@@ -163,8 +161,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)
zlog_debug(
"PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n",
- dplane_ctx_rule_get_ifname(ctx), seq, pri,
- unique, out_ifindex);
+ dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, out_ifindex);
return;
}
@@ -180,7 +177,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
memset(&ip, 0, sizeof(ip));
memset(&ip_mask, 0, sizeof(ip_mask));
- if (filter_bm & PBR_FILTER_SRC_IP) {
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP)) {
const struct prefix *src_ip;
src_ip = dplane_ctx_rule_get_src_ip(ctx);
@@ -188,7 +185,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
masklen2ip(src_ip->prefixlen, &tmp_mask);
ip_mask.hdr.src_addr = tmp_mask.s_addr;
}
- if (filter_bm & PBR_FILTER_DST_IP) {
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP)) {
const struct prefix *dst_ip;
dst_ip = dplane_ctx_rule_get_dst_ip(ctx);
@@ -196,7 +193,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
masklen2ip(dst_ip->prefixlen, &tmp_mask);
ip_mask.hdr.dst_addr = tmp_mask.s_addr;
}
- if (filter_bm & PBR_FILTER_IP_PROTOCOL) {
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_IP_PROTOCOL)) {
ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx);
ip_mask.hdr.next_proto_id = UINT8_MAX;
}
@@ -206,17 +203,15 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
items[item_cnt].last = NULL;
++item_cnt;
- if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) {
+ if (CHECK_FLAG(filter_bm, (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) {
memset(&udp, 0, sizeof(udp));
memset(&udp_mask, 0, sizeof(udp_mask));
- if (filter_bm & PBR_FILTER_SRC_PORT) {
- udp.hdr.src_port =
- RTE_BE16(dplane_ctx_rule_get_src_port(ctx));
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_PORT)) {
+ udp.hdr.src_port = RTE_BE16(dplane_ctx_rule_get_src_port(ctx));
udp_mask.hdr.src_port = UINT16_MAX;
}
- if (filter_bm & PBR_FILTER_DST_PORT) {
- udp.hdr.dst_port =
- RTE_BE16(dplane_ctx_rule_get_dst_port(ctx));
+ if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_PORT)) {
+ udp.hdr.dst_port = RTE_BE16(dplane_ctx_rule_get_dst_port(ctx));
udp_mask.hdr.dst_port = UINT16_MAX;
}
items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP;
@@ -273,8 +268,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx)
} else {
zlog_warn(
"PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n",
- dplane_ctx_rule_get_ifname(ctx), seq, pri, unique,
- error.type);
+ dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, error.type);
}
}
@@ -562,7 +556,7 @@ void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail)
for (count = 0; count < RTE_MAX_ETHPORTS; ++count) {
dport = &dpdk_ctx->dpdk_ports[count];
- if (dport->flags & ZD_DPDK_PORT_FLAG_INITED)
+ if (CHECK_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED))
zd_dpdk_port_show_entry(dport, vty, detail);
}
}
@@ -592,14 +586,14 @@ static void zd_dpdk_port_init(void)
dport = &dpdk_ctx->dpdk_ports[count];
count++;
dport->port_id = port_id;
- dport->flags |= ZD_DPDK_PORT_FLAG_PROBED;
+ SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_PROBED);
dev_info = &dport->dev_info;
if (rte_eth_dev_info_get(port_id, dev_info) < 0) {
zlog_warn("failed to get dev info for %u, %s", port_id,
rte_strerror(rte_errno));
continue;
}
- dport->flags |= ZD_DPDK_PORT_FLAG_INITED;
+ SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED);
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
zlog_debug(
"port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u",
@@ -611,12 +605,10 @@ static void zd_dpdk_port_init(void)
if (rte_flow_isolate(port_id, 1, &error)) {
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
zlog_debug(
- "Flow isolate on port %u failed %d",
- port_id, error.type);
+ "Flow isolate on port %u failed %d", port_id, error.type);
} else {
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
- zlog_debug("Flow isolate on port %u",
- port_id);
+ zlog_debug("Flow isolate on port %u", port_id);
}
rc = rte_eth_dev_start(port_id);
if (rc) {
@@ -625,8 +617,7 @@ static void zd_dpdk_port_init(void)
continue;
}
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
- zlog_debug("DPDK port %d started in promiscuous mode ",
- port_id);
+ zlog_debug("DPDK port %d started in promiscuous mode ", port_id);
}
if (!count) {
@@ -639,8 +630,7 @@ static void zd_dpdk_port_init(void)
static int zd_dpdk_init(void)
{
int rc;
- static const char *argv[] = {(char *)"/usr/lib/frr/zebra",
- (char *)"--"};
+ static const char *argv[] = {(char *)"/usr/lib/frr/zebra", (char *)"--"};
zd_dpdk_vty_init();
@@ -674,8 +664,7 @@ static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early)
if (early) {
if (IS_ZEBRA_DEBUG_DPLANE_DPDK)
- zlog_debug("%s early finish",
- dplane_provider_get_name(prov));
+ zlog_debug("%s early finish", dplane_provider_get_name(prov));
return 0;
}
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 147f5b93fa..ae9b3c49eb 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -109,21 +109,14 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt)
} else {
json_object_int_add(json, "vni", zevpn->vni);
json_object_string_add(json, "type", "L2");
-#if CONFDATE > 20240210
-CPP_NOTICE("Drop `vrf` from JSON output")
-#endif
- json_object_string_add(json, "vrf",
- vrf_id_to_name(zevpn->vrf_id));
- json_object_string_add(json, "tenantVrf",
- vrf_id_to_name(zevpn->vrf_id));
+ json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id));
}
if (!zevpn->vxlan_if) { // unexpected
if (json == NULL)
vty_out(vty, " VxLAN interface: unknown\n");
else
- json_object_string_add(json, "vxlanInterface",
- "unknown");
+ json_object_string_add(json, "vxlanInterface", "unknown");
return;
}
num_macs = num_valid_macs(zevpn);
@@ -135,35 +128,21 @@ CPP_NOTICE("Drop `vrf` from JSON output")
(zevpn->svi_if ? zevpn->svi_if->name : ""));
vty_out(vty, " SVI ifIndex: %u\n",
(zevpn->svi_if ? zevpn->svi_if->ifindex : 0));
- vty_out(vty, " Local VTEP IP: %pI4\n",
- &zevpn->local_vtep_ip);
- vty_out(vty, " Mcast group: %pI4\n",
- &zevpn->mcast_grp);
+ vty_out(vty, " Local VTEP IP: %pI4\n", &zevpn->local_vtep_ip);
+ vty_out(vty, " Mcast group: %pI4\n", &zevpn->mcast_grp);
} else {
- json_object_string_add(json, "vxlanInterface",
- zevpn->vxlan_if->name);
-#if CONFDATE > 20240210
-CPP_NOTICE("Drop `ifindex` from JSON output")
-#endif
- json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex);
- json_object_int_add(json, "vxlanIfindex",
- zevpn->vxlan_if->ifindex);
+ json_object_string_add(json, "vxlanInterface", zevpn->vxlan_if->name);
+ json_object_int_add(json, "vxlanIfindex", zevpn->vxlan_if->ifindex);
if (zevpn->svi_if) {
- json_object_string_add(json, "sviInterface",
- zevpn->svi_if->name);
- json_object_int_add(json, "sviIfindex",
- zevpn->svi_if->ifindex);
+ json_object_string_add(json, "sviInterface", zevpn->svi_if->name);
+ json_object_int_add(json, "sviIfindex", zevpn->svi_if->ifindex);
}
- json_object_string_addf(json, "vtepIp", "%pI4",
- &zevpn->local_vtep_ip);
- json_object_string_addf(json, "mcastGroup", "%pI4",
- &zevpn->mcast_grp);
+ json_object_string_addf(json, "vtepIp", "%pI4", &zevpn->local_vtep_ip);
+ json_object_string_addf(json, "mcastGroup", "%pI4", &zevpn->mcast_grp);
json_object_string_add(json, "advertiseGatewayMacip",
- zevpn->advertise_gw_macip ? "Yes"
- : "No");
+ zevpn->advertise_gw_macip ? "Yes" : "No");
json_object_string_add(json, "advertiseSviMacip",
- zevpn->advertise_svi_macip ? "Yes"
- : "No");
+ zevpn->advertise_svi_macip ? "Yes" : "No");
json_object_int_add(json, "numMacs", num_macs);
json_object_int_add(json, "numArpNd", num_neigh);
}
@@ -179,28 +158,21 @@ CPP_NOTICE("Drop `ifindex` from JSON output")
json_vtep_list = json_object_new_array();
for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
const char *flood_str = lookup_msg(
- zvtep_flood_str, zvtep->flood_control,
- VXLAN_FLOOD_STR_DEFAULT);
+ zvtep_flood_str, zvtep->flood_control, VXLAN_FLOOD_STR_DEFAULT);
if (json == NULL) {
- vty_out(vty, " %pI4 flood: %s\n",
- &zvtep->vtep_ip,
- flood_str);
+ vty_out(vty, " %pI4 flood: %s\n", &zvtep->vtep_ip, flood_str);
} else {
json_vtep = json_object_new_object();
- json_object_string_addf(json_vtep, "ip", "%pI4",
- &zvtep->vtep_ip);
- json_object_string_add(json_vtep, "flood",
- flood_str);
- json_object_array_add(json_vtep_list,
- json_vtep);
+ json_object_string_addf(json_vtep, "ip", "%pI4", &zvtep->vtep_ip);
+ json_object_string_add(json_vtep, "flood", flood_str);
+ json_object_array_add(json_vtep_list, json_vtep);
}
num_vteps++;
}
if (json) {
json_object_int_add(json, "numRemoteVteps", num_vteps);
- json_object_object_add(json, "remoteVteps",
- json_vtep_list);
+ json_object_object_add(json, "remoteVteps", json_vtep_list);
}
}
if (json == NULL) {
@@ -261,8 +233,7 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[])
json_object_int_add(json_evpn, "vni", zevpn->vni);
json_object_string_add(json_evpn, "type", "L2");
json_object_string_add(json_evpn, "vxlanIf",
- zevpn->vxlan_if ? zevpn->vxlan_if->name
- : "unknown");
+ zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown");
json_object_int_add(json_evpn, "numMacs", num_macs);
json_object_int_add(json_evpn, "numArpNd", num_neigh);
json_object_int_add(json_evpn, "numRemoteVteps", num_vteps);
@@ -272,13 +243,10 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[])
json_vtep_list = json_object_new_array();
for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) {
json_ip_str = json_object_new_string(
- inet_ntop(AF_INET, &zvtep->vtep_ip, buf,
- sizeof(buf)));
- json_object_array_add(json_vtep_list,
- json_ip_str);
+ inet_ntop(AF_INET, &zvtep->vtep_ip, buf, sizeof(buf)));
+ json_object_array_add(json_vtep_list, json_ip_str);
}
- json_object_object_add(json_evpn, "remoteVteps",
- json_vtep_list);
+ json_object_object_add(json_evpn, "remoteVteps", json_vtep_list);
}
json_object_object_add(json, vni_str, json_evpn);
}
@@ -490,8 +458,7 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn,
/* Remove neighbor from BGP. */
zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac,
- n->flags, ZEBRA_NEIGH_ACTIVE,
- false /*force*/);
+ n->flags, ZEBRA_NEIGH_ACTIVE, false /*force*/);
/* Delete this neighbor entry. */
zebra_evpn_neigh_del(zevpn, n);
@@ -521,8 +488,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
*/
if (zevpn->advertise_gw_macip) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip",
- zevpn->vni);
+ zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", zevpn->vni);
return;
}
@@ -694,8 +660,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
if (zif->brslave_info.br_if != br_if)
continue;
- vni_id =
- zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
+ vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
if (vni_id) {
found = 1;
break;
@@ -732,9 +697,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
in_param.zif = zif;
p_zevpn = &zevpn;
- ns_walk_func(zebra_evpn_map_vlan_ns,
- (void *)&in_param,
- (void **)p_zevpn);
+ ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn);
return zevpn;
}
@@ -854,9 +817,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
return zevpn;
}
-static int zvni_map_to_macvlan_ns(struct ns *ns,
- void *_in_param,
- void **_p_ifp)
+static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp)
{
struct zebra_ns *zns = ns->info;
struct zebra_from_svi_param *in_param =
@@ -918,9 +879,7 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */
- ns_walk_func(zvni_map_to_macvlan_ns,
- (void *)&in_param,
- (void **)p_ifp);
+ ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp);
return tmp_if;
}
@@ -1125,8 +1084,7 @@ struct zebra_evpn *zebra_evpn_add(vni_t vni)
/* Create hash table for MAC */
zevpn->mac_table = zebra_mac_db_create(buffer);
- snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u",
- vni);
+ snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", vni);
/* Create hash table for neighbors */
zevpn->neigh_table = zebra_neigh_db_create(buffer);
@@ -1205,8 +1163,8 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn)
client->vniadd_cnt++;
rc = zserv_send_message(client, s);
- if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) {
- zevpn->flags |= ZEVPN_READY_FOR_BGP;
+ if (!CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) {
+ SET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP);
/* once the EVPN is sent the ES-EVIs can also be replayed
* to BGP
*/
@@ -1228,8 +1186,8 @@ int zebra_evpn_send_del_to_client(struct zebra_evpn *zevpn)
if (!client)
return 0;
- if (zevpn->flags & ZEVPN_READY_FOR_BGP) {
- zevpn->flags &= ~ZEVPN_READY_FOR_BGP;
+ if (CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) {
+ UNSET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP);
/* the ES-EVIs must be removed from BGP before the EVPN is */
zebra_evpn_update_all_es(zevpn);
}
@@ -1350,8 +1308,7 @@ int zebra_evpn_vtep_install(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep)
if (is_vxlan_flooding_head_end() &&
(zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) {
if (ZEBRA_DPLANE_REQUEST_FAILURE ==
- dplane_vtep_add(zevpn->vxlan_if,
- &zvtep->vtep_ip, zevpn->vni))
+ dplane_vtep_add(zevpn->vxlan_if, &zvtep->vtep_ip, zevpn->vni))
return -1;
}
@@ -1442,9 +1399,7 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
zevpn->vni,
macaddr,
ipa_len ? " IP " : "",
- ipa_len ? ipaddr2str(ipaddr, ipbuf,
- sizeof(ipbuf))
- : "",
+ ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "",
sticky ? " sticky" : "",
remote_gw ? " remote_gw" : "");
return;
@@ -1459,16 +1414,13 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn,
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr,
- ipa_len, ipaddr,
- flags, seq, esi);
+ 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))
+ if (n && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, true))
return;
zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr,
@@ -1514,22 +1466,19 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
* SYNC - if ES is local
* REMOTE - if ES is not local
*/
- if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) {
+ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH)) {
struct zebra_evpn_es *es;
es = zebra_evpn_es_find(esi);
- if (es && (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)) {
+ if (es && CHECK_FLAG(es->flags, ZEBRA_EVPNES_READY_FOR_BGP)) {
zebra_evpn_process_sync_macip_add(zevpn, macaddr,
- ipa_len, ipaddr,
- flags, seq, esi);
+ ipa_len, ipaddr, flags, seq, esi);
} else {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
char esi_str[ESI_STR_LEN];
esi_to_str(esi, esi_str, sizeof(esi_str));
- zlog_debug(
- "Ignore sync-macip add; ES %s is not ready",
- esi_str);
+ zlog_debug("Ignore sync-macip add; ES %s is not ready", esi_str);
}
}
@@ -1543,8 +1492,7 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr,
if (vtep_ip.s_addr) {
zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip);
if (!zvtep) {
- zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip,
- VXLAN_FLOOD_DISABLED);
+ zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, VXLAN_FLOOD_DISABLED);
if (!zvtep) {
flog_err(
EC_ZEBRA_VTEP_ADD_FAILED,
@@ -1621,9 +1569,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
vnip = zebra_vxlan_if_vni_find(zif, vni);
if (!vnip) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "VNI %u not in interface upon remote MACIP DEL",
- vni);
+ zlog_debug("VNI %u not in interface upon remote MACIP DEL", vni);
return;
}
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index 7e1c43c204..e1ca5ec19b 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -456,6 +456,8 @@ const struct frr_yang_module_info frr_zebra_info = {
{
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities",
.cbs = {
+ .create = lib_interface_zebra_affinities_create,
+ .destroy = lib_interface_zebra_affinities_destroy,
},
},
{
@@ -531,6 +533,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0",
+ .cbs = {
+ .create = lib_interface_zebra_evpn_mh_type_0_create,
+ .destroy = lib_interface_zebra_evpn_mh_type_0_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi",
.cbs = {
.modify = lib_interface_zebra_evpn_mh_type_0_esi_modify,
@@ -538,6 +547,13 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3",
+ .cbs = {
+ .create = lib_interface_zebra_evpn_mh_type_3_create,
+ .destroy = lib_interface_zebra_evpn_mh_type_3_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac",
.cbs = {
.modify = lib_interface_zebra_evpn_mh_type_3_system_mac_modify,
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index 97979ef962..d7cf5f4040 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -145,6 +145,8 @@ int lib_interface_zebra_link_params_utilized_bandwidth_destroy(
int lib_interface_zebra_legacy_admin_group_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_legacy_admin_group_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args);
int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args);
@@ -175,9 +177,13 @@ int lib_interface_zebra_link_params_packet_loss_modify(
struct nb_cb_modify_args *args);
int lib_interface_zebra_link_params_packet_loss_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args);
int lib_interface_zebra_evpn_mh_type_0_esi_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args);
+int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args);
int lib_interface_zebra_evpn_mh_type_3_system_mac_modify(
struct nb_cb_modify_args *args);
int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy(
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index 46c95e6c0f..5cb9985ee4 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -1746,9 +1746,6 @@ int lib_interface_zebra_legacy_admin_group_modify(
iflp->admin_grp = admin_group_value;
SET_PARAM(iflp, LP_ADM_GRP);
-
- admin_group_clear(&iflp->ext_admin_grp);
- UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP);
break;
}
return NB_OK;
@@ -1778,6 +1775,35 @@ int lib_interface_zebra_legacy_admin_group_destroy(
/*
* XPath:
+ * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities
+ */
+int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ struct if_link_params *iflp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ iflp = if_link_params_get(ifp);
+
+ iflp->admin_grp = 0;
+ UNSET_PARAM(iflp, LP_ADM_GRP);
+
+ admin_group_clear(&iflp->ext_admin_grp);
+ UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
* /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity
*/
int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args)
@@ -2282,6 +2308,27 @@ static bool esi_unique(struct lyd_node *dnode)
}
/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0
+ */
+int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zebra_evpn_es_type0_esi_update(ifp->info, NULL);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi
*/
int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args)
@@ -2325,6 +2372,28 @@ int lib_interface_zebra_evpn_mh_type_0_esi_destroy(struct nb_cb_destroy_args *ar
}
/*
+ * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3
+ */
+int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args)
+{
+ return NB_OK;
+}
+
+int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ zebra_evpn_es_sys_mac_update(ifp->info, NULL);
+ zebra_evpn_es_lid_update(ifp->info, 0);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac
*/
int lib_interface_zebra_evpn_mh_type_3_system_mac_modify(
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 64eae38fc9..cc12cb4221 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -769,10 +769,6 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx)
json_evpn_list = json_object_new_array();
json_object_int_add(json, "vni", zl3vni->vni);
json_object_string_add(json, "type", "L3");
-#if CONFDATE > 20240210
-CPP_NOTICE("Drop `vrf` from JSON outputs")
-#endif
- json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni));
json_object_string_add(json, "tenantVrf",
zl3vni_vrf_name(zl3vni));
json_object_string_addf(json, "localVtepIp", "%pI4",