diff options
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 Binary files differnew file mode 100755 index 0000000000..4ad730f2a0 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg 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"; |
