summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c13
-rw-r--r--bgpd/bgp_attr.h4
-rw-r--r--bgpd/bgp_fsm.c24
-rw-r--r--bgpd/bgp_network.c37
-rw-r--r--bgpd/bgp_network.h5
-rw-r--r--bgpd/bgp_nexthop.c121
-rw-r--r--bgpd/bgp_nexthop.h33
-rw-r--r--bgpd/bgp_nht.c299
-rw-r--r--bgpd/bgp_open.c3
-rw-r--r--bgpd/bgp_routemap.c43
-rw-r--r--bgpd/bgp_zebra.c8
-rw-r--r--bgpd/bgpd.c17
-rw-r--r--bgpd/bgpd.h312
-rw-r--r--doc/figures/nodes.dot2
-rw-r--r--doc/user/isisd.rst27
-rw-r--r--doc/user/routemap.rst6
-rw-r--r--isisd/isis_circuit.c39
-rw-r--r--isisd/isis_cli.c160
-rw-r--r--isisd/isis_main.c5
-rw-r--r--isisd/isis_nb.c7
-rw-r--r--isisd/isis_nb.h1
-rw-r--r--isisd/isis_nb_config.c69
-rw-r--r--isisd/isis_zebra.c14
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c136
-rw-r--r--isisd/isisd.h9
-rw-r--r--ldpd/lde.c158
-rw-r--r--ldpd/lde.h3
-rw-r--r--ldpd/lde_lib.c20
-rw-r--r--ldpd/ldp_vty_cmds.c2
-rw-r--r--ldpd/ldpd.c43
-rw-r--r--ldpd/ldpe.c8
-rw-r--r--lib/hash.c15
-rw-r--r--lib/mpls.h3
-rw-r--r--lib/privs.c6
-rw-r--r--lib/stream.c24
-rw-r--r--lib/stream.h9
-rw-r--r--ospf6d/ospf6_interface.c5
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf40
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_vrf.conf21
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R1/zebra.conf21
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf37
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_vrf.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R2/zebra.conf21
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf37
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_vrf.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R3/zebra.conf21
-rwxr-xr-xtests/topotests/bgp-auth/test_bgp_auth.py747
-rw-r--r--tests/topotests/isis-topo1-vrf/__init__.py0
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/isisd.conf15
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_route.json57
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_route6.json40
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json14
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/r1_route_linux.json13
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_topology.json80
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/zebra.conf9
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/isisd.conf15
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_route.json57
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_route6.json40
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json14
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/r2_route_linux.json13
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_topology.json80
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/zebra.conf9
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/isisd.conf22
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_route.json112
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/r3_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_topology.json132
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/isisd.conf25
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_route.json105
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/r4_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_topology.json132
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/isisd.conf21
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_route.json106
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/r5_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_topology.json124
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot100
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpgbin0 -> 74340 bytes
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py455
-rw-r--r--tests/topotests/lib/topotest.py84
-rw-r--r--vtysh/vtysh.c5
-rw-r--r--yang/frr-isisd.yang15
112 files changed, 4791 insertions, 524 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index cac3ab1ca7..8817263cef 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -729,7 +729,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
&& attr1->distance == attr2->distance
&& srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
- && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
+ && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
+ && attr1->srte_color == attr2->srte_color)
return true;
}
@@ -1631,16 +1632,20 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
external peer, then this attribute MUST be ignored by the
receiving speaker. */
if (peer->sort == BGP_PEER_EBGP) {
- stream_forward_getp(peer->curr, length);
+ STREAM_FORWARD_GETP(peer->curr, length);
return BGP_ATTR_PARSE_PROCEED;
}
- attr->local_pref = stream_getl(peer->curr);
+ STREAM_GETL(peer->curr, attr->local_pref);
/* Set the local-pref flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
return BGP_ATTR_PARSE_PROCEED;
+
+stream_failure:
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
/* Atomic aggregate. */
@@ -3023,7 +3028,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
size_t lfl =
CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
/* Rewind to end of flag field */
- stream_forward_getp(BGP_INPUT(peer), -(1 + lfl));
+ stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
/* Type */
stream_get(&ndata[0], BGP_INPUT(peer), 1);
/* Length */
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index c57cf81007..e6e953364b 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -24,6 +24,7 @@
#include "mpls.h"
#include "bgp_attr_evpn.h"
#include "bgpd/bgp_encap_types.h"
+#include "srte.h"
/* Simple bit mapping. */
#define BITMAP_NBBY 8
@@ -290,6 +291,9 @@ struct attr {
/* EVPN ES */
esi_t esi;
+
+ /* SR-TE Color */
+ uint32_t srte_color;
};
/* rmap_change_flags definition */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 28e93c4096..58a2d42ba8 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1872,6 +1872,30 @@ static int bgp_establish(struct peer *peer)
}
}
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ if ((bgp_peer_gr_mode_get(peer) == PEER_GR)
+ || ((bgp_peer_gr_mode_get(peer) == PEER_GLOBAL_INHERIT)
+ && (bgp_global_gr_mode_get(peer->bgp) == GLOBAL_GR))) {
+ FOREACH_AFI_SAFI (afi, safi)
+ /* Send route processing complete
+ message to RIB */
+ bgp_zebra_update(
+ afi, safi, peer->bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ }
+ } else {
+ /* Peer sends R-bit. In this case, we need to send
+ * ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV)) {
+ FOREACH_AFI_SAFI (afi, safi)
+ /* Send route processing complete
+ message to RIB */
+ bgp_zebra_update(
+ afi, safi, peer->bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ }
+ }
+
peer->nsf_af_count = nsf_af_count;
if (nsf_af_count)
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index c324f259ba..cae11ae7bd 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -160,12 +160,26 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
*/
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
- if (listener->su.sa.sa_family
- == peer->su.sa.sa_family) {
+ if (listener->su.sa.sa_family ==
+ peer->su.sa.sa_family) {
uint16_t prefixlen =
peer->su.sa.sa_family == AF_INET
- ? IPV4_MAX_PREFIXLEN
- : IPV6_MAX_PREFIXLEN;
+ ? IPV4_MAX_PREFIXLEN
+ : IPV6_MAX_PREFIXLEN;
+
+ /*
+ * if we have stored a BGP vrf instance in the
+ * listener it must match the bgp instance in
+ * the peer otherwise the peer bgp instance
+ * must be the default vrf or a view instance
+ */
+ if (!listener->bgp) {
+ if (peer->bgp->vrf_id != VRF_DEFAULT
+ && peer->bgp->inst_type
+ != BGP_INSTANCE_TYPE_VIEW)
+ continue;
+ } else if (listener->bgp != peer->bgp)
+ continue;
ret = bgp_md5_set_socket(listener->fd,
&peer->su, prefixlen,
@@ -176,7 +190,7 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
return ret;
}
-int bgp_md5_set_prefix(struct prefix *p, const char *password)
+int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, const char *password)
{
int ret = 0;
union sockunion su;
@@ -186,7 +200,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)
/* Set or unset the password on the listen socket(s). */
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
- if (listener->su.sa.sa_family == p->family) {
+ if (listener->su.sa.sa_family == p->family
+ && ((bgp->vrf_id == VRF_DEFAULT)
+ || (listener->bgp == bgp))) {
prefix2sockunion(p, &su);
ret = bgp_md5_set_socket(listener->fd, &su,
p->prefixlen,
@@ -198,9 +214,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)
return ret;
}
-int bgp_md5_unset_prefix(struct prefix *p)
+int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p)
{
- return bgp_md5_set_prefix(p, NULL);
+ return bgp_md5_set_prefix(bgp, p, NULL);
}
int bgp_md5_set(struct peer *peer)
@@ -812,8 +828,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
listener->fd = sock;
listener->name = XSTRDUP(MTYPE_BGP_LISTENER, bgp->name);
- /* this socket needs a change of ns. record bgp back pointer */
- if (bgp->vrf_id != VRF_DEFAULT && vrf_is_backend_netns())
+ /* this socket is in a vrf record bgp back pointer */
+ if (bgp->vrf_id != VRF_DEFAULT
+ && bgp->inst_type != BGP_INSTANCE_TYPE_VIEW)
listener->bgp = bgp;
memcpy(&listener->su, sa, salen);
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 018efbc08e..0b5cc17523 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -31,8 +31,9 @@ extern void bgp_close(void);
extern int bgp_connect(struct peer *);
extern int bgp_getsockname(struct peer *);
-extern int bgp_md5_set_prefix(struct prefix *p, const char *password);
-extern int bgp_md5_unset_prefix(struct prefix *p);
+extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p,
+ const char *password);
+extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p);
extern int bgp_md5_set(struct peer *);
extern int bgp_md5_unset(struct peer *);
extern int bgp_set_socket_ttl(struct peer *, int fd);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 5cc0d60529..ed026a2fff 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -35,7 +35,6 @@
#include "filter.h"
#include "bgpd/bgpd.h"
-#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
@@ -48,10 +47,20 @@
DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
-char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b)
{
- prefix2str(bgp_dest_get_prefix(bnc->dest), buf, size);
- return buf;
+ if (a->srte_color < b->srte_color)
+ return -1;
+ if (a->srte_color > b->srte_color)
+ return 1;
+
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+{
+ return prefix2str(&bnc->prefix, buf, size);
}
void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
@@ -59,32 +68,62 @@ void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
nexthops_free(bnc->nexthop);
}
-struct bgp_nexthop_cache *bnc_new(void)
+struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix, uint32_t srte_color)
{
struct bgp_nexthop_cache *bnc;
bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
sizeof(struct bgp_nexthop_cache));
+ bnc->prefix = *prefix;
+ bnc->srte_color = srte_color;
+ bnc->tree = tree;
LIST_INIT(&(bnc->paths));
+ bgp_nexthop_cache_add(tree, bnc);
+
return bnc;
}
+bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc)
+{
+ struct bgp_nexthop_cache *bnc_tmp;
+
+ frr_each (bgp_nexthop_cache, bnc->tree, bnc_tmp) {
+ if (bnc_tmp == bnc)
+ continue;
+ if (prefix_cmp(&bnc->prefix, &bnc_tmp->prefix) == 0)
+ return true;
+ }
+ return false;
+}
+
void bnc_free(struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free(bnc);
+ bgp_nexthop_cache_del(bnc->tree, bnc);
XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);
}
+struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix, uint32_t srte_color)
+{
+ struct bgp_nexthop_cache bnc = {};
+
+ if (!tree)
+ return NULL;
+
+ bnc.prefix = *prefix;
+ bnc.srte_color = srte_color;
+ return bgp_nexthop_cache_find(tree, &bnc);
+}
+
/* Reset and free all BGP nexthop cache. */
-static void bgp_nexthop_cache_reset(struct bgp_table *table)
+static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
- for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ while (bgp_nexthop_cache_count(tree) > 0) {
+ bnc = bgp_nexthop_cache_first(tree);
while (!LIST_EMPTY(&(bnc->paths))) {
struct bgp_path_info *path = LIST_FIRST(&(bnc->paths));
@@ -93,8 +132,6 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table)
}
bnc_free(bnc);
- bgp_dest_set_bgp_nexthop_info(dest, NULL);
- bgp_dest_unlock_node(dest);
}
}
@@ -773,20 +810,21 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
}
static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
- struct bgp_dest *dest,
struct bgp_nexthop_cache *bnc,
bool specific)
{
char buf[PREFIX2STR_BUFFER];
time_t tbuf;
struct peer *peer;
- const struct prefix *p = bgp_dest_get_prefix(dest);
peer = (struct peer *)bnc->nht_info;
+ if (bnc->srte_color)
+ vty_out(vty, " SR-TE color %u -", bnc->srte_color);
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->metric, bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
@@ -794,7 +832,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
bgp_show_nexthops_detail(vty, bgp, bnc);
} else {
vty_out(vty, " %s invalid, #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
@@ -816,29 +855,21 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
bool import_table)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi;
- struct bgp_table **table;
+ struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
if (import_table)
vty_out(vty, "Current BGP import check cache:\n");
else
vty_out(vty, "Current BGP nexthop cache:\n");
if (import_table)
- table = bgp->import_check_table;
+ tree = &bgp->import_check_table;
else
- table = bgp->nexthop_cache_table;
+ tree = &bgp->nexthop_cache_table;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!table || !table[afi])
- continue;
- for (dest = bgp_table_top(table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
- bgp_show_nexthop(vty, bgp, dest, bnc, false);
- }
+ frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc)
+ bgp_show_nexthop(vty, bgp, bnc, false);
}
}
@@ -859,27 +890,21 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
if (nhopip_str) {
struct prefix nhop;
- struct bgp_table **table;
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc;
if (!str2prefix(nhopip_str, &nhop)) {
vty_out(vty, "nexthop address is malformed\n");
return CMD_WARNING;
}
- table = import_table ? \
- bgp->import_check_table : bgp->nexthop_cache_table;
- dest = bgp_node_lookup(table[family2afi(nhop.family)], &nhop);
- if (!dest) {
- vty_out(vty, "specified nexthop is not found\n");
- return CMD_SUCCESS;
- }
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ tree = import_table ? &bgp->import_check_table
+ : &bgp->nexthop_cache_table;
+ bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0);
if (!bnc) {
vty_out(vty, "specified nexthop does not have entry\n");
return CMD_SUCCESS;
}
- bgp_show_nexthop(vty, bgp, dest, bnc, true);
+ bgp_show_nexthop(vty, bgp, bnc, true);
} else
bgp_show_nexthops(vty, bgp, import_table);
@@ -966,12 +991,10 @@ void bgp_scan_init(struct bgp *bgp)
afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- bgp->nexthop_cache_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
+ bgp_nexthop_cache_init(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_init(&bgp->import_check_table[afi]);
bgp->connected_table[afi] = bgp_table_init(bgp, afi,
SAFI_UNICAST);
- bgp->import_check_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
}
}
@@ -988,16 +1011,12 @@ void bgp_scan_finish(struct bgp *bgp)
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
/* Only the current one needs to be reset. */
- bgp_nexthop_cache_reset(bgp->nexthop_cache_table[afi]);
- bgp_table_unlock(bgp->nexthop_cache_table[afi]);
- bgp->nexthop_cache_table[afi] = NULL;
+ bgp_nexthop_cache_reset(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_reset(&bgp->import_check_table[afi]);
bgp->connected_table[afi]->route_table->cleanup =
bgp_connected_cleanup;
bgp_table_unlock(bgp->connected_table[afi]);
bgp->connected_table[afi] = NULL;
-
- bgp_table_unlock(bgp->import_check_table[afi]);
- bgp->import_check_table[afi] = NULL;
}
}
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 416ab2a739..c4b913faf4 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -24,6 +24,7 @@
#include "if.h"
#include "queue.h"
#include "prefix.h"
+#include "bgp_table.h"
#define NEXTHOP_FAMILY(nexthop_len) \
(((nexthop_len) == 4 || (nexthop_len) == 12 \
@@ -36,8 +37,13 @@
#define BGP_MP_NEXTHOP_FAMILY NEXTHOP_FAMILY
+PREDECL_RBTREE_UNIQ(bgp_nexthop_cache);
+
/* BGP nexthop cache value structure. */
struct bgp_nexthop_cache {
+ /* RB-tree entry. */
+ struct bgp_nexthop_cache_item entry;
+
/* IGP route's metric. */
uint32_t metric;
@@ -61,13 +67,22 @@ struct bgp_nexthop_cache {
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
- struct bgp_dest *dest;
+ /* Back pointer to the cache tree this entry belongs to. */
+ struct bgp_nexthop_cache_head *tree;
+
+ uint32_t srte_color;
+ struct prefix prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
};
+extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b);
+DECLARE_RBTREE_UNIQ(bgp_nexthop_cache, struct bgp_nexthop_cache, entry,
+ bgp_nexthop_cache_compare);
+
/* Own tunnel-ip address structure */
struct tip_addr {
struct in_addr addr;
@@ -79,6 +94,12 @@ struct bgp_addrv6 {
struct list *ifp_name_list;
};
+/* Forward declaration(s). */
+struct peer;
+struct update_subgroup;
+struct bgp_dest;
+struct attr;
+
extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
extern void bgp_connected_delete(struct bgp *bgp, struct connected *c);
extern bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
@@ -94,10 +115,16 @@ extern int bgp_config_write_scan_time(struct vty *);
extern bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
uint8_t sub_type, struct attr *attr,
struct bgp_dest *dest);
-extern struct bgp_nexthop_cache *bnc_new(void);
+extern struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix,
+ uint32_t srte_color);
+extern bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
+extern struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix,
+ uint32_t srte_color);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
-extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
+extern const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
extern void bgp_scan_init(struct bgp *bgp);
extern void bgp_scan_finish(struct bgp *bgp);
extern void bgp_scan_vty_init(void);
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index a780fb7347..9573d118e5 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -72,15 +72,14 @@ static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%s)",
+ zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%u)(%s)",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->bgp->name_pretty);
+ bnc->srte_color, bnc->bgp->name_pretty);
}
- unregister_zebra_rnh(bnc,
- CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
- bnc->dest = NULL;
+ /* only unregister if this is the last nh for this prefix*/
+ if (!bnc_existing_for_prefix(bnc))
+ unregister_zebra_rnh(
+ bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
bnc_free(bnc);
}
}
@@ -100,16 +99,13 @@ void bgp_unlink_nexthop(struct bgp_path_info *path)
void bgp_unlink_nexthop_by_peer(struct peer *peer)
{
struct prefix p;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi = family2afi(peer->su.sa.sa_family);
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p);
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0);
if (!bnc)
return;
@@ -127,11 +123,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
afi_t afi, struct bgp_path_info *pi,
struct peer *peer, int connected)
{
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc;
struct prefix p;
+ uint32_t srte_color = 0;
int is_bgp_static_route = 0;
- const struct prefix *bnc_p;
if (pi) {
is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP)
@@ -155,6 +151,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
* addr */
if (make_prefix(afi, pi, &p) < 0)
return 1;
+
+ srte_color = pi->attr->srte_color;
} else if (peer) {
if (!sockunion2hostprefix(&peer->su, &p)) {
if (BGP_DEBUG(nht, NHT)) {
@@ -168,29 +166,24 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
return 0;
if (is_bgp_static_route)
- dest = bgp_node_get(bgp_nexthop->import_check_table[afi], &p);
+ tree = &bgp_nexthop->import_check_table[afi];
else
- dest = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p);
+ tree = &bgp_nexthop->nexthop_cache_table[afi];
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(tree, &p, srte_color);
if (!bnc) {
- bnc = bnc_new();
- bgp_dest_set_bgp_nexthop_info(dest, bnc);
- bnc->dest = dest;
+ bnc = bnc_new(tree, &p, srte_color);
bnc->bgp = bgp_nexthop;
- bgp_dest_lock_node(dest);
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("Allocated bnc %s(%s) peer %p",
+ zlog_debug("Allocated bnc %s(%u)(%s) peer %p",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->bgp->name_pretty, peer);
+ bnc->srte_color, bnc->bgp->name_pretty,
+ peer);
}
}
- bnc_p = bgp_dest_get_prefix(bnc->dest);
-
- bgp_dest_unlock_node(dest);
if (is_bgp_static_route) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
@@ -236,7 +229,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
} else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
- && !is_default_host_route(bnc_p))
+ && !is_default_host_route(&bnc->prefix))
register_zebra_rnh(bnc, is_bgp_static_route);
if (pi && pi->nexthop != bnc) {
@@ -269,7 +262,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct prefix p;
@@ -279,26 +271,15 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_lookup(
- peer->bgp->nexthop_cache_table[family2afi(p.family)], &p);
- if (!dest) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "Cannot find connected NHT node for peer %s(%s)",
- peer->host, peer->bgp->name_pretty);
- return;
- }
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)],
+ &p, 0);
if (!bnc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
- "Cannot find connected NHT node for peer %s(%s) on route_node as expected",
+ "Cannot find connected NHT node for peer %s(%s)",
peer->host, peer->bgp->name_pretty);
- bgp_dest_unlock_node(dest);
return;
}
- bgp_dest_unlock_node(dest);
if (bnc->nht_info != peer) {
if (BGP_DEBUG(nht, NHT))
@@ -317,95 +298,40 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
"Freeing connected NHT node %p for peer %s(%s)",
bnc, peer->host, bnc->bgp->name_pretty);
unregister_zebra_rnh(bnc, 0);
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
bnc_free(bnc);
}
}
-void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
+static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
+ struct zapi_route *nhr)
{
- struct bgp_dest *dest = NULL;
- struct bgp_nexthop_cache *bnc;
struct nexthop *nexthop;
struct nexthop *oldnh;
struct nexthop *nhlist_head = NULL;
struct nexthop *nhlist_tail = NULL;
int i;
- struct bgp *bgp;
- struct zapi_route nhr;
-
- bgp = bgp_lookup_by_vrf_id(vrf_id);
- if (!bgp) {
- flog_err(
- EC_BGP_NH_UPD,
- "parse nexthop update: instance not found for vrf_id %u",
- vrf_id);
- return;
- }
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug("%s[%s]: Failure to decode nexthop update",
- __func__, bgp->name_pretty);
- return;
- }
-
- if (command == ZEBRA_NEXTHOP_UPDATE)
- dest = bgp_node_lookup(
- bgp->nexthop_cache_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
- else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
- dest = bgp_node_lookup(
- bgp->import_check_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
-
- if (!dest) {
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nhr.prefix, buf, sizeof(buf));
- zlog_debug("parse nexthop update(%s(%s)): rn not found",
- buf, bgp->name_pretty);
- }
- return;
- }
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc) {
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(&nhr.prefix, buf, sizeof(buf));
- zlog_debug(
- "parse nexthop update(%s(%s)): bnc node info not found",
- buf, bgp->name_pretty);
- }
- bgp_dest_unlock_node(dest);
- return;
- }
-
- bgp_dest_unlock_node(dest);
bnc->last_update = bgp_clock();
bnc->change_flags = 0;
/* debug print the input */
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- prefix2str(&nhr.prefix, buf, sizeof(buf));
+ prefix2str(&nhr->prefix, buf, sizeof(buf));
zlog_debug(
- "%s(%u): Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
- bnc->bgp->name_pretty, vrf_id, buf, nhr.metric,
- bnc->metric, nhr.nexthop_num, bnc->nexthop_num,
- bnc->flags);
+ "%s(%u): Rcvd NH update %s(%u) - metric %d/%d #nhops %d/%d flags 0x%x",
+ bnc->bgp->name_pretty, bnc->bgp->vrf_id, buf,
+ bnc->srte_color, nhr->metric, bnc->metric,
+ nhr->nexthop_num, bnc->nexthop_num, bnc->flags);
}
- if (nhr.metric != bnc->metric)
+ if (nhr->metric != bnc->metric)
bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
- if (nhr.nexthop_num != bnc->nexthop_num)
+ if (nhr->nexthop_num != bnc->nexthop_num)
bnc->change_flags |= BGP_NEXTHOP_CHANGED;
- if (nhr.nexthop_num) {
+ if (nhr->nexthop_num) {
struct peer *peer = bnc->nht_info;
/* notify bgp fsm if nbr ip goes from invalid->valid */
@@ -413,15 +339,15 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
bnc->flags |= BGP_NEXTHOP_VALID;
- bnc->metric = nhr.metric;
- bnc->nexthop_num = nhr.nexthop_num;
+ bnc->metric = nhr->metric;
+ bnc->nexthop_num = nhr->nexthop_num;
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */
- for (i = 0; i < nhr.nexthop_num; i++) {
+ for (i = 0; i < nhr->nexthop_num; i++) {
int num_labels = 0;
- nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
+ nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]);
/*
* Turn on RA for the v6 nexthops
@@ -431,7 +357,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
if (peer && !peer->ifp
&& CHECK_FLAG(peer->flags,
PEER_FLAG_CAPABILITY_ENHE)
- && nhr.prefix.family == AF_INET6
+ && nhr->prefix.family == AF_INET6
&& nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
struct interface *ifp;
@@ -485,7 +411,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
bnc->nexthop = nhlist_head;
} else {
bnc->flags &= ~BGP_NEXTHOP_VALID;
- bnc->nexthop_num = nhr.nexthop_num;
+ bnc->nexthop_num = nhr->nexthop_num;
/* notify bgp fsm if nbr ip goes from valid->invalid */
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
@@ -497,26 +423,88 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
evaluate_paths(bnc);
}
+void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
+{
+ struct bgp_nexthop_cache_head *tree = NULL;
+ struct bgp_nexthop_cache *bnc;
+ struct bgp *bgp;
+ struct zapi_route nhr;
+ afi_t afi;
+
+ bgp = bgp_lookup_by_vrf_id(vrf_id);
+ if (!bgp) {
+ flog_err(
+ EC_BGP_NH_UPD,
+ "parse nexthop update: instance not found for vrf_id %u",
+ vrf_id);
+ return;
+ }
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s[%s]: Failure to decode nexthop update",
+ __PRETTY_FUNCTION__, bgp->name_pretty);
+ return;
+ }
+
+ afi = family2afi(nhr.prefix.family);
+ if (command == ZEBRA_NEXTHOP_UPDATE)
+ tree = &bgp->nexthop_cache_table[afi];
+ else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
+ tree = &bgp->import_check_table[afi];
+
+ bnc = bnc_find(tree, &nhr.prefix, nhr.srte_color);
+ if (!bnc) {
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&nhr.prefix, buf, sizeof(buf));
+ zlog_debug(
+ "parse nexthop update(%s(%u)(%s)): bnc info not found",
+ buf, nhr.srte_color, bgp->name_pretty);
+ }
+ return;
+ }
+
+ bgp_process_nexthop_update(bnc, &nhr);
+
+ /*
+ * HACK: if any BGP route is dependant on an SR-policy that doesn't
+ * exist, zebra will never send NH updates relative to that policy. In
+ * that case, whenever we receive an update about a colorless NH, update
+ * the corresponding colorful NHs that share the same endpoint but that
+ * are inactive. This ugly hack should work around the problem at the
+ * cost of a performance pernalty. Long term, what should be done is to
+ * make zebra's RNH subsystem aware of SR-TE colors (like bgpd is),
+ * which should provide a better infrastructure to solve this issue in
+ * a more efficient and elegant way.
+ */
+ if (nhr.srte_color == 0) {
+ struct bgp_nexthop_cache *bnc_iter;
+
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc_iter) {
+ if (!prefix_same(&bnc->prefix, &bnc_iter->prefix)
+ || bnc_iter->srte_color == 0
+ || CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID))
+ continue;
+
+ bgp_process_nexthop_update(bnc_iter, &nhr);
+ }
+ }
+}
+
/*
* Cleanup nexthop registration and status information for BGP nexthops
* pertaining to this VRF. This is invoked upon VRF deletion.
*/
void bgp_cleanup_nexthops(struct bgp *bgp)
{
- afi_t afi;
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
/* Clear relevant flags. */
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
@@ -609,7 +597,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
- const struct prefix *p;
bool exact_match = false;
int ret;
@@ -631,23 +618,18 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
"%s: We have not connected yet, cannot send nexthops",
__func__);
}
- p = bgp_dest_get_prefix(bnc->dest);
if ((command == ZEBRA_NEXTHOP_REGISTER
|| command == ZEBRA_IMPORT_ROUTE_REGISTER)
&& (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
exact_match = true;
- if (BGP_DEBUG(zebra, ZEBRA)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(p, buf, PREFIX2STR_BUFFER);
- zlog_debug("%s: sending cmd %s for %s (vrf %s)",
- __func__, zserv_command_string(command), buf,
- bnc->bgp->name_pretty);
- }
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__,
+ zserv_command_string(command), &bnc->prefix,
+ bnc->bgp->name_pretty);
- ret = zclient_send_rnh(zclient, command, p, exact_match,
+ ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,
bnc->bgp->vrf_id);
/* TBD: handle the failure */
if (ret < 0)
@@ -725,8 +707,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
char buf[PREFIX2STR_BUFFER];
bnc_str(bnc, buf, PREFIX2STR_BUFFER);
zlog_debug(
- "NH update for %s %s flags 0x%x chgflags 0x%x - evaluate paths",
- buf, bnc->bgp->name_pretty, bnc->flags,
+ "NH update for %s(%u)(%s) - flags 0x%x chgflags 0x%x - evaluate paths",
+ buf, bnc->srte_color, bnc->bgp->name_pretty, bnc->flags,
bnc->change_flags);
}
@@ -814,7 +796,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
path->extra->igpmetric = 0;
if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
- || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
+ || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)
+ || path->attr->srte_color != 0)
SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);
path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID);
@@ -901,21 +884,11 @@ void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc,
*/
void bgp_nht_register_nexthops(struct bgp *bgp)
{
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
- afi_t afi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
-
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
register_zebra_rnh(bnc, 0);
}
}
@@ -924,7 +897,6 @@ void bgp_nht_register_nexthops(struct bgp *bgp)
void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
@@ -934,10 +906,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
return;
bgp = peer->bgp;
-
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
@@ -946,11 +914,8 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
if (!bnc)
return;
@@ -973,7 +938,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
@@ -984,9 +948,6 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
bgp = peer->bgp;
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
@@ -996,11 +957,7 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
if (!bnc)
return;
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 732c8e6753..6cfcb9cc3d 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1102,6 +1102,9 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
zlog_debug("%s rcv OPEN w/ OPTION parameter len: %u",
peer->host, length);
+ /* Unset any previously received GR capability. */
+ UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV);
+
while (stream_get_getp(s) < end) {
uint8_t opt_type;
uint8_t opt_length;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 6d81cfaab4..09cc775d47 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1668,6 +1668,45 @@ static const struct route_map_rule_cmd route_match_tag_cmd = {
route_map_rule_tag_free,
};
+static enum route_map_cmd_result_t
+route_set_srte_color(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ uint32_t *srte_color = rule;
+ struct bgp_path_info *path;
+
+ if (type != RMAP_BGP)
+ return RMAP_OKAY;
+
+ path = object;
+
+ path->attr->srte_color = *srte_color;
+ path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR);
+
+ return RMAP_OKAY;
+}
+
+/* Route map `sr-te color' compile function */
+static void *route_set_srte_color_compile(const char *arg)
+{
+ uint32_t *color;
+
+ color = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
+ *color = atoi(arg);
+
+ return color;
+}
+
+/* Free route map's compiled `sr-te color' value. */
+static void route_set_srte_color_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for sr-te color set. */
+struct route_map_rule_cmd route_set_srte_color_cmd = {
+ "sr-te color", route_set_srte_color, route_set_srte_color_compile,
+ route_set_srte_color_free};
/* Set nexthop to object. ojbect must be pointer to struct attr. */
struct rmap_ip_nexthop_set {
@@ -5686,6 +5725,9 @@ void bgp_route_map_init(void)
route_map_match_tag_hook(generic_match_add);
route_map_no_match_tag_hook(generic_match_delete);
+ route_map_set_srte_color_hook(generic_set_add);
+ route_map_no_set_srte_color_hook(generic_set_delete);
+
route_map_set_ip_nexthop_hook(generic_set_add);
route_map_no_set_ip_nexthop_hook(generic_set_delete);
@@ -5728,6 +5770,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_vrl_source_vrf_cmd);
route_map_install_set(&route_set_table_id_cmd);
+ route_map_install_set(&route_set_srte_color_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd);
route_map_install_set(&route_set_local_pref_cmd);
route_map_install_set(&route_set_weight_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index dba114f86a..15bd6d33b8 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1265,6 +1265,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.tableid = info->attr->rmap_table_id;
}
+ if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRTE);
+
/* Metric is currently based on the best-path only */
metric = info->attr->med;
@@ -1303,6 +1306,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
continue;
}
api_nh = &api.nexthops[valid_nh_count];
+
+ if (CHECK_FLAG(info->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
+ api_nh->srte_color = info->attr->srte_color;
+
if (nh_family == AF_INET) {
if (bgp_debug_zebra(&api.prefix)) {
if (mpinfo->extra) {
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index aade3f0404..3056a5fe62 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2284,9 +2284,9 @@ int peer_delete(struct peer *peer)
/* Password configuration */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) {
XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer)
- && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR))
bgp_md5_unset(peer);
}
@@ -2668,7 +2668,7 @@ int peer_group_listen_range_add(struct peer_group *group, struct prefix *range)
/* Update passwords for new ranges */
if (group->conf->password)
- bgp_md5_set_prefix(prefix, group->conf->password);
+ bgp_md5_set_prefix(group->bgp, prefix, group->conf->password);
return 0;
}
@@ -2715,7 +2715,7 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)
/* Remove passwords for deleted ranges */
if (group->conf->password)
- bgp_md5_unset_prefix(prefix);
+ bgp_md5_unset_prefix(group->bgp, prefix);
return 0;
}
@@ -5621,9 +5621,9 @@ int peer_password_set(struct peer *peer, const char *password)
struct prefix *lr;
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
- bgp_md5_set_prefix(lr, password);
+ bgp_md5_set_prefix(peer->bgp, lr, password);
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
- bgp_md5_set_prefix(lr, password);
+ bgp_md5_set_prefix(peer->bgp, lr, password);
return ret;
}
@@ -5659,7 +5659,6 @@ int peer_password_unset(struct peer *peer)
/* Attempt to uninstall password on socket. */
if (!BGP_PEER_SU_UNSPEC(peer))
bgp_md5_unset(peer);
-
/* Skip peer-group mechanics for regular peers. */
return 0;
}
@@ -5694,9 +5693,9 @@ int peer_password_unset(struct peer *peer)
struct prefix *lr;
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
- bgp_md5_unset_prefix(lr);
+ bgp_md5_unset_prefix(peer->bgp, lr);
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
- bgp_md5_unset_prefix(lr);
+ bgp_md5_unset_prefix(peer->bgp, lr);
return 0;
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 6fc3f08836..87cdcd2e71 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -42,6 +42,7 @@
#include "vxlan.h"
#include "bgp_labelpool.h"
#include "bgp_addpath_types.h"
+#include "bgp_nexthop.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@@ -482,11 +483,11 @@ struct bgp {
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
- /* Route table for next-hop lookup cache. */
- struct bgp_table *nexthop_cache_table[AFI_MAX];
+ /* Tree for next-hop lookup cache. */
+ struct bgp_nexthop_cache_head nexthop_cache_table[AFI_MAX];
- /* Route table for import-check */
- struct bgp_table *import_check_table[AFI_MAX];
+ /* Tree for import-check */
+ struct bgp_nexthop_cache_head import_check_table[AFI_MAX];
struct bgp_table *connected_table[AFI_MAX];
@@ -996,41 +997,41 @@ struct peer {
/* Capability flags (reset in bgp_stop) */
uint32_t cap;
-#define PEER_CAP_REFRESH_ADV (1 << 0) /* refresh advertised */
-#define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */
-#define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc received */
-#define PEER_CAP_DYNAMIC_ADV (1 << 3) /* dynamic advertised */
-#define PEER_CAP_DYNAMIC_RCV (1 << 4) /* dynamic received */
-#define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */
-#define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */
-#define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */
-#define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */
-#define PEER_CAP_RESTART_BIT_ADV (1 << 9) /* sent restart state */
-#define PEER_CAP_RESTART_BIT_RCV (1 << 10) /* peer restart state */
-#define PEER_CAP_ADDPATH_ADV (1 << 11) /* addpath advertised */
-#define PEER_CAP_ADDPATH_RCV (1 << 12) /* addpath received */
-#define PEER_CAP_ENHE_ADV (1 << 13) /* Extended nexthop advertised */
-#define PEER_CAP_ENHE_RCV (1 << 14) /* Extended nexthop received */
-#define PEER_CAP_HOSTNAME_ADV (1 << 15) /* hostname advertised */
-#define PEER_CAP_HOSTNAME_RCV (1 << 16) /* hostname received */
+#define PEER_CAP_REFRESH_ADV (1U << 0) /* refresh advertised */
+#define PEER_CAP_REFRESH_OLD_RCV (1U << 1) /* refresh old received */
+#define PEER_CAP_REFRESH_NEW_RCV (1U << 2) /* refresh rfc received */
+#define PEER_CAP_DYNAMIC_ADV (1U << 3) /* dynamic advertised */
+#define PEER_CAP_DYNAMIC_RCV (1U << 4) /* dynamic received */
+#define PEER_CAP_RESTART_ADV (1U << 5) /* restart advertised */
+#define PEER_CAP_RESTART_RCV (1U << 6) /* restart received */
+#define PEER_CAP_AS4_ADV (1U << 7) /* as4 advertised */
+#define PEER_CAP_AS4_RCV (1U << 8) /* as4 received */
+#define PEER_CAP_RESTART_BIT_ADV (1U << 9) /* sent restart state */
+#define PEER_CAP_RESTART_BIT_RCV (1U << 10) /* peer restart state */
+#define PEER_CAP_ADDPATH_ADV (1U << 11) /* addpath advertised */
+#define PEER_CAP_ADDPATH_RCV (1U << 12) /* addpath received */
+#define PEER_CAP_ENHE_ADV (1U << 13) /* Extended nexthop advertised */
+#define PEER_CAP_ENHE_RCV (1U << 14) /* Extended nexthop received */
+#define PEER_CAP_HOSTNAME_ADV (1U << 15) /* hostname advertised */
+#define PEER_CAP_HOSTNAME_RCV (1U << 16) /* hostname received */
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
-#define PEER_CAP_ORF_PREFIX_SM_ADV (1 << 0) /* send-mode advertised */
-#define PEER_CAP_ORF_PREFIX_RM_ADV (1 << 1) /* receive-mode advertised */
-#define PEER_CAP_ORF_PREFIX_SM_RCV (1 << 2) /* send-mode received */
-#define PEER_CAP_ORF_PREFIX_RM_RCV (1 << 3) /* receive-mode received */
-#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1 << 4) /* send-mode received */
-#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1 << 5) /* receive-mode received */
-#define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart afi/safi received */
-#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1 << 7) /* graceful restart afi/safi F-bit received */
-#define PEER_CAP_ADDPATH_AF_TX_ADV (1 << 8) /* addpath tx advertised */
-#define PEER_CAP_ADDPATH_AF_TX_RCV (1 << 9) /* addpath tx received */
-#define PEER_CAP_ADDPATH_AF_RX_ADV (1 << 10) /* addpath rx advertised */
-#define PEER_CAP_ADDPATH_AF_RX_RCV (1 << 11) /* addpath rx received */
-#define PEER_CAP_ENHE_AF_ADV (1 << 12) /* Extended nexthopi afi/safi advertised */
-#define PEER_CAP_ENHE_AF_RCV (1 << 13) /* Extended nexthop afi/safi received */
-#define PEER_CAP_ENHE_AF_NEGO (1 << 14) /* Extended nexthop afi/safi negotiated */
+#define PEER_CAP_ORF_PREFIX_SM_ADV (1U << 0) /* send-mode advertised */
+#define PEER_CAP_ORF_PREFIX_RM_ADV (1U << 1) /* receive-mode advertised */
+#define PEER_CAP_ORF_PREFIX_SM_RCV (1U << 2) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_RCV (1U << 3) /* receive-mode received */
+#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1U << 4) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1U << 5) /* receive-mode received */
+#define PEER_CAP_RESTART_AF_RCV (1U << 6) /* graceful restart afi/safi received */
+#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1U << 7) /* graceful restart afi/safi F-bit received */
+#define PEER_CAP_ADDPATH_AF_TX_ADV (1U << 8) /* addpath tx advertised */
+#define PEER_CAP_ADDPATH_AF_TX_RCV (1U << 9) /* addpath tx received */
+#define PEER_CAP_ADDPATH_AF_RX_ADV (1U << 10) /* addpath rx advertised */
+#define PEER_CAP_ADDPATH_AF_RX_RCV (1U << 11) /* addpath rx received */
+#define PEER_CAP_ENHE_AF_ADV (1U << 12) /* Extended nexthopi afi/safi advertised */
+#define PEER_CAP_ENHE_AF_RCV (1U << 13) /* Extended nexthop afi/safi received */
+#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
/* Global configuration flags. */
/*
@@ -1089,34 +1090,34 @@ struct peer {
* flags_invert) must be respected.
*/
uint32_t flags;
-#define PEER_FLAG_PASSIVE (1 << 0) /* passive mode */
-#define PEER_FLAG_SHUTDOWN (1 << 1) /* shutdown */
-#define PEER_FLAG_DONT_CAPABILITY (1 << 2) /* dont-capability */
-#define PEER_FLAG_OVERRIDE_CAPABILITY (1 << 3) /* override-capability */
-#define PEER_FLAG_STRICT_CAP_MATCH (1 << 4) /* strict-match */
-#define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 5) /* dynamic capability */
-#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */
-#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */
-#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */
-#define PEER_FLAG_DELETE (1 << 9) /* mark the peer for deleting */
-#define PEER_FLAG_CONFIG_NODE (1 << 10) /* the node to update configs on */
-#define PEER_FLAG_LONESOUL (1 << 11)
-#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 12) /* dynamic neighbor */
-#define PEER_FLAG_CAPABILITY_ENHE (1 << 13) /* Extended next-hop (rfc 5549)*/
-#define PEER_FLAG_IFPEER_V6ONLY (1 << 14) /* if-based peer is v6 only */
-#define PEER_FLAG_IS_RFAPI_HD (1 << 15) /* attached to rfapi HD */
-#define PEER_FLAG_ENFORCE_FIRST_AS (1 << 16) /* enforce-first-as */
-#define PEER_FLAG_ROUTEADV (1 << 17) /* route advertise */
-#define PEER_FLAG_TIMER (1 << 18) /* keepalive & holdtime */
-#define PEER_FLAG_TIMER_CONNECT (1 << 19) /* connect timer */
-#define PEER_FLAG_PASSWORD (1 << 20) /* password */
-#define PEER_FLAG_LOCAL_AS (1 << 21) /* local-as */
-#define PEER_FLAG_UPDATE_SOURCE (1 << 22) /* update-source */
+#define PEER_FLAG_PASSIVE (1U << 0) /* passive mode */
+#define PEER_FLAG_SHUTDOWN (1U << 1) /* shutdown */
+#define PEER_FLAG_DONT_CAPABILITY (1U << 2) /* dont-capability */
+#define PEER_FLAG_OVERRIDE_CAPABILITY (1U << 3) /* override-capability */
+#define PEER_FLAG_STRICT_CAP_MATCH (1U << 4) /* strict-match */
+#define PEER_FLAG_DYNAMIC_CAPABILITY (1U << 5) /* dynamic capability */
+#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1U << 6) /* disable-connected-check */
+#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1U << 7) /* local-as no-prepend */
+#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1U << 8) /* local-as no-prepend replace-as */
+#define PEER_FLAG_DELETE (1U << 9) /* mark the peer for deleting */
+#define PEER_FLAG_CONFIG_NODE (1U << 10) /* the node to update configs on */
+#define PEER_FLAG_LONESOUL (1U << 11)
+#define PEER_FLAG_DYNAMIC_NEIGHBOR (1U << 12) /* dynamic neighbor */
+#define PEER_FLAG_CAPABILITY_ENHE (1U << 13) /* Extended next-hop (rfc 5549)*/
+#define PEER_FLAG_IFPEER_V6ONLY (1U << 14) /* if-based peer is v6 only */
+#define PEER_FLAG_IS_RFAPI_HD (1U << 15) /* attached to rfapi HD */
+#define PEER_FLAG_ENFORCE_FIRST_AS (1U << 16) /* enforce-first-as */
+#define PEER_FLAG_ROUTEADV (1U << 17) /* route advertise */
+#define PEER_FLAG_TIMER (1U << 18) /* keepalive & holdtime */
+#define PEER_FLAG_TIMER_CONNECT (1U << 19) /* connect timer */
+#define PEER_FLAG_PASSWORD (1U << 20) /* password */
+#define PEER_FLAG_LOCAL_AS (1U << 21) /* local-as */
+#define PEER_FLAG_UPDATE_SOURCE (1U << 22) /* update-source */
/* BGP-GR Peer related flags */
-#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1 << 23) /* Helper */
-#define PEER_FLAG_GRACEFUL_RESTART (1 << 24) /* Graceful Restart */
-#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */
+#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1U << 23) /* Helper */
+#define PEER_FLAG_GRACEFUL_RESTART (1U << 24) /* Graceful Restart */
+#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1130,9 +1131,9 @@ struct peer {
uint8_t nsf_af_count;
uint8_t peer_gr_new_status_flag;
-#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1 << 0)
-#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1 << 1)
-#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1 << 2)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1U << 0)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1U << 1)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1U << 2)
/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
char *tx_shutdown_message;
@@ -1154,33 +1155,33 @@ struct peer {
uint32_t af_flags_override[AFI_MAX][SAFI_MAX];
uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];
uint32_t af_flags[AFI_MAX][SAFI_MAX];
-#define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */
-#define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */
-#define PEER_FLAG_NEXTHOP_SELF (1 << 2) /* next-hop-self */
-#define PEER_FLAG_REFLECTOR_CLIENT (1 << 3) /* reflector-client */
-#define PEER_FLAG_RSERVER_CLIENT (1 << 4) /* route-server-client */
-#define PEER_FLAG_SOFT_RECONFIG (1 << 5) /* soft-reconfiguration */
-#define PEER_FLAG_AS_PATH_UNCHANGED (1 << 6) /* transparent-as */
-#define PEER_FLAG_NEXTHOP_UNCHANGED (1 << 7) /* transparent-next-hop */
-#define PEER_FLAG_MED_UNCHANGED (1 << 8) /* transparent-next-hop */
-#define PEER_FLAG_DEFAULT_ORIGINATE (1 << 9) /* default-originate */
-#define PEER_FLAG_REMOVE_PRIVATE_AS (1 << 10) /* remove-private-as */
-#define PEER_FLAG_ALLOWAS_IN (1 << 11) /* set allowas-in */
-#define PEER_FLAG_ORF_PREFIX_SM (1 << 12) /* orf capability send-mode */
-#define PEER_FLAG_ORF_PREFIX_RM (1 << 13) /* orf capability receive-mode */
-#define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */
-#define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */
-#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */
-#define PEER_FLAG_FORCE_NEXTHOP_SELF (1 << 17) /* next-hop-self force */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL (1 << 18) /* remove-private-as all */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as replace-as */
-#define PEER_FLAG_AS_OVERRIDE (1 << 20) /* as-override */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1 << 21) /* remove-private-as all replace-as */
-#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
-#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
-#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
-#define PEER_FLAG_MAX_PREFIX_OUT (1 << 27) /* outgoing maximum prefix */
-#define PEER_FLAG_MAX_PREFIX_FORCE (1 << 28) /* maximum-prefix <num> force */
+#define PEER_FLAG_SEND_COMMUNITY (1U << 0) /* send-community */
+#define PEER_FLAG_SEND_EXT_COMMUNITY (1U << 1) /* send-community ext. */
+#define PEER_FLAG_NEXTHOP_SELF (1U << 2) /* next-hop-self */
+#define PEER_FLAG_REFLECTOR_CLIENT (1U << 3) /* reflector-client */
+#define PEER_FLAG_RSERVER_CLIENT (1U << 4) /* route-server-client */
+#define PEER_FLAG_SOFT_RECONFIG (1U << 5) /* soft-reconfiguration */
+#define PEER_FLAG_AS_PATH_UNCHANGED (1U << 6) /* transparent-as */
+#define PEER_FLAG_NEXTHOP_UNCHANGED (1U << 7) /* transparent-next-hop */
+#define PEER_FLAG_MED_UNCHANGED (1U << 8) /* transparent-next-hop */
+#define PEER_FLAG_DEFAULT_ORIGINATE (1U << 9) /* default-originate */
+#define PEER_FLAG_REMOVE_PRIVATE_AS (1U << 10) /* remove-private-as */
+#define PEER_FLAG_ALLOWAS_IN (1U << 11) /* set allowas-in */
+#define PEER_FLAG_ORF_PREFIX_SM (1U << 12) /* orf capability send-mode */
+#define PEER_FLAG_ORF_PREFIX_RM (1U << 13) /* orf capability receive-mode */
+#define PEER_FLAG_MAX_PREFIX (1U << 14) /* maximum prefix */
+#define PEER_FLAG_MAX_PREFIX_WARNING (1U << 15) /* maximum prefix warning-only */
+#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1U << 16) /* leave link-local nexthop unchanged */
+#define PEER_FLAG_FORCE_NEXTHOP_SELF (1U << 17) /* next-hop-self force */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL (1U << 18) /* remove-private-as all */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1U << 19) /* remove-private-as replace-as */
+#define PEER_FLAG_AS_OVERRIDE (1U << 20) /* as-override */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1U << 21) /* remove-private-as all replace-as */
+#define PEER_FLAG_WEIGHT (1U << 24) /* weight */
+#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1U << 25) /* allowas-in origin */
+#define PEER_FLAG_SEND_LARGE_COMMUNITY (1U << 26) /* Send large Communities */
+#define PEER_FLAG_MAX_PREFIX_OUT (1U << 27) /* outgoing maximum prefix */
+#define PEER_FLAG_MAX_PREFIX_FORCE (1U << 28) /* maximum-prefix <num> force */
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1195,22 +1196,22 @@ struct peer {
/* Peer status flags. */
uint16_t sflags;
-#define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */
-#define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */
-#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */
-#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */
-#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */
-#define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */
-#define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */
+#define PEER_STATUS_ACCEPT_PEER (1U << 0) /* accept peer */
+#define PEER_STATUS_PREFIX_OVERFLOW (1U << 1) /* prefix-overflow */
+#define PEER_STATUS_CAPABILITY_OPEN (1U << 2) /* capability open send */
+#define PEER_STATUS_HAVE_ACCEPT (1U << 3) /* accept peer's parent */
+#define PEER_STATUS_GROUP (1U << 4) /* peer-group conf */
+#define PEER_STATUS_NSF_MODE (1U << 5) /* NSF aware peer */
+#define PEER_STATUS_NSF_WAIT (1U << 6) /* wait comeback peer */
/* Peer status af flags (reset in bgp_stop) */
uint16_t af_sflags[AFI_MAX][SAFI_MAX];
-#define PEER_STATUS_ORF_PREFIX_SEND (1 << 0) /* prefix-list send peer */
-#define PEER_STATUS_ORF_WAIT_REFRESH (1 << 1) /* wait refresh received peer */
-#define PEER_STATUS_PREFIX_THRESHOLD (1 << 2) /* exceed prefix-threshold */
-#define PEER_STATUS_PREFIX_LIMIT (1 << 3) /* exceed prefix-limit */
-#define PEER_STATUS_EOR_SEND (1 << 4) /* end-of-rib send to peer */
-#define PEER_STATUS_EOR_RECEIVED (1 << 5) /* end-of-rib received from peer */
+#define PEER_STATUS_ORF_PREFIX_SEND (1U << 0) /* prefix-list send peer */
+#define PEER_STATUS_ORF_WAIT_REFRESH (1U << 1) /* wait refresh received peer */
+#define PEER_STATUS_PREFIX_THRESHOLD (1U << 2) /* exceed prefix-threshold */
+#define PEER_STATUS_PREFIX_LIMIT (1U << 3) /* exceed prefix-limit */
+#define PEER_STATUS_EOR_SEND (1U << 4) /* end-of-rib send to peer */
+#define PEER_STATUS_EOR_RECEIVED (1U << 5) /* end-of-rib received from peer */
/* Configured timer values. */
_Atomic uint32_t holdtime;
@@ -1244,9 +1245,9 @@ struct peer {
/* Thread flags. */
_Atomic uint32_t thread_flags;
-#define PEER_THREAD_WRITES_ON (1 << 0)
-#define PEER_THREAD_READS_ON (1 << 1)
-#define PEER_THREAD_KEEPALIVES_ON (1 << 2)
+#define PEER_THREAD_WRITES_ON (1U << 0)
+#define PEER_THREAD_READS_ON (1U << 1)
+#define PEER_THREAD_KEEPALIVES_ON (1U << 2)
/* workqueues */
struct work_queue *clear_node_queue;
@@ -1337,11 +1338,11 @@ struct peer {
* whether the filter in filter (struct bgp_filter) is peer-specific.
*/
uint8_t filter_override[AFI_MAX][SAFI_MAX][FILTER_MAX];
-#define PEER_FT_DISTRIBUTE_LIST (1 << 0) /* distribute-list */
-#define PEER_FT_FILTER_LIST (1 << 1) /* filter-list */
-#define PEER_FT_PREFIX_LIST (1 << 2) /* prefix-list */
-#define PEER_FT_ROUTE_MAP (1 << 3) /* route-map */
-#define PEER_FT_UNSUPPRESS_MAP (1 << 4) /* unsuppress-map */
+#define PEER_FT_DISTRIBUTE_LIST (1U << 0) /* distribute-list */
+#define PEER_FT_FILTER_LIST (1U << 1) /* filter-list */
+#define PEER_FT_PREFIX_LIST (1U << 2) /* prefix-list */
+#define PEER_FT_ROUTE_MAP (1U << 3) /* route-map */
+#define PEER_FT_UNSUPPRESS_MAP (1U << 4) /* unsuppress-map */
/* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
@@ -1372,39 +1373,39 @@ struct peer {
/* peer reset cause */
uint8_t last_reset;
-#define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */
-#define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */
-#define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */
-#define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */
-#define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation id command */
-#define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */
-#define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor rr-client command */
-#define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor rs-client command */
-#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */
-#define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */
-#define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */
-#define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */
-#define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */
-#define PEER_DOWN_NOTIFY_SEND 14 /* notification send */
-#define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */
-#define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */
-#define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */
-#define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */
-#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */
-#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
-#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
-#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
-#define PEER_DOWN_V6ONLY_CHANGE 23 /* if-based peering v6only toggled */
-#define PEER_DOWN_BFD_DOWN 24 /* BFD down */
-#define PEER_DOWN_IF_DOWN 25 /* Interface down */
-#define PEER_DOWN_NBR_ADDR_DEL 26 /* Peer address lost */
-#define PEER_DOWN_WAITING_NHT 27 /* Waiting for NHT to resolve */
-#define PEER_DOWN_NBR_ADDR 28 /* Waiting for peer IPv6 IP Addr */
-#define PEER_DOWN_VRF_UNINIT 29 /* Associated VRF is not init yet */
-#define PEER_DOWN_NOAFI_ACTIVATED 30 /* No AFI/SAFI activated for peer */
-#define PEER_DOWN_AS_SETS_REJECT 31 /* Reject routes with AS_SET */
-#define PEER_DOWN_WAITING_OPEN 32 /* Waiting for open to succeed */
-#define PEER_DOWN_PFX_COUNT 33 /* Reached received prefix count */
+#define PEER_DOWN_RID_CHANGE 1U /* bgp router-id command */
+#define PEER_DOWN_REMOTE_AS_CHANGE 2U /* neighbor remote-as command */
+#define PEER_DOWN_LOCAL_AS_CHANGE 3U /* neighbor local-as command */
+#define PEER_DOWN_CLID_CHANGE 4U /* bgp cluster-id command */
+#define PEER_DOWN_CONFED_ID_CHANGE 5U /* bgp confederation id command */
+#define PEER_DOWN_CONFED_PEER_CHANGE 6U /* bgp confederation peer command */
+#define PEER_DOWN_RR_CLIENT_CHANGE 7U /* neighbor rr-client command */
+#define PEER_DOWN_RS_CLIENT_CHANGE 8U /* neighbor rs-client command */
+#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9U /* neighbor update-source command */
+#define PEER_DOWN_AF_ACTIVATE 10U /* neighbor activate command */
+#define PEER_DOWN_USER_SHUTDOWN 11U /* neighbor shutdown command */
+#define PEER_DOWN_USER_RESET 12U /* clear ip bgp command */
+#define PEER_DOWN_NOTIFY_RECEIVED 13U /* notification received */
+#define PEER_DOWN_NOTIFY_SEND 14U /* notification send */
+#define PEER_DOWN_CLOSE_SESSION 15U /* tcp session close */
+#define PEER_DOWN_NEIGHBOR_DELETE 16U /* neghbor delete */
+#define PEER_DOWN_RMAP_BIND 17U /* neghbor peer-group command */
+#define PEER_DOWN_RMAP_UNBIND 18U /* no neighbor peer-group command */
+#define PEER_DOWN_CAPABILITY_CHANGE 19U /* neighbor capability command */
+#define PEER_DOWN_PASSIVE_CHANGE 20U /* neighbor passive command */
+#define PEER_DOWN_MULTIHOP_CHANGE 21U /* neighbor multihop command */
+#define PEER_DOWN_NSF_CLOSE_SESSION 22U /* NSF tcp session close */
+#define PEER_DOWN_V6ONLY_CHANGE 23U /* if-based peering v6only toggled */
+#define PEER_DOWN_BFD_DOWN 24U /* BFD down */
+#define PEER_DOWN_IF_DOWN 25U /* Interface down */
+#define PEER_DOWN_NBR_ADDR_DEL 26U /* Peer address lost */
+#define PEER_DOWN_WAITING_NHT 27U /* Waiting for NHT to resolve */
+#define PEER_DOWN_NBR_ADDR 28U /* Waiting for peer IPv6 IP Addr */
+#define PEER_DOWN_VRF_UNINIT 29U /* Associated VRF is not init yet */
+#define PEER_DOWN_NOAFI_ACTIVATED 30U /* No AFI/SAFI activated for peer */
+#define PEER_DOWN_AS_SETS_REJECT 31U /* Reject routes with AS_SET */
+#define PEER_DOWN_WAITING_OPEN 32U /* Waiting for open to succeed */
+#define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */
/*
* Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason
@@ -1415,15 +1416,15 @@ struct peer {
/* The kind of route-map Flags.*/
uint16_t rmap_type;
-#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */
-#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */
-#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */
-#define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */
-#define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */
-#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */
-#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */
-#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */
-#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */
+#define PEER_RMAP_TYPE_IN (1U << 0) /* neighbor route-map in */
+#define PEER_RMAP_TYPE_OUT (1U << 1) /* neighbor route-map out */
+#define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network route-map */
+#define PEER_RMAP_TYPE_REDISTRIBUTE (1U << 3) /* redistribute route-map */
+#define PEER_RMAP_TYPE_DEFAULT (1U << 4) /* default-originate route-map */
+#define PEER_RMAP_TYPE_NOSET (1U << 5) /* not allow to set commands */
+#define PEER_RMAP_TYPE_IMPORT (1U << 6) /* neighbor route-map import */
+#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
+#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
/* peer specific BFD information */
struct bfd_info *bfd_info;
@@ -1537,6 +1538,7 @@ struct bgp_nlri {
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_PREFIX_SID 40
+#define BGP_ATTR_SRTE_COLOR 51
#ifdef ENABLE_BGP_VNC_ATTR
#define BGP_ATTR_VNC 255
#endif
diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot
index b548b5529a..4ce147b2c4 100644
--- a/doc/figures/nodes.dot
+++ b/doc/figures/nodes.dot
@@ -47,7 +47,7 @@ digraph climodes {
CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ];
CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ];
CONFIG_NODE -> LDP_NODE [ label="mpls ldp" ];
- CONFIG_NODE -> ISIS_NODE [ label="router isis WORD" ];
+ CONFIG_NODE -> ISIS_NODE [ label="router isis WORD [vrf NAME]" ];
CONFIG_NODE -> RMAP_NODE [ label="route-map WORD <deny|permit> (1-65535)" ];
CONFIG_NODE -> PW_NODE [ label="pseudowire IFNAME" ];
CONFIG_NODE -> VTY_NODE [ label="line vty" ];
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 1155b49eb1..8cbbe0809f 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -33,8 +33,8 @@ ISIS router
To start the ISIS process you have to specify the ISIS router. As of this
writing, *isisd* does not support multiple ISIS processes.
-.. index:: [no] router isis WORD
-.. clicmd:: [no] router isis WORD
+.. index:: [no] router isis WORD [vrf NAME]
+.. clicmd:: [no] router isis WORD [vrf NAME]
Enable or disable the ISIS process by specifying the ISIS domain with
'WORD'. *isisd* does not yet support multiple ISIS processes but you must
@@ -202,8 +202,8 @@ ISIS interface
.. _ip-router-isis-word:
-.. index:: [no] <ip|ipv6> router isis WORD
-.. clicmd:: [no] <ip|ipv6> router isis WORD
+.. index:: [no] <ip|ipv6> router isis WORD [vrf NAME]
+.. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]
Activate ISIS adjacency on this interface. Note that the name of ISIS
instance must be the same as the one used to configure the ISIS process (see
@@ -751,3 +751,22 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration.
segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null
!
+ISIS Vrf Configuration Examples
+===============================
+
+A simple vrf example:
+
+.. code-block:: frr
+
+ !
+ interface eth0 vrf RED
+ ip router isis FOO vrf RED
+ isis network point-to-point
+ isis circuit-type level-2-only
+ !
+ router isis FOO vrf RED
+ net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+ metric-style wide
+ is-type level-2-only
+
+
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index f557cbe022..fa5fc248a8 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -329,6 +329,12 @@ Route Map Set Command
Set the BGP table to a given table identifier
+.. index:: set sr-te color (1-4294967295)
+.. clicmd:: set sr-te color (1-4294967295)
+
+ Set the color of a SR-TE Policy to be applied to a learned route. The SR-TE
+ Policy is uniquely determined by the color and the BGP nexthop.
+
.. _route-map-call-command:
Route Map Call Command
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 985e07820f..1214c01a12 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1244,21 +1244,24 @@ static int isis_interface_config_write(struct vty *vty)
#else
static int isis_interface_config_write(struct vty *vty)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf = NULL;
int write = 0;
- struct interface *ifp;
- struct lyd_node *dnode;
- FOR_ALL_INTERFACES (vrf, ifp) {
- dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifp->name, vrf->name);
- if (dnode == NULL)
- continue;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct interface *ifp;
- write++;
- nb_cli_show_dnode_cmds(vty, dnode, false);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ struct lyd_node *dnode;
+ dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+ if (dnode == NULL)
+ continue;
+
+ write++;
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ }
}
return write;
}
@@ -1268,6 +1271,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
struct interface *ifp)
{
struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
+
if (circuit && circuit->area)
return NULL;
circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area);
@@ -1446,7 +1450,7 @@ int isis_if_delete_hook(struct interface *ifp)
/* Clean up the circuit data */
if (ifp && ifp->info) {
circuit = ifp->info;
- isis_csm_state_change(IF_DOWN_FROM_Z, circuit, circuit->area);
+ isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
}
return 0;
@@ -1454,10 +1458,15 @@ int isis_if_delete_hook(struct interface *ifp)
static int isis_ifp_create(struct interface *ifp)
{
- if (if_is_operative(ifp))
+ struct vrf *vrf = NULL;
+
+ if (if_is_operative(ifp)) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf)
+ isis_global_instance_create(vrf->name);
isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
ifp);
-
+ }
hook_call(isis_if_new_hook, ifp);
return 0;
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 4d02758003..31fe41db82 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -46,16 +46,21 @@
/*
* XPath: /frr-isisd:isis/instance
*/
-DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
- ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG_NOSH(router_isis, router_isis_cmd,
+ "router isis WORD$tag [vrf NAME$vrf_name]",
+ ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
int ret;
char base_xpath[XPATH_MAXLEN];
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
snprintf(base_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
/* default value in yang for is-type is level-1, but in FRR
* the first instance is assigned is-type level-1-2. We
@@ -77,25 +82,30 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
return ret;
}
-DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
- NO_STR ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG(no_router_isis, no_router_isis_cmd,
+ "no router isis WORD$tag [vrf NAME$vrf_name]",
+ NO_STR ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
struct listnode *node, *nnode;
struct isis_circuit *circuit = NULL;
struct isis_area *area = NULL;
- if (!yang_dnode_exists(vty->candidate_config->dnode,
- "/frr-isisd:isis/instance[area-tag='%s']",
- tag)) {
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ if (!yang_dnode_exists(
+ vty->candidate_config->dnode,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name)) {
vty_out(vty, "ISIS area %s not found.\n", tag);
return CMD_ERR_NOTHING_TODO;
}
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
- area = isis_area_lookup(tag, VRF_DEFAULT);
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (area && area->circuit_list && listcount(area->circuit_list)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) {
@@ -114,15 +124,23 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
}
return nb_cli_apply_changes(
- vty, "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ vty, "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
}
void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf = NULL;
+
+ vrf = yang_dnode_get_string(dnode, "./vrf");
+
vty_out(vty, "!\n");
- vty_out(vty, "router isis %s\n",
+ vty_out(vty, "router isis %s ",
yang_dnode_get_string(dnode, "./area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf"));
+ vty_out(vty, "\n");
}
/*
@@ -131,16 +149,18 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
* XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing
* XPath: /frr-isisd:isis/instance
*/
-DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
+ "ip router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
struct isis_area *area = NULL;
struct interface *ifp;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
@@ -150,16 +170,26 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return CMD_SUCCESS;
}
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp)
- area = isis_area_lookup(tag, ifp->vrf_id);
+ if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf && !vrf_name)
+ vrf_name = vrf->name;
+ }
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) {
+ isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -167,6 +197,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -192,6 +225,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
+
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@@ -206,16 +242,18 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
+ "ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
- struct isis_area *area = NULL;
struct interface *ifp;
+ struct isis_area *area;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
@@ -225,16 +263,25 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
return CMD_SUCCESS;
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp)
- area = isis_area_lookup(tag, ifp->vrf_id);
+ if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
+ vrf_name = VRF_DEFAULT_NAME;
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf && !vrf_name)
+ vrf_name = vrf->name;
+ }
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) {
+ isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -242,6 +289,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
+
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -267,6 +317,8 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@@ -282,13 +334,13 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
}
DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
- "no <ip|ipv6>$ip router isis [WORD]$tag",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+ "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n")
{
const struct lyd_node *dnode;
@@ -324,19 +376,33 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ip router isis %s\n",
+ vty_out(vty, " ip router isis %s ",
yang_dnode_get_string(dnode, "../area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, "\n");
}
void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ipv6 router isis %s\n",
+ vty_out(vty, " ipv6 router isis %s ",
yang_dnode_get_string(dnode, "../area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, "\n");
}
/*
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 6352303c23..26f5227aae 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -236,13 +236,12 @@ int main(int argc, char **argv, char **envp)
/* thread master */
isis_master_init(frr_init());
master = im->master;
-
/*
* initializations
*/
isis_error_init();
access_list_init();
- vrf_init(NULL, NULL, NULL, NULL, NULL);
+ isis_vrf_init();
prefix_list_init();
isis_init();
isis_circuit_init();
@@ -261,7 +260,7 @@ int main(int argc, char **argv, char **envp)
mt_init();
/* create the global 'isis' instance */
- isis_global_instance_create();
+ isis_global_instance_create(VRF_DEFAULT_NAME);
isis_zebra_init(master, instance);
isis_bfd_init();
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 2b8b02e3f1..33b0b4d02c 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -551,6 +551,13 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/vrf",
+ .cbs = {
+ .modify = lib_interface_isis_vrf_modify,
+ },
+ },
+
+ {
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
.cbs = {
.cli_show = cli_show_ip_isis_circ_type,
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index a9401bc86a..a79cb8ff57 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -168,6 +168,7 @@ int isis_instance_mpls_te_router_address_destroy(
int lib_interface_isis_create(struct nb_cb_create_args *args);
int lib_interface_isis_destroy(struct nb_cb_destroy_args *args);
int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args);
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index d722868414..170fe92c28 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -53,16 +53,19 @@ int isis_instance_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
const char *area_tag;
+ const char *vrf_name;
if (args->event != NB_EV_APPLY)
return NB_OK;
-
+ vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
+ isis_global_instance_create(vrf_name);
+ area = isis_area_lookup_by_vrf(area_tag, vrf_name);
if (area)
return NB_ERR_INCONSISTENCY;
- area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
+ area = isis_area_create(area_tag, vrf_name);
+
/* save area in dnode to avoid looking it up all the time */
nb_running_set_entry(args->dnode, area);
@@ -75,7 +78,6 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
if (args->event != NB_EV_APPLY)
return NB_OK;
-
area = nb_running_unset_entry(args->dnode);
isis_area_destroy(area);
@@ -116,7 +118,6 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
if (area == NULL)
return NB_ERR_VALIDATION;
-
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len);
if (addr.area_addr[addr.addr_len - 1] != 0) {
@@ -148,6 +149,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
case NB_EV_APPLY:
area = nb_running_get_entry(args->dnode, NULL, true);
addrr = args->resource->ptr;
+ assert(area);
if (area->isis->sysid_set == 0) {
/*
@@ -1830,8 +1832,10 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
{
struct isis_area *area = NULL;
struct interface *ifp;
- struct isis_circuit *circuit;
+ struct isis_circuit *circuit = NULL;
+ struct vrf *vrf;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
+ const char *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
uint32_t min_mtu, actual_mtu;
switch (args->event) {
@@ -1846,8 +1850,17 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
/* zebra might not know yet about the MTU - nothing we can do */
if (!ifp || ifp->mtu == 0)
break;
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (ifp->vrf_id != VRF_DEFAULT && vrf
+ && strcmp(vrf->name, vrf_name) != 0) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "interface %s not in vrf %s\n", ifp->name,
+ vrf_name);
+ return NB_ERR_VALIDATION;
+ }
actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
+
area = isis_area_lookup(area_tag, ifp->vrf_id);
if (area)
min_mtu = area->lsp_mtu;
@@ -1866,9 +1879,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
}
break;
case NB_EV_APPLY:
- ifp = nb_running_get_entry(args->dnode, NULL, true);
- if (ifp)
- area = isis_area_lookup(area_tag, ifp->vrf_id);
+ area = isis_area_lookup_by_vrf(area_tag, vrf_name);
/* The area should have already be created. We are
* setting the priority of the global isis area creation
* slightly lower, so it should be executed first, but I
@@ -1881,7 +1892,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
__func__, area_tag);
abort();
}
-
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
circuit = isis_circuit_create(area, ifp);
assert(circuit
&& (circuit->state == C_STATE_CONF
@@ -1957,6 +1968,44 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
}
/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/vrf
+ */
+int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct vrf *vrf;
+ const char *ifname, *vrfname, *vrf_name;
+ struct isis_circuit *circuit;
+
+ if (args->event == NB_EV_VALIDATE) {
+ /* libyang doesn't like relative paths across module boundaries
+ */
+ ifname = yang_dnode_get_string(args->dnode->parent->parent,
+ "./name");
+ vrfname = yang_dnode_get_string(args->dnode->parent->parent,
+ "./vrf");
+ vrf = vrf_lookup_by_name(vrfname);
+ assert(vrf);
+ ifp = if_lookup_by_name(ifname, vrf->vrf_id);
+
+ if (!ifp)
+ return NB_OK;
+
+ vrf_name = yang_dnode_get_string(args->dnode, NULL);
+ circuit = circuit_scan_by_ifp(ifp);
+ if (circuit && circuit->area && circuit->area->isis
+ && strcmp(circuit->area->isis->name, vrf_name)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "ISIS circuit is already defined on vrf %s",
+ circuit->area->isis->name);
+ return NB_ERR_VALIDATION;
+ }
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
*/
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 3aa21a9aed..a50eb607d9 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -577,6 +577,20 @@ int isis_zebra_label_manager_connect(void)
return 0;
}
+void isis_zebra_vrf_register(struct isis *isis)
+{
+ if (!zclient || zclient->sock < 0 || !isis)
+ return;
+
+ if (isis->vrf_id != VRF_UNKNOWN) {
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: Register VRF %s id %u", __func__,
+ isis->name, isis->vrf_id);
+ zclient_send_reg_requests(zclient, isis->vrf_id);
+ }
+}
+
+
static void isis_zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 4449b63c2e..768919ff46 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -57,5 +57,6 @@ bool isis_zebra_label_manager_ready(void);
int isis_zebra_label_manager_connect(void);
int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
int isis_zebra_release_label_range(uint32_t start, uint32_t end);
+void isis_zebra_vrf_register(struct isis *isis);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index aca98bf651..2a2c71b1fd 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -35,6 +35,7 @@
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "zclient.h"
#include "vrf.h"
#include "spf_backoff.h"
#include "lib/northbound_cli.h"
@@ -167,29 +168,32 @@ void isis_master_init(struct thread_master *master)
im->master = master;
}
-void isis_global_instance_create()
+void isis_global_instance_create(const char *vrf_name)
{
struct isis *isis;
- isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ isis = isis_lookup_by_vrfname(vrf_name);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(vrf_name);
isis_add(isis);
}
}
-struct isis *isis_new(vrf_id_t vrf_id)
+struct isis *isis_new(const char *vrf_name)
{
struct vrf *vrf;
struct isis *isis;
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
- isis->vrf_id = vrf_id;
- vrf = vrf_lookup_by_id(vrf_id);
+ vrf = vrf_lookup_by_name(vrf_name);
if (vrf) {
+ isis->vrf_id = vrf->vrf_id;
isis_vrf_link(isis, vrf);
isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+ } else {
+ isis->vrf_id = VRF_UNKNOWN;
+ isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
}
if (IS_DEBUG_EVENTS)
@@ -223,15 +227,20 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
if (vrf) {
isis = isis_lookup_by_vrfid(vrf->vrf_id);
if (isis == NULL) {
- isis = isis_new(vrf->vrf_id);
+ isis = isis_new(vrf_name);
+ isis_add(isis);
+ }
+ } else {
+ isis = isis_lookup_by_vrfid(VRF_UNKNOWN);
+ if (isis == NULL) {
+ isis = isis_new(vrf_name);
isis_add(isis);
}
- } else
- return NULL;
+ }
} else {
isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
isis_add(isis);
}
}
@@ -336,6 +345,24 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
return area;
}
+struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
+ const char *vrf_name)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis == NULL)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
+ if (strcmp(area->area_tag, area_tag) == 0)
+ return area;
+
+ return NULL;
+}
+
struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id)
{
struct isis_area *area;
@@ -449,6 +476,95 @@ void isis_area_destroy(struct isis_area *area)
}
+/* This is hook function for vrf create called as part of vrf_init */
+static int isis_vrf_new(struct vrf *vrf)
+{
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF Created: %s(%u)", __func__, vrf->name,
+ vrf->vrf_id);
+
+ return 0;
+}
+
+/* This is hook function for vrf delete call as part of vrf_init */
+static int isis_vrf_delete(struct vrf *vrf)
+{
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF Deletion: %s(%u)", __func__, vrf->name,
+ vrf->vrf_id);
+
+ return 0;
+}
+
+static int isis_vrf_enable(struct vrf *vrf)
+{
+ struct isis *isis;
+ vrf_id_t old_vrf_id;
+
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF %s id %u enabled", __func__, vrf->name,
+ vrf->vrf_id);
+
+ isis = isis_lookup_by_vrfname(vrf->name);
+ if (isis) {
+ if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
+ XFREE(MTYPE_ISIS, isis->name);
+ isis->name = NULL;
+ }
+ old_vrf_id = isis->vrf_id;
+ /* We have instance configured, link to VRF and make it "up". */
+ isis_vrf_link(isis, vrf);
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "%s: isis linked to vrf %s vrf_id %u (old id %u)",
+ __func__, vrf->name, isis->vrf_id, old_vrf_id);
+ if (old_vrf_id != isis->vrf_id) {
+ frr_with_privs (&isisd_privs) {
+ /* stop zebra redist to us for old vrf */
+ zclient_send_dereg_requests(zclient,
+ old_vrf_id);
+ /* start zebra redist to us for new vrf */
+ isis_zebra_vrf_register(isis);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int isis_vrf_disable(struct vrf *vrf)
+{
+ struct isis *isis;
+ vrf_id_t old_vrf_id = VRF_UNKNOWN;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF %s id %d disabled.", __func__, vrf->name,
+ vrf->vrf_id);
+ isis = isis_lookup_by_vrfname(vrf->name);
+ if (isis) {
+ old_vrf_id = isis->vrf_id;
+
+ /* We have instance configured, unlink
+ * from VRF and make it "down".
+ */
+ isis_vrf_unlink(isis, vrf);
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: isis old_vrf_id %d unlinked", __func__,
+ old_vrf_id);
+ }
+
+ return 0;
+}
+
+void isis_vrf_init(void)
+{
+ vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable,
+ isis_vrf_delete, isis_vrf_enable);
+}
+
void isis_finish(struct isis *isis)
{
struct vrf *vrf = NULL;
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 0c0a1eed10..c26a62dfac 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -73,7 +73,6 @@ struct isis_master {
struct list *isis;
/* ISIS thread master. */
struct thread_master *master;
- /* Various OSPF global configuration. */
uint8_t options;
};
#define F_ISIS_UNIT_TEST 0x01
@@ -213,15 +212,19 @@ void isis_finish(struct isis *isis);
void isis_master_init(struct thread_master *master);
void isis_vrf_link(struct isis *isis, struct vrf *vrf);
void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
-void isis_global_instance_create(void);
+void isis_global_instance_create(const char *vrf_name);
struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);
struct isis *isis_lookup_by_vrfname(const char *vrfname);
struct isis *isis_lookup_by_sysid(const uint8_t *sysid);
void isis_init(void);
-struct isis *isis_new(vrf_id_t vrf_id);
+void isis_vrf_init(void);
+
+struct isis *isis_new(const char *vrf_name);
struct isis_area *isis_area_create(const char *, const char *);
struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id);
+struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
+ const char *vrf_name);
int isis_area_get(struct vty *vty, const char *area_tag);
void isis_area_destroy(struct isis_area *area);
void print_debug(struct vty *, int, int);
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 734c1ea230..df64f908ea 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -468,6 +468,10 @@ lde_dispatch_parent(struct thread *thread)
iface = if_lookup_name(ldeconf, kif->ifname);
if (iface) {
if_update_info(iface, kif);
+
+ /* if up see if any labels need to be updated */
+ if (kif->operative)
+ lde_route_update(iface, AF_UNSPEC);
break;
}
@@ -786,7 +790,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.remote_label = fnh->remote_label;
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
-
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr));
break;
@@ -2271,3 +2274,156 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf,
if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)
lde_change_expnull_for_filter(af);
}
+
+void lde_route_update(struct iface *iface, int af)
+{
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ struct lde_nbr *ln;
+
+ /* update label of non-connected routes */
+ log_debug("update labels for interface %s", iface->name);
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+ if (IS_MPLS_UNRESERVED_LABEL(fn->local_label))
+ continue;
+
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ /* unspecified so process both address families */
+ break;
+ }
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ /*
+ * If connected leave existing label. If LDP
+ * configured on interface or a static route
+ * may need new label. If no LDP configured
+ * treat fec as a connected route
+ */
+ if (fnh->flags & F_FEC_NH_CONNECTED)
+ break;
+
+ if (fnh->ifindex != iface->ifindex)
+ continue;
+
+ fnh->flags &= ~F_FEC_NH_NO_LDP;
+ if (IS_MPLS_RESERVED_LABEL(fn->local_label)) {
+ fn->local_label = NO_LABEL;
+ fn->local_label = lde_update_label(fn);
+ if (fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(
+ ln, fn, 0);
+ }
+ break;
+ }
+ }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+ 0, NULL, 0);
+}
+
+void lde_route_update_release(struct iface *iface, int af)
+{
+ struct lde_nbr *ln;
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+
+ /* update label of interfaces no longer running LDP */
+ log_debug("release all labels for interface %s af %s", iface->name,
+ af == AF_INET ? "ipv4" : "ipv6");
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_route_update_release: unknown af");
+ }
+
+ if (fn->local_label == NO_LABEL)
+ continue;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ /*
+ * If connected leave existing label. If LDP
+ * removed from interface may need new label
+ * and would be treated as a connected route
+ */
+ if (fnh->flags & F_FEC_NH_CONNECTED)
+ break;
+
+ if (fnh->ifindex != iface->ifindex)
+ continue;
+
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+ lde_free_label(fn->local_label);
+ fn->local_label = NO_LABEL;
+ fn->local_label = lde_update_label(fn);
+ if (fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 0);
+ break;
+ }
+ }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+ 0, NULL, 0);
+}
+
+void lde_route_update_release_all(int af)
+{
+ struct lde_nbr *ln;
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+
+ /* remove labels from all interfaces as LDP is no longer running for
+ * this address family
+ */
+ log_debug("release all labels for address family %s",
+ af == AF_INET ? "ipv4" : "ipv6");
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_route_update_release: unknown af");
+ }
+
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ lde_send_delete_klabel(fn, fnh);
+ }
+ }
+}
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 9e6db3a90b..660aeafb34 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -193,6 +193,9 @@ void lde_change_allocate_filter(int);
void lde_change_advertise_filter(int);
void lde_change_accept_filter(int);
void lde_change_expnull_for_filter(int);
+void lde_route_update(struct iface *, int);
+void lde_route_update_release(struct iface *, int);
+void lde_route_update_release_all(int);
struct lde_addr *lde_address_find(struct lde_nbr *, int,
union ldpd_addr *);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 11d85b7449..bed276c7b1 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -404,10 +404,15 @@ lde_kernel_update(struct fec *fec)
* if LDP configured on interface or a static route
* clear flag else treat fec as a connected route
*/
- iface = if_lookup(ldeconf,fnh->ifindex);
- if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC)
- fnh->flags &=~F_FEC_NH_NO_LDP;
- else
+ if (ldeconf->flags & F_LDPD_ENABLED) {
+ iface = if_lookup(ldeconf,fnh->ifindex);
+ if (fnh->flags & F_FEC_NH_CONNECTED ||
+ iface ||
+ fnh->route_type == ZEBRA_ROUTE_STATIC)
+ fnh->flags &=~F_FEC_NH_NO_LDP;
+ else
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ } else
fnh->flags |= F_FEC_NH_NO_LDP;
} else {
lde_send_delete_klabel(fn, fnh);
@@ -437,6 +442,10 @@ lde_kernel_update(struct fec *fec)
lde_send_labelmapping(ln, fn, 1);
}
+ /* if no label created yet then don't try to program labeled route */
+ if (fn->local_label == NO_LABEL)
+ return;
+
LIST_FOREACH(fnh, &fn->nexthops, entry) {
lde_send_change_klabel(fn, fnh);
@@ -567,7 +576,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
fnh->flags &= ~F_FEC_NH_DEFER;
}
fnh->remote_label = map->label;
- lde_send_change_klabel(fn, fnh);
+ if (fn->local_label != NO_LABEL)
+ lde_send_change_klabel(fn, fnh);
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index fc84c7f76b..53a384fe55 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -616,6 +616,8 @@ DEFPY (ldp_show_mpls_ldp_binding,
"Show detailed information\n"
JSON_STR)
{
+ if (!(ldpd_conf->flags & F_LDPD_ENABLED))
+ return CMD_SUCCESS;
if (!local_label_str)
local_label = NO_LABEL;
if (!remote_label_str)
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 927c3a3c03..dca379e4eb 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -1329,6 +1329,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
int reset_nbrs_ipv4 = 0;
int reset_nbrs = 0;
int update_sockets = 0;
+ int change_ldp_disabled = 0;
/* update timers */
if (af_conf->keepalive != xa->keepalive) {
@@ -1362,6 +1363,11 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
!= (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
change_host_label = 1;
+ /* disabling LDP for address family */
+ if ((af_conf->flags & F_LDPD_AF_ENABLED) &&
+ !(xa->flags & F_LDPD_AF_ENABLED))
+ change_ldp_disabled = 1;
+
af_conf->flags = xa->flags;
/* update the transport address */
@@ -1409,6 +1415,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
lde_change_egress_label(af);
if (change_host_label)
lde_change_allocate_filter(af);
+ if (change_ldp_disabled)
+ lde_route_update_release_all(af);
+
break;
case PROC_LDP_ENGINE:
if (stop_init_backoff)
@@ -1434,13 +1443,22 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
struct iface *iface, *itmp, *xi;
RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
- /* find deleted interfaces */
+ /* find deleted interfaces, which occurs when LDP is removed
+ * for all address families
+ */
if (if_lookup_name(xconf, iface->name) == NULL) {
switch (ldpd_process) {
case PROC_LDP_ENGINE:
ldpe_if_exit(iface);
break;
case PROC_LDE_ENGINE:
+ if (iface->ipv4.enabled)
+ lde_route_update_release(iface,
+ AF_INET);
+ if (iface->ipv6.enabled)
+ lde_route_update_release(iface,
+ AF_INET6);
+ break;
case PROC_MAIN:
break;
}
@@ -1468,6 +1486,29 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
continue;
}
+ /* update labels when adding or removing ldp on an
+ * interface
+ */
+ if (ldpd_process == PROC_LDE_ENGINE) {
+ /* if we are removing lpd config for an address
+ * family on an interface then advertise routes
+ * learned over this interface as if they were
+ * connected routes
+ */
+ if (iface->ipv4.enabled && !xi->ipv4.enabled)
+ lde_route_update_release(iface, AF_INET);
+ if (iface->ipv6.enabled && !xi->ipv6.enabled)
+ lde_route_update_release(iface, AF_INET6);
+
+ /* if we are adding lpd config for an address
+ * family on an interface then add proper labels
+ */
+ if (!iface->ipv4.enabled && xi->ipv4.enabled)
+ lde_route_update(iface, AF_INET);
+ if (!iface->ipv6.enabled && xi->ipv6.enabled)
+ lde_route_update(iface, AF_INET6);
+ }
+
/* update existing interfaces */
merge_iface_af(&iface->ipv4, &xi->ipv4);
merge_iface_af(&iface->ipv6, &xi->ipv6);
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 655313bf16..9078e711fb 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -614,10 +614,8 @@ ldpe_dispatch_lde(struct thread *thread)
map = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid);
- if (nbr == NULL) {
- log_debug("ldpe_dispatch_lde: cannot find neighbor");
+ if (nbr == NULL)
break;
- }
if (nbr->state != NBR_STA_OPER)
break;
@@ -641,10 +639,8 @@ ldpe_dispatch_lde(struct thread *thread)
case IMSG_REQUEST_ADD_END:
case IMSG_WITHDRAW_ADD_END:
nbr = nbr_find_peerid(imsg.hdr.peerid);
- if (nbr == NULL) {
- log_debug("ldpe_dispatch_lde: cannot find neighbor");
+ if (nbr == NULL)
break;
- }
if (nbr->state != NBR_STA_OPER)
break;
diff --git a/lib/hash.c b/lib/hash.c
index 7f8a237047..85982774ac 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -77,9 +77,20 @@ void *hash_alloc_intern(void *arg)
return arg;
}
+/*
+ * ssq = ssq + (new^2 - old^2)
+ * = ssq + ((new + old) * (new - old))
+ */
#define hash_update_ssq(hz, old, new) \
- atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old), \
- memory_order_relaxed);
+ do { \
+ int _adjust = (new + old) * (new - old); \
+ if (_adjust < 0) \
+ atomic_fetch_sub_explicit(&hz->stats.ssq, -_adjust, \
+ memory_order_relaxed); \
+ else \
+ atomic_fetch_add_explicit(&hz->stats.ssq, _adjust, \
+ memory_order_relaxed); \
+ } while (0)
/* Expand hash if the chain length exceeds the threshold. */
static void hash_expand(struct hash *hash)
diff --git a/lib/mpls.h b/lib/mpls.h
index 8922a36664..74bd7aae3e 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -72,8 +72,7 @@ extern "C" {
/* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16
-#define IS_MPLS_RESERVED_LABEL(label) \
- (label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
+#define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)
#define IS_MPLS_UNRESERVED_LABEL(label) \
(label >= MPLS_LABEL_UNRESERVED_MIN \
diff --git a/lib/privs.c b/lib/privs.c
index 5c7e1240e2..dc43b7279d 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -1020,11 +1020,11 @@ void zprivs_get_ids(struct zprivs_ids_t *ids)
ids->uid_priv = getuid();
(zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
- : (ids->uid_normal = -1);
+ : (ids->uid_normal = (uid_t)-1);
(zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
- : (ids->gid_normal = -1);
+ : (ids->gid_normal = (uid_t)-1);
(zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
- : (ids->gid_vty = -1);
+ : (ids->gid_vty = (uid_t)-1);
return;
}
diff --git a/lib/stream.c b/lib/stream.c
index 6e62e11380..dc207c16a4 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -268,6 +268,30 @@ bool stream_forward_getp2(struct stream *s, size_t size)
return true;
}
+void stream_rewind_getp(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size)) {
+ STREAM_BOUND_WARN(s, "rewind getp");
+ return;
+ }
+
+ s->getp -= size;
+}
+
+bool stream_rewind_getp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size))
+ return false;
+
+ s->getp -= size;
+
+ return true;
+}
+
void stream_forward_endp(struct stream *s, size_t size)
{
STREAM_VERIFY_SANE(s);
diff --git a/lib/stream.h b/lib/stream.h
index f2c16b3486..23f85d809b 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -160,7 +160,6 @@ extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);
extern size_t stream_get_getp(const struct stream *s);
extern size_t stream_get_endp(const struct stream *s);
extern size_t stream_get_size(const struct stream *s);
-extern uint8_t *stream_get_data(struct stream *s);
/**
* Create a new stream structure; copy offset bytes from s1 to the new
@@ -174,6 +173,8 @@ extern void stream_set_getp(struct stream *, size_t);
extern void stream_set_endp(struct stream *, size_t);
extern void stream_forward_getp(struct stream *, size_t);
extern bool stream_forward_getp2(struct stream *, size_t);
+extern void stream_rewind_getp(struct stream *s, size_t size);
+extern bool stream_rewind_getp2(struct stream *s, size_t size);
extern void stream_forward_endp(struct stream *, size_t);
extern bool stream_forward_endp2(struct stream *, size_t);
@@ -461,6 +462,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
goto stream_failure; \
} while (0)
+#define STREAM_REWIND_GETP(STR, SIZE) \
+ do { \
+ if (!stream_rewind_getp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
#define STREAM_FORWARD_ENDP(STR, SIZE) \
do { \
if (!stream_forward_endp2((STR), (SIZE))) \
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 3985b08620..fabcc426ea 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -1031,7 +1031,10 @@ static int ospf6_interface_show_traffic(struct vty *vty,
struct vrf *vrf = NULL;
struct ospf6_interface *oi = NULL;
- vrf = vrf_lookup_by_id(intf_ifp->vrf_id);
+ if (intf_ifp)
+ vrf = vrf_lookup_by_id(intf_ifp->vrf_id);
+ else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (!display_once) {
vty_out(vty, "\n");
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index dae906b956..73bb531dc0 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -291,7 +291,7 @@ int main(int argc, char **argv)
/* IS-IS inits. */
yang_module_load("frr-isisd");
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
listnode_add(im->isis, isis);
SET_FLAG(im->options, F_ISIS_UNIT_TEST);
debug_spf_events |= DEBUG_SPF_EVENTS;
diff --git a/tests/topotests/bgp-auth/R1/bgpd.conf b/tests/topotests/bgp-auth/R1/bgpd.conf
new file mode 100644
index 0000000000..1cb26c6537
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65001
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 password hello1
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 password hello2
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..aab35073cf
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf
@@ -0,0 +1,40 @@
+log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
+debug bgp neighbor-events
+
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65001 vrf red
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..7e15720c7e
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_blue peer-group
+ neighbor TWO_GROUP_blue remote-as 65002
+ neighbor TWO_GROUP_blue update-source 1.1.1.1
+ neighbor TWO_GROUP_blue ebgp-multihop 3
+ neighbor TWO_GROUP_blue password blue1
+ neighbor THREE_GROUP_blue peer-group
+ neighbor THREE_GROUP_blue remote-as 65003
+ neighbor THREE_GROUP_blue update-source 1.1.1.1
+ neighbor THREE_GROUP_blue ebgp-multihop 3
+ neighbor THREE_GROUP_blue password blue2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_blue maximum-prefix 4294967295
+ neighbor THREE_GROUP_blue maximum-prefix 4294967295
+
+router bgp 65001 vrf red
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_red peer-group
+ neighbor TWO_GROUP_red remote-as 65002
+ neighbor TWO_GROUP_red update-source 1.1.1.1
+ neighbor TWO_GROUP_red ebgp-multihop 3
+ neighbor TWO_GROUP_red password red1
+ neighbor THREE_GROUP_red peer-group
+ neighbor THREE_GROUP_red remote-as 65003
+ neighbor THREE_GROUP_red update-source 1.1.1.1
+ neighbor THREE_GROUP_red ebgp-multihop 3
+ neighbor THREE_GROUP_red password red2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_red
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_red
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_red maximum-prefix 4294967295
+ neighbor THREE_GROUP_red maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/bgpd_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf
new file mode 100644
index 0000000000..9200b0501d
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65001
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP peer-group
+ neighbor TWO_GROUP remote-as 65002
+ neighbor TWO_GROUP update-source 1.1.1.1
+ neighbor TWO_GROUP ebgp-multihop 3
+ neighbor TWO_GROUP password hello1
+ neighbor THREE_GROUP peer-group
+ neighbor THREE_GROUP remote-as 65003
+ neighbor THREE_GROUP update-source 1.1.1.1
+ neighbor THREE_GROUP ebgp-multihop 3
+ neighbor THREE_GROUP password hello2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP
+ address-family ipv4 unicast
+ neighbor TWO_GROUP maximum-prefix 4294967295
+ neighbor THREE_GROUP maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf
new file mode 100644
index 0000000000..73aa8c1a03
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf
@@ -0,0 +1,21 @@
+log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
+debug bgp neighbor-events
+
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..d68951b406
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_blue peer-group
+ neighbor TWO_GROUP_blue remote-as 65002
+ neighbor TWO_GROUP_blue update-source 1.1.1.1
+ neighbor TWO_GROUP_blue ebgp-multihop 3
+ neighbor TWO_GROUP_blue password hello1
+ neighbor THREE_GROUP_blue peer-group
+ neighbor THREE_GROUP_blue remote-as 65003
+ neighbor THREE_GROUP_blue update-source 1.1.1.1
+ neighbor THREE_GROUP_blue ebgp-multihop 3
+ neighbor THREE_GROUP_blue password hello2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_blue maximum-prefix 4294967295
+ neighbor THREE_GROUP_blue maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/ospfd.conf b/tests/topotests/bgp-auth/R1/ospfd.conf
new file mode 100644
index 0000000000..79eb0e33da
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..e2a28000b8
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
+
+router ospf vrf red
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/ospfd_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf
new file mode 100644
index 0000000000..0b7fbae8c4
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/zebra.conf b/tests/topotests/bgp-auth/R1/zebra.conf
new file mode 100644
index 0000000000..d39915335a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 1.1.1.1/32
+interface lo1 vrf blue
+ ip address 1.1.1.1/32
+interface lo2 vrf red
+ ip address 1.1.1.1/32
+interface R1-eth0
+ ip address 10.10.0.1/24
+interface R1-eth1
+ ip address 10.20.0.1/24
+interface R1-eth2 vrf blue
+ ip address 10.10.0.1/24
+interface R1-eth3 vrf blue
+ ip address 10.20.0.1/24
+interface R1-eth4 vrf red
+ ip address 10.10.0.1/24
+interface R1-eth5 vrf red
+ ip address 10.20.0.1/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/R2/bgpd.conf b/tests/topotests/bgp-auth/R2/bgpd.conf
new file mode 100644
index 0000000000..fa2a570ef9
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65002
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..d5f70edf68
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf
@@ -0,0 +1,37 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65002 vrf red
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..d5f70edf68
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65002 vrf red
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf
new file mode 100644
index 0000000000..fa2a570ef9
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65002
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf
new file mode 100644
index 0000000000..d1f3847420
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf
@@ -0,0 +1,18 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..d1f3847420
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/ospfd.conf b/tests/topotests/bgp-auth/R2/ospfd.conf
new file mode 100644
index 0000000000..028b546a0c
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..a05dfb8e41
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
+
+router ospf vrf red
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/ospfd_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf
new file mode 100644
index 0000000000..b198d352e2
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/zebra.conf b/tests/topotests/bgp-auth/R2/zebra.conf
new file mode 100644
index 0000000000..fece68472a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 2.2.2.2/32
+interface lo1 vrf blue
+ ip address 2.2.2.2/32
+interface lo2 vrf red
+ ip address 2.2.2.2/32
+interface R2-eth0
+ ip address 10.10.0.2/24
+interface R2-eth1
+ ip address 10.30.0.2/24
+interface R2-eth2 vrf blue
+ ip address 10.10.0.2/24
+interface R2-eth3 vrf blue
+ ip address 10.30.0.2/24
+interface R2-eth4 vrf red
+ ip address 10.10.0.2/24
+interface R2-eth5 vrf red
+ ip address 10.30.0.2/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/R3/bgpd.conf b/tests/topotests/bgp-auth/R3/bgpd.conf
new file mode 100644
index 0000000000..deccfd418b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65003
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..fe3e64d8d5
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf
@@ -0,0 +1,37 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
+
+router bgp 65003 vrf red
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..fe3e64d8d5
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
+
+router bgp 65003 vrf red
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf
new file mode 100644
index 0000000000..deccfd418b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65003
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf
new file mode 100644
index 0000000000..c109aa801b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf
@@ -0,0 +1,18 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..c109aa801b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/ospfd.conf b/tests/topotests/bgp-auth/R3/ospfd.conf
new file mode 100644
index 0000000000..0f0a2e926a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..f32d2a8423
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
+!
+router ospf vrf red
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/ospfd_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf
new file mode 100644
index 0000000000..6465b635aa
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/zebra.conf b/tests/topotests/bgp-auth/R3/zebra.conf
new file mode 100644
index 0000000000..0fe3acdfd0
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 3.3.3.3/32
+interface lo1 vrf blue
+ ip address 3.3.3.3/32
+interface lo2 vrf red
+ ip address 3.3.3.3/32
+interface R3-eth0
+ ip address 10.20.0.3/24
+interface R3-eth1
+ ip address 10.30.0.3/24
+interface R3-eth2 vrf blue
+ ip address 10.20.0.3/24
+interface R3-eth3 vrf blue
+ ip address 10.30.0.3/24
+interface R3-eth4 vrf red
+ ip address 10.20.0.3/24
+interface R3-eth5 vrf red
+ ip address 10.30.0.3/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/test_bgp_auth.py b/tests/topotests/bgp-auth/test_bgp_auth.py
new file mode 100755
index 0000000000..6198997b86
--- /dev/null
+++ b/tests/topotests/bgp-auth/test_bgp_auth.py
@@ -0,0 +1,747 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_auth.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_auth.py: Test BGP Md5 Authentication
+
+ +------+
+ +--------| |--------+
+ | +------| R1 |------+ |
+ | | -----| |----+ | |
+ | | | +------+ | | |
+ | | | | | |
+ +------+ +------+
+ | |------------| |
+ | R2 |------------| R3 |
+ | |------------| |
+ +------+ +------+
+
+
+setup is 3 routers with 3 links between each each link in a different vrf
+Default, blue and red respectively
+Tests check various fiddling with passwords and checking that the peer
+establishment is as expected and passwords are not leaked across sockets
+for bgp instances
+"""
+
+import os
+import sys
+import json
+import platform
+from functools import partial
+import pytest
+from time import sleep
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+from lib.common_config import apply_raw_config
+
+ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
+
+
+class InvalidCLIError(Exception):
+ """Raise when the CLI command is wrong"""
+
+ pass
+
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # This function only purpose is to define allocation and relationship
+ # between routers, switches and hosts.
+ #
+ #
+ # Create routers
+ tgen.add_router("R1")
+ tgen.add_router("R2")
+ tgen.add_router("R3")
+
+ # R1-R2 1
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 1
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 1
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R1-R2 2
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 2
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 2
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R1-R2 3
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 2
+ switch = tgen.add_switch("s8")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 2
+ switch = tgen.add_switch("s9")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+ tgen.start_topology()
+
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ # blue vrf
+ r1.run("ip link add blue type vrf table 1001")
+ r1.run("ip link set up dev blue")
+ r2.run("ip link add blue type vrf table 1001")
+ r2.run("ip link set up dev blue")
+ r3.run("ip link add blue type vrf table 1001")
+ r3.run("ip link set up dev blue")
+
+ r1.run("ip link add lo1 type dummy")
+ r1.run("ip link set lo1 master blue")
+ r1.run("ip link set up dev lo1")
+ r2.run("ip link add lo1 type dummy")
+ r2.run("ip link set up dev lo1")
+ r2.run("ip link set lo1 master blue")
+ r3.run("ip link add lo1 type dummy")
+ r3.run("ip link set up dev lo1")
+ r3.run("ip link set lo1 master blue")
+
+ r1.run("ip link set R1-eth2 master blue")
+ r1.run("ip link set R1-eth3 master blue")
+ r2.run("ip link set R2-eth2 master blue")
+ r2.run("ip link set R2-eth3 master blue")
+ r3.run("ip link set R3-eth2 master blue")
+ r3.run("ip link set R3-eth3 master blue")
+
+ r1.run("ip link set up dev R1-eth2")
+ r1.run("ip link set up dev R1-eth3")
+ r2.run("ip link set up dev R2-eth2")
+ r2.run("ip link set up dev R2-eth3")
+ r3.run("ip link set up dev R3-eth2")
+ r3.run("ip link set up dev R3-eth3")
+
+ # red vrf
+ r1.run("ip link add red type vrf table 1002")
+ r1.run("ip link set up dev red")
+ r2.run("ip link add red type vrf table 1002")
+ r2.run("ip link set up dev red")
+ r3.run("ip link add red type vrf table 1002")
+ r3.run("ip link set up dev red")
+
+ r1.run("ip link add lo2 type dummy")
+ r1.run("ip link set lo2 master red")
+ r1.run("ip link set up dev lo2")
+ r2.run("ip link add lo2 type dummy")
+ r2.run("ip link set up dev lo2")
+ r2.run("ip link set lo2 master red")
+ r3.run("ip link add lo2 type dummy")
+ r3.run("ip link set up dev lo2")
+ r3.run("ip link set lo2 master red")
+
+ r1.run("ip link set R1-eth4 master red")
+ r1.run("ip link set R1-eth5 master red")
+ r2.run("ip link set R2-eth4 master red")
+ r2.run("ip link set R2-eth5 master red")
+ r3.run("ip link set R3-eth4 master red")
+ r3.run("ip link set R3-eth5 master red")
+
+ r1.run("ip link set up dev R1-eth4")
+ r1.run("ip link set up dev R1-eth5")
+ r2.run("ip link set up dev R2-eth4")
+ r2.run("ip link set up dev R2-eth5")
+ r3.run("ip link set up dev R3-eth4")
+ r3.run("ip link set up dev R3-eth5")
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all registred routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def vrf_str(vrf):
+ if vrf == "":
+ vrf_str = ""
+ else:
+ vrf_str = "vrf {}".format(vrf)
+
+ return vrf_str
+
+
+def peer_name(rtr, prefix, vrf):
+ "generate VRF string for CLI"
+ if vrf == "":
+ vrf_str = ""
+ else:
+ vrf_str = "_" + vrf
+
+ if prefix == "yes":
+ if rtr == "R2":
+ return "TWO_GROUP" + vrf_str
+ else:
+ return "THREE_GROUP" + vrf_str
+ else:
+ if rtr == "R2":
+ return "2.2.2.2"
+ else:
+ return "3.3.3.3"
+
+
+def print_diag(vrf):
+ "print failure disagnostics"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ print(rname + ":")
+ print(router.vtysh_cmd("show run"))
+ print(router.vtysh_cmd("show ip route {}".format(vrf_str(vrf))))
+ print(router.vtysh_cmd("show bgp {} neighbor".format(vrf_str(vrf))))
+
+
+def configure(conf_file):
+ "configure from a file"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ with open(
+ os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+"
+ ) as cfg:
+ new_config = cfg.read()
+
+ output = router.vtysh_multicmd(new_config, pretty_output=False)
+ for out_err in ERROR_LIST:
+ if out_err.lower() in output.lower():
+ raise InvalidCLIError("%s" % output)
+
+
+def clear_bgp(vrf=""):
+ " clear bgp configuration for a vrf"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ router_list = tgen.routers()
+ if vrf == "":
+ r1.vtysh_cmd("conf t\nno router bgp 65001")
+ r2.vtysh_cmd("conf t\nno router bgp 65002")
+ r2.vtysh_cmd("conf t\nno router bgp 65003")
+ else:
+ r1.vtysh_cmd("conf t\nno router bgp 65001 vrf {}".format(vrf))
+ r2.vtysh_cmd("conf t\nno router bgp 65002 vrf {}".format(vrf))
+ r3.vtysh_cmd("conf t\nno router bgp 65003 vrf {}".format(vrf))
+
+
+def clear_ospf(vrf=""):
+ "clear ospf configuration for a vrf"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ if vrf == "":
+ router.vtysh_cmd("conf t\nno router ospf")
+ else:
+ router.vtysh_cmd("conf t\nno router ospf vrf {}".format(vrf))
+
+
+def check_neigh_state(router, peer, state, vrf=""):
+ "check BGP neighbor state on a router"
+
+ count = 0
+ matched = False
+ neigh_output = ""
+ while count < 125:
+ if vrf == "":
+ neigh_output = router.vtysh_cmd("show bgp neighbors {} json".format(peer))
+ else:
+ neigh_output = router.vtysh_cmd(
+ "show bgp vrf {} neighbors {} json".format(vrf, peer)
+ )
+ neigh_output_json = json.loads(neigh_output)
+ if neigh_output_json[peer]["bgpState"] == state:
+ matched = True
+ break
+ count += 1
+ sleep(1)
+
+ assertmsg = "{} could not peer {} state expected {} got {} ".format(
+ router.name, peer, state, neigh_output_json[peer]["bgpState"]
+ )
+ if matched != True:
+ print_diag(vrf)
+ assert matched == True, assertmsg
+
+
+def check_all_peers_established(vrf=""):
+ "standard check for extablished peers per vrf"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+ # do r1 last as he might be the dynamic one
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+
+def check_vrf_peer_remove_passwords(vrf="", prefix="no"):
+ "selectively remove passwords checking state"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
+ vrf_str(vrf), peer_name("R2", prefix, vrf)
+ )
+ )
+
+ check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
+ vrf_str(vrf), peer_name("R3", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nno neighbor 3.3.3.3 password".format(vrf_str(vrf))
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nno neighbor 2.2.2.2 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+
+def check_vrf_peer_change_passwords(vrf="", prefix="no"):
+ "selectively change passwords checking state"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nneighbor {} password change1".format(
+ vrf_str(vrf), peer_name("R2", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nneighbor 1.1.1.1 password change1".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nneighbor {} password change2".format(
+ vrf_str(vrf), peer_name("R3", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nneighbor 1.1.1.1 password change2".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nneighbor 3.3.3.3 password change3".format(
+ vrf_str(vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nneighbor 2.2.2.2 password change3".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+
+def test_default_peer_established():
+ "default vrf 3 peers same password"
+
+ check_all_peers_established()
+ clear_bgp()
+ # tgen.mininet_cli()
+
+
+def test_default_peer_remove_passwords():
+ "selectively remove passwords checking state"
+
+ configure("bgpd.conf")
+ check_vrf_peer_remove_passwords()
+ clear_bgp()
+
+
+def test_default_peer_change_passwords():
+ "selectively change passwords checking state"
+
+ configure("bgpd.conf")
+ check_vrf_peer_change_passwords()
+ clear_bgp()
+
+
+def test_default_prefix_peer_established():
+ "default vrf 3 peers same password with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_prefix.conf")
+ check_all_peers_established()
+ clear_bgp()
+ # tgen.mininet_cli()
+
+
+def test_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+ configure("bgpd_prefix.conf")
+ check_vrf_peer_remove_passwords(prefix="yes")
+ clear_bgp()
+
+
+def test_prefix_peer_change_passwords():
+ "selecively change passwords checkig state with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+ configure("bgpd_prefix.conf")
+ check_vrf_peer_change_passwords(prefix="yes")
+ clear_bgp()
+ clear_ospf()
+
+
+def test_vrf_peer_established():
+ "default vrf 3 peers same password with VRF config"
+
+ # clean routers and load vrf config
+ configure("bgpd_vrf.conf")
+ configure("ospfd_vrf.conf")
+
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ # tgen.mininet_cli()
+
+
+def test_vrf_peer_remove_passwords():
+ "selectively remove passwords checking state with VRF config"
+
+ configure("bgpd_vrf.conf")
+ check_vrf_peer_remove_passwords(vrf="blue")
+ clear_bgp("blue")
+
+
+def test_vrf_peer_change_passwords():
+ "selectively change passwords checking state with VRF config"
+
+ configure("bgpd_vrf.conf")
+ check_vrf_peer_change_passwords(vrf="blue")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_established():
+ "default vrf 3 peers same password with VRF prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_bgp("blue")
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with VRF prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_change_passwords():
+ "selectively change passwords checking state with VRF prefix config"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_ospf("blue")
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
+ clear_bgp("blue")
+ clear_ospf("blue")
+
+
+def test_multiple_vrf_peer_established():
+ "default vrf 3 peers same password with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ configure("ospfd_multi_vrf.conf")
+ check_all_peers_established("blue")
+ check_all_peers_established("red")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_peer_remove_passwords():
+ "selectively remove passwords checking state with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ check_vrf_peer_remove_passwords("blue")
+ check_all_peers_established("red")
+ check_vrf_peer_remove_passwords("red")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_peer_change_passwords():
+ "selectively change passwords checking state with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ check_vrf_peer_change_passwords("blue")
+ check_all_peers_established("red")
+ check_vrf_peer_change_passwords("red")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_established():
+ "default vrf 3 peers same password with multilpe VRFs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_multi_vrf.conf")
+ configure("ospfd_multi_vrf.conf")
+ check_all_peers_established("blue")
+ check_all_peers_established("red")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with multiple vrfs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_multi_vrf_prefix.conf")
+ tgen = get_topogen()
+ check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
+ check_all_peers_established("red")
+ check_vrf_peer_remove_passwords(vrf="red", prefix="yes")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_change_passwords():
+ "selectively change passwords checking state with multiple vrfs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_bgp("blue")
+ clear_bgp("red")
+ clear_ospf("blue")
+ clear_ospf("red")
+ return
+
+ configure("bgpd_multi_vrf_prefix.conf")
+ check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
+ check_all_peers_established("red")
+ check_vrf_peer_change_passwords(vrf="red", prefix="yes")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ clear_ospf("blue")
+ clear_ospf("red")
+ # tgen.mininet_cli()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-topo1-vrf/__init__.py b/tests/topotests/isis-topo1-vrf/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/__init__.py
diff --git a/tests/topotests/isis-topo1-vrf/r1/isisd.conf b/tests/topotests/isis-topo1-vrf/r1/isisd.conf
new file mode 100755
index 0000000000..4ac4597015
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/isisd.conf
@@ -0,0 +1,15 @@
+hostname r1
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r1-eth0
+ ip router isis 1 vrf r1-cust1
+ ipv6 router isis 1 vrf r1-cust1
+ isis circuit-type level-2-only
+!
+router isis 1 vrf r1-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00
+ metric-style wide
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route.json b/tests/topotests/isis-topo1-vrf/r1/r1_route.json
new file mode 100644
index 0000000000..790808f2cd
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route.json
@@ -0,0 +1,57 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "ip": "10.0.20.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "ip": "10.0.20.1"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json
new file mode 100644
index 0000000000..332cbb3290
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json
@@ -0,0 +1,40 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json
new file mode 100755
index 0000000000..d1ace402ba
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json
@@ -0,0 +1,14 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r1-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r1-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json
new file mode 100755
index 0000000000..6af22297e9
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json
@@ -0,0 +1,13 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r1-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.20.1"
+ },
+ "10.0.20.0/24": {
+ "dev": "r1-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json
new file mode 100644
index 0000000000..8e3cdc7bd6
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json
@@ -0,0 +1,80 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r1"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r1"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r1"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r1(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r1"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r1(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/zebra.conf b/tests/topotests/isis-topo1-vrf/r1/zebra.conf
new file mode 100755
index 0000000000..fa1c02e5f8
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/zebra.conf
@@ -0,0 +1,9 @@
+hostname r1
+interface r1-eth0 vrf r1-cust1
+ ip address 10.0.20.2/24
+ ipv6 address 2001:db8:1:1::2/64
+!
+interface lo
+ ip address 10.254.0.1/32
+ ipv6 address 2001:db8:F::1/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r2/isisd.conf b/tests/topotests/isis-topo1-vrf/r2/isisd.conf
new file mode 100755
index 0000000000..4c68540265
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/isisd.conf
@@ -0,0 +1,15 @@
+hostname r2
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r2-eth0
+ ip router isis 1 vrf r2-cust1
+ ipv6 router isis 1 vrf r2-cust1
+ isis circuit-type level-2-only
+!
+router isis 1 vrf r2-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
+ metric-style wide
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route.json b/tests/topotests/isis-topo1-vrf/r2/r2_route.json
new file mode 100644
index 0000000000..b3ac86d218
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route.json
@@ -0,0 +1,57 @@
+{
+ "10.0.11.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "ip": "10.0.21.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "ip": "10.0.21.1"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json
new file mode 100644
index 0000000000..c8d11b4922
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json
@@ -0,0 +1,40 @@
+{
+ "2001:db8:1:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json
new file mode 100755
index 0000000000..27423e1936
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json
@@ -0,0 +1,14 @@
+{
+ "2001:db8:1:2::/64": {
+ "dev": "r2-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r2-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json
new file mode 100755
index 0000000000..744b0780f3
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json
@@ -0,0 +1,13 @@
+{
+ "10.0.11.0/24": {
+ "dev": "r2-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.21.1"
+ },
+ "10.0.21.0/24": {
+ "dev": "r2-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json
new file mode 100644
index 0000000000..72022a8167
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json
@@ -0,0 +1,80 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r2"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r2"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r2"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r2(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r2"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ },
+ {
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r2(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r4",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/isis-topo1-vrf/r2/zebra.conf b/tests/topotests/isis-topo1-vrf/r2/zebra.conf
new file mode 100755
index 0000000000..a62af1749e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/zebra.conf
@@ -0,0 +1,9 @@
+hostname r2
+interface r2-eth0 vrf r2-cust1
+ ip address 10.0.21.2/24
+ ipv6 address 2001:db8:1:2::2/64
+!
+interface lo
+ ip address 10.254.0.2/32
+ ipv6 address 2001:db8:F::2/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r3/isisd.conf b/tests/topotests/isis-topo1-vrf/r3/isisd.conf
new file mode 100755
index 0000000000..ca01876690
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/isisd.conf
@@ -0,0 +1,22 @@
+hostname r3
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r3-eth0
+ ip router isis 1 vrf r3-cust1
+ ipv6 router isis 1 vrf r3-cust1
+ isis circuit-type level-2-only
+!
+interface r3-eth1
+ ip router isis 1 vrf r3-cust1
+ ipv6 router isis 1 vrf r3-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r3-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-1
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route.json b/tests/topotests/isis-topo1-vrf/r3/r3_route.json
new file mode 100644
index 0000000000..709d6b9aeb
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route.json
@@ -0,0 +1,112 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0",
+ "ip": "10.0.20.2"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json
new file mode 100644
index 0000000000..3a7c3861fa
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json
new file mode 100755
index 0000000000..bc527d2e1e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r3-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r3-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json
new file mode 100755
index 0000000000..515d376475
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r3-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.11.0/24": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.1"
+ },
+ "10.0.20.0/24": {
+ "dev": "r3-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.21.0/24": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.1"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json
new file mode 100644
index 0000000000..62b895766e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json
@@ -0,0 +1,132 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "30",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "30",
+ "parent": "r3-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/zebra.conf b/tests/topotests/isis-topo1-vrf/r3/zebra.conf
new file mode 100755
index 0000000000..ac0b810fce
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/zebra.conf
@@ -0,0 +1,13 @@
+hostname r3
+interface r3-eth0 vrf r3-cust1
+ ip address 10.0.20.1/24
+ ipv6 address 2001:db8:1:1::1/64
+!
+interface r3-eth1 vrf r3-cust1
+ ip address 10.0.10.2/24
+ ipv6 address 2001:db8:2:1::2/64
+!
+interface lo
+ ip address 10.254.0.3/32
+ ipv6 address 2001:db8:F::3/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r4/isisd.conf b/tests/topotests/isis-topo1-vrf/r4/isisd.conf
new file mode 100755
index 0000000000..74b1603d85
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/isisd.conf
@@ -0,0 +1,25 @@
+hostname r4
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+debug isis lsp-gen
+debug isis lsp-sched
+
+interface r4-eth0
+ ip router isis 1 vrf r4-cust1
+ ipv6 router isis 1 vrf r4-cust1
+ isis circuit-type level-2-only
+!
+interface r4-eth1
+ ip router isis 1 vrf r4-cust1
+ ipv6 router isis 1 vrf r4-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r4-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-1
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route.json b/tests/topotests/isis-topo1-vrf/r4/r4_route.json
new file mode 100644
index 0000000000..c464607a2b
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route.json
@@ -0,0 +1,105 @@
+{
+ "10.0.10.0/24": [
+ {
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0",
+ "ip": "10.0.21.2"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json
new file mode 100644
index 0000000000..8d3ea570f0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json
new file mode 100755
index 0000000000..b1cd5b9db9
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r4-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r4-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json
new file mode 100755
index 0000000000..3198b85789
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.1"
+ },
+ "10.0.11.0/24": {
+ "dev": "r4-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.20.0/24": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.1"
+ },
+ "10.0.21.0/24": {
+ "dev": "r4-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json
new file mode 100644
index 0000000000..0d69550cad
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json
@@ -0,0 +1,132 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "30",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "30",
+ "parent": "r4-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r2"
+ },
+ {
+ "interface": "r2",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ },
+ {
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r2"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/zebra.conf b/tests/topotests/isis-topo1-vrf/r4/zebra.conf
new file mode 100755
index 0000000000..9c8941f7a5
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/zebra.conf
@@ -0,0 +1,13 @@
+hostname r4
+interface r4-eth0 vrf r4-cust1
+ ip address 10.0.21.1/24
+ ipv6 address 2001:db8:1:2::1/64
+!
+interface r4-eth1 vrf r4-cust1
+ ip address 10.0.11.2/24
+ ipv6 address 2001:db8:2:2::2/64
+!
+interface lo
+ ip address 10.254.0.4/32
+ ipv6 address 2001:db8:F::4/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r5/isisd.conf b/tests/topotests/isis-topo1-vrf/r5/isisd.conf
new file mode 100755
index 0000000000..9e9b030455
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/isisd.conf
@@ -0,0 +1,21 @@
+hostname r5
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r5-eth0
+ ip router isis 1 vrf r5-cust1
+ ipv6 router isis 1 vrf r5-cust1
+ isis circuit-type level-1
+!
+interface r5-eth1
+ ip router isis 1 vrf r5-cust1
+ ipv6 router isis 1 vrf r5-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r5-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00
+ metric-style wide
+ is-type level-1
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+!
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route.json b/tests/topotests/isis-topo1-vrf/r5/r5_route.json
new file mode 100644
index 0000000000..58aee5ddcc
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route.json
@@ -0,0 +1,106 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0",
+ "ip": "10.0.10.2"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1",
+ "ip": "10.0.11.2"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0",
+ "ip": "10.0.10.2"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1",
+ "ip": "10.0.11.2"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json
new file mode 100644
index 0000000000..e32bbcc2c1
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json
new file mode 100755
index 0000000000..3db3c93ea6
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r5-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r5-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r5-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r5-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json
new file mode 100755
index 0000000000..6a38ba864a
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r5-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.11.0/24": {
+ "dev": "r5-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.20.0/24": {
+ "dev": "r5-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.2"
+ },
+ "10.0.21.0/24": {
+ "dev": "r5-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.2"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json
new file mode 100644
index 0000000000..b4ed6a069d
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json
@@ -0,0 +1,124 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r5"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r5"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r3",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r4",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [],
+ "ipv6": []
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/isis-topo1-vrf/r5/zebra.conf b/tests/topotests/isis-topo1-vrf/r5/zebra.conf
new file mode 100755
index 0000000000..c6bc6302fc
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/zebra.conf
@@ -0,0 +1,13 @@
+hostname r5
+interface r5-eth0 vrf r5-cust1
+ ip address 10.0.10.1/24
+ ipv6 address 2001:db8:2:1::1/64
+!
+interface r5-eth1 vrf r5-cust1
+ ip address 10.0.11.1/24
+ ipv6 address 2001:db8:2:2::1/64
+!
+interface lo
+ ip address 10.254.0.5/32
+ ipv6 address 2001:db8:F::5/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot
new file mode 100755
index 0000000000..01f9ba780f
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot
@@ -0,0 +1,100 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="isis topo1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1\n10.254.0.1\n2001:DB8:F::1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2\n10.254.0.2\n2001:DB8:F::2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3\n10.254.0.3\n2001:DB8:F::3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4\n10.254.0.4\n2001:DB8:F::4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r5 [
+ shape=doubleoctagon
+ label="r5\n10.254.0.5\n2001:DB8:F::5",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n10.0.20.0/24\n2001:DB8:1:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.21.0/24\n2001:DB8:1:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n10.0.10.0/24\n2001:DB8:2:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw4 [
+ shape=oval,
+ label="sw4\n10.0.11.0/24\n2001:DB8:2:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ subgraph cluster0 {
+ label="level 2";
+
+ r1 -- sw1 [label="eth0\n.2"];
+ r2 -- sw2 [label="eth0\n.2"];
+ }
+
+ subgraph cluster1 {
+ label="level 1/2";
+
+ r3 -- sw1 [label="eth0\n.1"];
+ r3 -- sw3 [label="eth1\n.2"];
+
+ r4 -- sw4 [label="eth1\n.2"];
+ r4 -- sw2 [label="eth0\n.1"];
+ }
+
+ subgraph cluster2 {
+ label="level 1";
+
+ r5 -- sw3 [label="eth0\n.1"];
+ r5 -- sw4 [label="eth1\n.1"];
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg
new file mode 100755
index 0000000000..4ad730f2a0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg
Binary files differ
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
new file mode 100755
index 0000000000..a0e34b71b0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -0,0 +1,455 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by Niral Networks, Inc. ("Niral Networks")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_isis_topo1_vrf.py: Test ISIS vrf topology.
+"""
+
+import collections
+import functools
+import json
+import os
+import re
+import sys
+import pytest
+import platform
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from mininet.topo import Topo
+
+
+class ISISTopo1(Topo):
+ "Simple two layer ISIS vrf topology"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Add ISIS routers:
+ # r1 r2
+ # | sw1 | sw2
+ # r3 r4
+ # | |
+ # sw3 sw4
+ # \ /
+ # r5
+ for routern in range(1, 6):
+ tgen.add_router("r{}".format(routern))
+
+ # r1 <- sw1 -> r3
+ sw = tgen.add_switch("sw1")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["r3"])
+
+ # r2 <- sw2 -> r4
+ sw = tgen.add_switch("sw2")
+ sw.add_link(tgen.gears["r2"])
+ sw.add_link(tgen.gears["r4"])
+
+ # r3 <- sw3 -> r5
+ sw = tgen.add_switch("sw3")
+ sw.add_link(tgen.gears["r3"])
+ sw.add_link(tgen.gears["r5"])
+
+ # r4 <- sw4 -> r5
+ sw = tgen.add_switch("sw4")
+ sw.add_link(tgen.gears["r4"])
+ sw.add_link(tgen.gears["r5"])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(ISISTopo1, mod.__name__)
+ tgen.start_topology()
+
+ logger.info("Testing with VRF Lite support")
+ krel = platform.release()
+
+ # May need to adjust handling of vrf traffic depending on kernel version
+ l3mdev_accept = 0
+ if (
+ topotest.version_cmp(krel, "4.15") >= 0
+ and topotest.version_cmp(krel, "4.18") <= 0
+ ):
+ l3mdev_accept = 1
+
+ if topotest.version_cmp(krel, "5.0") >= 0:
+ l3mdev_accept = 1
+
+ logger.info(
+ "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept)
+ )
+
+ cmds = [
+ "ip link add {0}-cust1 type vrf table 1001",
+ "ip link add loop1 type dummy",
+ "ip link set {0}-eth0 master {0}-cust1",
+ "ip link set {0}-eth1 master {0}-cust1",
+ ]
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().iteritems():
+ # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept")
+ logger.info(
+ "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output)
+ )
+
+ if l3mdev_accept:
+ output = tgen.net[rname].cmd(
+ "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
+ )
+
+ for rname, router in tgen.routers().iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS,
+ os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+ has_version_20 = False
+ for router in tgen.routers().values():
+ if router.has_version("<", "4"):
+ has_version_20 = True
+
+ if has_version_20:
+ logger.info("Skipping ISIS vrf tests for FRR 2.0")
+ tgen.set_error("ISIS has convergence problems with IPv6")
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ # move back rx-eth0 to default VRF
+ # delete rx-vrf
+ tgen.stop_topology()
+
+def test_isis_convergence():
+ "Wait for the protocol to converge before starting to test"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for ISIS protocol to converge")
+
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
+ expected = json.loads(open(filename).read())
+ def compare_isis_topology(router, expected):
+ "Helper function to test ISIS vrf topology convergence."
+ actual = show_isis_topology(router)
+
+ return topotest.json_cmp(actual, expected)
+
+ test_func = functools.partial(compare_isis_topology, router, expected)
+ (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120)
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+def test_isis_route_installation():
+ "Check whether all expected routes are present"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf routes")
+ # Check for routes in 'show ip route vrf {}-cust1 json'
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True)
+ # Older FRR versions don't list interfaces in some ISIS routes
+ if router.has_version("<", "3.1"):
+ for network, routes in expected.iteritems():
+ for route in routes:
+ if route["protocol"] != "isis":
+ continue
+
+ for nexthop in route["nexthops"]:
+ nexthop.pop("interfaceIndex", None)
+ nexthop.pop("interfaceName", None)
+
+ assertmsg = "Router '{}' routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+
+def test_isis_linux_route_installation():
+
+ dist = platform.dist()
+
+ if (dist[1] == "16.04"):
+ pytest.skip("Kernel not supported for vrf")
+
+ "Check whether all expected routes are present and installed in the OS"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf routes in OS")
+ # Check for routes in `ip route show vrf {}-cust1`
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = topotest.ip4_vrf_route(router)
+
+ # Older FRR versions install routes using different proto
+ if router.has_version("<", "3.1"):
+ for network, netoptions in expected.iteritems():
+ if "proto" in netoptions and netoptions["proto"] == "187":
+ netoptions["proto"] = "zebra"
+
+ assertmsg = "Router '{}' OS routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_isis_route6_installation():
+ "Check whether all expected routes are present"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf IPv6 routes")
+ # Check for routes in 'show ipv6 route vrf {}-cust1 json'
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True)
+
+ # Older FRR versions don't list interfaces in some ISIS routes
+ if router.has_version("<", "3.1"):
+ for network, routes in expected.iteritems():
+ for route in routes:
+ if route["protocol"] != "isis":
+ continue
+
+ for nexthop in route["nexthops"]:
+ nexthop.pop("interfaceIndex", None)
+ nexthop.pop("interfaceName", None)
+
+ assertmsg = "Router '{}' routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_isis_linux_route6_installation():
+
+ dist = platform.dist()
+
+ if (dist[1] == "16.04"):
+ pytest.skip("Kernel not supported for vrf")
+
+ "Check whether all expected routes are present and installed in the OS"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
+ # Check for routes in `ip -6 route show vrf {}-cust1`
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = topotest.ip6_vrf_route(router)
+
+ # Older FRR versions install routes using different proto
+ if router.has_version("<", "3.1"):
+ for network, netoptions in expected.iteritems():
+ if "proto" in netoptions and netoptions["proto"] == "187":
+ netoptions["proto"] = "zebra"
+
+ assertmsg = "Router '{}' OS routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+
+
+#
+# Auxiliary functions
+#
+
+
+def dict_merge(dct, merge_dct):
+ """
+ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
+ updating only top-level keys, dict_merge recurses down into dicts nested
+ to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
+ ``dct``.
+ :param dct: dict onto which the merge is executed
+ :param merge_dct: dct merged into dct
+ :return: None
+
+ Source:
+ https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
+ """
+ for k, v in merge_dct.iteritems():
+ if (
+ k in dct
+ and isinstance(dct[k], dict)
+ and isinstance(merge_dct[k], collections.Mapping)
+ ):
+ dict_merge(dct[k], merge_dct[k])
+ else:
+ dct[k] = merge_dct[k]
+
+
+def parse_topology(lines, level):
+ """
+ Parse the output of 'show isis topology level-X' into a Python dict.
+ """
+ areas = {}
+ area = None
+ ipv = None
+
+ for line in lines:
+ area_match = re.match(r"Area (.+):", line)
+ if area_match:
+ area = area_match.group(1)
+ if area not in areas:
+ areas[area] = {level: {"ipv4": [], "ipv6": []}}
+ ipv = None
+ continue
+ elif area is None:
+ continue
+
+ if re.match(r"IS\-IS paths to level-. routers that speak IPv6", line):
+ ipv = "ipv6"
+ continue
+ if re.match(r"IS\-IS paths to level-. routers that speak IP", line):
+ ipv = "ipv4"
+ continue
+
+ item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
+ if item_match is not None:
+ # Skip header
+ if (
+ item_match.group(1) == "Vertex"
+ and item_match.group(2) == "Type"
+ and item_match.group(3) == "Metric"
+ and item_match.group(4) == "Next-Hop"
+ and item_match.group(5) == "Interface"
+ and item_match.group(6) == "Parent"
+ ):
+ continue
+
+ areas[area][level][ipv].append(
+ {
+ "vertex": item_match.group(1),
+ "type": item_match.group(2),
+ "metric": item_match.group(3),
+ "next-hop": item_match.group(4),
+ "interface": item_match.group(5),
+ "parent": item_match.group(6),
+ }
+ )
+ continue
+
+ item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
+ if item_match is not None:
+ areas[area][level][ipv].append(
+ {
+ "vertex": item_match.group(1),
+ "type": item_match.group(2),
+ "metric": item_match.group(3),
+ "parent": item_match.group(4),
+ }
+ )
+ continue
+
+ item_match = re.match(r"([^ ]+)", line)
+ if item_match is not None:
+ areas[area][level][ipv].append({"vertex": item_match.group(1)})
+ continue
+
+ return areas
+
+
+def show_isis_topology(router):
+ """
+ Get the ISIS vrf topology in a dictionary format.
+
+ Sample:
+ {
+ 'area-name': {
+ 'level-1': [
+ {
+ 'vertex': 'r1'
+ }
+ ],
+ 'level-2': [
+ {
+ 'vertex': '10.0.0.1/24',
+ 'type': 'IP',
+ 'parent': '0',
+ 'metric': 'internal'
+ }
+ ]
+ },
+ 'area-name-2': {
+ 'level-2': [
+ {
+ "interface": "rX-ethY",
+ "metric": "Z",
+ "next-hop": "rA",
+ "parent": "rC(B)",
+ "type": "TE-IS",
+ "vertex": "rD"
+ }
+ ]
+ }
+ }
+ """
+ l1out = topotest.normalize_text(
+ router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name))
+ ).splitlines()
+ l2out = topotest.normalize_text(
+ router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name))
+ ).splitlines()
+
+ l1 = parse_topology(l1out, "level-1")
+ l2 = parse_topology(l2out, "level-2")
+
+ dict_merge(l1, l2)
+ return l1
+
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 8a40490be3..e34d1cf0be 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -720,6 +720,49 @@ def ip4_route(node):
return result
+def ip4_vrf_route(node):
+ """
+ Gets a structured return of the command 'ip route show vrf {0}-cust1'.
+ It can be used in conjuction with json_cmp() to provide accurate assert explanations.
+
+ Return example:
+ {
+ '10.0.1.0/24': {
+ 'dev': 'eth0',
+ 'via': '172.16.0.1',
+ 'proto': '188',
+ },
+ '10.0.2.0/24': {
+ 'dev': 'eth1',
+ 'proto': 'kernel',
+ }
+ }
+ """
+ output = normalize_text(
+ node.run("ip route show vrf {0}-cust1".format(node.name))).splitlines()
+
+ result = {}
+ for line in output:
+ columns = line.split(" ")
+ route = result[columns[0]] = {}
+ prev = None
+ for column in columns:
+ if prev == "dev":
+ route["dev"] = column
+ if prev == "via":
+ route["via"] = column
+ if prev == "proto":
+ # translate protocol names back to numbers
+ route["proto"] = proto_name_to_number(column)
+ if prev == "metric":
+ route["metric"] = column
+ if prev == "scope":
+ route["scope"] = column
+ prev = column
+
+ return result
+
+
def ip6_route(node):
"""
Gets a structured return of the command 'ip -6 route'. It can be used in
@@ -760,6 +803,47 @@ def ip6_route(node):
return result
+def ip6_vrf_route(node):
+ """
+ Gets a structured return of the command 'ip -6 route show vrf {0}-cust1'.
+ It can be used in conjuction with json_cmp() to provide accurate assert explanations.
+
+ Return example:
+ {
+ '2001:db8:1::/64': {
+ 'dev': 'eth0',
+ 'proto': '188',
+ },
+ '2001:db8:2::/64': {
+ 'dev': 'eth1',
+ 'proto': 'kernel',
+ }
+ }
+ """
+ output = normalize_text(
+ node.run("ip -6 route show vrf {0}-cust1".format(node.name))).splitlines()
+ result = {}
+ for line in output:
+ columns = line.split(" ")
+ route = result[columns[0]] = {}
+ prev = None
+ for column in columns:
+ if prev == "dev":
+ route["dev"] = column
+ if prev == "via":
+ route["via"] = column
+ if prev == "proto":
+ # translate protocol names back to numbers
+ route["proto"] = proto_name_to_number(column)
+ if prev == "metric":
+ route["metric"] = column
+ if prev == "pref":
+ route["pref"] = column
+ prev = column
+
+ return result
+
+
def ip_rules(node):
"""
Gets a structured return of the command 'ip rule'. It can be used in
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index d3fc8bc338..4edbb7a889 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1892,10 +1892,11 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
}
#endif
-DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, "router isis WORD",
+DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
+ "router isis WORD [vrf NAME]",
ROUTER_STR
"ISO IS-IS\n"
- "ISO Routing area tag\n")
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
vty->node = ISIS_NODE;
return CMD_SUCCESS;
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 1bb693a1ef..00296516ef 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -340,6 +340,13 @@ module frr-isisd {
"Area-tag associated to this circuit.";
}
+ leaf vrf {
+ type string;
+ default "default";
+ description
+ "VRF NAME.";
+ }
+
leaf ipv4-routing {
type boolean;
default "false";
@@ -793,7 +800,7 @@ module frr-isisd {
description
"Configuration of the IS-IS routing daemon.";
list instance {
- key "area-tag";
+ key "area-tag vrf";
description
"IS-IS routing instance.";
leaf area-tag {
@@ -802,6 +809,12 @@ module frr-isisd {
"Area-tag associated to this routing instance.";
}
+ leaf vrf {
+ type string;
+ description
+ "VRF NAME.";
+ }
+
leaf is-type {
type level;
default "level-1-2";