diff options
99 files changed, 10259 insertions, 927 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index e0b00f9782..60753c1227 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -13,13 +13,13 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod lddtree libacl libatomic libattr - libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc + libblkid libburn libbz2 libc-dev libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs libltdl libressl libssh2 libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python2 python2-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs - py-sphinx rtrlib rtrlib-dev" + py-pip py-sphinx rtrlib rtrlib-dev" checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 5663ce54cb..f8ee66e2c8 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -516,7 +516,7 @@ DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]", } DEFPY(bfd_show_peer, bfd_show_peer_cmd, - "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]", + "show bfd [vrf <NAME$vrf_name>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -528,7 +528,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd, /* Look up the BFD peer. */ bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str, - ifname, vrfname); + ifname, vrf_name); if (bs == NULL) return CMD_WARNING_CONFIG_FAILED; @@ -543,7 +543,7 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd, } DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, - "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]", + "show bfd [vrf <NAME$vrf_name>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]", SHOW_STR "Bidirection Forwarding Detection\n" VRF_CMD_HELP_STR @@ -564,7 +564,7 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, /* Look up the BFD peer. */ bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str, - ifname, vrfname); + ifname, vrf_name); if (bs == NULL) return CMD_WARNING_CONFIG_FAILED; diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index f5652b07c5..6caeb7ca1f 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -2114,15 +2114,12 @@ static void *bgp_aggr_aspath_hash_alloc(void *p) static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) { - struct aspath *asmerge = NULL; struct aspath *hb_aspath = hb->data; struct aspath **aggr_aspath = arg; - if (*aggr_aspath) { - asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); - aspath_free(*aggr_aspath); - *aggr_aspath = asmerge; - } else + if (*aggr_aspath) + *aggr_aspath = aspath_aggregate(*aggr_aspath, hb_aspath); + else *aggr_aspath = aspath_dup(hb_aspath); } @@ -2136,6 +2133,15 @@ void bgp_aggr_aspath_remove(void *arg) void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, struct aspath *aspath) { + bgp_compute_aggregate_aspath_hash(aggregate, aspath); + + bgp_compute_aggregate_aspath_val(aggregate); + +} + +void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ struct aspath *aggr_aspath = NULL; if ((aggregate == NULL) || (aspath == NULL)) @@ -2154,17 +2160,29 @@ void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, */ aggr_aspath = hash_get(aggregate->aspath_hash, aspath, bgp_aggr_aspath_hash_alloc); + } - /* Compute aggregate's as-path. - */ + /* Increment reference counter. + */ + aggr_aspath->refcnt++; +} + +void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate) +{ + if (aggregate == NULL) + return; + /* Re-compute aggregate's as-path. + */ + if (aggregate->aspath) { + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + } + if (aggregate->aspath_hash + && aggregate->aspath_hash->count) { hash_iterate(aggregate->aspath_hash, bgp_aggr_aspath_prepare, &aggregate->aspath); } - - /* Increment refernce counter. - */ - aggr_aspath->refcnt++; } void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, @@ -2173,10 +2191,9 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, struct aspath *aggr_aspath = NULL; struct aspath *ret_aspath = NULL; - if ((aggregate == NULL) || (aspath == NULL)) - return; - - if (aggregate->aspath_hash == NULL) + if ((!aggregate) + || (!aggregate->aspath_hash) + || (!aspath)) return; /* Look-up the aspath in the hash. @@ -2189,17 +2206,41 @@ void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, ret_aspath = hash_release(aggregate->aspath_hash, aggr_aspath); aspath_free(ret_aspath); + ret_aspath = NULL; /* Remove aggregate's old as-path. */ aspath_free(aggregate->aspath); aggregate->aspath = NULL; - /* Compute aggregate's as-path. - */ - hash_iterate(aggregate->aspath_hash, - bgp_aggr_aspath_prepare, - &aggregate->aspath); + bgp_compute_aggregate_aspath_val(aggregate); } } } + +void bgp_remove_aspath_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + struct aspath *ret_aspath = NULL; + + if ((!aggregate) + || (!aggregate->aspath_hash) + || (!aspath)) + return; + + /* Look-up the aspath in the hash. + */ + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath) { + aggr_aspath->refcnt--; + + if (aggr_aspath->refcnt == 0) { + ret_aspath = hash_release(aggregate->aspath_hash, + aggr_aspath); + aspath_free(ret_aspath); + ret_aspath = NULL; + } + } +} + diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index f84b3740c9..10f6ee2821 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -134,8 +134,16 @@ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *); extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, struct aspath *aspath); + +extern void bgp_compute_aggregate_aspath_hash(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_compute_aggregate_aspath_val(struct bgp_aggregate *aggregate); extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, struct aspath *aspath); +extern void bgp_remove_aspath_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct aspath *aspath); + extern void bgp_aggr_aspath_remove(void *arg); #endif /* _QUAGGA_BGP_ASPATH_H */ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 248bbca8cf..a7cd3fee88 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1305,14 +1305,20 @@ bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr) if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) || IPV4_CLASS_DE(nexthop_h)) && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { + uint8_t data[7]; /* type(2) + length(1) + nhop(4) */ char buf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, INET_ADDRSTRLEN); flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf); - bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); + data[0] = BGP_ATTR_FLAG_TRANS; + data[1] = BGP_ATTR_NEXT_HOP; + data[2] = BGP_ATTR_NHLEN_IPV4; + memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4); + bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, + data, 7); return BGP_ATTR_PARSE_ERROR; } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 22d61f702d..432c922ea5 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -910,15 +910,13 @@ static void *bgp_aggr_communty_hash_alloc(void *p) static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) { - struct community *commerge = NULL; struct community *hb_community = hb->data; struct community **aggr_community = arg; - if (*aggr_community) { - commerge = community_merge(*aggr_community, hb_community); - *aggr_community = community_uniq_sort(commerge); - community_free(&commerge); - } else + if (*aggr_community) + *aggr_community = community_merge(*aggr_community, + hb_community); + else *aggr_community = community_dup(hb_community); } @@ -932,6 +930,14 @@ void bgp_aggr_community_remove(void *arg) void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, struct community *community) { + bgp_compute_aggregate_community_hash(aggregate, community); + bgp_compute_aggregate_community_val(aggregate); +} + + +void bgp_compute_aggregate_community_hash(struct bgp_aggregate *aggregate, + struct community *community) +{ struct community *aggr_community = NULL; if ((aggregate == NULL) || (community == NULL)) @@ -951,32 +957,47 @@ void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, */ aggr_community = hash_get(aggregate->community_hash, community, bgp_aggr_communty_hash_alloc); + } - /* Re-compute aggregate's community. - */ - if (aggregate->community) - community_free(&aggregate->community); + /* Increment reference counter. + */ + aggr_community->refcnt++; +} +void bgp_compute_aggregate_community_val(struct bgp_aggregate *aggregate) +{ + struct community *commerge = NULL; + + if (aggregate == NULL) + return; + + /* Re-compute aggregate's community. + */ + if (aggregate->community) + community_free(&aggregate->community); + if (aggregate->community_hash && + aggregate->community_hash->count) { hash_iterate(aggregate->community_hash, bgp_aggr_community_prepare, &aggregate->community); + commerge = aggregate->community; + aggregate->community = community_uniq_sort(commerge); + if (commerge) + community_free(&commerge); } - - /* Increment refernce counter. - */ - aggr_community->refcnt++; } + + void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, struct community *community) { struct community *aggr_community = NULL; struct community *ret_comm = NULL; - if ((aggregate == NULL) || (community == NULL)) - return; - - if (aggregate->community_hash == NULL) + if ((!aggregate) + || (!aggregate->community_hash) + || (!community)) return; /* Look-up the community in the hash. @@ -990,13 +1011,33 @@ void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, aggr_community); community_free(&ret_comm); - community_free(&aggregate->community); + bgp_compute_aggregate_community_val(aggregate); + } + } +} + +void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct community *community) +{ + + struct community *aggr_community = NULL; + struct community *ret_comm = NULL; - /* Compute aggregate's community. - */ - hash_iterate(aggregate->community_hash, - bgp_aggr_community_prepare, - &aggregate->community); + if ((!aggregate) + || (!aggregate->community_hash) + || (!community)) + return; + + /* Look-up the community in the hash. + */ + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community) { + aggr_community->refcnt--; + + if (aggr_community->refcnt == 0) { + ret_comm = hash_release(aggregate->community_hash, + aggr_community); + community_free(&ret_comm); } } } diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index f761a8f5e0..74a3a6b507 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -92,8 +92,16 @@ extern struct hash *community_hash(void); extern uint32_t community_val_get(struct community *com, int i); extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, struct community *community); + +extern void bgp_compute_aggregate_community_val( + struct bgp_aggregate *aggregate); +extern void bgp_compute_aggregate_community_hash( + struct bgp_aggregate *aggregate, + struct community *community); extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, struct community *community); +extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct community *community); extern void bgp_aggr_community_remove(void *arg); #endif /* _QUAGGA_BGP_COMMUNITY_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 850b85aa6a..11f5a326df 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1042,15 +1042,13 @@ static void *bgp_aggr_ecommunty_hash_alloc(void *p) static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) { - struct ecommunity *ecommerge = NULL; struct ecommunity *hb_ecommunity = hb->data; struct ecommunity **aggr_ecommunity = arg; - if (*aggr_ecommunity) { - ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); - *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else + if (*aggr_ecommunity) + *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity, + hb_ecommunity); + else *aggr_ecommunity = ecommunity_dup(hb_ecommunity); } @@ -1064,6 +1062,14 @@ void bgp_aggr_ecommunity_remove(void *arg) void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, struct ecommunity *ecommunity) { + bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity); + bgp_compute_aggregate_ecommunity_val(aggregate); +} + + +void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ struct ecommunity *aggr_ecommunity = NULL; if ((aggregate == NULL) || (ecommunity == NULL)) @@ -1083,20 +1089,34 @@ void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, aggr_ecommunity = hash_get(aggregate->ecommunity_hash, ecommunity, bgp_aggr_ecommunty_hash_alloc); + } - /* Re-compute aggregate's ecommunity. - */ - if (aggregate->ecommunity) - ecommunity_free(&aggregate->ecommunity); + /* Increment reference counter. + */ + aggr_ecommunity->refcnt++; +} +void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate) +{ + struct ecommunity *ecommerge = NULL; + + if (aggregate == NULL) + return; + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + if (aggregate->ecommunity_hash + && aggregate->ecommunity_hash->count) { hash_iterate(aggregate->ecommunity_hash, bgp_aggr_ecommunity_prepare, &aggregate->ecommunity); + ecommerge = aggregate->ecommunity; + aggregate->ecommunity = ecommunity_uniq_sort(ecommerge); + if (ecommerge) + ecommunity_free(&ecommerge); } - - /* Increment refernce counter. - */ - aggr_ecommunity->refcnt++; } void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -1105,10 +1125,9 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, struct ecommunity *aggr_ecommunity = NULL; struct ecommunity *ret_ecomm = NULL; - if ((aggregate == NULL) || (ecommunity == NULL)) - return; - - if (aggregate->ecommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) return; /* Look-up the ecommunity in the hash. @@ -1121,14 +1140,33 @@ void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, ret_ecomm = hash_release(aggregate->ecommunity_hash, aggr_ecommunity); ecommunity_free(&ret_ecomm); + bgp_compute_aggregate_ecommunity_val(aggregate); + } + } +} + +void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; - ecommunity_free(&aggregate->ecommunity); + if ((!aggregate) + || (!aggregate->ecommunity_hash) + || (!ecommunity)) + return; - /* Compute aggregate's ecommunity. - */ - hash_iterate(aggregate->ecommunity_hash, - bgp_aggr_ecommunity_prepare, - &aggregate->ecommunity); + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); } } } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 79be4ee422..249e5bf7de 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -190,9 +190,18 @@ extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, extern void bgp_compute_aggregate_ecommunity( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); + +extern void bgp_compute_aggregate_ecommunity_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_compute_aggregate_ecommunity_val( + struct bgp_aggregate *aggregate); extern void bgp_remove_ecommunity_from_aggregate( struct bgp_aggregate *aggregate, struct ecommunity *ecommunity); +extern void bgp_remove_ecomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); extern void bgp_aggr_ecommunity_remove(void *arg); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index aeb290719a..3243ce96b5 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -555,15 +555,13 @@ static void *bgp_aggr_lcommunty_hash_alloc(void *p) static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) { - struct lcommunity *lcommerge = NULL; struct lcommunity *hb_lcommunity = hb->data; struct lcommunity **aggr_lcommunity = arg; - if (*aggr_lcommunity) { - lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); - *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else + if (*aggr_lcommunity) + *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity, + hb_lcommunity); + else *aggr_lcommunity = lcommunity_dup(hb_lcommunity); } @@ -577,6 +575,15 @@ void bgp_aggr_lcommunity_remove(void *arg) void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, struct lcommunity *lcommunity) { + + bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); +} + +void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; if ((aggregate == NULL) || (lcommunity == NULL)) @@ -596,20 +603,34 @@ void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, aggr_lcommunity = hash_get(aggregate->lcommunity_hash, lcommunity, bgp_aggr_lcommunty_hash_alloc); + } - /* Re-compute aggregate's lcommunity. - */ - if (aggregate->lcommunity) - lcommunity_free(&aggregate->lcommunity); + /* Increment reference counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate) +{ + struct lcommunity *lcommerge = NULL; + + if (aggregate == NULL) + return; + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + if (aggregate->lcommunity_hash && + aggregate->lcommunity_hash->count) { hash_iterate(aggregate->lcommunity_hash, bgp_aggr_lcommunity_prepare, &aggregate->lcommunity); + lcommerge = aggregate->lcommunity; + aggregate->lcommunity = lcommunity_uniq_sort(lcommerge); + if (lcommerge) + lcommunity_free(&lcommerge); } - - /* Increment refernce counter. - */ - aggr_lcommunity->refcnt++; } void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, @@ -618,10 +639,9 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, struct lcommunity *aggr_lcommunity = NULL; struct lcommunity *ret_lcomm = NULL; - if ((aggregate == NULL) || (lcommunity == NULL)) - return; - - if (aggregate->lcommunity_hash == NULL) + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) return; /* Look-up the lcommunity in the hash. @@ -635,13 +655,33 @@ void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, aggr_lcommunity); lcommunity_free(&ret_lcomm); - lcommunity_free(&aggregate->lcommunity); + bgp_compute_aggregate_lcommunity_val(aggregate); + + } + } +} + +void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; - /* Compute aggregate's lcommunity. - */ - hash_iterate(aggregate->lcommunity_hash, - bgp_aggr_lcommunity_prepare, - &aggregate->lcommunity); + if ((!aggregate) + || (!aggregate->lcommunity_hash) + || (!lcommunity)) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); } } } diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index a512395492..7d63f4d26a 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -75,9 +75,19 @@ extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); extern void bgp_compute_aggregate_lcommunity( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); + +extern void bgp_compute_aggregate_lcommunity_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_compute_aggregate_lcommunity_val( + struct bgp_aggregate *aggregate); + extern void bgp_remove_lcommunity_from_aggregate( struct bgp_aggregate *aggregate, struct lcommunity *lcommunity); +extern void bgp_remove_lcomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); extern void bgp_aggr_lcommunity_remove(void *arg); #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 05974bb2ba..d083586c93 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5927,33 +5927,41 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, */ /* Compute aggregate route's as-path. */ - bgp_compute_aggregate_aspath(aggregate, - pi->attr->aspath); + bgp_compute_aggregate_aspath_hash(aggregate, + pi->attr->aspath); /* Compute aggregate route's community. */ if (pi->attr->community) - bgp_compute_aggregate_community( + bgp_compute_aggregate_community_hash( aggregate, pi->attr->community); /* Compute aggregate route's extended community. */ if (pi->attr->ecommunity) - bgp_compute_aggregate_ecommunity( + bgp_compute_aggregate_ecommunity_hash( aggregate, pi->attr->ecommunity); /* Compute aggregate route's large community. */ if (pi->attr->lcommunity) - bgp_compute_aggregate_lcommunity( + bgp_compute_aggregate_lcommunity_hash( aggregate, pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) { + bgp_compute_aggregate_aspath_val(aggregate); + bgp_compute_aggregate_community_val(aggregate); + bgp_compute_aggregate_ecommunity_val(aggregate); + bgp_compute_aggregate_lcommunity_val(aggregate); + } + + bgp_unlock_node(top); @@ -6034,28 +6042,28 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (aggregate->as_set) { /* Remove as-path from aggregate. */ - bgp_remove_aspath_from_aggregate( + bgp_remove_aspath_from_aggregate_hash( aggregate, pi->attr->aspath); if (pi->attr->community) /* Remove community from aggregate. */ - bgp_remove_community_from_aggregate( + bgp_remove_comm_from_aggregate_hash( aggregate, pi->attr->community); if (pi->attr->ecommunity) /* Remove ecommunity from aggregate. */ - bgp_remove_ecommunity_from_aggregate( + bgp_remove_ecomm_from_aggregate_hash( aggregate, pi->attr->ecommunity); if (pi->attr->lcommunity) /* Remove lcommunity from aggregate. */ - bgp_remove_lcommunity_from_aggregate( + bgp_remove_lcomm_from_aggregate_hash( aggregate, pi->attr->lcommunity); } @@ -6066,6 +6074,17 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, if (match) bgp_process(bgp, rn, afi, safi); } + if (aggregate->as_set) { + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + if (aggregate->community) + community_free(&aggregate->community); + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + } + bgp_unlock_node(top); } @@ -6543,6 +6562,7 @@ DEFUN (aggregate_address_mask, argv_find(argv, argc, "A.B.C.D", &idx); char *prefix = argv[idx]->arg; char *mask = argv[idx + 1]->arg; + bool rmap_found; char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6551,8 +6571,8 @@ DEFUN (aggregate_address_mask, ? AGGREGATE_SUMMARY_ONLY : 0; - argv_find(argv, argc, "WORD", &idx); - if (idx) + rmap_found = argv_find(argv, argc, "WORD", &idx); + if (rmap_found) rmap = argv[idx]->arg; char prefix_str[BUFSIZ]; @@ -6569,14 +6589,16 @@ DEFUN (aggregate_address_mask, DEFUN (no_aggregate_address, no_aggregate_address_cmd, - "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D/M", &idx); @@ -6586,7 +6608,7 @@ DEFUN (no_aggregate_address, DEFUN (no_aggregate_address_mask, no_aggregate_address_mask_cmd, - "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" @@ -6594,7 +6616,9 @@ DEFUN (no_aggregate_address_mask, "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D", &idx); @@ -6628,6 +6652,7 @@ DEFUN (ipv6_aggregate_address, argv_find(argv, argc, "X:X::X:X/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; + bool rmap_found; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6636,8 +6661,8 @@ DEFUN (ipv6_aggregate_address, ? AGGREGATE_SUMMARY_ONLY : 0; - argv_find(argv, argc, "WORD", &idx); - if (idx) + rmap_found = argv_find(argv, argc, "WORD", &idx); + if (rmap_found) rmap = argv[idx]->arg; return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap, @@ -6646,14 +6671,16 @@ DEFUN (ipv6_aggregate_address, DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, - "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", + "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index de7b05bdd9..4b6af935e0 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -570,8 +570,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; if (filter->map[RMAP_OUT].name) - vty_out(vty, " Outgoing route map: %s%s\n", - filter->map[RMAP_OUT].map ? "X" : "", + vty_out(vty, " Outgoing route map: %s\n", filter->map[RMAP_OUT].name); vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv); if (updgrp->conf->change_local_as) @@ -613,6 +612,9 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) subgrp->peer_refreshes_combined); vty_out(vty, " Merge checks triggered: %u\n", subgrp->merge_checks_triggered); + vty_out(vty, " Coalesce Time: %u%s\n", + (UPDGRP_INST(subgrp->update_group))->coalesce_time, + subgrp->t_coalesce ? "(Running)" : ""); vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version); vty_out(vty, " Packet queue length: %d\n", bpacket_queue_length(SUBGRP_PKTQ(subgrp))); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 21f1dff60d..5c1483a768 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -324,8 +324,9 @@ static int subgroup_coalesce_timer(struct thread *thread) subgrp = THREAD_ARG(thread); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) zlog_debug("u%" PRIu64 ":s%" PRIu64 - " announcing routes upon coalesce timer expiry", - (SUBGRP_UPDGRP(subgrp))->id, subgrp->id); + " announcing routes upon coalesce timer expiry(%u ms)", + (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, + subgrp->v_coalesce), subgrp->t_coalesce = NULL; subgrp->v_coalesce = 0; subgroup_announce_route(subgrp); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 688abae0e4..9329c8d892 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -391,6 +391,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, struct peer *peer; char buf[BUFSIZ]; char buf2[BUFSIZ]; + struct bgp_filter *filter; s = stream_dup(pkt->buffer); peer = PAF_PEER(paf); @@ -401,6 +402,8 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, afi_t nhafi; int route_map_sets_nh; nhlen = stream_getc_from(s, vec->offset); + filter = &peer->filter[paf->afi][paf->safi]; + if (peer_cap_enhe(peer, paf->afi, paf->safi)) nhafi = AFI_IP6; else @@ -439,25 +442,25 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, mod_v4nh = &v4nh; /* - * If route-map has set the nexthop, that is always - * used; if it is - * specified as peer-address, the peering address is - * picked up. - * Otherwise, if NH is unavailable from attribute, the - * peering addr - * is picked up; the "NH unavailable" case also covers - * next-hop-self - * and some other scenarios -- see - * subgroup_announce_check(). In - * all other cases, use the nexthop carried in the - * attribute unless - * it is EBGP non-multiaccess and there is no - * next-hop-unchanged setting. + * If route-map has set the nexthop, that is normally + * used; if it is specified as peer-address, the peering + * address is picked up. Otherwise, if NH is unavailable + * from attribute, the peering addr is picked up; the + * "NH unavailable" case also covers next-hop-self and + * some other scenarios - see subgroup_announce_check(). + * In all other cases, use the nexthop carried in the + * attribute unless it is EBGP non-multiaccess and there + * is no next-hop-unchanged setting or the peer is EBGP + * and the route-map that changed the next-hop value + * was applied inbound rather than outbound. Updates to + * an EBGP peer should only modify the next-hop if it + * was set in an outbound route-map to that peer. * Note: It is assumed route-map cannot set the nexthop - * to an - * invalid value. + * to an invalid value. */ - if (route_map_sets_nh) { + if (route_map_sets_nh + && ((peer->sort != BGP_PEER_EBGP) + || ROUTE_MAP_OUT(filter))) { if (CHECK_FLAG( vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) { @@ -543,7 +546,15 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, stream_get_from(&v6nhglobal, s, offset_nhglobal, IPV6_MAX_BYTELEN); - if (route_map_sets_nh) { + + /* + * Updates to an EBGP peer should only modify the + * next-hop if it was set in an outbound route-map + * to that peer. + */ + if (route_map_sets_nh + && ((peer->sort != BGP_PEER_EBGP) + || ROUTE_MAP_OUT(filter))) { if (CHECK_FLAG( vec->flags, BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9d45d96987..320f1ec96c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1202,7 +1202,7 @@ struct peer { uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE]; /* The kind of route-map Flags.*/ - uint8_t rmap_type; + 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 */ diff --git a/configure.ac b/configure.ac index 6c1b35b5f2..88f1c4f627 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.60]) -AC_INIT([frr], [7.2-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -1452,6 +1452,12 @@ if test "x$enable_pcreposix" = "xyes"; then fi AC_SUBST([HAVE_LIBPCREPOSIX]) +dnl ########################################################################## +dnl test "${enable_clippy_only}" != "yes" +fi +dnl END OF LARGE if block +dnl ########################################################################## + dnl ------------------ dnl check C-Ares library dnl ------------------ @@ -1462,12 +1468,6 @@ PKG_CHECK_MODULES([CARES], [libcares], [ ]) AM_CONDITIONAL([CARES], [$c_ares_found]) -dnl ########################################################################## -dnl test "${enable_clippy_only}" != "yes" -fi -dnl END OF LARGE if block -dnl ########################################################################## - dnl ---------------------------------------------------------------------------- dnl figure out if domainname is available in the utsname struct (GNU extension). @@ -1535,9 +1535,11 @@ case "$host_os" in no) ;; yes) + if test "${enable_clippy_only}" != "yes"; then if test "$c_ares_found" != "true" ; then AC_MSG_ERROR([nhrpd requires libcares. Please install c-ares and its -dev headers.]) fi + fi NHRPD="nhrpd" ;; *) @@ -2041,9 +2043,11 @@ if test "${enable_capabilities}" != "no"; then case "$host_os" in linux*) + if test "${enable_clippy_only}" != "yes"; then if test "$frr_ac_lcaps" != "yes"; then AC_MSG_ERROR([libcap and/or its headers were not found. Running FRR without libcap support built in causes a huge performance penalty.]) fi + fi ;; esac else diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 32ca5707d2..525a31d486 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -79,8 +79,8 @@ BFDd Commands `vrf` selects which domain we want to use. -.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}] -.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}] +.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] +.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] Stops and removes the selected peer. @@ -89,8 +89,8 @@ BFDd Commands Show all configured BFD peers information and current status. -.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] -.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] +.. index:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] +.. clicmd:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] Show status for a specific BFD peer. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 7b3cdf2c4b..8edd19026d 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2396,6 +2396,23 @@ Displaying Routes by AS Path Print a summary of neighbor connections for the specified AFI/SAFI combination. +Displaying Update Group Information +----------------------------------- + +..index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue] +..clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue] + + Display Information about each individual update-group being used. + If SUBGROUP-ID is specified only display about that particular group. If + advertise-queue is specified the list of routes that need to be sent + to the peers in the update-group is displayed, advertised-routes means + the list of routes we have sent to the peers in the update-group and + packet-queue specifies the list of packets in the queue to be sent. + +..index:: show bgp update-groups statistics +..clicmd:: show bgp update-groups statistics + + Display Information about update-group events in FRR. .. _bgp-route-reflector: diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index b7283d83de..5d2cfbc337 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -663,19 +663,30 @@ kernel. .. clicmd:: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can - be **any** or one of + be: - - system, - - kernel, + - any, + - babel, + - bgp, - connected, - - static, - - rip, - - ripng, + - eigrp, + - isis, + - kernel, + - nhrp, + - openfabric, - ospf, - ospf6, - - isis, - - bgp, - - hsls. + - rip, + - sharp, + - static, + - ripng, + - table, + - vnc. + + If you choose any as the option that will cause all protocols that are sending + routes to zebra. You can specify a :dfn:`ip protocol PROTOCOL route-map ROUTEMAP` + on a per vrf basis, by entering this command under vrf mode for the vrf you + want to apply the route-map against. .. index:: set src ADDRESS .. clicmd:: set src ADDRESS diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 815983a394..88c8f88f81 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -9,7 +9,8 @@ RUN source /src/alpine/APKBUILD.in \ --no-cache \ --update-cache \ $makedepends \ - gzip + gzip \ + && pip install pytest COPY . /src ARG PKGVER @@ -29,6 +30,8 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/reposit abuild \ alpine-conf \ alpine-sdk \ + py-pip \ + && pip install pytest \ && setup-apkcache /var/cache/apk \ && mkdir -p /pkgs/apk \ && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index c7ffbf9f0e..3e09ec41bb 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -55,12 +55,15 @@ static void eigrp_network_run_interface(struct eigrp *, struct prefix *, int eigrp_sock_init(struct vrf *vrf) { - int eigrp_sock; + int eigrp_sock = -1; int ret; #ifdef IP_HDRINCL int hincl = 1; #endif + if (!vrf) + return eigrp_sock; + frr_with_privs(&eigrpd_privs) { eigrp_sock = vrf_socket( AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id, diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index bc6688012c..232df14e12 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_FIB_RULES_H #define __LINUX_FIB_RULES_H @@ -22,13 +23,23 @@ struct fib_rule_hdr { __u8 tos; __u8 table; - __u8 res1; /* reserved */ + __u8 res1; /* reserved */ __u8 res2; /* reserved */ __u8 action; __u32 flags; }; +struct fib_rule_uid_range { + __u32 start; + __u32 end; +}; + +struct fib_rule_port_range { + __u16 start; + __u16 end; +}; + enum { FRA_UNSPEC, FRA_DST, /* destination address */ @@ -43,7 +54,7 @@ enum { FRA_UNUSED5, FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ - FRA_UNUSED6, + FRA_TUN_ID, FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, /* Extended table id */ @@ -51,6 +62,11 @@ enum { FRA_OIFNAME, FRA_PAD, FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ + FRA_UID_RANGE, /* UID range */ + FRA_PROTOCOL, /* Originator of the rule */ + FRA_IP_PROTO, /* ip proto */ + FRA_SPORT_RANGE, /* sport */ + FRA_DPORT_RANGE, /* dport */ __FRA_MAX }; diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index a924606f36..dfcf3ce009 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -34,6 +34,7 @@ enum { IFA_MULTICAST, IFA_FLAGS, IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + IFA_TARGET_NETNSID, __IFA_MAX, }; @@ -63,7 +64,9 @@ struct ifa_cacheinfo { }; /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif #endif diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 156f4434ca..fb79481cb2 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Linux ethernet bridge * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_IF_BRIDGE_H -#define _LINUX_IF_BRIDGE_H +#ifndef _UAPI_LINUX_IF_BRIDGE_H +#define _UAPI_LINUX_IF_BRIDGE_H #include <linux/types.h> #include <linux/if_ether.h> @@ -96,7 +97,7 @@ struct __fdb_entry { __u32 ageing_timer_value; __u8 port_hi; __u8 pad0; - __u16 unused; + __u16 vlan; }; /* Bridge Flags */ @@ -236,6 +237,7 @@ struct br_mdb_entry { #define MDB_PERMANENT 1 __u8 state; #define MDB_FLAGS_OFFLOAD (1 << 0) +#define MDB_FLAGS_FAST_LEAVE (1 << 1) __u8 flags; __u16 vid; struct { @@ -291,4 +293,4 @@ struct br_mcast_stats { __u64 mcast_bytes[BR_MCAST_DIR_SIZE]; __u64 mcast_packets[BR_MCAST_DIR_SIZE]; }; -#endif /* _LINUX_IF_BRIDGE_H */ +#endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 1f97d0560b..22a45914a2 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_IF_LINK_H -#define _LINUX_IF_LINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_IF_LINK_H +#define _UAPI_LINUX_IF_LINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -158,6 +159,14 @@ enum { IFLA_PAD, IFLA_XDP, IFLA_EVENT, + IFLA_NEW_NETNSID, + IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, + IFLA_NEW_IFINDEX, + IFLA_MIN_MTU, + IFLA_MAX_MTU, __IFLA_MAX }; @@ -165,8 +174,10 @@ enum { #define IFLA_MAX (__IFLA_MAX - 1) /* backwards compatibility for userspace */ +#ifndef __KERNEL__ #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif enum { IFLA_INET_UNSPEC, @@ -276,6 +287,7 @@ enum { IFLA_BR_MCAST_STATS_ENABLED, IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, __IFLA_BR_MAX, }; @@ -323,6 +335,14 @@ enum { IFLA_BRPORT_MCAST_TO_UCAST, IFLA_BRPORT_VLAN_TUNNEL, IFLA_BRPORT_BCAST_FLOOD, + IFLA_BRPORT_GROUP_FWD_MASK, + IFLA_BRPORT_NEIGH_SUPPRESS, + IFLA_BRPORT_ISOLATED, + IFLA_BRPORT_BACKUP_PORT, + IFLA_BRPORT_PEER_LINK = 60, /* MLAG peer link */ + IFLA_BRPORT_DUAL_LINK, /* MLAG Dual Connected link */ + IFLA_BRPORT_GROUP_FWD_MASKHI, + IFLA_BRPORT_DUAL_LINK_READY, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -448,6 +468,16 @@ enum { #define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + enum macsec_validation_type { MACSEC_VALIDATE_DISABLED = 0, MACSEC_VALIDATE_CHECK = 1, @@ -460,6 +490,7 @@ enum macsec_validation_type { enum { IFLA_IPVLAN_UNSPEC, IFLA_IPVLAN_MODE, + IFLA_IPVLAN_FLAGS, __IFLA_IPVLAN_MAX }; @@ -472,6 +503,9 @@ enum ipvlan_mode { IPVLAN_MODE_MAX }; +#define IPVLAN_F_PRIVATE 0x01 +#define IPVLAN_F_VEPA 0x02 + /* VXLAN section */ enum { IFLA_VXLAN_UNSPEC, @@ -502,6 +536,7 @@ enum { IFLA_VXLAN_COLLECT_METADATA, IFLA_VXLAN_LABEL, IFLA_VXLAN_GPE, + IFLA_VXLAN_TTL_INHERIT, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -585,6 +620,8 @@ enum { IFLA_BOND_AD_USER_PORT_KEY, IFLA_BOND_AD_ACTOR_SYSTEM, IFLA_BOND_TLB_DYNAMIC_LB, + IFLA_BOND_CL_START = 60, + IFLA_BOND_AD_LACP_BYPASS = IFLA_BOND_CL_START, __IFLA_BOND_MAX, }; @@ -612,6 +649,9 @@ enum { IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + + IFLA_BOND_SLAVE_CL_START = 50, + IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START, __IFLA_BOND_SLAVE_MAX, }; @@ -721,6 +761,8 @@ enum { IFLA_VF_STATS_BROADCAST, IFLA_VF_STATS_MULTICAST, IFLA_VF_STATS_PAD, + IFLA_VF_STATS_RX_DROPPED, + IFLA_VF_STATS_TX_DROPPED, __IFLA_VF_STATS_MAX, }; @@ -872,6 +914,7 @@ enum { enum { LINK_XSTATS_TYPE_UNSPEC, LINK_XSTATS_TYPE_BRIDGE, + LINK_XSTATS_TYPE_BOND, __LINK_XSTATS_TYPE_MAX }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) @@ -902,6 +945,7 @@ enum { XDP_ATTACHED_DRV, XDP_ATTACHED_SKB, XDP_ATTACHED_HW, + XDP_ATTACHED_MULTI, }; enum { @@ -910,6 +954,9 @@ enum { IFLA_XDP_ATTACHED, IFLA_XDP_FLAGS, IFLA_XDP_PROG_ID, + IFLA_XDP_DRV_PROG_ID, + IFLA_XDP_SKB_PROG_ID, + IFLA_XDP_HW_PROG_ID, __IFLA_XDP_MAX, }; @@ -925,4 +972,43 @@ enum { IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */ }; -#endif /* _LINUX_IF_LINK_H */ +/* tun section */ + +enum { + IFLA_TUN_UNSPEC, + IFLA_TUN_OWNER, + IFLA_TUN_GROUP, + IFLA_TUN_TYPE, + IFLA_TUN_PI, + IFLA_TUN_VNET_HDR, + IFLA_TUN_PERSIST, + IFLA_TUN_MULTI_QUEUE, + IFLA_TUN_NUM_QUEUES, + IFLA_TUN_NUM_DISABLED_QUEUES, + __IFLA_TUN_MAX, +}; + +#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) + +/* rmnet section */ + +#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0) +#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1) +#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2) +#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3) + +enum { + IFLA_RMNET_UNSPEC, + IFLA_RMNET_MUX_ID, + IFLA_RMNET_FLAGS, + __IFLA_RMNET_MAX, +}; + +#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1) + +struct ifla_rmnet_flags { + __u32 flags; + __u32 mask; +}; + +#endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h index 3298426271..de696ca12f 100644 --- a/include/linux/lwtunnel.h +++ b/include/linux/lwtunnel.h @@ -1,5 +1,6 @@ -#ifndef _LWTUNNEL_H_ -#define _LWTUNNEL_H_ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LWTUNNEL_H_ +#define _UAPI_LWTUNNEL_H_ #include <linux/types.h> @@ -67,4 +68,4 @@ enum { #define LWT_BPF_MAX_HEADROOM 256 -#endif /* _LWTUNNEL_H_ */ +#endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h index 1a0e57b45a..521f2e605f 100644 --- a/include/linux/mpls_iptunnel.h +++ b/include/linux/mpls_iptunnel.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * mpls tunnel api * @@ -10,8 +11,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _LINUX_MPLS_IPTUNNEL_H -#define _LINUX_MPLS_IPTUNNEL_H +#ifndef _UAPI_LINUX_MPLS_IPTUNNEL_H +#define _UAPI_LINUX_MPLS_IPTUNNEL_H /* MPLS tunnel attributes * [RTA_ENCAP] = { @@ -27,4 +28,4 @@ enum { }; #define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) -#endif /* _LINUX_MPLS_IPTUNNEL_H */ +#endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */ diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h index 3199d28980..cd144e3099 100644 --- a/include/linux/neighbour.h +++ b/include/linux/neighbour.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_NEIGHBOUR_H #define __LINUX_NEIGHBOUR_H @@ -27,6 +28,7 @@ enum { NDA_MASTER, NDA_LINK_NETNSID, NDA_SRC_VNI, + NDA_PROTOCOL, /* Originator of entry */ __NDA_MAX }; @@ -42,6 +44,7 @@ enum { #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_EXT_LEARNED 0x10 #define NTF_OFFLOADED 0x20 +#define NTF_STICKY 0x40 #define NTF_ROUTER 0x80 /* diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h index 9a92b7e14a..0187c74d88 100644 --- a/include/linux/net_namespace.h +++ b/include/linux/net_namespace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* Copyright (c) 2015 6WIND S.A. * Author: Nicolas Dichtel <nicolas.dichtel@6wind.com> * @@ -5,8 +6,8 @@ * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. */ -#ifndef _LINUX_NET_NAMESPACE_H_ -#define _LINUX_NET_NAMESPACE_H_ +#ifndef _UAPI_LINUX_NET_NAMESPACE_H_ +#define _UAPI_LINUX_NET_NAMESPACE_H_ /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ enum { @@ -20,4 +21,4 @@ enum { #define NETNSA_MAX (__NETNSA_MAX - 1) -#endif /* _LINUX_NET_NAMESPACE_H_ */ +#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 0b2c29bd08..0a4d733177 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef __LINUX_NETLINK_H -#define __LINUX_NETLINK_H +#ifndef _UAPI__LINUX_NETLINK_H +#define _UAPI__LINUX_NETLINK_H #include <linux/kernel.h> #include <linux/socket.h> /* for __kernel_sa_family_t */ @@ -147,12 +147,15 @@ enum nlmsgerr_attrs { #define NETLINK_PKTINFO 3 #define NETLINK_BROADCAST_ERROR 4 #define NETLINK_NO_ENOBUFS 5 +#ifndef __KERNEL__ #define NETLINK_RX_RING 6 #define NETLINK_TX_RING 7 +#endif #define NETLINK_LISTEN_ALL_NSID 8 #define NETLINK_LIST_MEMBERSHIPS 9 #define NETLINK_CAP_ACK 10 #define NETLINK_EXT_ACK 11 +#define NETLINK_GET_STRICT_CHK 12 struct nl_pktinfo { __u32 group; @@ -175,6 +178,7 @@ struct nl_mmap_hdr { __u32 nm_gid; }; +#ifndef __KERNEL__ enum nl_mmap_status { NL_MMAP_STATUS_UNUSED, NL_MMAP_STATUS_RESERVED, @@ -186,6 +190,7 @@ enum nl_mmap_status { #define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO #define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) #define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) +#endif #define NET_MAJOR 36 /* Major 36 is reserved for networking */ @@ -244,4 +249,4 @@ struct nla_bitfield32 { __u32 selector; }; -#endif /* __LINUX_NETLINK_H */ +#endif /* _UAPI__LINUX_NETLINK_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 813e9e0767..ce2a623abb 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -1,5 +1,6 @@ -#ifndef __LINUX_RTNETLINK_H -#define __LINUX_RTNETLINK_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI__LINUX_RTNETLINK_H +#define _UAPI__LINUX_RTNETLINK_H #include <linux/types.h> #include <linux/netlink.h> @@ -149,6 +150,20 @@ enum { RTM_NEWCACHEREPORT = 96, #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + RTM_NEWCHAIN = 100, +#define RTM_NEWCHAIN RTM_NEWCHAIN + RTM_DELCHAIN, +#define RTM_DELCHAIN RTM_DELCHAIN + RTM_GETCHAIN, +#define RTM_GETCHAIN RTM_GETCHAIN + + RTM_NEWNEXTHOP = 104, +#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP + RTM_DELNEXTHOP, +#define RTM_DELNEXTHOP RTM_DELNEXTHOP + RTM_GETNEXTHOP, +#define RTM_GETNEXTHOP RTM_GETNEXTHOP + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -253,6 +268,11 @@ enum { #define RTPROT_DHCP 16 /* DHCP client */ #define RTPROT_MROUTED 17 /* Multicast daemon */ #define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_BGP 186 /* BGP Routes */ +#define RTPROT_ISIS 187 /* ISIS Routes */ +#define RTPROT_OSPF 188 /* OSPF Routes */ +#define RTPROT_RIP 189 /* RIP Routes */ +#define RTPROT_EIGRP 192 /* EIGRP Routes */ /* rtm_scope @@ -326,6 +346,10 @@ enum rtattr_type_t { RTA_PAD, RTA_UID, RTA_TTL_PROPAGATE, + RTA_IP_PROTO, + RTA_SPORT, + RTA_DPORT, + RTA_NH_ID, __RTA_MAX }; @@ -430,6 +454,8 @@ enum { #define RTAX_QUICKACK RTAX_QUICKACK RTAX_CC_ALGO, #define RTAX_CC_ALGO RTAX_CC_ALGO + RTAX_FASTOPEN_NO_COOKIE, +#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE __RTAX_MAX }; @@ -538,9 +564,19 @@ struct tcmsg { int tcm_ifindex; __u32 tcm_handle; __u32 tcm_parent; +/* tcm_block_index is used instead of tcm_parent + * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK + */ +#define tcm_block_index tcm_parent __u32 tcm_info; }; +/* For manipulation of filters in shared block, tcm_ifindex is set to + * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index + * which is the block index. + */ +#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) + enum { TCA_UNSPEC, TCA_KIND, @@ -554,6 +590,9 @@ enum { TCA_PAD, TCA_DUMP_INVISIBLE, TCA_CHAIN, + TCA_HW_OFFLOAD, + TCA_INGRESS_BLOCK, + TCA_EGRESS_BLOCK, __TCA_MAX }; @@ -586,6 +625,7 @@ enum { #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) +#ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 #define RTMGRP_NOTIFY 2 @@ -606,6 +646,7 @@ enum { #define RTMGRP_DECnet_ROUTE 0x4000 #define RTMGRP_IPV6_PREFIX 0x20000 +#endif /* RTnetlink multicast groups */ enum rtnetlink_groups { @@ -671,6 +712,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV6_MROUTE_R, #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R + RTNLGRP_NEXTHOP, +#define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) @@ -715,4 +758,4 @@ enum { -#endif /* __LINUX_RTNETLINK_H */ +#endif /* _UAPI__LINUX_RTNETLINK_H */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 8c1e501774..8eb9602170 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -1,5 +1,6 @@ -#ifndef _LINUX_SOCKET_H -#define _LINUX_SOCKET_H +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_SOCKET_H +#define _UAPI_LINUX_SOCKET_H /* * Desired design of maximum size and alignment (see RFC2553) @@ -18,4 +19,4 @@ struct __kernel_sockaddr_storage { /* _SS_MAXSIZE value minus size of ss_family */ } __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */ -#endif /* _LINUX_SOCKET_H */ +#endif /* _UAPI_LINUX_SOCKET_H */ diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 9b368cc404..d2ec6ff566 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -254,6 +254,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, reason ? reason : "unspecified"); } + circuit->adj_state_changes++; #ifndef FABRICD /* send northbound notification */ isis_notif_adj_state_change(adj, new_state, reason); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index e834e31600..f677d3aded 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -146,6 +146,13 @@ struct isis_circuit { uint32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */ uint32_t rej_adjacencies; /* rejectedAdjacencies */ + /* + * Counters as in ietf-isis@2019-09-09.yang + */ + uint32_t id_len_mismatches; /* id-len-mismatch */ + uint32_t max_area_addr_mismatches; /* max-area-addresses-mismatch */ + uint32_t auth_type_failures; /*authentication-type-fails */ + uint32_t auth_failures; /* authentication-fails */ QOBJ_FIELDS }; diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 7f49e9d89a..718924daf2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -243,7 +243,7 @@ int main(int argc, char **argv, char **envp) mt_init(); /* create the global 'isis' instance */ - isis_new(1); + isis_new(1, VRF_DEFAULT); isis_zebra_init(master); isis_bfd_init(); diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index bd61918697..1e21efa7ce 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -49,6 +49,23 @@ #include "lib/vrf.h" /* + * Helper functions. + */ +static const char *isis_yang_adj_state(enum isis_adj_state state) +{ + switch (state) { + case ISIS_ADJ_DOWN: + return "down"; + case ISIS_ADJ_UP: + return "up"; + case ISIS_ADJ_INITIALIZING: + return "init"; + default: + return "failed"; + } +} + +/* * XPath: /frr-isisd:isis/instance */ static int isis_instance_create(enum nb_event event, @@ -1542,9 +1559,9 @@ static int lib_interface_isis_create(enum nb_event event, /* check if interface mtu is sufficient. If the area has not * been created yet, assume default MTU for the area */ - ifp = nb_running_get_entry(dnode, NULL, true); + ifp = nb_running_get_entry(dnode, NULL, false); /* zebra might not know yet about the MTU - nothing we can do */ - if (ifp->mtu == 0) + if (!ifp || ifp->mtu == 0) break; actual_mtu = if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu; @@ -2304,6 +2321,368 @@ static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify( } /* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency + */ +static const void * +lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj, *adj_next = NULL; + struct list *list; + struct listnode *node, *node_next; + + /* Get first adjacency. */ + if (list_entry == NULL) { + ifp = (struct interface *)parent_list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; + level++) { + adj = listnode_head( + circuit->u.bc.adjdb[level - 1]); + if (adj) + break; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + break; + default: + adj = NULL; + break; + } + + return adj; + } + + /* Get next adjacency. */ + adj = (struct isis_adjacency *)list_entry; + circuit = adj->circuit; + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + list = circuit->u.bc.adjdb[adj->level - 1]; + node = listnode_lookup(list, adj); + node_next = listnextnode(node); + if (node_next) + adj_next = listgetdata(node_next); + else if (adj->level == ISIS_LEVEL1) { + /* + * Once we finish the L1 adjacencies, move to the L2 + * adjacencies list. + */ + list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1]; + adj_next = listnode_head(list); + } + break; + case CIRCUIT_T_P2P: + /* P2P circuits have at most one adjacency. */ + default: + break; + } + + return adj_next; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_enum(xpath, adj->level); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, sysid_print(adj->sysid)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint32(xpath, adj->circuit->circuit_id); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, snpa_print(adj->snpa)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint16(xpath, adj->hold_time); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem( + const char *xpath, const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state + */ +static struct yang_data * +lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath, + const void *list_entry) +{ + const struct isis_adjacency *adj = list_entry; + + return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state)); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_changes_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->adj_state_changes); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_number_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct isis_adjacency *adj; + struct listnode *node; + uint32_t total = 0; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + /* + * TODO: keep track of the number of adjacencies instead of calculating + * it on demand. + */ + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { + for (ALL_LIST_ELEMENTS_RO( + circuit->u.bc.adjdb[level - 1], node, adj)) + total++; + } + break; + case CIRCUIT_T_P2P: + adj = circuit->u.p2p.neighbor; + if (adj) + total = 1; + break; + default: + break; + } + + return yang_data_new_uint32(xpath, total); +} + +/* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath, + const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->init_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects + */ +static struct yang_data * +lib_interface_isis_event_counters_adjacency_rejects_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->rej_adjacencies); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_id_len_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->id_len_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch + */ +static struct yang_data * +lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_type_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_type_failures); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails + */ +static struct yang_data * +lib_interface_isis_event_counters_authentication_fails_get_elem( + const char *xpath, const void *list_entry) +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = (struct interface *)list_entry; + if (!ifp) + return NULL; + + circuit = circuit_scan_by_ifp(ifp); + if (!circuit) + return NULL; + + return yang_data_new_uint32(xpath, circuit->auth_failures); +} + +/* * NOTIFICATIONS */ static void notif_prep_instance_hdr(const char *xpath, @@ -2545,19 +2924,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj, listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath); - switch (new_state) { - case ISIS_ADJ_DOWN: - data = yang_data_new_string(xpath_arg, "down"); - break; - case ISIS_ADJ_UP: - data = yang_data_new_string(xpath_arg, "up"); - break; - case ISIS_ADJ_INITIALIZING: - data = yang_data_new_string(xpath_arg, "init"); - break; - default: - data = yang_data_new_string(xpath_arg, "failed"); - } + data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state)); listnode_add(arguments, data); if (new_state == ISIS_ADJ_DOWN) { snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath); @@ -3484,6 +3851,102 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency", + .cbs = { + .get_next = lib_interface_isis_adjacencies_adjacency_get_next, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state", + .cbs = { + .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_init_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects", + .cbs = { + .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch", + .cbs = { + .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails", + .cbs = { + .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem, + } + }, + { .xpath = NULL, }, } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index ecfce392ff..46b013ddd0 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -576,6 +576,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (p2p_hello) { if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn("p2p hello on non p2p circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "p2p hello on non p2p circuit", @@ -586,6 +587,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, } else { if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("lan hello on non broadcast circuit"); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "lan hello on non broadcast circuit", @@ -598,6 +600,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_debug( "level %d LAN Hello received over circuit with externalDomain = true", level); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, @@ -614,6 +617,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, circuit->area->area_tag, circuit->interface->name); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Interface level mismatch", raw_pdu); @@ -643,6 +647,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16, circuit->area->area_tag, pdu_name, circuit->interface->name, iih.pdu_len); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Invalid PDU length", raw_pdu); @@ -654,6 +659,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, flog_err(EC_ISIS_PACKET, "Level %d LAN Hello with Circuit Type %d", level, iih.circ_type); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "LAN Hello with wrong IS-level", raw_pdu); @@ -667,6 +673,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), circuit->rcv_stream, &iih.tlvs, &error_log)) { zlog_warn("isis_unpack_tlvs() failed: %s", error_log); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs", raw_pdu); @@ -685,6 +692,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (!iih.tlvs->protocols_supported.count) { zlog_warn("No supported protocols TLV in %s", pdu_name); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "No supported protocols TLV", raw_pdu); @@ -702,11 +710,14 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -715,6 +726,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_warn( "ISIS-Adj (%s): Received IIH with own sysid - discard", circuit->area->area_tag); + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Received IIH with our own sysid", raw_pdu); @@ -752,6 +764,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH", circuit->area->area_tag); } + circuit->rej_adjacencies++; #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Neither IPv4 not IPv6 considered usable", @@ -940,11 +953,14 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, hdr.lsp_id); #ifndef FABRICD /* send northbound notification */ - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1373,12 +1389,15 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); - if (auth_code == ISIS_AUTH_FAILURE) + if (auth_code == ISIS_AUTH_FAILURE) { + circuit->auth_failures++; isis_notif_authentication_failure(circuit, raw_pdu); - else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + circuit->auth_type_failures++; isis_notif_authentication_type_failure(circuit, raw_pdu); + } #endif /* ifndef FABRICD */ goto out; } @@ -1614,6 +1633,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8 ", while the parameter for this IS is %u", id_len, ISIS_SYS_ID_LEN); + circuit->id_len_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_id_len_mismatch(circuit, id_len, raw_pdu); @@ -1666,6 +1686,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8 " while the parameter for this IS is %u", max_area_addrs, isis->max_area_addrs); + circuit->max_area_addr_mismatches++; #ifndef FABRICD /* send northbound notification */ isis_notif_max_area_addr_mismatch(circuit, max_area_addrs, diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 44fa45d02b..9871d2bcb9 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -81,8 +81,7 @@ void isis_link_params_update(struct isis_circuit *circuit, return; /* Sanity Check */ - if ((circuit == NULL) || (ifp == NULL) - || (circuit->state != C_STATE_UP)) + if ((ifp == NULL) || (circuit->state != C_STATE_UP)) return; zlog_debug("TE(%s): Update circuit parameters for interface %s", diff --git a/isisd/isisd.c b/isisd/isisd.c index 67f557ab50..029a9e0688 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -75,12 +75,13 @@ int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); -void isis_new(unsigned long process_id) +void isis_new(unsigned long process_id, vrf_id_t vrf_id) { isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); /* * Default values */ + isis->vrf_id = vrf_id; isis->max_area_addrs = 3; isis->process_id = process_id; isis->router_id = 0; diff --git a/isisd/isisd.h b/isisd/isisd.h index 308f018c19..f825b6ecb4 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -62,6 +62,7 @@ extern struct zebra_privs_t isisd_privs; struct fabricd; struct isis { + vrf_id_t vrf_id; unsigned long process_id; int sysid_set; uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ @@ -189,7 +190,7 @@ struct isis_area { DECLARE_QOBJ_TYPE(isis_area) void isis_init(void); -void isis_new(unsigned long); +void isis_new(unsigned long process_id, vrf_id_t vrf_id); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup(const char *); int isis_area_get(struct vty *vty, const char *area_tag); @@ -1231,7 +1231,7 @@ void if_link_params_free(struct interface *ifp) */ DEFPY_NOSH (interface, interface_cmd, - "interface IFNAME [vrf NAME$vrfname]", + "interface IFNAME [vrf NAME$vrf_name]", "Select an interface to configure\n" "Interface's name\n" VRF_CMD_HELP_STR) @@ -1241,8 +1241,8 @@ DEFPY_NOSH (interface, struct interface *ifp; int ret; - if (!vrfname) - vrfname = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; /* * This command requires special handling to maintain backward @@ -1251,7 +1251,7 @@ DEFPY_NOSH (interface, * interface is found, then a new one should be created on the default * VRF. */ - VRF_GET_ID(vrf_id, vrfname, false); + VRF_GET_ID(vrf_id, vrf_name, false); ifp = if_lookup_by_name_all_vrf(ifname); if (ifp && ifp->vrf_id != vrf_id) { struct vrf *vrf; @@ -1262,24 +1262,24 @@ DEFPY_NOSH (interface, */ if (vrf_id != VRF_DEFAULT) { vty_out(vty, "%% interface %s not in %s vrf\n", ifname, - vrfname); + vrf_name); return CMD_WARNING_CONFIG_FAILED; } /* * Special case 2: a VRF name was *not* specified, and the found * interface is associated to a VRF other than the default one. - * Update vrf_id and vrfname to account for that. + * Update vrf_id and vrf_name to account for that. */ vrf = vrf_lookup_by_id(ifp->vrf_id); assert(vrf); vrf_id = ifp->vrf_id; - vrfname = vrf->name; + vrf_name = vrf->name; } snprintf(xpath_list, sizeof(xpath_list), "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname, - vrfname); + vrf_name); nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); ret = nb_cli_apply_changes(vty, xpath_list); @@ -1302,20 +1302,20 @@ DEFPY_NOSH (interface, DEFPY (no_interface, no_interface_cmd, - "no interface IFNAME [vrf NAME$vrfname]", + "no interface IFNAME [vrf NAME$vrf_name]", NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n" VRF_CMD_HELP_STR) { - if (!vrfname) - vrfname = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifname, vrfname); + ifname, vrf_name); } static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index abe2096cec..9564321d38 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -475,7 +475,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ |INTERFACE$intf\ >\ - [nexthop-vrf NAME$name]", + [nexthop-vrf NAME$vrf_name]", NO_STR "Specify one of the nexthops in this ECMP group\n" "v4 Address\n" @@ -490,7 +490,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, struct nexthop *nh; bool legal; - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name); + legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name); if (nhop.type == NEXTHOP_TYPE_IPV6 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -502,7 +502,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nh = nexthop_exists(&nhgc->nhg, &nhop); if (no) { - nexthop_group_unsave_nhop(nhgc, name, addr, intf); + nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf); if (nh) { _nexthop_del(&nhgc->nhg, nh); @@ -520,7 +520,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, _nexthop_add(&nhgc->nhg.nexthop, nh); } - nexthop_group_save_nhop(nhgc, name, addr, intf); + nexthop_group_save_nhop(nhgc, vrf_name, addr, intf); if (legal && nhg_hooks.add_nexthop) nhg_hooks.add_nexthop(nhgc, nh); @@ -472,6 +472,14 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { .varname = "vrf", .completions = vrf_autocomplete, }, + { + .varname = "vrf_name", + .completions = vrf_autocomplete, + }, + { + .varname = "nexthop_vrf", + .completions = vrf_autocomplete, + }, {.completions = NULL}, }; diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index e62efc5a0d..a56ba0a694 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -356,8 +356,6 @@ void ospf6_interface_state_update(struct interface *ifp) oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) return; - if (oi->area == NULL) - return; if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) return; @@ -684,6 +682,9 @@ int interface_up(struct thread *thread) oi = (struct ospf6_interface *)THREAD_ARG(thread); assert(oi && oi->interface); + if (!oi->type_cfg) + oi->type = ospf6_default_iftype(oi->interface); + /* * Remove old pointer. If this thread wasn't a timer this * operation won't make a difference, because it is already NULL. @@ -775,8 +776,7 @@ int interface_up(struct thread *thread) } /* decide next interface state */ - if ((if_is_pointopoint(oi->interface)) - || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi); } else if (oi->priority == 0) ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi); @@ -881,6 +881,19 @@ int interface_down(struct thread *thread) } +static const char *ospf6_iftype_str(uint8_t iftype) +{ + switch (iftype) { + case OSPF_IFTYPE_LOOPBACK: + return "LOOPBACK"; + case OSPF_IFTYPE_BROADCAST: + return "BROADCAST"; + case OSPF_IFTYPE_POINTOPOINT: + return "POINTOPOINT"; + } + return "UNKNOWN"; +} + /* show specified interface structure */ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) { @@ -889,23 +902,16 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) struct prefix *p; struct listnode *i; char strbuf[PREFIX2STR_BUFFER], drouter[32], bdrouter[32]; - const char *type; + uint8_t default_iftype; struct timeval res, now; char duration[32]; struct ospf6_lsa *lsa; - /* check physical interface type */ - if (if_is_loopback(ifp)) - type = "LOOPBACK"; - else if (if_is_broadcast(ifp)) - type = "BROADCAST"; - else if (if_is_pointopoint(ifp)) - type = "POINTOPOINT"; - else - type = "UNKNOWN"; + default_iftype = ospf6_default_iftype(ifp); vty_out(vty, "%s is %s, type %s\n", ifp->name, - (if_is_operative(ifp) ? "up" : "down"), type); + (if_is_operative(ifp) ? "up" : "down"), + ospf6_iftype_str(default_iftype)); vty_out(vty, " Interface ID: %d\n", ifp->ifindex); if (ifp->info == NULL) { @@ -914,6 +920,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) } else oi = (struct ospf6_interface *)ifp->info; + if (if_is_operative(ifp) && oi->type != default_iftype) + vty_out(vty, " Operating as type %s\n", + ospf6_iftype_str(oi->type)); + vty_out(vty, " Internet Address:\n"); for (ALL_LIST_ELEMENTS_RO(ifp->connected, i, c)) { @@ -1810,6 +1820,8 @@ DEFUN (ipv6_ospf6_network, } assert(oi); + oi->type_cfg = true; + if (strncmp(argv[idx_network]->arg, "b", 1) == 0) { if (oi->type == OSPF_IFTYPE_BROADCAST) return CMD_SUCCESS; @@ -1850,6 +1862,8 @@ DEFUN (no_ipv6_ospf6_network, return CMD_SUCCESS; } + oi->type_cfg = false; + type = ospf6_default_iftype(ifp); if (oi->type == type) { return CMD_SUCCESS; @@ -1917,13 +1931,10 @@ static int config_write_ospf6_interface(struct vty *vty) if (oi->mtu_ignore) vty_out(vty, " ipv6 ospf6 mtu-ignore\n"); - if (oi->type != ospf6_default_iftype(ifp)) { - if (oi->type == OSPF_IFTYPE_POINTOPOINT) - vty_out(vty, - " ipv6 ospf6 network point-to-point\n"); - else if (oi->type == OSPF_IFTYPE_BROADCAST) - vty_out(vty, " ipv6 ospf6 network broadcast\n"); - } + if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT) + vty_out(vty, " ipv6 ospf6 network point-to-point\n"); + else if (oi->type_cfg && oi->type == OSPF_IFTYPE_BROADCAST) + vty_out(vty, " ipv6 ospf6 network broadcast\n"); ospf6_bfd_write_config(vty, oi); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index e0c39a29b4..53a8910f4d 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -55,6 +55,7 @@ struct ospf6_interface { /* Network Type */ uint8_t type; + bool type_cfg; /* Router Priority */ uint8_t priority; diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index b551dbdfa6..0a9f1c6f7c 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -298,13 +298,17 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend, void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; if (lsdb == NULL) return; - for (ALL_LSDB(lsdb, lsa)) + for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_lsdb_remove(lsa, lsdb); + } } void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa) @@ -319,9 +323,12 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa) int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb) { int reschedule = 0; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; - for (ALL_LSDB(lsdb, lsa)) { + for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); if (!OSPF6_LSA_IS_MAXAGE(lsa)) continue; if (lsa->retrans_count != 0) { diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 4acb5e3b2e..da42a24252 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1866,7 +1866,8 @@ int ospf6_dbdesc_send(struct thread *thread) int ospf6_dbdesc_send_newone(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; unsigned int size = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -1876,7 +1877,10 @@ int ospf6_dbdesc_send_newone(struct thread *thread) structure) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc); - for (ALL_LSDB(on->summary_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->summary_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); if (size + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock(lsa); @@ -2019,7 +2023,8 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); on->thread_send_lsupdate = (struct thread *)NULL; @@ -2044,7 +2049,9 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ - for (ALL_LSDB(on->lsupdate_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->lsupdate_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header)) > ospf6_packet_max(on->ospf6_if)) { @@ -2074,7 +2081,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) p += OSPF6_LSA_SIZE(lsa->header); lsa_cnt++; - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, on->lsupdate_list); } @@ -2202,7 +2209,8 @@ int ospf6_lsupdate_send_interface(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; oi = (struct ospf6_interface *)THREAD_ARG(thread); oi->thread_send_lsupdate = (struct thread *)NULL; @@ -2228,7 +2236,9 @@ int ospf6_lsupdate_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); lsa_cnt = 0; - for (ALL_LSDB(oi->lsupdate_list, lsa)) { + for (iterend = ospf6_lsdb_head(oi->lsupdate_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header))) > ospf6_packet_max(oi)) { @@ -2263,7 +2273,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread) p += OSPF6_LSA_SIZE(lsa->header); lsa_cnt++; - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, oi->lsupdate_list); } @@ -2289,7 +2299,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) struct ospf6_neighbor *on; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; int lsa_cnt = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -2312,7 +2323,9 @@ int ospf6_lsack_send_neighbor(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(on->lsack_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->lsack_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { @@ -2340,7 +2353,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header)); p += sizeof(struct ospf6_lsa_header); - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, on->lsack_list); lsa_cnt++; } @@ -2367,7 +2380,8 @@ int ospf6_lsack_send_interface(struct thread *thread) struct ospf6_interface *oi; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; int lsa_cnt = 0; oi = (struct ospf6_interface *)THREAD_ARG(thread); @@ -2391,7 +2405,9 @@ int ospf6_lsack_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(oi->lsack_list, lsa)) { + for (iterend = ospf6_lsdb_head(oi->lsack_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(oi)) { @@ -2409,7 +2425,7 @@ int ospf6_lsack_send_interface(struct thread *thread) memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header)); p += sizeof(struct ospf6_lsa_header); - assert(lsa->lock == 2); + assert(lsa->lock == 1); ospf6_lsdb_remove(lsa, oi->lsack_list); lsa_cnt++; } diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 46dc621ae7..4318db5225 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -112,11 +112,15 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -287,7 +291,8 @@ int twoway_received(struct thread *thread) int negotiation_done(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -301,7 +306,10 @@ int negotiation_done(struct thread *thread) /* clear ls-list */ ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -495,7 +503,8 @@ int seqnumber_mismatch(struct thread *thread) int bad_lsreq(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -514,7 +523,10 @@ int bad_lsreq(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -532,7 +544,8 @@ int bad_lsreq(struct thread *thread) int oneway_received(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsa_next; + const struct route_node *iterend; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -549,7 +562,9 @@ int oneway_received(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa; + lsa = lsa_next) { + lsa_next = ospf6_lsdb_next(iterend, lsa); ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -618,7 +633,7 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on) snprintf(deadtime, sizeof(deadtime), "%02ld:%02ld:%02ld", h, m, s); /* Neighbor State */ - if (if_is_pointopoint(on->ospf6_if->interface)) + if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT) snprintf(nstate, sizeof(nstate), "PointToPoint"); else { if (on->router_id == on->drouter) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index fc7c6177d7..1ba89f3bd6 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -1130,9 +1130,9 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(ntohl(oi->area->area_id)); break; case OSPFv3IFTYPE: - if (if_is_broadcast(oi->interface)) + if (oi->type == OSPF_IFTYPE_BROADCAST) return SNMP_INTEGER(1); - else if (if_is_pointopoint(oi->interface)) + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) return SNMP_INTEGER(3); else break; /* Unknown, don't put anything */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 40c6123810..95dafff84e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -136,7 +136,7 @@ static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) ospf6_abr_originate_summary(route); } -static struct ospf6 *ospf6_create(void) +static struct ospf6 *ospf6_create(vrf_id_t vrf_id) { struct ospf6 *o; @@ -144,6 +144,7 @@ static struct ospf6 *ospf6_create(void) /* initialize */ monotime(&o->starttime); + o->vrf_id = vrf_id; o->area_list = list_new(); o->area_list->cmp = ospf6_area_cmp; o->lsdb = ospf6_lsdb_create(o); @@ -325,7 +326,7 @@ DEFUN_NOSH (router_ospf6, OSPF6_STR) { if (ospf6 == NULL) { - ospf6 = ospf6_create(); + ospf6 = ospf6_create(VRF_DEFAULT); if (ospf6->router_id == 0) ospf6_router_id_update(); } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 381027dcff..ba41fca65b 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -31,6 +31,9 @@ struct ospf6_master { /* OSPFv3 top level data structure */ struct ospf6 { + /* The relevant vrf_id */ + vrf_id_t vrf_id; + /* my router id */ uint32_t router_id; diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 359f869c42..ae04402f49 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -711,7 +711,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, } if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - || pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + || pnhc->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { /* GATEWAY_IFINDEX type shouldn't resolve to group */ if (pnhi->nhr->nexthop_num > 1) { diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 5e7addc9d2..a6e764bbb0 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -254,7 +254,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ |INTERFACE$intf\ >\ - [nexthop-vrf NAME$name]", + [nexthop-vrf NAME$vrf_name]", NO_STR "Set for the PBR-MAP\n" "Specify one of the nexthops in this map\n" @@ -276,13 +276,13 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, return CMD_WARNING_CONFIG_FAILED; } - if (name) - vrf = vrf_lookup_by_name(name); + if (vrf_name) + vrf = vrf_lookup_by_name(vrf_name); else vrf = vrf_lookup_by_id(VRF_DEFAULT); if (!vrf) { - vty_out(vty, "Specified: %s is non-existent\n", name); + vty_out(vty, "Specified: %s is non-existent\n", vrf_name); return CMD_WARNING_CONFIG_FAILED; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 12b28ed9af..cd2d306f3d 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -574,6 +574,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, ip->ip_id = htons(++ip_id); ip->ip_hl = 5; ip->ip_v = 4; + ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; ip->ip_p = PIM_IP_PROTO_PIM; ip->ip_src = src; ip->ip_dst = dst; diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 82255cd3b0..7f03e18389 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -255,6 +255,12 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, } } + /* Set Tx socket DSCP byte */ + if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to PIM/IGMP socket %d: %s", + fd, safe_strerror(errno)); + } + return fd; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index db0aedad6a..dadcbbe65d 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -964,12 +964,6 @@ void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; - int input_iface_vif_index = 0; - struct pim_instance *pim; - struct pim_interface *pim_ifp; - - pim_ifp = ch->interface->info; - pim = pim_ifp->pim; if (PIM_DEBUG_PIM_TRACE) { char source_str[INET_ADDRSTRLEN]; @@ -987,55 +981,6 @@ void pim_forward_start(struct pim_ifchannel *ch) inet_ntoa(up->upstream_addr)); } - /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, - as part of mroute_del called by pim_forward_stop. - */ - if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) { - struct prefix src, grp; - - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = up->sg.src; - - if (pim_ecmp_nexthop_lookup(pim, &up->rpf.source_nexthop, &src, - &grp, 0)) - input_iface_vif_index = pim_if_find_vifindex_by_ifindex( - pim, up->rpf.source_nexthop.interface->ifindex); - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_PIM_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", up->sg.src, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - pim_channel_oil_change_iif(pim, up->channel_oil, - MAXVIFS, - __PRETTY_FUNCTION__); - } - - else - pim_channel_oil_change_iif(pim, up->channel_oil, - input_iface_vif_index, - __PRETTY_FUNCTION__); - - if (PIM_DEBUG_TRACE) { - struct interface *in_intf = pim_if_find_by_vif_index( - pim, input_iface_vif_index); - zlog_debug( - "%s: Update channel_oil IIF %s VIFI %d entry %s ", - __PRETTY_FUNCTION__, - in_intf ? in_intf->name : "Unknown", - input_iface_vif_index, up->sg_str); - } - } - if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) mask = PIM_OIF_FLAG_PROTO_IGMP; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 60cfb2e486..486ccf6bfe 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,7 +39,7 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", + "sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -54,12 +54,12 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, struct prefix p; bool type_import; - if (!name) - name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -83,7 +83,7 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", + "sharp watch [vrf NAME$vrf_name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -98,12 +98,12 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, struct prefix p; bool type_import; - if (!name) - name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -162,7 +162,7 @@ DEFPY (install_routes_data_dump, DEFPY (install_routes, install_routes_cmd, - "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" @@ -209,13 +209,13 @@ DEFPY (install_routes, } sg.r.orig_prefix = prefix; - if (!name) - name = VRF_DEFAULT_NAME; + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; - vrf = vrf_lookup_by_name(name); + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name); + vrf_name); return CMD_WARNING; } @@ -252,7 +252,7 @@ DEFPY (install_routes, } DEFPY(vrf_label, vrf_label_cmd, - "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$name label (0-100000)$label", + "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$vrf_name label (0-100000)$label", "Sharp Routing Protocol\n" "Give a vrf a label\n" "Pop and forward for IPv4\n" @@ -264,10 +264,10 @@ DEFPY(vrf_label, vrf_label_cmd, struct vrf *vrf; afi_t afi = (ipv4) ? AFI_IP : AFI_IP6; - if (strcmp(name, "default") == 0) + if (strcmp(vrf_name, "default") == 0) vrf = vrf_lookup_by_id(VRF_DEFAULT); else - vrf = vrf_lookup_by_name(name); + vrf = vrf_lookup_by_name(vrf_name); if (!vrf) { vty_out(vty, "Unable to find vrf you silly head"); @@ -283,7 +283,7 @@ DEFPY(vrf_label, vrf_label_cmd, DEFPY (remove_routes, remove_routes_cmd, - "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", + "sharp remove routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", "Sharp Routing Protocol\n" "Remove some routes\n" "Routes to remove\n" @@ -314,10 +314,10 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } - vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name ? name : VRF_DEFAULT_NAME); + vrf_name ? vrf_name : VRF_DEFAULT_NAME); return CMD_WARNING; } diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 9dd25fbdd1..abb64aad3f 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -27,6 +27,7 @@ #include "static_memory.h" #include "static_vrf.h" #include "static_routes.h" +#include "static_zebra.h" #include "static_vty.h" static void zebra_stable_node_cleanup(struct route_table *table, @@ -76,6 +77,8 @@ static int static_vrf_new(struct vrf *vrf) static int static_vrf_enable(struct vrf *vrf) { + static_zebra_vrf_register(vrf); + static_fixup_vrf_ids(vrf->info); /* @@ -89,6 +92,7 @@ static int static_vrf_enable(struct vrf *vrf) static int static_vrf_disable(struct vrf *vrf) { + static_zebra_vrf_unregister(vrf); return 0; } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index b364dd6290..976f892efb 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -484,3 +484,17 @@ void static_zebra_init(void) static_nht_hash_cmp, "Static Nexthop Tracking hash"); } + +void static_zebra_vrf_register(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_reg_requests(zclient, vrf->vrf_id); +} + +void static_zebra_vrf_unregister(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + zclient_send_dereg_requests(zclient, vrf->vrf_id); +} diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index 15f5410b81..962dc3908f 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -28,4 +28,7 @@ extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, vrf_id_t vrf_id, safi_t safi, bool install); extern void static_zebra_init(void); +extern void static_zebra_vrf_register(struct vrf *vrf); +extern void static_zebra_vrf_unregister(struct vrf *vrf); + #endif diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo1.json b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json new file mode 100644 index 0000000000..e89263961d --- /dev/null +++ b/tests/topotests/bgp-route-map/bgp_route_map_topo1.json @@ -0,0 +1,187 @@ +{ + "address_types": ["ipv4","ipv6"], + "ipv4base":"10.0.0.0", + "ipv4mask":30, + "ipv6base":"fd00::", + "ipv6mask":64, + "link_ip_start":{"ipv4":"10.0.0.0", "v4mask":30, "ipv6":"fd00::", "v6mask":64}, + "lo_prefix":{"ipv4":"1.0.", "v4mask":32, "ipv6":"2001:DB8:F::", "v6mask":128}, + "routers":{ + "r1":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r2":{"ipv4":"auto", "ipv6":"auto"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r1":{"ipv4":"auto", "ipv6":"auto"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r1":{"ipv4":"auto", "ipv6":"auto"}, + "r2":{"ipv4":"auto", "ipv6":"auto"}, + "r4":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4":{ + "links":{ + "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"}, + "r3":{"ipv4":"auto", "ipv6":"auto"} + }, + "bgp":{ + "local_as":"200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp-route-map/bgp_route_map_topo2.json b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json new file mode 100755 index 0000000000..c22a4c3ea7 --- /dev/null +++ b/tests/topotests/bgp-route-map/bgp_route_map_topo2.json @@ -0,0 +1,316 @@ +{ + "address_types": ["ipv4", "ipv6"], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + }, + + "static_routes": [{ + "network": "10.0.20.1/32", + "no_of_ip": 2, + "next_hop": "10.0.0.2" + }, + { + "network": "1::1/128", + "no_of_ip": 2, + "next_hop": "fd00::2" + }] + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py new file mode 100755 index 0000000000..86ec6c82d2 --- /dev/null +++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py @@ -0,0 +1,1361 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +------- | R2 | + | +-------+ + | | + +-------+ | + | R1 | | + +-------+ | + | | + | +-------+ +-------+ + +---------- | R3 |----------| R4 | + +-------+ +-------+ + +""" + +################################# +# TEST SUMMARY +################################# +""" +Following tests are covered to test route-map functionality: +TC_34: + Verify if route-maps is applied in both inbound and + outbound direction to same neighbor/interface. +TC_36: + Test permit/deny statements operation in route-maps with a + permutation and combination of permit/deny in prefix-lists +TC_35: + Test multiple sequence numbers in a single route-map for different + match/set clauses. +TC_37: + Test add/remove route-maps with multiple set + clauses and without any match statement.(Set only) +TC_38: + Test add/remove route-maps with multiple match + clauses and without any set statement.(Match only) +""" + +import sys +import json +import time +import pytest +import inspect +import os +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, get_topogen +from mininet.topo import Topo + +# Required to instantiate the topology builder class. +from lib.topojson import * +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, verify_bgp_community, + verify_rib, delete_route_maps, create_bgp_community_lists, + interface_status, create_route_maps, create_prefix_lists, + verify_route_maps, check_address_types, + shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify, verify_bgp_attributes) +from lib.topojson import build_topo_from_json, build_config_from_json + + +# Global variables +bgp_convergence = False +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_route_map_topo1.json".format(CWD) +try: + with open(jsonFile, 'r') as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["11.0.20.1/32", "20.0.20.1/32"], + "ipv6": ["1::1/128", "2::1/128"] +} +MASK = {"ipv4": "32", "ipv6": "128"} +NEXT_HOP = { + "ipv4": "10.0.0.2", + "ipv6": "fd00::2" +} +ADDR_TYPES = check_address_types() + + +class CreateTopo(Topo): + """ + Test topology builder + + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function""" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(CreateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ("setup_module :Failed \n Error:" + " {}".format(bgp_convergence)) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}". + format(time.asctime(time.localtime(time.time())))) + logger.info("=" * 40) + + +def test_route_map_inbound_outbound_same_neighbor_p0(request): + """ + TC_34: + Verify if route-maps is applied in both inbound and + outbound direction to same neighbor/interface. + """ + + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[adt][0], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + input_dict_2 = { + "r4": { + "static_routes": [ + { + "network": NETWORK[adt][1], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = create_static_routes(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_5 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "action": "permit", + "network": NETWORK["ipv4"][0] + }], + "pf_list_2_ipv4": [{ + "seqid": 10, + "action": "permit", + "network": NETWORK["ipv4"][1] + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "action": "permit", + "network": NETWORK["ipv6"][0] + }], + "pf_list_2_ipv6": [{ + "seqid": 100, + "action": "permit", + "network": NETWORK["ipv6"][1] + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + "r3": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + }], + "rmap_match_tag_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_tag_1_ipv4", + "direction": "in"}, + {"name": + "rmap_match_tag_1_ipv4", + "direction": "out"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_tag_1_ipv6", + "direction": "in"}, + {"name": + "rmap_match_tag_1_ipv6", + "direction": "out"} + ] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + dut = "r3" + protocol = "bgp" + input_dict_2 = { + "r4": { + "static_routes": [ + { + "network": [NETWORK[adt][1]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + assert result is not True, "Testcase {} : Failed \n" + "Expected behavior: routes are not present in rib \n" + "Error: {}".format( + tc_name, result) + + # Verifying RIB routes + dut = "r4" + input_dict = { + "r1": { + "static_routes": [ + { + "network": [NETWORK[adt][0]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + result = verify_rib(tgen, adt, dut, input_dict, protocol=protocol) + assert result is not True, "Testcase {} : Failed \n " + "Expected behavior: routes are not present in rib \n " + "Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +@pytest.mark.parametrize("prefix_action, rmap_action", [("permit", "permit"), + ("permit", "deny"), ("deny", "permit"), + ("deny", "deny")]) +def test_route_map_with_action_values_combination_of_prefix_action_p0( + request, prefix_action, rmap_action): + """ + TC_36: + Test permit/deny statements operation in route-maps with a permutation and + combination of permit/deny in prefix-lists + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[adt][0], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt] + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Permit in perfix list and route-map + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": prefix_action + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": prefix_action + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": rmap_action, + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_pf_1_ipv4", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": + "rmap_match_pf_1_ipv6", + "direction": "in"} + ] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + dut = "r3" + protocol = "bgp" + input_dict_2 = { + "r1": { + "static_routes": [ + { + "network": [NETWORK[adt][0]], + "no_of_ip": 9, + "next_hop": NEXT_HOP[adt], + } + ] + } + } + + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + if "deny" in [prefix_action, rmap_action]: + assert result is not True, "Testcase {} : Failed \n Error: {}".\ + format(tc_name, result) + else: + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + +def test_route_map_multiple_seq_different_match_set_clause_p0(request): + """ + TC_35: + Test multiple sequence numbers in a single route-map for different + match/set clauses. + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [ + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + }, + "set": { + "aspath": { + "as_num": 500 + } + } + }, + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_2_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }, + { + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + dut = "r3" + protocol = "bgp" + input_dict = { + "r3": { + "route_maps": { + "rmap_match_pf_list1": [{ + "set": { + "med": 50, + } + }], + } + } + } + + static_routes = [NETWORK[adt][0]] + + time.sleep(2) + result = verify_bgp_attributes(tgen, adt, dut, static_routes, + "rmap_match_pf_list1", input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + dut = "r4" + result = verify_bgp_attributes(tgen, adt, dut, static_routes, + "rmap_match_pf_list1", input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + logger.info("Testcase " + tc_name + " :Passed \n") + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_map_set_only_no_match_p0(request): + """ + TC_37: + Test add/remove route-maps with multiple set + clauses and without any match statement.(Set only) + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1": [ + { + "action": "permit", + "set": { + "med": 50, + "localpref": 150, + "weight": 4000 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rmap_match_pf_1", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + time.sleep(2) + for adt in ADDR_TYPES: + input_dict_4 = { + "r3": { + "route_maps": { + "rmap_match_pf_1": [ + { + "action": "permit", + "set": { + "med": 50, + } + } + ] + } + } + } + # Verifying RIB routes + static_routes = [NETWORK[adt][0]] + result = verify_bgp_attributes(tgen, adt, "r3", static_routes, + "rmap_match_pf_1", input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + result = verify_bgp_attributes(tgen, adt, "r4", static_routes, + "rmap_match_pf_1", input_dict_4) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + logger.info("Testcase " + tc_name + " :Passed \n") + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_map_match_only_no_set_p0(request): + """ + TC_38: + Test add/remove route-maps with multiple match + clauses and without any set statement.(Match only) + """ + + tgen = get_topogen() + # test case name + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + for adt in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [{ + "network": NETWORK[adt][0], + "no_of_ip": 1, + "next_hop": NEXT_HOP[adt] + }] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + "r1": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "set": { + "med": 50, + "localpref": 150, + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create ip prefix list + input_dict_5 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" + }] + }, + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + "r3": { + "route_maps": { + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": + "pf_list_1_{}".format(addr_type) + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_7 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + # Verifying RIB routes + static_routes = [NETWORK[adt][0]] + result = verify_bgp_attributes(tgen, adt, "r3", static_routes, + "rmap_match_pf_1", input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + + diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py new file mode 100755 index 0000000000..7009fc97ce --- /dev/null +++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py @@ -0,0 +1,3916 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +"""Following tests are covered to test route-map functionality. +TC_57: + Create route map to match prefix-list and permit inbound + and outbound prefixes and set criteria on match +TC_52: + Test modify set/match clauses in a route-map to see + if it takes immediate effect. +TC_61: + Delete the route maps. +TC_50_1: + Test modify/remove prefix-lists referenced by a + route-map for match statement. +TC_50_1: + Remove prefix-list referencec by route-map match cluase + and verifying it reflecting as intended +TC_51: + Add and remove community-list referencec by route-map match cluase + and verifying it reflecting as intended +TC_45: + Test multiple match statements as part of a route-map's single + sequence number. (Logical OR-ed of multiple match statements) +TC_44: + Test multiple match statements as part of a route-map's single + sequence number. (Logical AND of multiple match statements) +TC_41: + Test add/remove route-maps to specific neighbor and see if + it takes effect as intended +TC_56: + Test clear BGP sessions and interface flaps to see if + route-map properties are intact. +TC_46: + Verify if a blank sequence number can be create(without any + match/set clause) and check if it allows all the traffic/prefixes +TC_48: + Create route map setting local preference and weight to eBGP peeer + and metric to ibgp peer and verifying it should not get advertised +TC_43: + Test multiple set statements as part of a route-map's + single sequence number. +TC_54: + Verify route-maps continue clause functionality. +TC_55: + Verify route-maps goto clause functionality. +TC_53: + Verify route-maps call clause functionality. +TC_58: + Create route map deny inbound and outbound prefixes on + match prefix list and set criteria on match +TC_59: + Create route map to permit inbound prefixes with filter + match tag and set criteria +TC_60 + Create route map to deny outbound prefixes with filter match tag, + and set criteria +""" + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +--------- | R2 | + | +-------+ + |iBGP | + +-------+ | + | R1 | |iBGP + +-------+ | + | | + | iBGP +-------+ eBGP +-------+ + +---------- | R3 |----------| R4 | + +-------+ +-------+ + | + |eBGP + | + +-------+ + | R5 | + +-------+ + + +""" + +import sys +import json +import time +import pytest +import inspect +import os +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, get_topogen +from mininet.topo import Topo + +# Required to instantiate the topology builder class. +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, create_static_routes, + verify_rib, delete_route_maps, create_bgp_community_lists, + interface_status, create_route_maps, create_prefix_lists, + verify_route_maps, check_address_types, verify_bgp_community, + shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify, verify_bgp_attributes) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_route_map_topo2.json".format(CWD) + +try: + with open(jsonFile, 'r') as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["11.0.20.1/32", "11.0.20.2/32"], + "ipv6": ["2::1/128", "2::2/128"] +} + +bgp_convergence = False +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() + + +class BGPRmapTopo(Topo): + """BGPRmapTopo. + + BGPRmap topology 1 + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function.""" + tgen = get_topogen(self) + + # Building topology and configuration from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """setup_module. + + Set up the pytest environment + * `mod`: module name + """ + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("="*40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(BGPRmapTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ('setup_module :Failed \n Error:' + ' {}'.format(bgp_convergence)) + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """teardown_module. + + Teardown the pytest environment. + * `mod`: module name + """ + logger.info("Running teardown_module to delete topology") + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}".format( + time.asctime(time.localtime(time.time())))) + logger.info("="*40) + + +##################################################### +# Tests starting +##################################################### + + +def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): + """ + TC: 57 + Create route map to match prefix-list and permit inbound + and outbound prefixes and set criteria on match + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + } + } + } + } + + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + for addr_type in ADDR_TYPES: + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }, + ], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "med": 50 + } + }, + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_modify_set_match_clauses_in_rmap_p0(): + """ + TC_52: + Test modify set/match clauses in a route-map to see + if it takes immediate effect. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }], + 'pf_list_2_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }], + 'pf_list_2_ipv6': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + # dual stack changes + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + # dual stack changes + for addr_type in ADDR_TYPES: + result4 = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result4) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Modify set/match clause of in-used route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 1000, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 2000 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_delete_route_maps_p1(): + """ + TC_61: + Delete the route maps. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Delete route maps + for addr_type in ADDR_TYPES: + input_dict = { + 'r3': { + 'route_maps': ['rmap_match_tag_1_{}'.format(addr_type)] + } + } + result = delete_route_maps(tgen, input_dict) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + result = verify_route_maps(tgen, input_dict) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_modify_prefix_list_referenced_by_rmap_p0(): + """ + TC_50_1: + Test modify/remove prefix-lists referenced by a + route-map for match statement. + """ + + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit', + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Modify ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'deny' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'deny' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + sleep(5) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_remove_prefix_list_referenced_by_rmap_p0(): + """ + TC_50_1: + Remove prefix-list referencec by route-map match cluase + and verifying it reflecting as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Remove/Delete prefix list + input_dict_3 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit', + 'delete': True + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit', + 'delete': True + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + result = verify_prefix_lists(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Api call to clear bgp, so config changes would be reflected + dut = 'r3' + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_add_and_remove_community_list_referenced_by_rmap_p0(): + """ + TC_51: + Add and remove community-list referencec by route-map match cluase + and verifying it reflecting as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Creating configuration from JSON + # build_config_from_json(tgen, topo) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_5 = { + "r1": { + "route_maps": { + "rm_r1_out_{}".format(addr_type): [{ + "action": "permit", + "set": { + "large_community": {"num": "1:1:1 1:2:3 2:1:1 2:2:2"} + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_6 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rm_r1_out_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rm_r1_out_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create standard large commumity-list + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create route map + input_dict_2 = { + "r3": { + "route_maps": { + "rm_r3_in_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type : { + "large-community-list": {"id": "rmap_lcomm_"+ + addr_type} + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_3 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rm_r3_in_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": "rm_r3_in_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + sleep(5) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verify large-community-list + dut = 'r3' + networks = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + input_dict_4 = { + 'largeCommunity': '1:1:1 1:2:3 2:1:1 2:2:2' + } + for addr_type in ADDR_TYPES: + result = verify_bgp_community(tgen, addr_type, dut, networks[ + addr_type],input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_match_statement_in_route_map_logical_ORed_p0(): + """ + TC_45: + Test multiple match statements as part of a route-map's single + sequence number. (Logical OR-ed of multiple match statements) + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Api call to advertise networks + input_dict_nw1 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": '10.0.30.1/32'} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": '1::1/128'} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_nw1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Api call to advertise networks + input_dict_nw2 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": '20.0.30.1/32'} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": '2::1/128'} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_nw2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_2_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_2_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + input_dict_3_addr_type ={} + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 200 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_6 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.30.1/32"], + "ipv6": ["1::1/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + routes = { + "ipv4": ["20.0.30.1/32"], + "ipv6": ["2::1/128"] + } + for addr_type in ADDR_TYPES: + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_match_statement_in_route_map_logical_ANDed(): + """ + TC_44: + Test multiple match statements as part of a route-map's single + sequence number. (Logical AND of multiple match statements) + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_5 = { + "r1": { + "route_maps": { + "rm_r1_out_{}".format(addr_type): [{ + "action": "permit", + "set": { + "large_community": { + "num": "1:1:1 1:2:3 2:1:1 2:2:2"} + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_6 = { + 'r1': { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rm_r1_out_{}".format(addr_type), + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create standard large commumity-list + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + for addr_type in ADDR_TYPES: + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type : { + "large_community_list": {"id": "rmap_lcomm_"+ + addr_type} + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # Configure neighbor for route map + for addr_type in ADDR_TYPES: + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_{}".format(addr_type), + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # sleep(10) + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_add_remove_rmap_to_specific_neighbor_p0(): + """ + TC_41: + Test add/remove route-maps to specific neighbor and see if + it takes effect as intended + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'deny' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'deny' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : \n' + 'Expected Behavior: Routes are not present in RIB \n' + ' Error: {}'.format( + tc_name, result) + + # Remove applied rmap from neighbor + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in', + "delete": True + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in', + "delete": True + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): + """ + TC_56: + Test clear BGP sessions and interface flaps to see if + route-map properties are intact. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # clear bgp, so config changes would be reflected + dut = 'r3' + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Flap interface to see if route-map properties are intact + # Shutdown interface + dut = "r3" + intf = "r3-r1-eth0" + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(5) + + # Bringup interface + dut = "r3" + intf = "r3-r1-eth0" + shutdown_bringup_interface(tgen, dut, intf, True) + + # Verify BGP convergence once interface is up + result = verify_bgp_convergence(tgen, topo) + assert result is True, ( + 'setup_module :Failed \n Error:' ' {}'.format(result)) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_rmap_without_match_and_set_clause_p0(): + """ + TC_46: + Verify if a blank sequence number can be create(without any + match/set clause) and check if it allows all the traffic/prefixes + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_no_match_set_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '5' + }], + "rmap_no_match_set_2_{}".format(addr_type): [{ + "action": "deny", + 'seq_id': '5' + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_2_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_no_match_set_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): + """ + TC_48: + Create route map setting local preference and weight to eBGP peeer + and metric to ibgp peer and verifying it should not get advertised + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + input_dict_3_addr_type ={} + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + } + }, + "set": { + "med": 50 + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + }}, + "set": { + "localpref": 150 + } + }], + "rmap_match_pf_3_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format( + addr_type) + }}, + "set": { + "weight": 1000 + } + }] + } + } + } + input_dict_3_addr_type[addr_type] = input_dict_3 + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv4", + "direction": 'out' + }] + } + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_3_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_3_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r4' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_2" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: Attributes are not set \n' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r5' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + # Verifying BGP set attributes + dut = 'r5' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + rmap_name = "rmap_match_pf_3" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_3_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3_addr_type[addr_type]) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: Attributes are not set \n' + 'Error: {}'.format( + tc_name, result) + + logger.info("Expected behaviour: {}".format(result)) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_multiple_set_on_single_sequence_in_rmap_p0(): + """ + TC_43: + Test multiple set statements as part of a route-map's + single sequence number. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + "weight": 100, + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_continue_clause_p0(): + """ + TC_54: + Verify route-maps continue clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '10', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + }, + "continue": "30" + }, + { + "action": "permit", + 'seq_id': '20', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + }, + { + "action": "permit", + 'seq_id': '30', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 100 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + rmap_name = "rmap_match_pf_1" + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + seq_id = { + "ipv4": ["10", "30"], + "ipv6": ["10", "30"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3, seq_id[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_goto_clause_p0(): + """ + TC_55: + Verify route-maps goto clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + 'seq_id': '10', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "goto": "30" + }, + { + "action": "permit", + 'seq_id': '20', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 100 + } + }, + { + "action": "permit", + 'seq_id': '30', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + rmap_name = "rmap_match_pf_1" + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + seq_id = { + "ipv4": ["10", "30"], + "ipv6": ["10", "30"] + } + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[ + addr_type],rmap_name, input_dict_3, seq_id[addr_type]) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_route_maps_with_call_clause_p0(): + """ + TC_53: + Verify route-maps call clause functionality. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150 + }, + "call": "rmap_match_pf_2_{}".format(addr_type) + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 200 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv6", + "direction": 'in' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying BGP set attributes + dut = 'r3' + routes = { + "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], + "ipv6": ["1::1/128", "1::2/128"] + } + rmap_name = "rmap_match_pf_1" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_1_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + rmap_name = "rmap_match_pf_2" + for addr_type in ADDR_TYPES: + rmap_name = "rmap_match_pf_2_{}".format(addr_type) + result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], + rmap_name, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): + """ + TC_58: + Create route map deny inbound and outbound prefixes on + match prefix list and set criteria on match + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + # Create ip prefix list + input_dict_2 = { + 'r3': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': 'any', + 'action': 'permit' + }] + }, + 'ipv6': { + 'pf_list_1_ipv6': [{ + 'seqid': 100, + 'network': 'any', + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create route map + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r3": { + "route_maps": { + "rmap_match_pf_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "localpref": 150, + } + }], + "rmap_match_pf_2_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r3': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_1_ipv4", + "direction": 'in' + }] + } + } + }, + "r4": { + "dest_link": { + "r3": { + "route_maps": [{ + "name": + "rmap_match_pf_2_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + input_dict = topo["routers"] + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r4' + protocol = 'bgp' + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behaviour: routes are not present \n ' + 'Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): + """ + TC_59: + Create route map to permit inbound prefixes with filter + match tag and set criteria + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "permit", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + + for addr_type in ADDR_TYPES: + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + + +def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): + """ + TC_60 + Create route map to deny outbound prefixes with filter match tag, + and set criteria + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip('skipped because of BGP Convergence failure') + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Create Static routes + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call to redistribute static routes + input_dict_1 = { + "r1": { + "bgp": { + "local_as": 100, + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r1": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [{ + "action": "deny", + "match": { + addr_type: { + "tag": "4001" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + 'r1': { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv4", + "direction": 'out' + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": + "rmap_match_tag_1_ipv6", + "direction": 'out' + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Verifying RIB routes + dut = 'r3' + protocol = 'bgp' + + for addr_type in ADDR_TYPES: + input_dict = { + "r1": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": "Null0", + "tag": 4001 + } + ] + } + } + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is not True, 'Testcase {} : Failed \n' + 'Expected behavior: routes are denied \n Error: {}'.format( + tc_name, result) + + write_test_footer(tc_name) + + # Uncomment next line for debugging + # tgen.mininet_cli() + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 149a420a32..547a5949a3 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -11,16 +11,17 @@ for rtr in l3mdev_rtrs: rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: - luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP,LOWER_UP','pass','VRF cust1 up') - luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4: .*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') + luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP','pass','VRF cust1 intf up') + luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4.*UP','pass','VRF cust1 IP intf up') + luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'192.168','pass','VRF cust1 IP config') luCommand(rtr, 'ip route show vrf {}-cust1'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust1 interface route') -luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up') -luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') +luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP','pass','VRF cust2 up') +luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP.* 192.168','pass','VRF cust1 IP config') luCommand(rtr, 'ip route show vrf r4-cust2'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust2 interface route') rtrs = ['ce1', 'ce2', 'ce3'] for rtr in rtrs: luCommand(rtr, 'ip route show','192.168...0/24 dev ce.-eth0','pass','CE interface route') luCommand(rtr,'ping 192.168.1.1 -c 1',' 0. packet loss','wait','CE->PE ping') -luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up') +luCommand('ce4', 'ip link show type vrf ce4-cust2','cust2: .*UP','pass','VRF cust2 up') luCommand('ce4', 'ip route show vrf ce4-cust2','192.168...0/24 dev ce.-eth0','pass','CE interface route') luCommand('ce4','ping 192.168.2.1 -c 1 -I ce4-cust2',' 0. packet loss','wait','CE4->PE4 ping') diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref deleted file mode 100644 index fb193265be..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,31 +0,0 @@ -{ - "neighbors":[ - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} - diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index 7c4d0ab58c..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "2.2.2.2":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 2270c3fdde..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r1/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "2.2.2.2":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.1.2", - "ifaceName":"r1-eth1:10.0.1.1" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.2.3", - "ifaceName":"r1-eth2:10.0.2.1" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref deleted file mode 100644 index 1376579757..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index a982c1cbd3..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - } - ], - "3.3.3.3":[ - { - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index 18ffbc2f8a..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r2/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.1.1", - "ifaceName":"r2-eth1:10.0.1.2" - }, - "3.3.3.3":{ - "priority":1, - "state":"Full/DR", - "address":"10.0.3.3", - "ifaceName":"r2-eth2:10.0.3.2" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref deleted file mode 100644 index 41de304b2b..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref +++ /dev/null @@ -1,30 +0,0 @@ -{ - "neighbors":[ - { - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - }, - { - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3", - "retransmitCounter":0, - "requestCounter":0, - "dbSummaryCounter":0 - } - ] - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh deleted file mode 100644 index d7e0e42405..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-no-neigh +++ /dev/null @@ -1,18 +0,0 @@ -{ - "1.1.1.1":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - } - ], - "2.2.2.2":[ - { - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } - ] -} diff --git a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist b/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist deleted file mode 100644 index b0669742ab..0000000000 --- a/tests/topotests/ldp-vpls-topo1/r3/show_ip_ospf_neighbor.ref-old-nolist +++ /dev/null @@ -1,14 +0,0 @@ -{ - "1.1.1.1":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.2.1", - "ifaceName":"r3-eth1:10.0.2.3" - }, - "2.2.2.2":{ - "priority":1, - "state":"Full/Backup", - "address":"10.0.3.2", - "ifaceName":"r3-eth2:10.0.3.3" - } -} diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index 0948c2e41b..ce651c50cd 100755 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -144,9 +144,6 @@ def setup_module(mod): ) tgen.start_router() - for router in router_list.values(): - if router.has_version('<', '3'): - tgen.set_error('unsupported version') def teardown_module(mod): "Teardown the pytest environment" @@ -180,30 +177,8 @@ def test_ospf_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - # Old output (before FRR PR1383) didn't show a list of neighbors. - # Check for dict object and compare to old output if this is the case - tgen = get_topogen() - router = tgen.gears['r1'] - output = router.vtysh_cmd("show ip ospf neighbor json", isjson=True) - - # We could have either old format (without "neighbors" and direct list - # of IP's or new format from PR1659 with "neighbors". - # Trying old formats first and fall back to new format - # - # New format: neighbors have dict instead of list of dicts (PR1723). - if output.has_key('neighbors'): - if isinstance(output['neighbors'], dict): - reffile = "show_ip_ospf_neighbor.json" - else: - reffile = "show_ip_ospf_neighbor.ref" - else: - if isinstance(output["2.2.2.2"], dict): - reffile = "show_ip_ospf_neighbor.ref-old-nolist" - else: - reffile = "show_ip_ospf_neighbor.ref-no-neigh" - for rname in ['r1', 'r2', 'r3']: - router_compare_json_output(rname, "show ip ospf neighbor json", reffile) + router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json") def test_rib(): logger.info("Test: verify RIB") diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index c05e14a95e..bfc34c25e4 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1229,6 +1229,150 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): return True +@retry(attempts=3, wait=4, return_is_str=True) +def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, + input_dict, seq_id=None): + """ + API will verify BGP attributes set by Route-map for given prefix and + DUT. it will run "show bgp ipv4/ipv6 {prefix_address} json" command + in DUT to verify BGP attributes set by route-map, Set attributes + values will be read from input_dict and verified with command output. + + * `tgen`: topogen object + * `addr_type` : ip type, ipv4/ipv6 + * `dut`: Device Under Test + * `static_routes`: Static Routes for which BGP set attributes needs to be + verified + * `rmap_name`: route map name for which set criteria needs to be verified + * `input_dict`: defines for which router, AS numbers needs + * `seq_id`: sequence number of rmap, default is None + + Usage + ----- + input_dict = { + "r3": { + "route_maps": { + "rmap_match_pf_1_ipv4": [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "localpref": 150, + "weight": 100 + } + }], + "rmap_match_pf_2_ipv6": [{ + "action": "permit", + 'seq_id': '5', + "match": { + addr_type: { + "prefix_lists": "pf_list_1_" + addr_type + } + }, + "set": { + "med": 50 + } + }] + } + } + } + result = verify_bgp_attributes(tgen, 'ipv4', "r1", "10.0.20.1/32", + rmap_match_pf_1_ipv4, input_dict) + + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_bgp_attributes()") + for router, rnode in tgen.routers().iteritems(): + if router != dut: + continue + + logger.info('Verifying BGP set attributes for dut {}:'.format(router)) + + for static_route in static_routes: + cmd = "show bgp {} {} json".format(addr_type, static_route) + show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True) + print("show_bgp_json $$$$$", show_bgp_json) + + dict_to_test = [] + tmp_list = [] + for rmap_router in input_dict.keys(): + for rmap, values in input_dict[rmap_router][ + "route_maps"].items(): + print("rmap == rmap_name $$$$1", rmap, rmap_name) + if rmap == rmap_name: + print("rmap == rmap_name $$$$", rmap, rmap_name) + dict_to_test = values + for rmap_dict in values: + if seq_id is not None: + if type(seq_id) is not list: + seq_id = [seq_id] + + if "seq_id" in rmap_dict: + rmap_seq_id = \ + rmap_dict["seq_id"] + for _seq_id in seq_id: + if _seq_id == rmap_seq_id: + tmp_list.append(rmap_dict) + if tmp_list: + dict_to_test = tmp_list + + print("dict_to_test $$$$", dict_to_test) + for rmap_dict in dict_to_test: + if "set" in rmap_dict: + for criteria in rmap_dict["set"].keys(): + if criteria not in show_bgp_json[ + "paths"][0]: + errormsg = ("BGP attribute: {}" + " is not found in" + " cli: {} output " + "in router {}". + format(criteria, + cmd, + router)) + return errormsg + + if rmap_dict["set"][criteria] == \ + show_bgp_json["paths"][0][ + criteria]: + logger.info("Verifying BGP " + "attribute {} for" + " route: {} in " + "router: {}, found" + " expected value:" + " {}". + format(criteria, + static_route, + dut, + rmap_dict[ + "set"][ + criteria])) + else: + errormsg = \ + ("Failed: Verifying BGP " + "attribute {} for route:" + " {} in router: {}, " + " expected value: {} but" + " found: {}". + format(criteria, + static_route, + dut, + rmap_dict["set"] + [criteria], + show_bgp_json[ + 'paths'][ + 0][criteria])) + return errormsg + + logger.debug("Exiting lib API: verify_bgp_attributes()") + return True + @retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute): diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index f2d33f94ae..ba8a4cb0f4 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -21,6 +21,7 @@ from collections import OrderedDict from datetime import datetime from time import sleep +from copy import deepcopy from subprocess import call from subprocess import STDOUT as SUB_STDOUT from subprocess import PIPE as SUB_PIPE @@ -208,6 +209,7 @@ def create_common_configuration(tgen, router, data, config_type=None, "interface_config": "! Interfaces Config\n", "static_route": "! Static Route Config\n", "prefix_list": "! Prefix List Config\n", + "bgp_community_list": "! Community List Config\n", "route_maps": "! Route Maps Config\n", "bgp": "! BGP Config\n" }) @@ -547,13 +549,11 @@ def generate_ips(network, no_of_ips): Returns list of IPs. based on start_ip and no_of_ips - * `network` : from here the ip will start generating, start_ip will be - first ip + * `network` : from here the ip will start generating, + start_ip will be * `no_of_ips` : these many IPs will be generated - - Limitation: It will generate IPs only for ip_mask 32 - """ + ipaddress_list = [] if type(network) is not list: network = [network] @@ -893,6 +893,7 @@ def create_static_routes(tgen, input_dict, build=False): """ result = False logger.debug("Entering lib API: create_static_routes()") + input_dict = deepcopy(input_dict) try: for router in input_dict.keys(): if "static_routes" not in input_dict[router]: @@ -918,16 +919,21 @@ def create_static_routes(tgen, input_dict, build=False): next_hop = static_route["next_hop"] network = static_route["network"] - ip_list = generate_ips([network], no_of_ip) + if type(network) is not list: + network = [network] + + ip_list = generate_ips(network, no_of_ip) for ip in ip_list: addr_type = validate_ip_address(ip) + if addr_type == "ipv4": cmd = "ip route {} {}".format(ip, next_hop) else: cmd = "ipv6 route {} {}".format(ip, next_hop) if tag: - cmd = "{} {}".format(cmd, str(tag)) + cmd = "{} tag {}".format(cmd, str(tag)) + if admin_distance: cmd = "{} {}".format(cmd, admin_distance) @@ -1112,11 +1118,11 @@ def create_route_maps(tgen, input_dict, build=False): "prefix_list": "pf_list_1" } - "large-community-list": "{ + "large-community-list": { "id": "community_1", "exact_match": True } - "community": { + "community_list": { "id": "community_2", "exact_match": True } @@ -1152,12 +1158,11 @@ def create_route_maps(tgen, input_dict, build=False): result = False logger.debug("Entering lib API: create_route_maps()") - + input_dict = deepcopy(input_dict) try: for router in input_dict.keys(): if "route_maps" not in input_dict[router]: - errormsg = "route_maps not present in input_dict" - logger.debug(errormsg) + logger.debug("route_maps not present in input_dict") continue rmap_data = [] for rmap_name, rmap_value in \ @@ -1187,10 +1192,41 @@ def create_route_maps(tgen, input_dict, build=False): rmap_name, rmap_action, seq_id )) + if "continue" in rmap_dict: + continue_to = rmap_dict["continue"] + if continue_to: + rmap_data.append("on-match goto {}". + format(continue_to)) + else: + logger.error("In continue, 'route-map entry " + "sequence number' is not provided") + return False + + if "goto" in rmap_dict: + go_to = rmap_dict["goto"] + if go_to: + rmap_data.append("on-match goto {}". + format(go_to)) + else: + logger.error("In goto, 'Goto Clause number' is not" + " provided") + return False + + if "call" in rmap_dict: + call_rmap = rmap_dict["call"] + if call_rmap: + rmap_data.append("call {}". + format(call_rmap)) + else: + logger.error("In call, 'destination Route-Map' is" + " not provided") + return False + # Verifying if SET criteria is defined if "set" in rmap_dict: set_data = rmap_dict["set"] - + ipv4_data = set_data.setdefault("ipv4", {}) + ipv6_data = set_data.setdefault("ipv6", {}) local_preference = set_data.setdefault("localpref", None) metric = set_data.setdefault("med", None) @@ -1199,7 +1235,10 @@ def create_route_maps(tgen, input_dict, build=False): community = set_data.setdefault("community", {}) large_community = set_data.setdefault( "large_community", {}) + large_comm_list = set_data.setdefault( + "large_comm_list", {}) set_action = set_data.setdefault("set_action", None) + nexthop = set_data.setdefault("nexthop", None) # Local Preference if local_preference: @@ -1243,42 +1282,84 @@ def create_route_maps(tgen, input_dict, build=False): rmap_data.append(cmd) else: - logger.errror("In large_community, AS Num not" - " provided") + logger.error("In large_community, AS Num not" + " provided") + return False + if large_comm_list: + id = large_comm_list.setdefault("id", None) + del_comm = large_comm_list.setdefault("delete", + None) + if id: + cmd = "set large-comm-list {}".format(id) + if del_comm: + cmd = "{} delete".format(cmd) + + rmap_data.append(cmd) + else: + logger.error("In large_comm_list 'id' not" + " provided") return False # Weight if weight: - rmap_data.append("set weight {}".format( + rmap_data.append("set weight {} \n".format( weight)) - + if ipv6_data: + nexthop = ipv6_data.setdefault("nexthop",None) + if nexthop: + rmap_data.append("set ipv6 next-hop \ + {}".format(nexthop)) # Adding MATCH and SET sequence to RMAP if defined if "match" in rmap_dict: match_data = rmap_dict["match"] ipv4_data = match_data.setdefault("ipv4", {}) ipv6_data = match_data.setdefault("ipv6", {}) - community = match_data.setdefault("community-list", - {}) + community = match_data.setdefault( + "community_list",{}) large_community = match_data.setdefault( - "large-community-list", {} + "large_community", {} + ) + large_community_list = match_data.setdefault( + "large_community_list", {} ) - tag = match_data.setdefault("tag", None) if ipv4_data: - prefix_name = ipv4_data.setdefault("prefix_lists", - None) + # fetch prefix list data from rmap + prefix_name = \ + ipv4_data.setdefault("prefix_lists", + None) if prefix_name: - rmap_data.append("match ip address prefix-list" - " {}".format(prefix_name)) + rmap_data.append("match ip address" + " prefix-list {}".format(prefix_name)) + + # fetch tag data from rmap + tag = ipv4_data.setdefault("tag", None) + if tag: + rmap_data.append("match tag {}".format(tag)) + + # fetch large community data from rmap + large_community_list = ipv4_data.setdefault( + "large_community_list",{}) + large_community = match_data.setdefault( + "large_community", {}) + if ipv6_data: prefix_name = ipv6_data.setdefault("prefix_lists", None) if prefix_name: - rmap_data.append("match ipv6 address " - "prefix-list {}". - format(prefix_name)) - if tag: - rmap_data.append("match tag {}".format(tag)) + rmap_data.append("match ipv6 address" + " prefix-list {}".format(prefix_name)) + + # fetch tag data from rmap + tag = ipv6_data.setdefault("tag", None) + if tag: + rmap_data.append("match tag {}".format(tag)) + + # fetch large community data from rmap + large_community_list = ipv6_data.setdefault( + "large_community_list",{}) + large_community = match_data.setdefault( + "large_community", {}) if community: if "id" not in community: @@ -1293,10 +1374,9 @@ def create_route_maps(tgen, input_dict, build=False): cmd = "{} exact-match".format(cmd) rmap_data.append(cmd) - if large_community: if "id" not in large_community: - logger.error("'num' is mandatory for " + logger.error("'id' is mandatory for " "large-community-list in match " "criteria") return False @@ -1306,7 +1386,19 @@ def create_route_maps(tgen, input_dict, build=False): "exact_match", False) if exact_match: cmd = "{} exact-match".format(cmd) - + rmap_data.append(cmd) + if large_community_list: + if "id" not in large_community_list: + logger.error("'id' is mandatory for " + "large-community-list in match " + "criteria") + return False + cmd = "match large-community {}".format( + large_community_list["id"]) + exact_match = large_community_list.setdefault( + "exact_match", False) + if exact_match: + cmd = "{} exact-match".format(cmd) rmap_data.append(cmd) result = create_common_configuration(tgen, router, @@ -1320,10 +1412,178 @@ def create_route_maps(tgen, input_dict, build=False): logger.error(errormsg) return errormsg - logger.debug("Exiting lib API: create_prefix_lists()") + logger.debug("Exiting lib API: create_route_maps()") + return result + + +def delete_route_maps(tgen, input_dict): + """ + Delete ip route maps from device + + * `tgen` : Topogen object + * `input_dict` : for which router, + route map has to be deleted + + Usage + ----- + # Delete route-map rmap_1 and rmap_2 from router r1 + input_dict = { + "r1": { + "route_maps": ["rmap_1", "rmap__2"] + } + } + result = delete_route_maps("ipv4", input_dict) + + Returns + ------- + errormsg(str) or True + """ + logger.info("Entering lib API: delete_route_maps()") + + for router in input_dict.keys(): + route_maps = input_dict[router]["route_maps"][:] + rmap_data = input_dict[router] + rmap_data["route_maps"] = {} + for route_map_name in route_maps: + rmap_data["route_maps"].update({ + route_map_name: + [{ + "delete": True + }] + }) + + return create_route_maps(tgen, input_dict) + + +def create_bgp_community_lists(tgen, input_dict, build=False): + """ + Create bgp community-list or large-community-list on the devices as per + the arguments passed. Takes list of communities in input. + + Parameters + ---------- + * `tgen` : Topogen object + * `input_dict` : Input dict data, required when configuring from testcase + * `build` : Only for initial setup phase this is set as True. + Usage + ----- + input_dict_1 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "rmap_lcomm_{}".format(addr_type), + "value": "1:1:1 1:2:3 2:1:1 2:2:2", + "large": True + } + ] + } + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + """ + + result = False + logger.debug("Entering lib API: create_bgp_community_lists()") + input_dict = deepcopy(input_dict) + try: + for router in input_dict.keys(): + if "bgp_community_lists" not in input_dict[router]: + errormsg = "bgp_community_lists not present in input_dict" + logger.debug(errormsg) + continue + + config_data = [] + + community_list = input_dict[router]["bgp_community_lists"] + for community_dict in community_list: + del_action = community_dict.setdefault("delete", False) + community_type = community_dict.setdefault("community_type", + None) + action = community_dict.setdefault("action", None) + value = community_dict.setdefault("value", '') + large = community_dict.setdefault("large", None) + name = community_dict.setdefault("name", None) + if large: + cmd = "bgp large-community-list" + else: + cmd = "bgp community-list" + + if not large and not (community_type and action and value): + errormsg = "community_type, action and value are " \ + "required in bgp_community_list" + logger.error(errormsg) + return False + + try: + community_type = int(community_type) + cmd = "{} {} {} {}".format(cmd, community_type, action, + value) + except ValueError: + + cmd = "{} {} {} {} {}".format( + cmd, community_type, name, action, value) + + if del_action: + cmd = "no {}".format(cmd) + + config_data.append(cmd) + + result = create_common_configuration(tgen, router, config_data, + "bgp_community_list", + build=build) + + except InvalidCLIError: + # Traceback + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: create_bgp_community_lists()") return result +def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False): + """ + Shutdown or bringup router's interface " + + * `tgen` : Topogen object + * `dut` : Device under test + * `intf_name` : Interface name to be shut/no shut + * `ifaceaction` : Action, to shut/no shut interface, + by default is False + + Usage + ----- + dut = "r3" + intf = "r3-r1-eth0" + # Shut down ineterface + shutdown_bringup_interface(tgen, dut, intf, False) + + # Bring up ineterface + shutdown_bringup_interface(tgen, dut, intf, True) + + Returns + ------- + errormsg(str) or True + """ + + from topotest import interface_set_status + router_list = tgen.routers() + if ifaceaction: + logger.info("Bringing up interface : {}".format(intf_name)) + else: + logger.info("Shutting down interface : {}".format(intf_name)) + + interface_set_status(router_list[dut], intf_name, + ifaceaction) + + if ifaceaction: + # Disabling v6 link local once interfac comes up back + disable_v6_link_local(tgen, dut, intf_name=intf_name) + + ############################################# # Verification APIs ############################################# @@ -1625,5 +1885,133 @@ def verify_prefix_lists(tgen, input_dict): logger.info("Prefix list %s is/are not present in the router" " from router %s", prefix_list, router) - logger.debug("Exiting lib API: verify_prefix_lissts()") + logger.debug("Exiting lib API: verify_prefix_lists()") + return True + + +@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2) +def verify_route_maps(tgen, input_dict): + """ + Running "show route-map" command and verifying given route-map + is present in router. + Parameters + ---------- + * `tgen` : topogen object + * `input_dict`: data to verify prefix lists + Usage + ----- + # To verify rmap_1 and rmap_2 are present in router r1 + input_dict = { + "r1": { + "route_maps": ["rmap_1", "rmap_2"] + } + } + result = verify_route_maps(tgen, input_dict) + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_route_maps()") + + for router in input_dict.keys(): + if router not in tgen.routers(): + continue + + rnode = tgen.routers()[router] + # Show ip route-map + show_route_maps = rnode.vtysh_cmd("show route-map") + + # Verify route-map is deleted + route_maps = input_dict[router]["route_maps"] + for route_map in route_maps: + if route_map in show_route_maps: + errormsg = ("Route map {} is not deleted from router" + " {}".format(route_map, router)) + return errormsg + + logger.info("Route map %s is/are deleted successfully from" + " router %s", route_maps, router) + + logger.debug("Exiting lib API: verify_route_maps()") + return True + + +@retry(attempts=3, wait=4, return_is_str=True) +def verify_bgp_community(tgen, addr_type, router, network, input_dict=None): + """ + API to veiryf BGP large community is attached in route for any given + DUT by running "show bgp ipv4/6 {route address} json" command. + + Parameters + ---------- + * `tgen`: topogen object + * `addr_type` : ip type, ipv4/ipv6 + * `dut`: Device Under Test + * `network`: network for which set criteria needs to be verified + * `input_dict`: having details like - for which router, community and + values needs to be verified + Usage + ----- + networks = ["200.50.2.0/32"] + input_dict = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None) + + Returns + ------- + errormsg(str) or True + """ + + logger.info("Entering lib API: verify_bgp_community()") + if router not in tgen.routers(): + return False + + rnode = tgen.routers()[router] + + logger.debug("Verifying BGP community attributes on dut %s: for %s " + "network %s", router, addr_type, network) + + for net in network: + cmd = "show bgp {} {} json".format(addr_type, net) + show_bgp_json = rnode.vtysh_cmd(cmd, isjson=True) + logger.info(show_bgp_json) + if "paths" not in show_bgp_json: + return "Prefix {} not found in BGP table of router: {}". \ + format(net, router) + + as_paths = show_bgp_json["paths"] + found = False + for i in range(len(as_paths)): + if "largeCommunity" in show_bgp_json["paths"][i] or \ + "community" in show_bgp_json["paths"][i]: + found = True + logger.info("Large Community attribute is found for route:" + " %s in router: %s", net, router) + if input_dict is not None: + for criteria, comm_val in input_dict.items(): + show_val = show_bgp_json["paths"][i][criteria][ + "string"] + if comm_val == show_val: + logger.info("Verifying BGP %s for prefix: %s" + " in router: %s, found expected" + " value: %s", criteria, net, router, + comm_val) + else: + errormsg = "Failed: Verifying BGP attribute" \ + " {} for route: {} in router: {}" \ + ", expected value: {} but found" \ + ": {}".format( + criteria, net, router, comm_val, + show_val) + return errormsg + + if not found: + errormsg = ( + "Large Community attribute is not found for route: " + "{} in router: {} ".format(net, router)) + return errormsg + + logger.debug("Exiting lib API: verify_bgp_community()") return True diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index 7a00fe4c50..fff5a1e82f 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -35,6 +35,7 @@ from lib.common_config import ( create_static_routes, create_prefix_lists, create_route_maps, + create_bgp_community_lists ) from lib.bgp import create_router_bgp @@ -179,6 +180,7 @@ def build_config_from_json(tgen, topo, save_bkup=True): ("links", create_interfaces_cfg), ("static_routes", create_static_routes), ("prefix_lists", create_prefix_lists), + ("bgp_community_list", create_bgp_community_lists), ("route_maps", create_route_maps), ("bgp", create_router_bgp) ]) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index a762e9555c..08126f6885 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2422,6 +2422,53 @@ DEFUN (vtysh_show_error_code, return CMD_SUCCESS; } +/* Northbound. */ +DEFUN (show_yang_operational_data, + show_yang_operational_data_cmd, + "show yang operational-data XPATH$xpath\ + [{\ + format <json$json|xml$xml>\ + |translate WORD$translator_family\ + }]" DAEMONS_LIST, + SHOW_STR + "YANG information\n" + "Show YANG operational data\n" + "XPath expression specifying the YANG data path\n" + "Set the output format\n" + "JavaScript Object Notation\n" + "Extensible Markup Language\n" + "Translate operational data\n" + "YANG module translator\n" + DAEMONS_STR) +{ + int idx_protocol = argc - 1; + char *fcmd = argv_concat(argv, argc - 1, 0); + int ret = vtysh_client_execute_name(argv[idx_protocol]->text, fcmd); + XFREE(MTYPE_TMP, fcmd); + return ret; +} + +DEFUNSH(VTYSH_ALL, debug_nb, + debug_nb_cmd, + "[no] debug northbound\ + [<\ + callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ + |notifications$notifications\ + |events$events\ + >]", + NO_STR + DEBUG_STR + "Northbound debugging\n" + "Callbacks\n" + "Configuration\n" + "State\n" + "RPC\n" + "Notifications\n" + "Events\n") +{ + return CMD_SUCCESS; +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -2548,10 +2595,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd, } DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, - "no log facility [FACILITY]", NO_STR + "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]", + NO_STR "Logging control\n" "Reset syslog facility to default (daemon)\n" - "Syslog facility\n") + LOG_FACILITY_DESC) { return CMD_SUCCESS; } @@ -4017,6 +4065,11 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd); install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd); + /* northbound */ + install_element(VIEW_NODE, &show_yang_operational_data_cmd); + install_element(ENABLE_NODE, &debug_nb_cmd); + install_element(CONFIG_NODE, &debug_nb_cmd); + /* misc lib show commands */ install_element(VIEW_NODE, &vtysh_show_memory_cmd); install_element(VIEW_NODE, &vtysh_show_modules_cmd); diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 3313dc2f20..faa880eff4 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -61,6 +61,13 @@ module frr-isisd { "This type defines IS-IS level of an object."; } + typedef extended-circuit-id { + type uint32; + description + "This type defines the extended circuit ID + associated with an interface."; + } + typedef network-type { type enumeration { enum "unknown" { @@ -95,6 +102,20 @@ module frr-isisd { pattern, An example LSP ID is 0143.0438.AeF0.02-01"; } + typedef snpa { + type string { + length "0 .. 20"; + } + description + "This type defines the Subnetwork Point + of Attachment (SNPA) format. + The SNPA should be encoded according to the rules + specified for the particular type of subnetwork + being used. As an example, for an ethernet subnetwork, + the SNPA is encoded as a MAC address like + '00aa.bbcc.ddee'."; + } + typedef system-id { type string { pattern "[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}"; @@ -275,6 +296,399 @@ module frr-isisd { } } + grouping interface-config { + description "Interface configuration grouping"; + + leaf area-tag { + type string; + mandatory true; + description + "Area-tag associated to this circuit."; + } + + leaf ipv4-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv4 traffic over this circuit."; + } + + leaf ipv6-routing { + type boolean; + default "false"; + description + "Routing IS-IS IPv6 traffic over this circuit."; + } + + leaf circuit-type { + type level; + default "level-1-2"; + description + "IS-type of this circuit."; + } + + leaf bfd-monitoring { + type boolean; + default false; + description "Monitor IS-IS peers on this circuit."; + } + + container csnp-interval { + description + "Complete Sequence Number PDU (CSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..600"; + } + units "seconds"; + default "10"; + description + "CNSP interval for level-2"; + } + } + + container psnp-interval { + description + "Partial Sequence Number PDU (PSNP) generation interval."; + leaf level-1 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PNSP interval for level-1"; + } + + leaf level-2 { + type uint16 { + range "1..120"; + } + units "seconds"; + default "2"; + description + "PCNSP interval for level-2"; + } + } + + container hello { + description + "Parameters related to IS-IS hello PDUs."; + leaf padding { + type boolean; + default "true"; + description + "Add padding to IS-IS hello PDUs."; + } + + container interval { + description + "Interval between consecutive hello messages."; + leaf level-1 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-1; interval will depend on multiplier."; + } + + leaf level-2 { + type uint32 { + range "1..600"; + } + units "seconds"; + default "3"; + description + "Holding time for level-2; interval will depend on multiplier."; + } + } + + container multiplier { + description + "Multiplier for the hello messages holding time."; + leaf level-1 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + + leaf level-2 { + type uint16 { + range "2..100"; + } + default "10"; + description + "Multiplier for the hello holding time."; + } + } + } + + container metric { + description + "Default metric for this IS-IS circuit."; + leaf level-1 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-1 metric for this IS-IS circuit."; + } + + leaf level-2 { + type uint32 { + range "0..16777215"; + } + must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + default "10"; + description + "Default level-2 metric for this IS-IS circuit."; + } + } + + container priority { + description + "Priority for Designated Router election."; + leaf level-1 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-1 priority for this IS-IS circuit."; + } + + leaf level-2 { + type uint8 { + range "0..127"; + } + default "64"; + description + "Level-2 priority for this IS-IS circuit."; + } + } + + leaf network-type { + type network-type; + default "broadcast"; + must "(. = \"point-to-point\") or (. = \"broadcast\")"; + description + "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; + } + + leaf passive { + type boolean; + default "false"; + description + "Interface is in passive mode."; + } + + container password { + presence "Present if a password is set for this IS interface."; + uses isis-password; + } + + leaf disable-three-way-handshake { + type boolean; + default "false"; + description + "Disables three-way handshake when creating new adjacencies."; + } + + container multi-topology { + description + "IS-IS topologies configured on this circuit."; + leaf ipv4-unicast { + type boolean; + default "true"; + description + "IPv4 unicast topology."; + } + + leaf ipv4-multicast { + type boolean; + default "true"; + description + "IPv4 multicast topology."; + } + + leaf ipv4-management { + type boolean; + default "true"; + description + "IPv4 management topology."; + } + + leaf ipv6-unicast { + type boolean; + default "true"; + description + "IPv6 unicast topology."; + } + + leaf ipv6-multicast { + type boolean; + default "true"; + description + "IPv6 multicast topology."; + } + + leaf ipv6-management { + type boolean; + default "true"; + description + "IPv6 management topology."; + } + + leaf ipv6-dstsrc { + type boolean; + default "true"; + description + "IPv6 destination-source topology."; + } + } + } + + grouping adjacency-state { + container adjacencies { + config false; + list adjacency { + leaf neighbor-sys-type { + type level; + description + "Level capability of neighboring system"; + } + leaf neighbor-sysid { + type system-id; + description + "The system-id of the neighbor"; + } + leaf neighbor-extended-circuit-id { + type extended-circuit-id; + description + "Circuit ID of the neighbor"; + } + leaf neighbor-snpa { + type snpa; + description + "SNPA of the neighbor"; + } + leaf hold-timer { + type uint16; + units seconds; + description + "The holding time in seconds for this + adjacency. This value is based on + received hello PDUs and the elapsed + time since receipt."; + } + leaf neighbor-priority { + type uint8 { + range "0 .. 127"; + } + description + "Priority of the neighboring IS for becoming + the DIS."; + } + leaf state { + type adj-state-type; + description + "This leaf describes the state of the interface."; + } + + description + "List of operational adjacencies."; + } + description + "This container lists the adjacencies of + the local node."; + } + description + "Adjacency state"; + } + + grouping event-counters { + container event-counters { + config false; + leaf adjacency-changes { + type uint32; + description + "The number of times an adjacency state change has + occurred on this interface."; + } + leaf adjacency-number { + type uint32; + description + "The number of adjacencies on this interface."; + } + leaf init-fails { + type uint32; + description + "The number of times initialization of this + interface has failed. This counts events such + as PPP NCP failures. Failures to form an + adjacency are counted by adjacency-rejects."; + } + leaf adjacency-rejects { + type uint32; + description + "The number of times an adjacency has been + rejected on this interface."; + } + leaf id-len-mismatch { + type uint32; + description + "The number of times an IS-IS PDU with an ID + field length different from that for this + system has been received on this interface."; + } + leaf max-area-addresses-mismatch { + type uint32; + description + "The number of times an IS-IS PDU has been + received on this interface with the + max area address field differing from that of + this system."; + } + leaf authentication-type-fails { + type uint32; + description + "Number of authentication type mismatches."; + } + leaf authentication-fails { + type uint32; + description + "Number of authentication key failures."; + } + description "IS-IS interface event counters."; + } + description + "Grouping for IS-IS interface event counters"; + } + + grouping interface-state { + description + "IS-IS interface operational state."; + uses adjacency-state; + uses event-counters; + } + grouping notification-instance-hdr { description "Instance specific IS-IS notification data grouping"; @@ -313,7 +727,7 @@ module frr-isisd { } leaf extended-circuit-id { - type uint32; + type extended-circuit-id; description "Eextended circuit-id of the interface."; } @@ -733,270 +1147,8 @@ module frr-isisd { presence "Present if an IS-IS circuit is defined for this interface."; description "IS-IS interface parameters."; - leaf area-tag { - type string; - mandatory true; - description - "Area-tag associated to this circuit."; - } - - leaf ipv4-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv4 traffic over this circuit."; - } - - leaf ipv6-routing { - type boolean; - default "false"; - description - "Routing IS-IS IPv6 traffic over this circuit."; - } - - leaf circuit-type { - type level; - default "level-1-2"; - description - "IS-type of this circuit."; - } - - leaf bfd-monitoring { - type boolean; - default false; - description "Monitor IS-IS peers on this circuit."; - } - - container csnp-interval { - description - "Complete Sequence Number PDU (CSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..600"; - } - units "seconds"; - default "10"; - description - "CNSP interval for level-2"; - } - } - - container psnp-interval { - description - "Partial Sequence Number PDU (PSNP) generation interval."; - leaf level-1 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PNSP interval for level-1"; - } - - leaf level-2 { - type uint16 { - range "1..120"; - } - units "seconds"; - default "2"; - description - "PCNSP interval for level-2"; - } - } - - container hello { - description - "Parameters related to IS-IS hello PDUs."; - leaf padding { - type boolean; - default "true"; - description - "Add padding to IS-IS hello PDUs."; - } - - container interval { - description - "Interval between consecutive hello messages."; - leaf level-1 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-1; interval will depend on multiplier."; - } - - leaf level-2 { - type uint32 { - range "1..600"; - } - units "seconds"; - default "3"; - description - "Holding time for level-2; interval will depend on multiplier."; - } - } - - container multiplier { - description - "Multiplier for the hello messages holding time."; - leaf level-1 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - - leaf level-2 { - type uint16 { - range "2..100"; - } - default "10"; - description - "Multiplier for the hello holding time."; - } - } - } - - container metric { - description - "Default metric for this IS-IS circuit."; - leaf level-1 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-1 metric for this IS-IS circuit."; - } - - leaf level-2 { - type uint32 { - range "0..16777215"; - } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; - default "10"; - description - "Default level-2 metric for this IS-IS circuit."; - } - } - - container priority { - description - "Priority for Designated Router election."; - leaf level-1 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-1 priority for this IS-IS circuit."; - } - - leaf level-2 { - type uint8 { - range "0..127"; - } - default "64"; - description - "Level-2 priority for this IS-IS circuit."; - } - } - - leaf network-type { - type network-type; - default "broadcast"; - must "(. = \"point-to-point\") or (. = \"broadcast\")"; - description - "Explicitly configured type of IS-IS circuit (broadcast or point-to-point)."; - } - - leaf passive { - type boolean; - default "false"; - description - "Interface is in passive mode."; - } - - container password { - presence "Present if a password is set for this IS interface."; - uses isis-password; - } - - leaf disable-three-way-handshake { - type boolean; - default "false"; - description - "Disables three-way handshake when creating new adjacencies."; - } - - container multi-topology { - description - "IS-IS topologies configured on this circuit."; - leaf ipv4-unicast { - type boolean; - default "true"; - description - "IPv4 unicast topology."; - } - - leaf ipv4-multicast { - type boolean; - default "true"; - description - "IPv4 multicast topology."; - } - - leaf ipv4-management { - type boolean; - default "true"; - description - "IPv4 management topology."; - } - - leaf ipv6-unicast { - type boolean; - default "true"; - description - "IPv6 unicast topology."; - } - - leaf ipv6-multicast { - type boolean; - default "true"; - description - "IPv6 multicast topology."; - } - - leaf ipv6-management { - type boolean; - default "true"; - description - "IPv6 management topology."; - } - - leaf ipv6-dstsrc { - type boolean; - default "true"; - description - "IPv6 destination-source topology."; - } - } + uses interface-config; + uses interface-state; } } diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang new file mode 100644 index 0000000000..00ba02a3c3 --- /dev/null +++ b/yang/frr-nexthop.yang @@ -0,0 +1,200 @@ +module frr-nexthop { + yang-version 1.1; + namespace "http://frrouting.org/yang/nexthop"; + prefix frr-nexthop; + + import ietf-inet-types { + prefix inet; + } + + import ietf-routing-types { + prefix rt-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines a model for managing FRR nexthop information."; + + revision 2019-08-15 { + description + "Initial revision."; + } + + typedef gateway-address { + type inet:ip-address; + } + + typedef nexthop-type { + type enumeration { + enum "ifindex" { + value 1; + description + "Specific interface."; + } + enum "ip4" { + value 2; + description + "IPv4 address."; + } + enum "ip4-ifindex" { + value 3; + description + "IPv4 address and interface."; + } + enum "ip6" { + value 4; + description + "IPv6 address."; + } + enum "ip6-ifindex" { + value 5; + description + "IPv6 address and interface."; + } + enum "blackhole" { + value 6; + description + "Unreachable or prohibited."; + } + } + description + "Nexthop types."; + } + + typedef blackhole-type { + type enumeration { + enum "unspec" { + value 0; + description + "Generic unreachable."; + } + enum "null" { + value 1; + description + "Null type."; + } + enum "reject" { + value 2; + description + "ICMP unreachable."; + } + enum "prohibited" { + value 3; + description + "ICMP admin-prohibited."; + } + } + default "null"; + description + "Nexthop blackhole types."; + } + + /* + * Nexthop object + */ + grouping frr-nexthop { + leaf nh-type { + type nexthop-type; + mandatory true; + description + "The nexthop type."; + } + + leaf gateway { + type gateway-address; + description + "The nexthop gateway address."; + } + + leaf vrf { + type string; + description + "The nexthop vrf name, if different from the route."; + } + + leaf interface { + type string; + description + "The nexthop egress interface."; + } + + leaf bh-type { + type blackhole-type; + description + "A blackhole sub-type, if the nexthop is a blackhole type."; + } + + leaf flags { + type uint32; + description + "The nexthop's raw flags value."; + } + + leaf is-duplicate { + type empty; + description + "Duplicate nexthop; will be ignored."; + } + leaf is-recursive { + type empty; + description + "Nexthop must be resolved through another gateway."; + } + leaf is-onlink { + type empty; + description + "Nexthop is directly connected."; + } + leaf is-active { + type empty; + description + "Nexthop is active."; + } + + uses rt-types:mpls-label-stack { + description + "Nexthop's MPLS label stack."; + } + + leaf mtu { + type uint32; + description + "The nexthop's specific MTU."; + } + + } // End of nexthop + + /* + * Nexthop-group container + */ + grouping frr-nexthop-group { + description + "A nexthop-group, represented as a list of nexthop objects."; + + leaf name { + type string; + description + "The nexthop-group name."; + } + + list entry { + key "id"; + description + "A list of nexthop objects."; + leaf id { + type uint32; + description + "Identifies a nexthop within a nexthop group; the entries + are ordered by id value, and the value has no other meaning."; + } + + uses frr-nexthop; + + } + } // End of frr-nexthop-group + +} diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang new file mode 100644 index 0000000000..b5ca5c9a40 --- /dev/null +++ b/yang/frr-zebra.yang @@ -0,0 +1,1788 @@ +module frr-zebra { + yang-version 1.1; + namespace "http://frrouting.org/yang/zebra"; + prefix frr-zebra; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import frr-route-types { + prefix frr-route-types; + } + + import ietf-routing-types { + prefix rt-types; + } + + import frr-nexthop { + prefix frr-nh; + } + + import frr-interface { + prefix frr-interface; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines a model for managing the FRR zebra daemon."; + + revision 2019-06-01 { + description + "Initial revision."; + } + + typedef unix-timestamp { + type uint32; + units "seconds"; + description + "An absolute time in seconds since the unix epoch."; + } + + /* + * Multicast RPF mode configurable type + */ + typedef mcast-rpf-lookup-mode { + type enumeration { + enum "none" { + value 0; + description + "No mode set."; + } + enum "mrib-only" { + value 1; + description + "Lookup in unicast RIB only."; + } + enum "urib-only" { + value 2; + description + "Lookup in multicast RIB only."; + } + enum "mrib-then-urib" { + value 3; + description + "Try multicast RIB first, fall back to unicast RIB."; + } + enum "lower-distance" { + value 4; + description + "Lookup both unicast and mcast, use entry with lower distance."; + } + enum "longer-prefix" { + value 5; + description + "Lookup both unicast and mcast, use entry with longer prefix."; + } + } + description + "Multicast RPF lookup behavior"; + } + + /* + * Common route data, shared by v4 and v6 routes. + */ + grouping route-common { + description + "Common information about a route."; + + leaf vrf { + type string; + description + "The route's vrf name."; + } + + leaf distance { + type uint8; + description + "Admin distance based on routing protocol."; + } + leaf metric { + type uint32; + description + "Route metric value."; + } + leaf tag { + type uint32 { + range "1..4294967295"; + } + description + "Route tag value."; + } + + leaf is-selected { + type empty; + description + "Route is the selected or preferred route for the prefix."; + } + leaf is-installed { + type empty; + description + "Route is installed in the FIB."; + } + leaf is-failed { + type empty; + description + "Route installation in FIB has failed."; + } + leaf is-queued { + type empty; + description + "Route has a pending FIB operation that has not completed."; + } + + leaf internal-flags { + type int32; + description + "Internal flags for the route."; + } + leaf internal-status { + type int32; + description + "Internal status for the route."; + } + + leaf uptime { + type uint32; + units "seconds"; + description + "Uptime for the route."; + } + + container nexthop-group { + description + "Nexthop information for the route."; + + uses frr-nh:frr-nexthop-group; + } + + } // End of route-common + + /* + * IPv4 Route object. + */ + grouping ip4-route { + description + "An IPv4 route."; + + leaf prefix { + type inet:ipv4-prefix; + description + "IP address (in the form A.B.C.D) and prefix length, + separated by the slash (/) character. The range of + values for the prefix-length is 0 to 32."; + } + leaf "protocol" { + type frr-route-types:frr-route-types-v4; + description + "The protocol owning the route."; + } + + uses route-common; + + } // End of ip4-route + + /* + * IPv6 Route object. + */ + grouping ip6-route { + description + "An IPv6 route."; + + leaf prefix { + type inet:ipv6-prefix; + description + "The route's IPv6 prefix."; + } + leaf "protocol" { + type frr-route-types:frr-route-types-v6; + description + "The protocol owning the route."; + } + + uses route-common; + + } // End of ip6-route + + /* + * VxLAN Network Identifier type + */ + typedef vni-id-type { + type uint32 { + range "0..16777215"; + } + description + "A VxLAN network identifier value."; + } + + typedef vni-vtep-flood-type { + type enumeration { + enum "head-end-repl" { + value 0; + description + "Head-end replication."; + } + enum "disabled" { + value 1; + description + "Flooding disabled."; + } + enum pim-sm { + value 2; + description + "Multicast PIM-SM."; + } + } + } + + /* + * Information about EVPN VNIs + */ + grouping vni-information { + choice type-choice { + case l2 { + leaf is-layer2 { + type empty; + description + "Information about an L2 VNI."; + } + leaf vtep-count { + type uint32; + description + "Number of VTEPs."; + } + } + case l3 { + leaf is-layer3 { + type empty; + description + "Information about an L3 VNI."; + } + } + } + leaf vni-id { + type vni-id-type; + description + "The VNI identifier."; + } + leaf vxlan-ifname { + type frr-interface:interface-ref; + description + "The VxLAN interface name."; + } + leaf mac-count { + type uint32; + description + "Number of valid MACs."; + } + leaf neighbor-count { + type uint32; + description + "Number of neighbors."; + } + leaf vrf { + type string; + description + "The tenant VRF."; + } + leaf local-vtep-addr { + type inet:ipv4-address; + description + "The local VTEP IP address."; + } + } + + /* + * Detailed EVPN VNI information for L2. + */ + grouping vni-l2-detail { + leaf if-index { + type uint32; + description + "The VxLAN ifindex."; + } + leaf advertise-gw { + type empty; + description + "The gateway MAC-IP is being advertised."; + } + leaf mcase-group { + type rt-types:ipv4-multicast-group-address; + description + "The VNI multicast group for BUM traffic."; + } + list remote-vtep-list { + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + leaf vtep-flood { + type vni-vtep-flood-type; + } + } + } + + /* + * Detailed EVPN VNI information for L3. + */ + grouping vni-l3-detail { + leaf svi-interface { + type string; + description + "The SVI interface."; + } + leaf is-up { + type empty; + description + "The state is active."; + } + leaf prefix-only { + type empty; + description + "Prefix routes only"; + } + leaf router-mac { + type yang:mac-address; + description + "The VNI Router MAC address."; + } + list vni-list { + description + "A list of the associated L2 VNIs."; + leaf vni-id { + type vni-id-type; + description + "An L2 VNI identifier."; + } + } + } + + /* + * Debug options + */ + grouping zebra-debugs { + leaf debug-events { + type boolean; + description "Debug ZAPI events."; + } + leaf debug-zapi-send { + type boolean; + description "Debug ZAPI messages sent."; + } + leaf debug-zapi-recv { + type boolean; + description "Debug ZAPI messages received."; + } + leaf debug-zapi-detail { + type boolean; + description "Debug ZAPI details."; + } + leaf debug-kernel { + type boolean; + description "Debug kernel events."; + } + leaf debug-kernel-msg-send { + type boolean; + description "Debug kernel messages sent."; + } + leaf debug-kernel-msg-recv { + type boolean; + description "Debug kernel messages received."; + } + leaf debug-rib { + type boolean; + description "Debug RIB processing."; + } + leaf debug-rib-detail { + type boolean; + description "Debug RIB processing details."; + } + leaf debug-fpm { + type boolean; + description "Debug the FIB Push Interface subsystem."; + } + leaf debug-nht { + type boolean; + description "Debug Nexthop-tracking."; + } + leaf debug-nht-detail { + type boolean; + description "Debug Nexthop-tracking details."; + } + leaf debug-mpls { + type boolean; + description "Debug MPLS."; + } + leaf debug-vxlan { + type boolean; + description "Debug VxLAN."; + } + leaf debug-pw { + type boolean; + description "Debug pseudowires."; + } + leaf debug-dplane { + type boolean; + description "Debug the dataplane subsystem."; + } + leaf debug-dplane-detail { + type boolean; + description "Debug dataplane subsystem details."; + } + leaf debug-mlag { + type boolean; + description "Debug MLAG."; + } + } + + /* + * Main zebra container + */ + container zebra { + description + "Data model for the Zebra daemon."; + + leaf mcast-rpf-lookup { + type frr-zebra:mcast-rpf-lookup-mode; + default "mrib-then-urib"; + description + "Multicast RPF lookup behavior."; + } + + leaf ip-forwarding { + type boolean; + description + "IP forwarding status."; + } + + leaf ipv6-forwarding { + type enumeration { + enum "unknown" { + value -1; + description + "Unknown state."; + } + enum "off" { + value 0; + description + "IPv6 forwarding disabled."; + } + enum "on" { + value 1; + description + "IPv6 forwarding enabled."; + } + } + description + "IPv6 forwarding status."; + } + + leaf workqueue-hold-timer { + type uint32 { + range "0..10000"; + } + units "milliseconds"; + default "10"; + description + "Work-queue processing hold timer, in milliseconds."; + } + + leaf zapi-packets { + type uint32 { + range "1..10000"; + } + default "1000"; + description + "Number of ZAPI packets to process before relinquishing + the main thread."; + } + + container import-kernel-table { + description + "Parameters to use when importing IPv4 routes from a non-main kernel + routing table."; + + leaf table-id { + type uint32 { + range "1..252"; + } + description + "The kernel table id."; + } + leaf distance { + type uint32 { + range "1..255"; + } + default "15"; + description + "The admin distance to use for imported routes."; + } + leaf route-map { + type string; + description + "A route-map to filter imported routes."; + } + } + + leaf allow-external-route-update { + type empty; + description + "Allow FRR-controlled routes to be overwritten by external processes"; + } + + leaf dplane-queue-limit { + type uint32 { + range "0..10000"; + } + default "200"; + description + "Limit on the number of updates queued to the dataplane subsystem."; + } + + list vrf-vni-mapping { + description + "EVPN VNI mapping corresponding to a VRF."; + key "vrf-id"; + leaf vrf-id { + type uint32; + description + "The identifier for a VRF."; + } + leaf vni-id { + type vni-id-type; + description + "The VNI id to map to the VRF."; + } + leaf prefix-only { + type empty; + description + "Prefix routes only."; + } + } + + /* + * Debug options + */ + container debugs { + uses zebra-debugs; + } /* End of debugs */ + + /* + * End of configuration attributes + */ + + /* + * Operational data. + */ + container state { + config false; + description + "Operational data."; + + } // End of operational / state container + + } // End of zebra container + + /* + * RPCs + */ + rpc get-route-information { + description + "Retrieve IPv4 or IPv6 unicast routes."; + + input { + + choice ip-type { + case v4 { + leaf ipv4 { + type empty; + mandatory true; + description + "Retrieve IPv4 routes."; + } + leaf prefix-v4 { + type inet:ipv4-prefix; + description + "Retrieve routes matching a specific prefix."; + } + leaf supernets-only { + type empty; + description + "Skip routes that are subnets of classful prefix sizes."; + } + } + case v6 { + leaf ipv6 { + type empty; + mandatory true; + description + "Retrieve IPv6 routes."; + } + leaf prefix-v6 { + type inet:ipv6-prefix; + description + "Retrieve routes matching a specific prefix."; + } + } + } + + choice vrf-choice { + case single { + leaf vrf { + type string; + description + "Retrieve routes in a non-default vrf."; + } + } + case all { + leaf all-vrfs { + type empty; + description + "Retrieve routes from all vrfs."; + } + } + } + + leaf fib-routes { + type empty; + description + "Retrieve FIB routes rather than RIB routes."; + } + + leaf table-id { + type uint32 { + range "1..4294967295"; + } + description + "Routing table id to retrieve."; + } + + leaf protocol { + type frr-route-types:frr-route-types-v4; + description + "Retrieve routes from a specific protocol daemon."; + } + leaf ospf-instance { + type uint32 { + range "1..65535"; + } + must '../protocol = "ospf"'; + description + "Retrieve routes from a specific OSPF instance."; + } + + choice detail { + case det { + leaf include-detail { + type empty; + description + "Include detailed information."; + } + } + case summ { + leaf summary { + type empty; + description + "Include summary information only."; + } + } + } + } // End of input + + output { + choice route-list { + case v4 { + container routes-v4 { + description + "IPv4 route information."; + list route { + uses ip4-route; + } + } + } + case v6 { + container routes-v6 { + description + "IPv6 route information."; + list route { + uses ip6-route; + } + } + } + } + } // End of output + + } // End get-route-information + + rpc get-v6-mroute-info { + description + "Retrieve IPv6 multicast routes."; + + input { + choice vrf-choice { + case single { + leaf vrf { + type string; + description + "Retrieve routes in a non-default vrf."; + } + } + case all { + leaf all-vrfs { + type empty; + description + "Retrieve routes from all vrfs."; + } + } + } + } + + output { + container routes { + description + "IPv6 mcast route information."; + list route { + uses ip6-route; + } + } + } + + }// End get-v6-mroute-info + + + rpc get-vrf-info { + description + "Retrieve VRF information; the default VRF is elided."; + + // Note: no input clause. + + output { + list vrf-list { + leaf name { + type string; + description + "The VRF name"; + } + leaf is-user-config { + type empty; + description + "The VRF was configured by an admin."; + } + leaf vrf-id { + type uint32; + description + "The VRF id."; + } + choice vrf-type { + case inactive { + leaf is-inactive { + type empty; + description + "The VRF is inactive."; + } + } + case netns { + leaf netns-name { + type string; + description + "The net namespace name associated with the VRF."; + } + } + case table { + leaf table-id { + type uint32; + description + "The table-id associated with the VRF."; + } + } + } + } + } + } // End get-vrf-info + + rpc get-vrf-vni-info { + description + "Retrieve mappings between EVPN VNI and VRF."; + + // Note: no input clause. + + output { + list vrf-vni-list { + leaf vrf-name { + type string; + description + "The VRF name."; + } + leaf vni-id { + type vni-id-type; + description + "The EVPN VNI."; + } + leaf vxlan-if-name { + type frr-interface:interface-ref; + description + "The VxLAN interface name."; + } + leaf svi-if-name { + type frr-interface:interface-ref; + description + "The SVI interface name."; + } + leaf router-mac-addr { + type yang:mac-address; + description + "Router MAC address."; + } + leaf is-up { + type empty; + description + "The state is active."; + } + } + } + } // End get-vrf-vni-info + + rpc get-evpn-info { + description + "Retrieve global information about EVPN."; + + // Note: No input clause. + + output { + leaf l2vni-count { + type uint32; + description + "Number of L2 VNIs."; + } + leaf l3vni-count { + type uint32; + description + "Number of L3 VNIs."; + } + leaf advertise-gateway { + type empty; + description + "Advertise the gateway MAC-IP."; + } + leaf advertise-svi { + type empty; + description + "Advertise SVI MAC-IP."; + } + leaf dup-detect { + type empty; + description + "Duplicate address detection is enabled."; + } + leaf dad-max-moves { + type uint32; + description + "Maximum moves allowed before address is considered duplicate."; + } + leaf dad-timeout { + type uint32; + units "seconds"; + description + "Duplicate address detection timeout."; + } + leaf dad-freeze { + type empty; + description + "Duplicate address detection freeze enabled."; + } + + choice dad-freeze-choice { + case freeze-permanent { + leaf dad-freeze-perm { + type empty; + description + "Duplicate address detection freeze is permanent."; + } + } + case freeze-time { + leaf dad-freeze-time { + type uint32; + units "seconds"; + description + "Duplicate address detection freeze timer."; + } + } + } + } + } // End get-evpn-info + + rpc get-vni-info { + // If no vni is specified, retrieve global list. + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + } + } + leaf detailed-info { + type empty; + description + "Retrieve detailed information."; + } + } + + output { + list vni-list { + description + "Information about EVPN VNI objects."; + + uses vni-information; + + choice detail-choice { + case l2 { + description + "Detailed L2 information."; + uses vni-l2-detail; + } + case l3 { + description + "Detailed L3 information."; + uses vni-l3-detail; + } + } + } + } + } // End get-vni-info + + rpc get-evpn-vni-rmac { + description + "Retrieve information about VxLAN VNI RMACs."; + + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + leaf vni-rmac { + type yang:mac-address; + description + "A single RMAC address."; + } + } + } + } + + output { + list rmac-info-list { + leaf rmac { + type yang:mac-address; + description + "The RMAC address."; + } + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + leaf refcount { + type uint32; + description + "The refcount of the RMAC."; + } + list prefix-list { + leaf prefix-item { + type inet:ip-prefix; + description + "IP prefixes associated with the RMAC."; + } + } + } + } + } // End get-evpn-vni-rmac + + rpc get-evpn-vni-nexthops { + description + "Retrieve information about EVPN nexthops."; + + input { + choice vni-choice { + default "all-vnis"; + case all-vnis { + leaf all-vnis { + type empty; + description + "Retrieve information about all VNIs."; + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information about a specific EVPN VNI."; + } + leaf vni-ipaddr { + type inet:ip-address; + description + "A single host IP address (v4 or v6)."; + } + } + } + } + + output { + list nh-info-list { + leaf ip-addr { + type inet:ip-address; + description + "The nexthop IP address."; + } + leaf mac-addr { + type yang:mac-address; + description + "The nexthop MAC address."; + } + leaf refcount { + type uint32; + description + "The refcount of the RMAC."; + } + list prefix-list { + leaf prefix-item { + type inet:ip-prefix; + description + "IP prefixes associated with the RMAC."; + } + } + } + } + } // End get-evpn-vni-vteps + + rpc clear-evpn-dup-addr { + description + "Clear duplicate address detection state for one or all VNIs."; + input { + choice clear-dup-choice { + case all-case { + leaf all-vnis { + type empty; + description + "Clear all VNIs."; + } + } + case single-case { + leaf vni-id { + type vni-id-type; + description + "Clear state for a single EVPN VNI."; + } + choice ip-mac-choice { + description + "Clear state for a specific MAC or IP address."; + case ip-case { + leaf vni-ipaddr { + type inet:ip-address; + description + "A specific IP address (v4 or v6)."; + } + } + case mac-case { + leaf mac-addr { + type yang:mac-address; + description + "A specific MAC address."; + } + } + } + } + } + } + } // End clear-evpn-dup-addr + + rpc get-evpn-macs { + description + "Retrieve information about EVPN MAC addresses."; + input { + choice all-choice { + default "all-vni"; + + case all-vni { + leaf all-vnis { + type empty; + description + "Retrieve information for all VNIs."; + } + choice all-choices { + case detail-case { + leaf all-detail { + type empty; + description + "Include detailed results."; + } + } + case vtep-case { + leaf all-vtep-addr { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case dup-case { + leaf all-dup { + type empty; + description + "Show duplicate addresses."; + } + } + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information for a single VNI."; + } + choice single-choices { + case detail-case { + leaf single-detail { + type empty; + description + "Include detailed results."; + } + } + case mac-case { + leaf single-mac { + type yang:mac-address; + description + "A specific MAC address."; + } + } + case vtep-case { + leaf single-vtep { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case dup-case { + leaf single-dup { + type empty; + description + "Show duplicate addresses."; + } + } + } + } + } + } // End of input section + + output { + list mac-list { + leaf mac-addr { + type yang:mac-address; + description + "The MAC address."; + } + leaf vni { + type vni-id-type; + description + "The VNI value."; + } + leaf local-sequence { + type uint32; + description + "Local sequence number."; + } + leaf remote-sequence { + type uint32; + description + "Remote sequence number."; + } + leaf dad-count { + type uint32; + description + "Duplicate detection counter."; + } + leaf is-duplicate { + type empty; + description + "Duplicate MAC detected."; + } + leaf dup-detect-time { + type unix-timestamp; + description + "If a duplicate, the detection time."; + } + container dup-detect-started { + leaf dup-detect-start { + type unix-timestamp; + description + "Duplicate detection process start time."; + } + leaf dup-count { + type uint32; + description + "Duplicate detection count."; + } + } + + leaf is-auto { + type empty; + description + "This is an Auto MAC."; + } + leaf is-sticky { + type empty; + description + "This is a sticky MAC."; + } + leaf is-default-gw { + type empty; + description + "This is a default-gateway MAC."; + } + leaf is-remote-gw { + type empty; + description + "This is a remote-gateway MAC."; + } + list neighbor-list { + leaf neighbor-addr { + type inet:ip-address; + description + "Neighbor address."; + } + leaf is-active { + type empty; + description + "Neighbor is active."; + } + } + + leaf mac-count { + type uint32; + description + "Number of MACs (local and remote)."; + } + choice local-rem-choice { + case local-case { + leaf intf { + type frr-interface:interface-ref; + description + "The local interface name."; + } + leaf vlan { + type uint32; + description + "A VLAN id."; + } + } + case remote-case { + leaf vtep-addr { + type inet:ipv4-address; + description + "The remote VTEP IP address."; + } + } + } + } + } + } // End get-evpn-macs + + rpc get-evpn-arp-cache { + description + "Retrieve information about EVPN neighbor cache entries."; + input { + choice all-choice { + default "all-vni"; + + case all-vni { + leaf all-vnis { + type empty; + description + "Retrieve information for all VNIs."; + } + choice all-choices { + case detail-case { + leaf all-detail { + type empty; + description + "Include detailed results."; + } + } + case dup-case { + leaf all-dup { + type empty; + description + "Show duplicates."; + } + } + } + } + case single-vni { + leaf vni-id { + type vni-id-type; + description + "Retrieve information for a single VNI."; + } + choice single-choices { + case vtep-case { + leaf single-vtep { + type inet:ipv4-address; + description + "A single VTEP address."; + } + } + case neighbor-case { + leaf neighbor-addr { + type inet:ip-address; + description + "A single neighbor address."; + } + } + case dup-case { + leaf single-dup { + type empty; + description + "Show duplicates."; + } + } + } + } + } + } // End input section + + output { + list vni-list { + container vni-container { + description + "Information for one VNI."; + leaf vni-id { + type vni-id-type; + description + "The VNI id."; + } + list neigh-list { + description + "Information about a VNI's neighbor cache."; + + leaf mac-addr { + type yang:mac-address; + description + "A neighbor MAC address."; + } + leaf ip-addr { + type inet:ip-address; + description + "A neighbor IP address."; + } + leaf state-active { + type empty; + description + "Indicates whether the entry is active."; + } + + choice local-remote-choice { + case local-case { + leaf is-local { + type empty; + description + "The entry is local."; + } + } + case remote-case { + leaf is-remote { + type empty; + description + "The entry is remote."; + } + } + } + + leaf is-dup { + type empty; + description + "The entry is a detected duplicate."; + } + leaf is-default-gw { + type empty; + description + "The entry is a default gateway."; + } + leaf is-router { + type empty; + description + "The entry is a router."; + } + leaf local-sequence { + type uint32; + description + "The local sequence number."; + } + leaf remote-sequence { + type uint32; + description + "The remote sequence number."; + } + leaf remote-vtep { + type inet:ipv4-address; + description + "The remote VTEP address."; + } + } + } + } + } + } // End get-evpn-arp-cache + + rpc get-pbr-ipset { + input { + leaf name { + type string; + description + "An optional specific IPset name."; + } + } + + output { + list ipset-list { + leaf name { + type string; + description + "The IPset name."; + } + leaf ipset-type { + type enumeration { + enum "net-net" { + value 1; + description + ""; + } + enum "net-port-net" { + value 2; + description + ""; + } + enum "net-port" { + value 3; + description + ""; + } + enum "net" { + value 4; + description + ""; + } + } + } + leaf src-prefix { + type inet:ip-prefix; + description + ""; + } + leaf dest-prefix { + type inet:ip-prefix; + description + ""; + } + leaf src-port { + type inet:port-number; + description + ""; + } + leaf dest-port { + type inet:port-number; + description + ""; + } + + choice proto-choice { + description + "Filter UDP/TCP only, or a specific protocol number."; + case udp-tcp-case { + leaf is-udp-tcp { + type empty; + description + "Filter TCP/UDP ports only."; + } + } + case proto-case { + leaf proto { + type uint32; + description + "Filter a specific protocol number."; + } + } + } + container icmp-info { + description + "Additional information for ICMP filters."; + leaf type-min { + type uint8; + description + ""; + } + leaf type-max { + type uint8; + description + ""; + } + leaf code-min { + type uint8; + description + ""; + } + leaf code-max { + type uint8; + description + ""; + } + } + container ipset-stats { + leaf is-unique { + type empty; + description + ""; + } + leaf packet-counter { + type uint64; + description + ""; + } + leaf bytes-counter { + type uint64; + description + ""; + } + } + } + } + } // End get-pbr-ipset + + rpc get-pbr-iptable { + input { + leaf name { + type string; + description + "An optional single IPtable name."; + } + } + + output { + list iptable-list { + leaf name { + type string; + description + "The IPtable name."; + } + leaf unique-val { + type uint32; + description + ""; + } + choice action-choice { + description "The table action."; + case drop-case { + leaf action-drop { + type empty; + description ""; + } + } + case redirect-case { + leaf action-redirect { + type empty; + description ""; + } + } + } + leaf min-packet { + type uint32; + description + ""; + } + leaf max-packet { + type uint32; + description + ""; + } + leaf lookup-src-port { + type empty; + description + ""; + } + leaf lookup-dst-port { + type empty; + description + ""; + } + leaf tcp-flags { + type uint16; + description + ""; + } + leaf tcp-flags-mask { + type uint16; + description + ""; + } + leaf protocol-val { + type uint32; + description "An IP protocol number."; + } + container dscp-info { + leaf dscp-value { + type uint32; + description + "A DSCP value to match."; + } + leaf invert-match { + type empty; + description + "If set, exclude the specified value"; + } + } + container fragment-info { + leaf fragment-val { + type uint32; + description "An IP fragment value."; + } + leaf invert-match { + type empty; + description + "If set, exclude the specified value."; + } + } + container iptable-stats { + leaf packet-counter { + type uint64; + description + ""; + } + leaf bytes-counter { + type uint64; + description + ""; + } + } + container rule-info { + description + "Information about a rule, for redirect tables."; + leaf table-id { + type uint32; + description + "The rule table id."; + } + leaf table-fwmark { + type uint32; + description + "The firewall mark for the rule."; + } + } + } + } + } // End get-pbr-iptable + + /* + * Handy 'all-at-once' api to retrieve debugs + */ + rpc get-debugs { + output { + uses zebra-debugs; + } + } // End get-debugs + + augment "/frr-interface:lib/frr-interface:interface" { + description + "Extends interface model with Zebra-related parameters."; + container zebra { + list ip4-addr-list { + description + "IPv4 prefixes for an interface."; + key "ip4-prefix"; + leaf ip4-prefix { + type inet:ipv4-prefix; + description + "IPv4 address prefix."; + } + leaf ip4-peer { + type inet:ipv4-prefix; + description + "Peer prefix, for peer-to-peer interfaces."; + } + leaf label { + type string; + description + "Optional string label for the address."; + } + } + list ip6-addr-list { + description + "IPv6 prefixes for an interface."; + key "ip6-prefix"; + leaf ip6-prefix { + type inet:ipv6-prefix; + description + "IPv6 address prefix."; + } + leaf label { + type string; + description + "Optional string label for the address."; + } + } + + leaf multicast { + type boolean; + description + "Multicast flag for the interface."; + } + leaf link-detect { + type boolean; + description + "Link-detection for the interface."; + } + leaf shutdown { + type boolean; + description + "Interface admin status."; + } + leaf bandwidth { + type uint32 { + range "1..100000"; + } + description + "Link bandwidth informational parameter, in megabits."; + } + + // TODO -- link-params for (experimental/partial TE use in IGP extensions) + + } + } // End interface model augmentation + +} diff --git a/zebra/connected.c b/zebra/connected.c index 6b92945c63..87cf8c8f20 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -385,7 +385,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) return; break; default: - zlog_info("Unknown AFI: %s", afi2str(afi)); + zlog_warn("Unknown AFI: %s", afi2str(afi)); break; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index bb6b9973bf..35cb3a6f5f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -365,7 +365,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, } } -static int get_iflink_speed(struct interface *interface) +static int get_iflink_speed(struct interface *interface, int *error) { struct ifreq ifdata; struct ethtool_cmd ecmd; @@ -373,6 +373,8 @@ static int get_iflink_speed(struct interface *interface) int rc; const char *ifname = interface->name; + if (error) + *error = 0; /* initialize struct */ memset(&ifdata, 0, sizeof(ifdata)); @@ -393,6 +395,9 @@ static int get_iflink_speed(struct interface *interface) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Failure to read interface %s speed: %d %s", ifname, errno, safe_strerror(errno)); + /* no vrf socket creation may probably mean vrf issue */ + if (error) + *error = -1; return 0; } /* Get the current link state for the interface */ @@ -404,6 +409,9 @@ static int get_iflink_speed(struct interface *interface) zlog_debug( "IOCTL failure to read interface %s speed: %d %s", ifname, errno, safe_strerror(errno)); + /* no device means interface unreachable */ + if (errno == ENODEV && error) + *error = -1; ecmd.speed_hi = 0; ecmd.speed = 0; } @@ -413,9 +421,9 @@ static int get_iflink_speed(struct interface *interface) return (ecmd.speed_hi << 16) | ecmd.speed; } -uint32_t kernel_get_speed(struct interface *ifp) +uint32_t kernel_get_speed(struct interface *ifp, int *error) { - return get_iflink_speed(ifp); + return get_iflink_speed(ifp, error); } static int netlink_extract_bridge_info(struct rtattr *link_data, @@ -696,7 +704,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; - ifp->speed = get_iflink_speed(ifp); + ifp->speed = get_iflink_speed(ifp, NULL); ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; /* Set zebra interface type */ @@ -1032,7 +1040,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { - zlog_debug("%s: NULL address", __func__); + zlog_debug("%s: Local Interface Address is NULL for %s", + __func__, ifp->name); return -1; } diff --git a/zebra/interface.c b/zebra/interface.c index baf94ad285..ef03cf87f6 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -70,10 +70,19 @@ static int if_zebra_speed_update(struct thread *thread) struct zebra_if *zif = ifp->info; uint32_t new_speed; bool changed = false; + int error = 0; zif->speed_update = NULL; - new_speed = kernel_get_speed(ifp); + new_speed = kernel_get_speed(ifp, &error); + + /* error may indicate vrf not available or + * interfaces not available. + * note that loopback & virtual interfaces can return 0 as speed + */ + if (error < 0) + return 1; + if (new_speed != ifp->speed) { zlog_info("%s: %s old speed: %u new speed: %u", __PRETTY_FUNCTION__, ifp->name, ifp->speed, @@ -261,8 +270,10 @@ struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns, for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) { ifp = (struct interface *)rn->info; - if (ifp && strcmp(ifp->name, ifname) == 0) + if (ifp && strcmp(ifp->name, ifname) == 0) { + route_unlock_node(rn); return (ifp); + } } return NULL; @@ -1563,7 +1574,7 @@ struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1}; #endif /* Show all interfaces to vty. */ DEFPY(show_interface, show_interface_cmd, - "show interface [vrf NAME$name] [brief$brief]", + "show interface [vrf NAME$vrf_name] [brief$brief]", SHOW_STR "Interface status and configuration\n" VRF_CMD_HELP_STR @@ -1575,8 +1586,8 @@ DEFPY(show_interface, show_interface_cmd, interface_update_stats(); - if (name) - VRF_GET_ID(vrf_id, name, false); + if (vrf_name) + VRF_GET_ID(vrf_id, vrf_name, false); /* All interface print. */ vrf = vrf_lookup_by_id(vrf_id); @@ -2041,13 +2052,13 @@ DEFUN (link_params_enable, /* This command could be issue at startup, when activate MPLS TE */ /* on a new interface or after a ON / OFF / ON toggle */ /* In all case, TE parameters are reset to their default factory */ - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: enable TE link parameters on interface %s", ifp->name); if (!if_link_params_get(ifp)) { - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) zlog_debug( "Link-params: failed to init TE link parameters %s", ifp->name); @@ -2070,8 +2081,9 @@ DEFUN (no_link_params_enable, { VTY_DECLVAR_CONTEXT(interface, ifp); - zlog_debug("MPLS-TE: disable TE link parameters on interface %s", - ifp->name); + if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) + zlog_debug("MPLS-TE: disable TE link parameters on interface %s", + ifp->name); if_link_params_free(ifp); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 4f72e2414a..227226b5f9 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -119,7 +119,7 @@ static void zebra_redistribute(struct zserv *client, int type, srcdest_rnode_prefixes(rn, &dst_p, &src_p); - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_RIB) zlog_debug( "%s: client %s %s(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", __func__, @@ -201,7 +201,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, send_redistribute = 1; if (send_redistribute) { - if (IS_ZEBRA_DEBUG_EVENT) { + if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( "%s: client %s %s(%u), type=%d, distance=%d, metric=%d", __func__, diff --git a/zebra/rt.h b/zebra/rt.h index 59b42fed18..f311a6b9d3 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -66,7 +66,7 @@ extern int kernel_interface_set_master(struct interface *master, extern int mpls_kernel_init(void); -extern uint32_t kernel_get_speed(struct interface *ifp); +extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); /* diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 91a3024038..43e44cad16 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1440,6 +1440,7 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, int llalen, ns_id_t ns_id) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1460,6 +1461,8 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); @@ -1930,6 +1933,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1950,6 +1954,8 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6); req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); @@ -2297,6 +2303,7 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, static enum zebra_dplane_result netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2330,6 +2337,8 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) else req.ndm.ndm_flags |= NTF_EXT_LEARNED; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); addattr_l(&req.n, sizeof(req), NDA_LLADDR, dplane_ctx_mac_get_addr(ctx), 6); req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); @@ -2748,6 +2757,7 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd) { + uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2782,6 +2792,8 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, req.ndm.ndm_type = RTN_UNICAST; req.ndm.ndm_flags = flags; + addattr_l(&req.n, sizeof(req), + NDA_PROTOCOL, &protocol, sizeof(protocol)); ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); if (mac) diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index dc0f29bdbc..981ef7a889 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -396,7 +396,7 @@ extern int kernel_interface_set_master(struct interface *master, return 0; } -uint32_t kernel_get_speed(struct interface *ifp) +uint32_t kernel_get_speed(struct interface *ifp, int *error) { return ifp->speed; } diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 8cc5b52b34..711c4e0877 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -54,6 +54,7 @@ */ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) { + uint8_t protocol = RTPROT_ZEBRA; int family; int bytelen; struct { @@ -78,6 +79,9 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) req.frh.family = family; req.frh.action = FR_ACT_TO_TBL; + addattr_l(&req.n, sizeof(req), + FRA_PROTOCOL, &protocol, sizeof(protocol)); + /* rule's pref # */ addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 12f8a1ae3d..bf343e06e5 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -2511,6 +2511,18 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed) } /* + * Helper for 'show run' etc. + */ +int dplane_config_write_helper(struct vty *vty) +{ + if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED) + vty_out(vty, "zebra dplane limit %u\n", + zdplane_info.dg_max_queued_updates); + + return 0; +} + +/* * Provider registration */ int dplane_provider_register(const char *name, diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 30dfdafdf5..be945632c1 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -455,6 +455,7 @@ uint32_t dplane_get_in_queue_len(void); */ int dplane_show_helper(struct vty *vty, bool detailed); int dplane_show_provs_helper(struct vty *vty, bool detailed); +int dplane_config_write_helper(struct vty *vty); /* * Dataplane providers: modules that process or consume dataplane events. diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 4144c0afe0..5d88d4eeb4 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -711,7 +711,6 @@ static void zfpm_connection_down(const char *detail) * Start thread to clean up state after the connection goes down. */ assert(!zfpm_g->t_conn_down); - zfpm_debug("Starting conn_down thread"); zfpm_rnodes_iter_init(&zfpm_g->t_conn_down_state.iter); zfpm_g->t_conn_down = NULL; thread_add_timer_msec(zfpm_g->master, zfpm_conn_down_thread_cb, NULL, 0, @@ -806,8 +805,6 @@ static int zfpm_read_cb(struct thread *thread) goto done; } - zfpm_debug("Read out a full fpm message"); - /* * Just throw it away for now. */ @@ -1249,7 +1246,7 @@ static int zfpm_connect_cb(struct thread *t) sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - zfpm_debug("Failed to create socket for connect(): %s", + zlog_err("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; return 0; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5428b6eaef..f0601012b6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1046,14 +1046,18 @@ static struct route_entry *rib_choose_best(struct route_entry *current, struct nexthop *nexthop = NULL; for (ALL_NEXTHOPS(alternate->ng, nexthop)) { - if (if_is_loopback_or_vrf(if_lookup_by_index( - nexthop->ifindex, alternate->vrf_id))) + struct interface *ifp = if_lookup_by_index( + nexthop->ifindex, alternate->vrf_id); + + if (ifp && if_is_loopback_or_vrf(ifp)) return alternate; } for (ALL_NEXTHOPS(current->ng, nexthop)) { - if (if_is_loopback_or_vrf(if_lookup_by_index( - nexthop->ifindex, current->vrf_id))) + struct interface *ifp = if_lookup_by_index( + nexthop->ifindex, current->vrf_id); + + if (ifp && if_is_loopback_or_vrf(ifp)) return current; } @@ -1556,7 +1560,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, changed_p = true; UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - break; + + /* Keep checking nexthops */ + continue; } if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) { @@ -1992,6 +1998,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) * not-installed; or not-installed to installed. */ if (start_count > 0 && end_count > 0) { + if (debug_p) + zlog_debug("%u:%s applied nexthop changes from dplane notification", + dplane_ctx_get_vrf(ctx), dest_str); /* Changed nexthops - update kernel/others */ dplane_route_notif_update(rn, re, diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index bcaf1b5204..5df5d94f4b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -337,7 +337,7 @@ static void addr2hostprefix(int af, const union g_addr *addr, break; default: memset(prefix, 0, sizeof(*prefix)); - zlog_debug("%s: unknown address family %d", __func__, af); + zlog_warn("%s: unknown address family %d", __func__, af); break; } } @@ -916,7 +916,8 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, table = get_rnh_table(vrfid, afi, type); if (!table) { - zlog_debug("print_rnhs: rnh table not found"); + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("print_rnhs: rnh table not found"); return; } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 72d0b6866d..4f1868311c 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -92,7 +92,7 @@ static int zebra_vrf_new(struct vrf *vrf) struct zebra_vrf *zvrf; if (IS_ZEBRA_DEBUG_EVENT) - zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id); + zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id); zvrf = zebra_vrf_alloc(); vrf->info = zvrf; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7984481093..5ce9d3f293 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -394,6 +394,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + struct vrf *vrf = NULL; rib_dest_t *dest = rib_dest_from_rnode(rn); struct nexthop_group *nhg; @@ -422,9 +423,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "instance", re->instance); - if (re->vrf_id) + if (re->vrf_id) { json_object_int_add(json_route, "vrfId", re->vrf_id); + vrf = vrf_lookup_by_id(re->vrf_id); + json_object_string_add(json_route, "vrfName", + vrf->name); + } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); @@ -565,9 +570,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if ((nexthop->vrf_id != re->vrf_id) && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { - struct vrf *vrf = - vrf_lookup_by_id(nexthop->vrf_id); - + vrf = vrf_lookup_by_id(nexthop->vrf_id); json_object_string_add(json_nexthop, "vrf", vrf->name); } @@ -2655,6 +2658,10 @@ static int config_write_protocol(struct vty *vty) == MCAST_MIX_DISTANCE ? "lower-distance" : "longer-prefix"); + + /* Include dataplane info */ + dplane_config_write_helper(vty); + return 1; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index c7f2976ace..2417b505ad 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -9153,6 +9153,11 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) if (zvni->advertise_svi_macip == advertise) return; + /* Store flag even though SVI is not present. + * Once SVI comes up triggers self MAC-IP route add. + */ + zvni->advertise_svi_macip = advertise; + ifp = zvni->vxlan_if; if (!ifp) return; @@ -9164,20 +9169,17 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) return; zl2_info = zif->l2info.vxl; - vlan_if = zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); if (!vlan_if) return; if (advertise) { - zvni->advertise_svi_macip = advertise; /* Add primary SVI MAC-IP */ zvni_add_macip_for_intf(vlan_if, zvni); } else { - /* Del primary MAC-IP */ + /* Del primary SVI MAC-IP */ zvni_del_macip_for_intf(vlan_if, zvni); - zvni->advertise_svi_macip = advertise; } } |
