diff options
183 files changed, 3790 insertions, 2298 deletions
diff --git a/babeld/.gitignore b/babeld/.gitignore index fbdb90f677..71ef6786c7 100644 --- a/babeld/.gitignore +++ b/babeld/.gitignore @@ -4,5 +4,4 @@ !LICENCE !Makefile !subdir.am -!babeld.conf.sample !.gitignore diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample deleted file mode 100644 index a77453a734..0000000000 --- a/babeld/babeld.conf.sample +++ /dev/null @@ -1,30 +0,0 @@ -debug babel common -!debug babel kernel -!debug babel filter -!debug babel timeout -!debug babel interface -!debug babel route -!debug babel all - -router babel -! network wlan0 -! network eth0 -! redistribute ipv4 kernel -! no redistribute ipv6 static - -! The defaults are fine for a wireless interface - -!interface wlan0 - -! A few optimisation tweaks are optional but recommended on a wired interface -! Disable link quality estimation, enable split horizon processing, and -! increase the hello and update intervals. - -!interface eth0 -! babel wired -! babel split-horizon -! babel hello-interval 12000 -! babel update-interval 36000 - -! log file /var/log/quagga/babeld.log -log stdout diff --git a/babeld/subdir.am b/babeld/subdir.am index 8e5b46350d..c9b6959fca 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -5,7 +5,6 @@ if BABELD noinst_LIBRARIES += babeld/libbabel.a sbin_PROGRAMS += babeld/babeld -dist_examples_DATA += babeld/babeld.conf.sample vtysh_scan += \ babeld/babel_interface.c \ babeld/babel_zebra.c \ diff --git a/bfdd/bfdd.conf.sample b/bfdd/bfdd.conf.sample deleted file mode 100644 index 9981e262bc..0000000000 --- a/bfdd/bfdd.conf.sample +++ /dev/null @@ -1,5 +0,0 @@ -password zebra -! -log stdout -! -line vty diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 42ed587f20..6ec724d80c 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -273,11 +273,8 @@ DEFPY_YANG( void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - if (show_defaults) - vty_out(vty, " no shutdown\n"); - else - vty_out(vty, " %sshutdown\n", - yang_dnode_get_bool(dnode, NULL) ? "" : "no "); + vty_out(vty, " %sshutdown\n", + yang_dnode_get_bool(dnode, NULL) ? "" : "no "); } DEFPY_YANG( @@ -294,11 +291,8 @@ DEFPY_YANG( void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - if (show_defaults) - vty_out(vty, " no passive-mode\n"); - else - vty_out(vty, " %spassive-mode\n", - yang_dnode_get_bool(dnode, NULL) ? "" : "no "); + vty_out(vty, " %spassive-mode\n", + yang_dnode_get_bool(dnode, NULL) ? "" : "no "); } DEFPY_YANG( @@ -335,11 +329,7 @@ DEFPY_YANG( void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - if (show_defaults) - vty_out(vty, " minimum-ttl 254\n"); - else - vty_out(vty, " minimum-ttl %s\n", - yang_dnode_get_string(dnode, NULL)); + vty_out(vty, " minimum-ttl %s\n", yang_dnode_get_string(dnode, NULL)); } DEFPY_YANG( @@ -356,12 +346,8 @@ DEFPY_YANG( void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - if (show_defaults) - vty_out(vty, " detect-multiplier %d\n", - BFD_DEFDETECTMULT); - else - vty_out(vty, " detect-multiplier %s\n", - yang_dnode_get_string(dnode, NULL)); + vty_out(vty, " detect-multiplier %s\n", + yang_dnode_get_string(dnode, NULL)); } DEFPY_YANG( @@ -382,15 +368,9 @@ DEFPY_YANG( void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - uint32_t value; + uint32_t value = yang_dnode_get_uint32(dnode, NULL); - if (show_defaults) - vty_out(vty, " receive-interval %d\n", - BFD_DEFREQUIREDMINRX); - else { - value = yang_dnode_get_uint32(dnode, NULL); - vty_out(vty, " receive-interval %u\n", value / 1000); - } + vty_out(vty, " receive-interval %u\n", value / 1000); } DEFPY_YANG( @@ -411,15 +391,9 @@ DEFPY_YANG( void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - uint32_t value; + uint32_t value = yang_dnode_get_uint32(dnode, NULL); - if (show_defaults) - vty_out(vty, " transmit-interval %d\n", - BFD_DEFDESIREDMINTX); - else { - value = yang_dnode_get_uint32(dnode, NULL); - vty_out(vty, " transmit-interval %u\n", value / 1000); - } + vty_out(vty, " transmit-interval %u\n", value / 1000); } DEFPY_YANG( @@ -445,11 +419,8 @@ DEFPY_YANG( void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - if (show_defaults) - vty_out(vty, " no echo-mode\n"); - else - vty_out(vty, " %secho-mode\n", - yang_dnode_get_bool(dnode, NULL) ? "" : "no "); + vty_out(vty, " %secho-mode\n", + yang_dnode_get_bool(dnode, NULL) ? "" : "no "); } DEFPY_YANG( @@ -498,15 +469,9 @@ DEFPY_YANG( void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - uint32_t value; + uint32_t value = yang_dnode_get_uint32(dnode, NULL); - if (show_defaults) - vty_out(vty, " echo transmit-interval %d\n", - BFD_DEF_DES_MIN_ECHO_TX); - else { - value = yang_dnode_get_uint32(dnode, NULL); - vty_out(vty, " echo transmit-interval %u\n", value / 1000); - } + vty_out(vty, " echo transmit-interval %u\n", value / 1000); } DEFPY_YANG( @@ -538,19 +503,12 @@ DEFPY_YANG( void bfd_cli_show_required_echo_receive_interval(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - uint32_t value; - - if (show_defaults) - vty_out(vty, " echo receive-interval %d\n", - BFD_DEF_REQ_MIN_ECHO_RX); - else { - value = yang_dnode_get_uint32(dnode, NULL); - if (value) - vty_out(vty, " echo receive-interval %u\n", - value / 1000); - else - vty_out(vty, " echo receive-interval disabled\n"); - } + uint32_t value = yang_dnode_get_uint32(dnode, NULL); + + if (value) + vty_out(vty, " echo receive-interval %u\n", value / 1000); + else + vty_out(vty, " echo receive-interval disabled\n"); } /* diff --git a/bfdd/subdir.am b/bfdd/subdir.am index e572d4a3c0..8d35b933d7 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -5,7 +5,6 @@ if BFDD noinst_LIBRARIES += bfdd/libbfd.a sbin_PROGRAMS += bfdd/bfdd -dist_examples_DATA += bfdd/bfdd.conf.sample vtysh_scan += bfdd/bfdd_vty.c vtysh_scan += bfdd/bfdd_cli.c vtysh_daemons += bfdd diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f658b0d0f0..71e4b56a00 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -3734,7 +3734,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct aspath *aspath; int send_as4_path = 0; int send_as4_aggregator = 0; - int use32bit = (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; + bool use32bit = CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV); if (!bgp) bgp = peer->bgp; diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index f1bdcc8bb4..958d7cf0ed 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -424,8 +424,7 @@ void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer, void bgp_bfd_show_info(struct vty *vty, const struct peer *peer, json_object *json_neigh) { - if (peer->bfd_config->session) - bfd_sess_show(vty, json_neigh, peer->bfd_config->session); + bfd_sess_show(vty, json_neigh, peer->bfd_config->session); } DEFUN (neighbor_bfd, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 381e6f082b..ed8a6a9506 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3452,12 +3452,6 @@ DEFUN (no_bgp_evpn_advertise_default_gw, if (!bgp) return CMD_WARNING; - if (!EVPN_ENABLED(bgp)) { - vty_out(vty, - "This command is only supported under the EVPN VRF\n"); - return CMD_WARNING; - } - evpn_unset_advertise_default_gw(bgp, NULL); return CMD_SUCCESS; @@ -3718,16 +3712,16 @@ DEFPY(bgp_evpn_advertise_svi_ip, if (!bgp) return CMD_WARNING; - if (!EVPN_ENABLED(bgp)) { - vty_out(vty, - "This command is only supported under EVPN VRF\n"); - return CMD_WARNING; - } - if (no) evpn_set_advertise_svi_macip(bgp, NULL, 0); - else + else { + if (!EVPN_ENABLED(bgp)) { + vty_out(vty, + "This command is only supported under EVPN VRF\n"); + return CMD_WARNING; + } evpn_set_advertise_svi_macip(bgp, NULL, 1); + } return CMD_SUCCESS; } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index a902c63dea..62fed931f9 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1417,7 +1417,6 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */ struct bgp *bgp_vpn, /* from */ afi_t afi) { - struct prefix_rd prd; struct bgp_dest *pdest; safi_t safi = SAFI_MPLS_VPN; @@ -1428,16 +1427,10 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */ */ for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest; pdest = bgp_route_next(pdest)) { - const struct prefix *p = bgp_dest_get_prefix(pdest); struct bgp_table *table; struct bgp_dest *bn; struct bgp_path_info *bpi; - memset(&prd, 0, sizeof(prd)); - prd.family = AF_UNSPEC; - prd.prefixlen = 64; - memcpy(prd.val, &p->u.val, 8); - /* This is the per-RD table of prefixes */ table = bgp_dest_get_bgp_table_info(pdest); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 35a9316221..1c2ad7fc73 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8223,8 +8223,8 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, } /* Static function to display route. */ -static void route_vty_out_route(const struct prefix *p, struct vty *vty, - json_object *json, bool wide) +static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, + struct vty *vty, json_object *json, bool wide) { int len = 0; char buf[BUFSIZ]; @@ -8241,6 +8241,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty, json_object_int_add(json, "prefixLen", p->prefixlen); prefix2str(p, buf2, PREFIX_STRLEN); json_object_string_add(json, "network", buf2); + json_object_int_add(json, "version", dest->version); } } else if (p->family == AF_ETHERNET) { len = vty_out(vty, "%pFX", p); @@ -8265,6 +8266,7 @@ static void route_vty_out_route(const struct prefix *p, struct vty *vty, json_object_int_add(json, "prefixLen", p->prefixlen); prefix2str(p, buf2, PREFIX_STRLEN); json_object_string_add(json, "network", buf2); + json_object_int_add(json, "version", dest->version); } } @@ -8460,11 +8462,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, if (!json_paths) { /* print prefix and mask */ if (!display) - route_vty_out_route(p, vty, json_path, wide); + route_vty_out_route(path->net, p, vty, json_path, wide); else vty_out(vty, "%*s", (wide ? 45 : 17), " "); } else { - route_vty_out_route(p, vty, json_path, wide); + route_vty_out_route(path->net, p, vty, json_path, wide); } /* @@ -8924,9 +8926,9 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } /* called from terminal list command */ -void route_vty_out_tmp(struct vty *vty, const struct prefix *p, - struct attr *attr, safi_t safi, bool use_json, - json_object *json_ar, bool wide) +void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, + const struct prefix *p, struct attr *attr, safi_t safi, + bool use_json, json_object *json_ar, bool wide) { json_object *json_status = NULL; json_object *json_net = NULL; @@ -8958,7 +8960,7 @@ void route_vty_out_tmp(struct vty *vty, const struct prefix *p, json_object_string_add(json_net, "network", buff); } } else - route_vty_out_route(p, vty, NULL, wide); + route_vty_out_route(dest, p, vty, NULL, wide); /* Print attribute */ if (attr) { @@ -9106,7 +9108,7 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, /* print prefix and mask */ if (json == NULL) { if (!display) - route_vty_out_route(p, vty, NULL, false); + route_vty_out_route(path->net, p, vty, NULL, false); else vty_out(vty, "%*s", 17, " "); } @@ -9208,7 +9210,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, /* print prefix and mask */ if (!display) - route_vty_out_route(p, vty, json_path, false); + route_vty_out_route(path->net, p, vty, json_path, false); else vty_out(vty, "%*s", 17, " "); @@ -9313,7 +9315,7 @@ static void damp_route_vty_out(struct vty *vty, const struct prefix *p, /* print prefix and mask */ if (!use_json) { if (!display) - route_vty_out_route(p, vty, NULL, false); + route_vty_out_route(path->net, p, vty, NULL, false); else vty_out(vty, "%*s", 17, " "); } @@ -9384,7 +9386,7 @@ static void flap_route_vty_out(struct vty *vty, const struct prefix *p, /* print prefix and mask */ if (!use_json) { if (!display) - route_vty_out_route(p, vty, NULL, false); + route_vty_out_route(path->net, p, vty, NULL, false); else vty_out(vty, "%*s", 17, " "); } @@ -10121,6 +10123,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ", valid"); } + if (json_paths) + json_object_int_add(json_path, "version", bn->version); + if (path->peer != bgp->peer_self) { if (path->peer->as == path->peer->local_as) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { @@ -10616,6 +10621,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, for (; pi; pi = pi->next) { total_count++; + if (type == bgp_show_type_prefix_version) { + uint32_t version = + strtoul(output_arg, NULL, 10); + if (dest->version < version) + continue; + } + if (type == bgp_show_type_rpki) { if (dest_p->family == AF_INET || dest_p->family == AF_INET6) @@ -11086,16 +11098,22 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } } else { if (!json) { - vty_out(vty, "BGP routing table entry for %s%s%pFX\n", + vty_out(vty, + "BGP routing table entry for %s%s%pFX, version %" PRIu64 + "\n", ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ? prefix_rd2str(prd, buf1, sizeof(buf1)) : ""), - safi == SAFI_MPLS_VPN ? ":" : "", p); + safi == SAFI_MPLS_VPN ? ":" : "", p, + dest->version); - } else + } else { json_object_string_add(json, "prefix", prefix2str(p, prefix_str, sizeof(prefix_str))); + json_object_int_add(json, "version", dest->version); + + } } if (has_valid_label) { @@ -11886,6 +11904,7 @@ DEFPY (show_ip_bgp_json, |route-filter-v4|route-filter-translated-v6\ |route-filter-translated-v4] [exact-match]\ |rpki <invalid|valid|notfound>\ + |version (1-4294967295)\ ] [json$uj | wide$wide]", SHOW_STR IP_STR @@ -11919,6 +11938,8 @@ DEFPY (show_ip_bgp_json, "A valid path as determined by rpki\n" "A invalid path as determined by rpki\n" "A path that has no rpki data\n" + "Display prefixes with matching version numbers\n" + "Version number and above\n" JSON_STR "Increase table width for longer prefixes\n") { @@ -11929,6 +11950,7 @@ DEFPY (show_ip_bgp_json, int idx = 0; int exact_match = 0; char *community = NULL; + char *prefix_version = NULL; bool first = true; uint8_t show_flags = 0; enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; @@ -11996,12 +12018,22 @@ DEFPY (show_ip_bgp_json, rpki_target_state = RPKI_INVALID; } + /* Display prefixes with matching version numbers */ + if (argv_find(argv, argc, "version", &idx)) { + sh_type = bgp_show_type_prefix_version; + prefix_version = argv[idx + 1]->arg; + } + if (!all) { /* show bgp: AFI_IP6, show ip bgp: AFI_IP */ if (community) return bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); + else if (prefix_version) + return bgp_show(vty, bgp, afi, safi, sh_type, + prefix_version, show_flags, + rpki_target_state); else return bgp_show(vty, bgp, afi, safi, sh_type, NULL, show_flags, rpki_target_state); @@ -12039,6 +12071,11 @@ DEFPY (show_ip_bgp_json, bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); + else if (prefix_version) + return bgp_show(vty, bgp, afi, safi, + sh_type, prefix_version, + show_flags, + rpki_target_state); else bgp_show(vty, bgp, afi, safi, sh_type, NULL, show_flags, @@ -12071,6 +12108,11 @@ DEFPY (show_ip_bgp_json, bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); + else if (prefix_version) + return bgp_show(vty, bgp, afi, safi, + sh_type, prefix_version, + show_flags, + rpki_target_state); else bgp_show(vty, bgp, afi, safi, sh_type, NULL, show_flags, @@ -13283,7 +13325,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, && (route_filtered || ret == RMAP_DENY)) (*filtered_count)++; - route_vty_out_tmp(vty, rn_p, &attr, safi, + route_vty_out_tmp(vty, dest, rn_p, &attr, safi, use_json, json_ar, wide); bgp_attr_undup(&attr, ain->attr); (*output_count)++; @@ -13325,8 +13367,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, } } route_vty_out_tmp( - vty, rn_p, &attr, safi, - use_json, json_ar, + vty, dest, rn_p, &attr, + safi, use_json, json_ar, wide); (*output_count)++; } else { @@ -13350,7 +13392,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) continue; - route_vty_out_tmp(vty, + route_vty_out_tmp(vty, dest, bgp_dest_get_prefix(dest), pi->attr, safi, use_json, json_ar, wide); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 0a4fd026e4..1bf5dcf186 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -58,6 +58,7 @@ enum bgp_show_type { bgp_show_type_damp_neighbor, bgp_show_type_detail, bgp_show_type_rpki, + bgp_show_type_prefix_version, }; enum bgp_show_adj_route_type { @@ -714,9 +715,10 @@ extern void route_vty_out(struct vty *vty, const struct prefix *p, extern void route_vty_out_tag(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json); -extern void route_vty_out_tmp(struct vty *vty, const struct prefix *p, - struct attr *attr, safi_t safi, bool use_json, - json_object *json_ar, bool wide); +extern void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, + const struct prefix *p, struct attr *attr, + safi_t safi, bool use_json, json_object *json_ar, + bool wide); extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index fb64f010f9..bb0c95e32f 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -267,7 +267,7 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp, } if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv && adj->adv->baa) { - route_vty_out_tmp(vty, dest_p, + route_vty_out_tmp(vty, dest, dest_p, adj->adv->baa->attr, SUBGRP_SAFI(subgrp), 0, NULL, false); @@ -275,7 +275,7 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp, } if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr) { - route_vty_out_tmp(vty, dest_p, + route_vty_out_tmp(vty, dest, dest_p, adj->attr, SUBGRP_SAFI(subgrp), 0, NULL, false); diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index cb459ae13c..8d2cffbb47 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -229,8 +229,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, } rd_header = 0; } - route_vty_out_tmp(vty, bgp_dest_get_prefix(rm), attr, - safi, use_json, json_routes, false); + route_vty_out_tmp(vty, rm, bgp_dest_get_prefix(rm), + attr, safi, use_json, json_routes, + false); output_count++; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9ecf02aae0..1e465d2620 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1390,7 +1390,6 @@ DEFUN_YANG_NOSH(router_bgp, NB_OP_MODIFY, "true"); } - nb_cli_pending_commit_check(vty); ret = nb_cli_apply_changes(vty, base_xpath); if (ret == CMD_SUCCESS) { VTY_PUSH_XPATH(BGP_NODE, base_xpath); @@ -1399,6 +1398,7 @@ DEFUN_YANG_NOSH(router_bgp, * For backward compatibility with old commands we still * need to use the qobj infrastructure. */ + nb_cli_pending_commit_check(vty); bgp = bgp_lookup(as, name); if (bgp) VTY_PUSH_CONTEXT(BGP_NODE, bgp); diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample deleted file mode 100644 index 1fb4f1600b..0000000000 --- a/bgpd/bgpd.conf.sample +++ /dev/null @@ -1,31 +0,0 @@ -! -*- bgp -*- -! -! BGPd sample configuration file -! -! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul Exp $ -! -hostname bgpd -password zebra -!enable password please-set-at-here -! -! -router bgp 7675 -! bgp router-id 10.0.0.1 -! network 10.0.0.0/8 -! neighbor 10.0.0.2 remote-as 7675 -! neighbor 10.0.0.2 ebgp-multihop -! -! address-family ipv4 unicast -! neighbor 10.0.0.2 route-map set-nexthop out -! neighbor 10.0.0.2 next-hop-self -! exit-address-family -! -! access-list all permit any -! -!route-map set-nexthop permit 10 -! match ip address all -! set ip next-hop 10.0.0.1 -! -!log file bgpd.log -! -log stdout diff --git a/bgpd/bgpd.conf.vnc.sample b/bgpd/bgpd.conf.vnc.sample deleted file mode 100644 index a8a2dc5fa0..0000000000 --- a/bgpd/bgpd.conf.vnc.sample +++ /dev/null @@ -1,91 +0,0 @@ -hostname H192.1.1.1 -password zebra -#enable password zebra -log stdout notifications -log monitor notifications -#debug bgp - -line vty -exec-timeout 1000 -exit - - -router bgp 64512 - - # Must set a router-id if no zebra (default 0.0.0.0) - bgp router-id 192.1.1.1 - - neighbor 192.1.1.2 remote-as 64512 - neighbor 192.1.1.2 description H192.1.1.2 - neighbor 192.1.1.2 update-source 192.1.1.1 - neighbor 192.1.1.2 advertisement-interval 1 - - neighbor 192.1.1.3 remote-as 64512 - neighbor 192.1.1.3 description H192.1.1.3 - neighbor 192.1.1.3 update-source 192.1.1.1 - neighbor 192.1.1.3 advertisement-interval 1 - - address-family ipv4 unicast - no neighbor 192.1.1.2 activate - no neighbor 192.1.1.3 activate - - address-family vpnv4 - neighbor 192.1.1.2 activate - neighbor 192.1.1.3 activate - exit-address-family - - address-family vpnv6 - neighbor 192.1.1.2 activate - neighbor 192.1.1.3 activate - exit-address-family - - vnc defaults - rd auto:vn:5226 - response-lifetime 45 - rt both 1000:1 1000:2 - exit-vnc - - vnc nve-group group1 - prefix vn 172.16.0.0/16 - exit-vnc - - vnc nve-group red - prefix vn 10.0.0.0/8 - rd auto:vn:10 - rt both 1000:10 - exit-vnc - - vnc nve-group blue - prefix vn 20.0.0.0/8 - rd auto:vn:20 - rt both 1000:20 - exit-vnc - - vnc nve-group green - prefix vn 30.0.0.0/8 - rd auto:vn:20 - rt both 1000:30 - exit-vnc - - vnc nve-group rfc4291v6c - prefix vn ::ac10:0/112 - rd auto:vn:5227 - rt both 2000:1 - exit-vnc - - vnc nve-group rfc4291v6m - prefix vn ::ffff:ac10:0/112 - rd auto:vn:5528 - rt both 3000:1 - exit-vnc - - vnc nve-group rfc6052v6 - prefix vn 64:ff9b::ac10:0/112 - rd auto:vn:5529 - rt both 4000:1 - exit-vnc - -exit - - - diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 583d1cd207..07e71ba601 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -6,11 +6,6 @@ if BGPD noinst_LIBRARIES += bgpd/libbgp.a sbin_PROGRAMS += bgpd/bgpd noinst_PROGRAMS += bgpd/bgp_btoa -dist_examples_DATA += \ - bgpd/bgpd.conf.sample \ - bgpd/bgpd.conf.sample2 \ - bgpd/bgpd.conf.vnc.sample \ - # end vtysh_scan += \ bgpd/bgp_bfd.c \ bgpd/bgp_debug.c \ diff --git a/debian/frr.dirs b/debian/frr.dirs index 9e592e370c..e3832d10a1 100644 --- a/debian/frr.dirs +++ b/debian/frr.dirs @@ -2,7 +2,6 @@ etc/frr/ etc/iproute2/rt_protos.d/ etc/logrotate.d/ usr/share/doc/frr/ -usr/share/doc/frr/examples/ usr/share/lintian/overrides/ usr/share/yang/ var/log/frr/ diff --git a/debian/frr.install b/debian/frr.install index 9972b579f0..48263222f8 100644 --- a/debian/frr.install +++ b/debian/frr.install @@ -1,5 +1,6 @@ debian/frr.conf usr/lib/tmpfiles.d etc/ +tools/etc/frr/frr.conf etc/frr/ tools/frr-reload usr/lib/frr/ usr/bin/mtracebis usr/bin/vtysh @@ -16,6 +17,5 @@ usr/lib/frr/*.sh usr/lib/frr/*d usr/lib/frr/watchfrr usr/lib/frr/zebra -usr/share/doc/frr/examples usr/share/man/ usr/share/yang/ diff --git a/debian/rules b/debian/rules index 25ae04261d..93d0cdb2a0 100755 --- a/debian/rules +++ b/debian/rules @@ -43,7 +43,6 @@ export PYTHON=python3 override_dh_auto_configure: $(shell dpkg-buildflags --export=sh); \ dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr \ --sysconfdir=/etc/frr \ @@ -92,8 +91,6 @@ endif cp -r tools/etc/* debian/tmp/etc/ -rm debian/tmp/etc/frr/daemons.conf - sed -e 's#^!log file #!log file /var/log/frr/#' -i debian/tmp/usr/share/doc/frr/examples/*sample* - # drop dev-only files find debian/tmp -name '*.la' -o -name '*.a' -o -name 'lib*.so' | xargs rm -f rm -rf debian/tmp/usr/include diff --git a/doc/developer/building-frr-for-alpine.rst b/doc/developer/building-frr-for-alpine.rst index f88fc7bfdc..68e58c9d76 100644 --- a/doc/developer/building-frr-for-alpine.rst +++ b/doc/developer/building-frr-for-alpine.rst @@ -85,8 +85,6 @@ startup. To configure by hand: docker exec -it frr /bin/sh vi /etc/frr/daemons - cp /etc/frr/zebra.conf.sample /etc/frr/zebra.conf - vi /etc/frr/zebra.conf /etc/init.d/frr start Or, to configure the daemons using /etc/frr from a host volume, put the diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 2a6d2dda34..a86566dbb0 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -480,6 +480,15 @@ Some things to keep in mind: - Avoid including unstable data in your test: don't rely on link-local addresses or ifindex values, for example, because these can change from run to run. +- Using sleep is almost never appropriate to wait for some convergence + event as the sole item done. As an example: if the test resets the peers + in BGP, the test should look for the peers reconverging instead of just + sleeping an arbitrary amount of time and continuing on. It is ok to + use sleep in a tight loop with appropriate show commands to ensure that + the protocol reaches the desired state. This should be bounded by + appropriate timeouts for the protocol in question though. See + verify_bgp_convergence as a good example of this. If you are having + troubles figuring out what to look for, please do not be afraid to ask. Topotest File Hierarchy diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index abdbea5a9c..b4ddec10c9 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -500,10 +500,22 @@ made. For example, a change in :file:`bgpd/rfapi` would be formatted as:: The first line should be no longer than 50 characters. Subsequent lines should be wrapped to 72 characters. +The purpose of commit messages is to briefly summarize what the commit is +changing. Therefore, the extended summary portion should be in the form of an +English paragraph. Brief examples of program output are acceptable but if +present should be short (on the order of 10 lines) and clearly demonstrate what +has changed. The goal should be that someone with only passing familiarity with +the code in question can understand what is being changed. + +Commit messages consisting entirely of program output are *unacceptable*. These +do not describe the behavior changed. For example, putting VTYSH output or the +result of test runs as the sole content of commit messages is unacceptable. + You must also sign off on your commit. .. seealso:: :ref:`signing-off` + Source File Header ------------------ diff --git a/doc/user/babeld.rst b/doc/user/babeld.rst index e6d4aa5c97..c8015bb7e5 100644 --- a/doc/user/babeld.rst +++ b/doc/user/babeld.rst @@ -233,3 +233,41 @@ Babel debugging commands .. note:: If you have compiled with the ``NO_DEBUG`` flag, then these commands aren't available. + + +Babel sample configuration file +=============================== + +.. code-block:: frr + + debug babel common + !debug babel kernel + !debug babel filter + !debug babel timeout + !debug babel interface + !debug babel route + !debug babel all + + router babel + ! network wlan0 + ! network eth0 + ! redistribute ipv4 kernel + ! no redistribute ipv6 static + + ! The defaults are fine for a wireless interface + + !interface wlan0 + + ! A few optimisation tweaks are optional but recommended on a wired interface + ! Disable link quality estimation, enable split horizon processing, and + ! increase the hello and update intervals. + + !interface eth0 + ! babel wired + ! babel split-horizon + ! babel hello-interval 12000 + ! babel update-interval 36000 + + ! log file /var/log/quagga/babeld.log + log stdout + diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 5cbd3692dc..519f30d5e6 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -444,7 +444,7 @@ Terminal Mode Commands Shows the current log filters applied to each daemon. -.. clicmd:: show memory +.. clicmd:: show memory [DAEMON] Show information on how much memory is used for which specific things in |PACKAGE_NAME|. Output may vary depending on system capabilities but will @@ -502,7 +502,8 @@ Terminal Mode Commands the column may be missing if system support is not available. When executing this command from ``vtysh``, each of the daemons' memory - usage is printed sequentially. + usage is printed sequentially. You can specify the daemon's name to print + only its memory usage. .. clicmd:: show history @@ -513,32 +514,43 @@ Terminal Mode Commands Send a message to all logging destinations that are enabled for messages of the given severity. -.. clicmd:: find COMMAND... +.. clicmd:: find REGEX... - This command performs a simple substring search across all defined commands - in all modes. As an example, suppose you're in enable mode and can't - remember where the command to turn OSPF segment routing on is: + This command performs a regex search across all defined commands in all + modes. As an example, suppose you're in enable mode and can't remember where + the command to turn OSPF segment routing on is: :: frr# find segment-routing on (ospf) segment-routing on + (isis) segment-routing on + The CLI mode is displayed next to each command. In this example, :clicmd:`segment-routing on` is under the `router ospf` mode. - Similarly, suppose you want a listing of all commands that contain "l2vpn": + Similarly, suppose you want a listing of all commands that contain "l2vpn" + and "neighbor": :: - frr# find l2vpn - (view) show [ip] bgp l2vpn evpn [json] - (view) show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json] - (view) show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json] - (view) show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json] - (view) show [ip] bgp l2vpn evpn all overlay + frr# find l2vpn.*neighbor + (view) show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json] + (view) show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> routes [json] + (view) show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json] + (view) show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> routes [json] ... + + Note that when entering spaces as part of a regex specification, repeated + spaces will be compressed into a single space for matching purposes. This is + a consequence of spaces being used to delimit CLI tokens. If you need to + match more than one space, use the ``\s`` escape. + + POSIX Extended Regular Expressions are supported. + + .. _common-show-commands: .. clicmd:: show thread cpu [r|w|t|e|x] diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5118c12843..adb87d386d 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1624,6 +1624,16 @@ Configuring Peers peer in question. This number is between 0 and 600 seconds, with the default advertisement interval being 0. +.. clicmd:: neighbor PEER timers (0-65535) (0-65535) + + Set keepalive and hold timers for a neighbor. The first value is keepalive + and the second is hold time. + +.. clicmd:: neighbor PEER connect (1-65535) + + Set connect timer for a neighbor. The connect timer controls how long BGP + waits between connection attempts to a neighbor. + .. clicmd:: neighbor PEER timers delayopen (1-240) This command allows the user enable the @@ -3224,6 +3234,26 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. Display flap statistics of routes of the selected afi and safi selected. +.. clicmd:: show bgp [afi] [safi] [all] version (1-4294967295) [wide|json] + + Display prefixes with matching version numbers. The version number and + above having prefixes will be listed here. + + It helps to identify which prefixes were installed at some point. + + Here is an example of how to check what prefixes were installed starting + with an arbitrary version:: + + .. code-block:: frr + + ~# vtysh -c 'show bgp ipv4 unicast json' | jq '.tableVersion' + 9 + ~# vtysh -c 'show ip bgp version 9 json' | jq -r '.routes | keys[]' + 192.168.3.0/24 + ~# vtysh -c 'show ip bgp version 8 json' | jq -r '.routes | keys[]' + 192.168.2.0/24 + 192.168.3.0/24 + .. clicmd:: show bgp [afi] [safi] statistics Display statistics of routes of the selected afi and safi. diff --git a/doc/user/eigrpd.rst b/doc/user/eigrpd.rst index 88d289d27e..573e2ca2e4 100644 --- a/doc/user/eigrpd.rst +++ b/doc/user/eigrpd.rst @@ -183,3 +183,18 @@ Debug for EIGRP protocol. ``show debugging eigrp`` will show all information currently set for eigrpd debug. + +Sample configuration +==================== + +.. code-block:: frr + + hostname eigrpd + password zebra + enable password please-set-at-here + ! + router eigrp 4453 + network 192.168.1.0/24 + ! + log stdout + diff --git a/doc/user/fabricd.rst b/doc/user/fabricd.rst index 611bc1caaa..48d264f30e 100644 --- a/doc/user/fabricd.rst +++ b/doc/user/fabricd.rst @@ -60,7 +60,6 @@ in the configuration: .. clicmd:: set-overload-bit - Set overload bit to avoid any transit traffic. .. clicmd:: purge-originator @@ -256,9 +255,8 @@ Debugging OpenFabric Print which OpenFabric debug levels are active. - -OpenFabric configuration example -================================ +Sample configuration +==================== A simple example: @@ -281,3 +279,26 @@ A simple example: ! router openfabric 1 net 49.0000.0000.0001.00 + + +Alternative example: + +.. code-block:: frr + + hostname fabricd + + router openfabric DEAD + net 47.0023.0000.0003.0300.0100.0102.0304.0506.00 + lsp-lifetime 65535 + + hostname isisd-router + domain-password foobar + + interface eth0 + ip router openfabric DEAD + openfabric hello-interval 5 + openfabric lsp-interval 1000 + + ! -- optional + openfabric retransmit-interval 10 + openfabric retransmit-throttle-interval diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index 3e662b14d8..a6b3d9d97f 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -242,8 +242,9 @@ LDP debugging commands - ``messages`` - ``zebra`` -LDP Example Configuration -========================= + +Sample configuration +==================== Below configuration gives a typical MPLS configuration of a device located in a MPLS backbone. LDP is enabled on two interfaces and will attempt to peer with @@ -306,3 +307,45 @@ that traffic to that destination will be applied. O>* 10.200.0.0/24 [110/210] via 10.115.0.1, eth2, label 17, 00:00:15 north-vm# + +Additional example demonstrating use of some miscellaneous config options: + +.. code-block:: frr + + interface eth0 + ! + interface eth1 + ! + interface lo + ! + mpls ldp + dual-stack cisco-interop + neighbor 10.0.1.5 password opensourcerouting + neighbor 172.16.0.1 password opensourcerouting + ! + address-family ipv4 + discovery transport-address 10.0.1.1 + label local advertise explicit-null + ! + interface eth0 + ! + interface eth1 + ! + ! + address-family ipv6 + discovery transport-address 2001:db8::1 + ! + interface eth1 + ! + ! + ! + l2vpn ENG type vpls + bridge br0 + member interface eth2 + ! + member pseudowire mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! + ! + diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 17251e11ac..43c0f62ea3 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -243,8 +243,9 @@ Showing OSPF6 information JSON object, with each router having "cost", "isLeafNode" and "children" as arguments. -OSPF6 Configuration Examples -============================ + +Sample configuration +==================== Example of ospf6d configured on one interface and area: @@ -258,3 +259,53 @@ Example of ospf6d configured on one interface and area: area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! + + +Larger example with policy and various options set: + + +.. code-block:: frr + + debug ospf6 neighbor state + ! + interface fxp0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 0 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 + ! + interface lo0 + ipv6 ospf6 cost 1 + ipv6 ospf6 hello-interval 10 + ipv6 ospf6 dead-interval 40 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 priority 1 + ipv6 ospf6 transmit-delay 1 + ipv6 ospf6 instance-id 0 + ! + router ospf6 + router-id 255.1.1.1 + redistribute static route-map static-ospf6 + interface fxp0 area 0.0.0.0 + ! + access-list access4 permit 127.0.0.1/32 + ! + ipv6 access-list access6 permit 3ffe:501::/32 + ipv6 access-list access6 permit 2001:200::/48 + ipv6 access-list access6 permit ::1/128 + ! + ipv6 prefix-list test-prefix seq 1000 deny any + ! + route-map static-ospf6 permit 10 + match ipv6 address prefix-list test-prefix + set metric-type type-2 + set metric 2000 + ! + line vty + access-class access4 + ipv6 access-class access6 + exec-timeout 0 0 + ! diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 85b6007f36..800530901e 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -280,7 +280,7 @@ To start OSPF process you have to specify the OSPF router. This command enables or disables sending ARP requests to update neighbor table entries. It speeds up convergence for /32 networks on a P2P - connection. + connection. This feature is enabled by default. @@ -1089,8 +1089,9 @@ Debugging OSPF Debug commnd to enable/disable external route summarisation specific debugs. -OSPF Configuration Examples -=========================== + +Sample Configuration +==================== A simple example, with MD5 authentication enabled: diff --git a/doc/user/overview.rst b/doc/user/overview.rst index b4f56260c9..efe64b72f0 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -58,6 +58,33 @@ routes to Internet exchanges running full Internet tables. FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. Feature support varies by platform; see the :ref:`feature-matrix`. +System Requirements +------------------- + +System resources needed by FRR are highly dependent on workload. Routing +software performance is particularly susceptible to external factors such as: + +* Kernel networking stack +* Physical NIC +* Peer behavior +* Routing information scale + +Because of these factors - especially the last one - it's difficult to lay out +resource requirements. + +To put this in perspective, FRR can be run on very low resource systems such as +SBCs, provided it is not stressed too much. If you want to set up 4 Raspberry +Pis to play with BGP or OSPF, it should work fine. If you ask a FRR to process +a complete internet routing table on a Raspberry Pi, you will be disappointed. +However, given enough resources, FRR ought to be capable of acting as a core IX +router. Such a use case requires at least 4gb of memory and a recent quad-core +server processor at a minimum. + +If you are new to networking, an important thing to remember is that FRR is +control plane software. It does not itself forward packets - it exchanges +information with peers about how to forward packets. Forwarding plane +performance largely depends on choice of NIC / ASIC. + System Architecture ------------------- diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst index fe50a5e7eb..5fc3837839 100644 --- a/doc/user/pathd.rst +++ b/doc/user/pathd.rst @@ -395,3 +395,52 @@ learned through BGP using route-maps: ! In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected. + + +Sample configuration +==================== + +.. code-block:: frr + + ! Default pathd configuration sample + ! + password frr + log stdout + + segment-routing + traffic-eng + segment-list test1 + index 10 mpls label 123 + index 20 mpls label 456 + ! + segment-list test2 + index 10 mpls label 321 + index 20 mpls label 654 + ! + policy color 1 endpoint 1.1.1.1 + name one + binding-sid 100 + candidate-path preference 100 name test1 explicit segment-list test1 + candidate-path preference 200 name test2 explicit segment-list test2 + ! + policy color 2 endpoint 2.2.2.2 + name two + binding-sid 101 + candidate-path preference 100 name def explicit segment-list test2 + candidate-path preference 200 name dyn dynamic + bandwidth 12345 + metric bound abc 16 required + metric te 10 + ! + ! + pcep + pcc-peer PCE1 + address ip 127.0.0.1 + sr-draft07 + ! + pcc + peer PCE1 + ! + ! + ! + diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 14a05a69d7..77134a7704 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -290,3 +290,22 @@ kernel that points to a table to use for forwarding once the rule matches. The creation of a nexthop or nexthop-group is translated to a default route in a table with the nexthops specified as the nexthops for the default route. + +Sample configuration +==================== + +.. code-block:: frr + + nexthop-group TEST + nexthop 4.5.6.7 + nexthop 5.6.7.8 + ! + pbr-map BLUE seq 100 + match dst-ip 9.9.9.0/24 + match src-ip 10.10.10.0/24 + set nexthop-group TEST + ! + int swp1 + pbr-policy BLUE + + diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 86716b49a4..6b7cae2c5d 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -656,3 +656,34 @@ setup. This is existing PIM configuration: - Enable pim on the underlay L3 interface via the "ip pim" command. - Configure RPs for the BUM multicast group range. - Ensure the PIM is enabled on the lo of the VTEPs and the RP. + + +Sample configuration +==================== + +.. code-block:: frr + + debug igmp + debug pim + debug pim zebra + + ! You may want to enable ssmpingd for troubleshooting + ! See http://www.venaas.no/multicast/ssmping/ + ! + ip ssmpingd 1.1.1.1 + ip ssmpingd 2.2.2.2 + + ! HINTS: + ! - Enable "ip pim ssm" on the interface directly attached to the + ! multicast source host (if this is the first-hop router) + ! - Enable "ip pim ssm" on pim-routers-facing interfaces + ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces + ! - In order to inject IGMPv3 local membership information in the + ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on + ! the same interface; otherwise PIM won't advertise + ! IGMPv3-learned membership to other PIM routers + + interface eth0 + ip pim ssm + ip igmp + diff --git a/doc/user/ripd.rst b/doc/user/ripd.rst index cba93e0d84..83c8c93b1c 100644 --- a/doc/user/ripd.rst +++ b/doc/user/ripd.rst @@ -539,3 +539,21 @@ Debug for RIP protocol. Shows all information currently set for ripd debug. + +Sample configuration +==================== + +.. code-block:: frr + + + debug rip events + debug rip packet + + router rip + network 11.0.0.0/8 + network eth0 + route 10.0.0.0/8 + distribute-list private-only in eth0 + + access-list private-only permit 10.0.0.0/8 + access-list private-only deny any diff --git a/doc/user/ripngd.rst b/doc/user/ripngd.rst index 0387e36305..b273eb3bfa 100644 --- a/doc/user/ripngd.rst +++ b/doc/user/ripngd.rst @@ -71,3 +71,19 @@ ripngd Filtering Commands distribute-list local-only out sit1 + +Sample configuration +==================== + +.. code-block:: frr + + debug ripng events + debug ripng packet + + router ripng + network sit1 + route 3ffe:506::0/32 + distribute-list local-only out sit1 + + ipv6 access-list local-only permit 3ffe:506::0/32 + ipv6 access-list local-only deny any diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 7f357b0925..3cb83cc652 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -333,10 +333,10 @@ Route Map Exit Action Command Route Map Optimization Command ============================== -.. clicmd:: route-map optimization +.. clicmd:: route-map ROUTE-MAP-NAME optimization - Enable route-map processing optimization. The optimization is - enabled by default. + Enable route-map processing optimization for `route-map-name`. + The optimization is enabled by default. Instead of sequentially passing through all the route-map indexes until a match is found, the search for the best-match index will be based on a look-up in a prefix-tree. A per-route-map prefix-tree diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index e5cd1de201..205b25e53e 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -1020,3 +1020,68 @@ For protocols requiring an IPv6 router-id, the following commands are available: .. clicmd:: show ipv6 router-id [vrf NAME] Display the user configured IPv6 router-id. + + +Debugging +========= + +.. clicmd:: debug zebra mpls [detailed] + + MPLS-related events and information. + +.. clicmd:: debug zebra events + + Zebra events + +.. clicmd:: debug zebra nht [detailed] + + Nexthop-tracking / reachability information + +.. clicmd:: debug zebra vxlan + + VxLAN (EVPN) events + +.. clicmd:: debug zebra pseudowires + + Pseudowire events. + +.. clicmd:: debug zebra packet [<recv|send>] [detail] + + ZAPI message and packet details + +.. clicmd:: debug zebra kernel + + Kernel / OS events. + +.. clicmd:: debug zebra kernel msgdump [<recv|send>] + + Raw OS (netlink) message details. + +.. clicmd:: debug zebra rib [detailed] + + RIB events. + +.. clicmd:: debug zebra fpm + + FPM (forwarding-plane manager) events. + +.. clicmd:: debug zebra dplane [detailed] + + Dataplane / FIB events. + +.. clicmd:: debug zebra pbr + + PBR (policy-based routing) events. + +.. clicmd:: debug zebra mlag + + MLAG events. + +.. clicmd:: debug zebra evpn mh <es|mac|neigh|nh> + + EVPN multi-hop events. + +.. clicmd:: debug zebra nexthop [detail] + + Nexthop and nexthop-group events. + diff --git a/eigrpd/eigrpd.conf.sample b/eigrpd/eigrpd.conf.sample deleted file mode 100644 index 662e667d3f..0000000000 --- a/eigrpd/eigrpd.conf.sample +++ /dev/null @@ -1,13 +0,0 @@ -! -*- eigrpd -*- -! -! EIGRPDd sample configuration file -! -! -hostname eigrpd -password zebra -!enable password please-set-at-here -! -!router eigrp 4453 -! network 192.168.1.0/24 -! -log stdout diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index ba9445acb9..82873a4960 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -5,7 +5,6 @@ if EIGRPD noinst_LIBRARIES += eigrpd/libeigrp.a sbin_PROGRAMS += eigrpd/eigrpd -dist_examples_DATA += eigrpd/eigrpd.conf.sample vtysh_scan += \ eigrpd/eigrp_cli.c \ eigrpd/eigrp_dump.c \ diff --git a/isisd/fabricd.conf.sample b/isisd/fabricd.conf.sample deleted file mode 100644 index be9e33ba62..0000000000 --- a/isisd/fabricd.conf.sample +++ /dev/null @@ -1,27 +0,0 @@ -! -*- openfabric -*- -! -! fabricd sample configuration file -! -hostname fabricd -password foo -enable password foo -log stdout -!log file /tmp/fabricd.log -! -! -router openfabric DEAD - net 47.0023.0000.0003.0300.0100.0102.0304.0506.00 -! lsp-lifetime 65535 - -! hostname isisd-router -! domain-password foobar - -interface eth0 - ip router openfabric DEAD -! openfabric hello-interval 5 -! openfabric lsp-interval 1000 - -! -- optional -! openfabric retransmit-interval 10 -! openfabric retransmit-throttle-interval -! diff --git a/isisd/isisd.conf.sample b/isisd/isisd.conf.sample deleted file mode 100644 index 47b15953fd..0000000000 --- a/isisd/isisd.conf.sample +++ /dev/null @@ -1,39 +0,0 @@ -! -*- isis -*- -! -! ISISd sample configuration file -! -hostname isisd -password foo -enable password foo -log stdout -!log file /tmp/isisd.log -! -! -router isis DEAD - net 47.0023.0000.0003.0300.0100.0102.0304.0506.00 -! is-type level-1 - -! -- set the lifetime either for level-1, level-2 or both -! lsp-lifetime level-1 65535 -! lsp-lifetime level-2 65535 -! lsp-lifetime 65535 - -! hostname isisd-router -! area-password foobar -! domain-password foobar - -interface eth0 - ip router isis DEAD -! isis hello-interval 5 -! isis lsp-interval 1000 - -! -- optional -! isis circuit-type level-1 -! isis password lallaa level-1 -! isis metric 1 level-1 -! isis csnp-interval 5 level-1 -! isis retransmit-interval 10 -! isis retransmit-throttle-interval -! isis hello-multiplier 2 level-1 -! isis priority 64 -! diff --git a/isisd/subdir.am b/isisd/subdir.am index 4cefe6e10b..11bae41657 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -5,7 +5,6 @@ if ISISD noinst_LIBRARIES += isisd/libisis.a sbin_PROGRAMS += isisd/isisd -dist_examples_DATA += isisd/isisd.conf.sample vtysh_scan += \ isisd/isis_cli.c \ isisd/isis_ldp_sync.c \ @@ -26,7 +25,6 @@ endif if FABRICD noinst_LIBRARIES += isisd/libfabric.a sbin_PROGRAMS += isisd/fabricd -dist_examples_DATA += isisd/fabricd.conf.sample if !ISISD vtysh_scan += \ isisd/isis_cli.c \ diff --git a/ldpd/ldpd.conf.sample b/ldpd/ldpd.conf.sample deleted file mode 100644 index 49da35c284..0000000000 --- a/ldpd/ldpd.conf.sample +++ /dev/null @@ -1,46 +0,0 @@ -! -*- ldp -*- -! -! LDPd sample configuration file -! -hostname ldpd -password zebra -log stdout -! -interface eth0 -! -interface eth1 -! -interface lo -! -mpls ldp - dual-stack cisco-interop - neighbor 10.0.1.5 password opensourcerouting - neighbor 172.16.0.1 password opensourcerouting - ! - address-family ipv4 - discovery transport-address 10.0.1.1 - label local advertise explicit-null - ! - interface eth0 - ! - interface eth1 - ! - ! - address-family ipv6 - discovery transport-address 2001:db8::1 - ! - interface eth1 - ! - ! -! -l2vpn ENG type vpls - bridge br0 - member interface eth2 - ! - member pseudowire mpw0 - neighbor lsr-id 1.1.1.1 - pw-id 100 - ! -! -line vty -! diff --git a/ldpd/subdir.am b/ldpd/subdir.am index aa9b751bcc..5fc3847c6d 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -5,7 +5,6 @@ if LDPD noinst_LIBRARIES += ldpd/libldp.a sbin_PROGRAMS += ldpd/ldpd -dist_examples_DATA += ldpd/ldpd.conf.sample vtysh_scan += ldpd/ldp_vty_cmds.c vtysh_daemons += ldpd man8 += $(MANBUILD)/frr-ldpd.8 @@ -988,6 +988,9 @@ void bfd_sess_show(struct vty *vty, struct json_object *json, json_object *json_bfd = NULL; char time_buf[64]; + if (!bsp) + return; + /* Show type. */ if (json) { json_bfd = json_object_new_object(); diff --git a/lib/command.c b/lib/command.c index 770e2fc5ac..d2798b5002 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2226,18 +2226,19 @@ DEFUN (no_banner_motd, DEFUN(find, find_cmd, - "find REGEX", + "find REGEX...", "Find CLI command matching a regular expression\n" "Search pattern (POSIX regex)\n") { - char *pattern = argv[1]->arg; const struct cmd_node *node; const struct cmd_element *cli; vector clis; regex_t exp = {}; + char *pattern = argv_concat(argv, argc, 1); int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED); + XFREE(MTYPE_TMP, pattern); if (cr != 0) { switch (cr) { diff --git a/lib/elf_py.c b/lib/elf_py.c index d26e443b82..b47aa3d795 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -1032,7 +1032,7 @@ static char *elfdata_strptr(Elf_Data *data, size_t offset) static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, size_t entries, Elf_Data *symdata, - Elf_Data *strdata) + Elf_Data *strdata, Elf_Type typ) { size_t i; @@ -1041,12 +1041,59 @@ static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, size_t symidx; GElf_Rela *rela; GElf_Sym *sym; + GElf_Addr rel_offs = 0; relw = (struct elfreloc *)typeobj_elfreloc.tp_alloc( &typeobj_elfreloc, 0); relw->ef = w; - rela = relw->rela = gelf_getrela(reldata, i, &relw->_rela); + if (typ == ELF_T_REL) { + GElf_Rel _rel, *rel; + GElf_Addr offs; + + rel = gelf_getrel(reldata, i, &_rel); + relw->rela = &relw->_rela; + relw->rela->r_offset = rel->r_offset; + relw->rela->r_info = rel->r_info; + relw->rela->r_addend = 0; + relw->relative = true; + + /* REL uses the pointer contents itself instead of the + * RELA addend field :( ... theoretically this could + * be some weird platform specific encoding, but since + * we only care about data relocations it should + * always be a pointer... + */ + if (elffile_virt2file(w, rel->r_offset, &offs)) { + Elf_Data *ptr, *conv; + GElf_Addr tmp; + Elf_Data mem = { + .d_buf = (void *)&tmp, + .d_type = ELF_T_ADDR, + .d_version = EV_CURRENT, + .d_size = sizeof(tmp), + .d_off = 0, + .d_align = 0, + }; + + ptr = elf_getdata_rawchunk(w->elf, offs, + w->elfclass / 8, + ELF_T_ADDR); + + conv = gelf_xlatetom(w->elf, &mem, ptr, + w->mmap[EI_DATA]); + if (conv) { + memcpy(&rel_offs, conv->d_buf, + conv->d_size); + + relw->relative = false; + relw->rela->r_addend = rel_offs; + } + } + } else + relw->rela = gelf_getrela(reldata, i, &relw->_rela); + + rela = relw->rela; symidx = relw->symidx = GELF_R_SYM(rela->r_info); sym = relw->sym = gelf_getsym(symdata, symidx, &relw->_sym); if (sym) { @@ -1062,9 +1109,16 @@ static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, relw->st_value = 0; } - debugf("dynreloc @ %016llx sym %5llu %016llx %s\n", - (long long)rela->r_offset, (unsigned long long)symidx, - (long long)rela->r_addend, relw->symname); + if (typ == ELF_T_RELA) + debugf("dynrela @ %016llx sym %5llu %016llx %s\n", + (long long)rela->r_offset, + (unsigned long long)symidx, + (long long)rela->r_addend, relw->symname); + else + debugf("dynrel @ %016llx sym %5llu (%016llx) %s\n", + (long long)rela->r_offset, + (unsigned long long)symidx, + (unsigned long long)rel_offs, relw->symname); elfrelocs_add(&w->dynrelocs, relw); } @@ -1166,8 +1220,10 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, Elf_Data *dyndata = elf_getdata_rawchunk(w->elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN); - GElf_Addr dynrela = 0, symtab = 0, strtab = 0; - size_t dynrelasz = 0, dynrelaent = 0, strsz = 0; + GElf_Addr dynrela = 0, dynrel = 0, symtab = 0, strtab = 0; + size_t dynrelasz = 0, dynrelaent = 0; + size_t dynrelsz = 0, dynrelent = 0; + size_t strsz = 0; GElf_Dyn _dyn, *dyn; for (size_t j = 0;; j++) { @@ -1198,16 +1254,20 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, dynrelaent = dyn->d_un.d_val; break; + case DT_REL: + dynrel = dyn->d_un.d_ptr; + break; case DT_RELSZ: - if (dyn->d_un.d_val) - fprintf(stderr, - "WARNING: ignoring non-empty DT_REL!\n"); + dynrelsz = dyn->d_un.d_val; + break; + case DT_RELENT: + dynrelent = dyn->d_un.d_val; break; } } GElf_Addr offset; - Elf_Data *symdata = NULL, *strdata = NULL, *reladata = NULL; + Elf_Data *symdata = NULL, *strdata = NULL; if (elffile_virt2file(w, symtab, &offset)) symdata = elf_getdata_rawchunk(w->elf, offset, @@ -1217,19 +1277,37 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, strdata = elf_getdata_rawchunk(w->elf, offset, strsz, ELF_T_BYTE); - if (!dynrela || !dynrelasz || !dynrelaent) - continue; + size_t c; - if (!elffile_virt2file(w, dynrela, &offset)) - continue; + if (dynrela && dynrelasz && dynrelaent + && elffile_virt2file(w, dynrela, &offset)) { + Elf_Data *reladata = NULL; - debugf("dynrela @%llx/%llx+%llx\n", (long long)dynrela, - (long long)offset, (long long)dynrelasz); + debugf("dynrela @%llx/%llx+%llx\n", (long long)dynrela, + (long long)offset, (long long)dynrelasz); - reladata = elf_getdata_rawchunk(w->elf, offset, dynrelasz, - ELF_T_RELA); - elffile_add_dynreloc(w, reladata, dynrelasz / dynrelaent, - symdata, strdata); + reladata = elf_getdata_rawchunk(w->elf, offset, + dynrelasz, ELF_T_RELA); + + c = dynrelasz / dynrelaent; + elffile_add_dynreloc(w, reladata, c, symdata, strdata, + ELF_T_RELA); + } + + if (dynrel && dynrelsz && dynrelent + && elffile_virt2file(w, dynrel, &offset)) { + Elf_Data *reldata = NULL; + + debugf("dynrel @%llx/%llx+%llx\n", (long long)dynrel, + (long long)offset, (long long)dynrelsz); + + reldata = elf_getdata_rawchunk(w->elf, offset, dynrelsz, + ELF_T_REL); + + c = dynrelsz / dynrelent; + elffile_add_dynreloc(w, reldata, c, symdata, strdata, + ELF_T_REL); + } } #endif @@ -1056,15 +1056,30 @@ struct connected *connected_get_linklocal(struct interface *ifp) void if_terminate(struct vrf *vrf) { struct interface *ifp; + bool delete; + + /* + * If the default VRF is being terminated or has + * already been terminated it means that + * the program is shutting down and we need to + * delete all the interfaces. Otherwise, we only + * need to move VRF's interfaces to the default VRF. + */ + delete = vrf_is_backend_netns() || vrf->vrf_id == VRF_DEFAULT + || !vrf_lookup_by_id(VRF_DEFAULT); while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) { ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name); - if (ifp->node) { - ifp->node->info = NULL; - route_unlock_node(ifp->node); + if (delete) { + if (ifp->node) { + ifp->node->info = NULL; + route_unlock_node(ifp->node); + } + if_delete(&ifp); + } else { + if_update_to_new_vrf(ifp, VRF_DEFAULT); } - if_delete(&ifp); } } @@ -464,7 +464,15 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST), DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY), DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD), - DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL)}; + DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL), + DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED), + DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED), + DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET), + DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER), + DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER), + DESC_ENTRY(ZEBRA_NEIGH_IP_ADD), + DESC_ENTRY(ZEBRA_NEIGH_IP_DEL), + DESC_ENTRY(ZEBRA_CONFIGURE_ARP)}; #undef DESC_ENTRY static const struct zebra_desc_table unknown = {0, "unknown", '?'}; diff --git a/lib/routemap.c b/lib/routemap.c index 33c65ac333..b2cb299fd3 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -2906,29 +2906,6 @@ void route_map_notify_dependencies(const char *affected_name, } /* VTY related functions. */ -DEFUN(no_routemap_optimization, no_routemap_optimization_cmd, - "no route-map optimization", - NO_STR - "route-map\n" - "optimization\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - - index->map->optimization_disabled = true; - return CMD_SUCCESS; -} - -DEFUN(routemap_optimization, routemap_optimization_cmd, - "route-map optimization", - "route-map\n" - "optimization\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - - index->map->optimization_disabled = false; - return CMD_SUCCESS; -} - static void clear_route_map_helper(struct route_map *map) { struct route_map_index *index; @@ -3241,8 +3218,5 @@ void route_map_init(void) install_element(ENABLE_NODE, &debug_rmap_cmd); install_element(ENABLE_NODE, &no_debug_rmap_cmd); - install_element(RMAP_NODE, &routemap_optimization_cmd); - install_element(RMAP_NODE, &no_routemap_optimization_cmd); - install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd); } diff --git a/lib/routemap.h b/lib/routemap.h index 6385193bbf..5b6b64eaeb 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -902,6 +902,9 @@ extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode, extern void route_map_description_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +extern void route_map_optimization_disabled_show(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); extern void route_map_cli_init(void); #ifdef __cplusplus diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 9a53c11a4c..e11b9eea74 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -1396,6 +1396,74 @@ void route_map_description_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL)); } +DEFPY_YANG( + route_map_optimization, route_map_optimization_cmd, + "[no] route-map WORD$name optimization", + NO_STR + ROUTE_MAP_CMD_STR + "Configure route-map optimization\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf( + xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']/optimization-disabled", + name); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, no ? "true" : "false"); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_optimization_disabled_show(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults) +{ + const char *name = yang_dnode_get_string(dnode, "../name"); + const bool disabled = yang_dnode_get_bool(dnode, NULL); + + vty_out(vty, "%sroute-map %s optimization\n", disabled ? "no " : "", + name); +} + +#if CONFDATE > 20220409 +CPP_NOTICE("Time to remove old route-map optimization command") +#endif + +DEFPY_HIDDEN( + routemap_optimization, routemap_optimization_cmd, + "[no] route-map optimization", + NO_STR + "route-map\n" + "optimization\n") +{ + const struct lyd_node *rmi_dnode; + const char *rm_name; + char xpath[XPATH_MAXLEN]; + + vty_out(vty, + "%% This command is deprecated. Please, use `route-map NAME optimization` from the config node.\n"); + + rmi_dnode = + yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); + if (!rmi_dnode) { + vty_out(vty, "%% Failed to get RMI dnode in candidate DB\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + rm_name = yang_dnode_get_string(rmi_dnode, "../name"); + + snprintf( + xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']/optimization-disabled", + rm_name); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, no ? "true" : "false"); + return nb_cli_apply_changes(vty, NULL); +} + static int route_map_config_write(struct vty *vty) { struct lyd_node *dnode; @@ -1447,6 +1515,7 @@ void route_map_cli_init(void) install_element(CONFIG_NODE, &route_map_cmd); install_element(CONFIG_NODE, &no_route_map_cmd); install_element(CONFIG_NODE, &no_route_map_all_cmd); + install_element(CONFIG_NODE, &route_map_optimization_cmd); /* Install the on-match stuff */ install_element(RMAP_NODE, &rmap_onmatch_next_cmd); @@ -1513,4 +1582,6 @@ void route_map_cli_init(void) install_element(RMAP_NODE, &set_srte_color_cmd); install_element(RMAP_NODE, &no_set_srte_color_cmd); + + install_element(RMAP_NODE, &routemap_optimization_cmd); } diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 410eb51f5e..db06e9caac 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -141,6 +141,30 @@ static int lib_route_map_destroy(struct nb_cb_destroy_args *args) } /* + * XPath: /frr-route-map:lib/route-map/optimization-disabled + */ +static int +lib_route_map_optimization_disabled_modify(struct nb_cb_modify_args *args) +{ + struct route_map *rm; + bool disabled = yang_dnode_get_bool(args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rm = nb_running_get_entry(args->dnode, NULL, true); + rm->optimization_disabled = disabled; + break; + } + + return NB_OK; +} + +/* * XPath: /frr-route-map:lib/route-map/entry */ static int lib_route_map_entry_create(struct nb_cb_create_args *args) @@ -1198,6 +1222,13 @@ const struct frr_yang_module_info frr_route_map_info = { } }, { + .xpath = "/frr-route-map:lib/route-map/optimization-disabled", + .cbs = { + .modify = lib_route_map_optimization_disabled_modify, + .cli_show = route_map_optimization_disabled_show, + } + }, + { .xpath = "/frr-route-map:lib/route-map/entry", .cbs = { .create = lib_route_map_entry_create, diff --git a/lib/zclient.c b/lib/zclient.c index c78937c1ec..d613906d82 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3916,6 +3916,21 @@ static int zclient_read(struct thread *thread) (*zclient->zebra_client_close_notify)(command, zclient, length, vrf_id); break; + case ZEBRA_NHRP_NEIGH_ADDED: + if (zclient->neighbor_added) + (*zclient->neighbor_added)(command, zclient, length, + vrf_id); + break; + case ZEBRA_NHRP_NEIGH_REMOVED: + if (zclient->neighbor_removed) + (*zclient->neighbor_removed)(command, zclient, length, + vrf_id); + break; + case ZEBRA_NHRP_NEIGH_GET: + if (zclient->neighbor_get) + (*zclient->neighbor_get)(command, zclient, length, + vrf_id); + break; default: break; } @@ -4181,3 +4196,59 @@ char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len) return buf; } + +static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add) +{ + uint8_t family; + + STREAM_GETC(s, family); + if (family != AF_INET && family != AF_INET6) + return -1; + + STREAM_GET(&add->ip.addr, s, family2addrsize(family)); + add->ipa_type = family; + return 0; + stream_failure: + return -1; +} + +int zclient_neigh_ip_encode(struct stream *s, + uint16_t cmd, + union sockunion *in, + union sockunion *out, + struct interface *ifp) +{ + int ret = 0; + + zclient_create_header(s, cmd, ifp->vrf_id); + stream_putc(s, sockunion_family(in)); + stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in)); + if (out && sockunion_family(out) != AF_UNSPEC) { + stream_putc(s, sockunion_family(out)); + stream_write(s, sockunion_get_addr(out), + sockunion_get_addrlen(out)); + } else + stream_putc(s, AF_UNSPEC); + stream_putl(s, ifp->ifindex); + if (out) + stream_putl(s, ZEBRA_NEIGH_STATE_REACHABLE); + else + stream_putl(s, ZEBRA_NEIGH_STATE_FAILED); + return ret; +} + +int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api) +{ + int ret; + + ret = zclient_neigh_ip_read_entry(s, &api->ip_in); + if (ret < 0) + return -1; + zclient_neigh_ip_read_entry(s, &api->ip_out); + + STREAM_GETL(s, api->index); + STREAM_GETL(s, api->ndm_state); + return 0; + stream_failure: + return -1; +} diff --git a/lib/zclient.h b/lib/zclient.h index bd952ea1e6..90240e40b2 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -23,6 +23,7 @@ /* For struct zapi_route. */ #include "prefix.h" +#include "ipaddr.h" /* For struct interface and struct connected. */ #include "if.h" @@ -223,6 +224,14 @@ typedef enum { ZEBRA_NEIGH_DISCOVER, ZEBRA_ROUTE_NOTIFY_REQUEST, ZEBRA_CLIENT_CLOSE_NOTIFY, + ZEBRA_NHRP_NEIGH_ADDED, + ZEBRA_NHRP_NEIGH_REMOVED, + ZEBRA_NHRP_NEIGH_GET, + ZEBRA_NHRP_NEIGH_REGISTER, + ZEBRA_NHRP_NEIGH_UNREGISTER, + ZEBRA_NEIGH_IP_ADD, + ZEBRA_NEIGH_IP_DEL, + ZEBRA_CONFIGURE_ARP, } zebra_message_types_t; enum zebra_error_types { @@ -381,6 +390,9 @@ struct zclient { int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS); int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS); int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS); + void (*neighbor_added)(ZAPI_CALLBACK_ARGS); + void (*neighbor_removed)(ZAPI_CALLBACK_ARGS); + void (*neighbor_get)(ZAPI_CALLBACK_ARGS); }; /* Zebra API message flag. */ @@ -794,6 +806,27 @@ struct zclient_options { extern struct zclient_options zclient_options_default; +/* link layer representation for GRE like interfaces + * ip_in is the underlay IP, ip_out is the tunnel dest + * index stands for the index of the interface + * ndm state stands for the NDM value in netlink + */ +#define ZEBRA_NEIGH_STATE_REACHABLE (0x02) +#define ZEBRA_NEIGH_STATE_FAILED (0x20) +struct zapi_neigh_ip { + int cmd; + struct ipaddr ip_in; + struct ipaddr ip_out; + ifindex_t index; + uint32_t ndm_state; +}; +int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api); +int zclient_neigh_ip_encode(struct stream *s, + uint16_t cmd, + union sockunion *in, + union sockunion *out, + struct interface *ifp); + /* * We reserve the top 4 bits for l2-NHG, everything else * is for zebra/proto l3-NHG. diff --git a/nhrpd/linux.c b/nhrpd/linux.c index 59c82b1c55..9cabdbf065 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -154,7 +154,6 @@ int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af) break; } ret |= linux_configure_arp(ifname, 1); - ret |= netlink_configure_arp(ifindex, af); return ret; } diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index dc4697cda0..ecea0a9ec5 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -19,6 +19,8 @@ #include <linux/netfilter/nfnetlink_log.h> #include "thread.h" +#include "stream.h" +#include "prefix.h" #include "nhrpd.h" #include "netlink.h" #include "znl.h" @@ -27,129 +29,11 @@ int netlink_req_fd = -1; int netlink_nflog_group; static int netlink_log_fd = -1; static struct thread *netlink_log_thread; -static int netlink_listen_fd = -1; - -typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma) { - struct nlmsghdr *n; - struct ndmsg *ndm; - struct zbuf *zb = zbuf_alloc(512); - - n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, - NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); - ndm = znl_push(zb, sizeof(*ndm)); - *ndm = (struct ndmsg){ - .ndm_family = sockunion_family(proto), - .ndm_ifindex = ifp->ifindex, - .ndm_type = RTN_UNICAST, - .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED, - }; - znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), - family2addrsize(sockunion_family(proto))); - if (nbma) - znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), - family2addrsize(sockunion_family(nbma))); - znl_nlmsg_complete(zb, n); - zbuf_send(zb, netlink_req_fd); - zbuf_recv(zb, netlink_req_fd); - zbuf_free(zb); -} - -static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb) -{ - struct ndmsg *ndm; - struct rtattr *rta; - struct nhrp_cache *c; - struct interface *ifp; - struct zbuf payload; - union sockunion addr, lladdr; - size_t len; - int state; - - memset(&lladdr, 0, sizeof(lladdr)); - ndm = znl_pull(zb, sizeof(*ndm)); - if (!ndm) - return; - - sockunion_family(&addr) = AF_UNSPEC; - while ((rta = znl_rta_pull(zb, &payload)) != NULL) { - len = zbuf_used(&payload); - switch (rta->rta_type) { - case NDA_DST: - sockunion_set(&addr, ndm->ndm_family, - zbuf_pulln(&payload, len), len); - break; - case NDA_LLADDR: - sockunion_set(&lladdr, ndm->ndm_family, - zbuf_pulln(&payload, len), len); - break; - } - } - - ifp = if_lookup_by_index(ndm->ndm_ifindex, VRF_DEFAULT); - if (!ifp || sockunion_family(&addr) == AF_UNSPEC) - return; - - c = nhrp_cache_get(ifp, &addr, 0); - if (!c) - return; - - debugf(NHRP_DEBUG_KERNEL, - "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u", - (msg->nlmsg_type == RTM_GETNEIGH) - ? "who-has" - : (msg->nlmsg_type == RTM_NEWNEIGH) ? "new-neigh" - : "del-neigh", - &addr, ifp->name, &lladdr, ndm->ndm_state, c->used, c->cur.type); - - if (msg->nlmsg_type == RTM_GETNEIGH) { - if (c->cur.type >= NHRP_CACHE_CACHED) { - nhrp_cache_set_used(c, 1); - debugf(NHRP_DEBUG_KERNEL, - "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU", - &addr, ifp->name, &c->cur.remote_nbma_natoa, - &c->cur.peer->vc->remote.nbma, &lladdr); - /* In case of shortcuts, nbma is given by lladdr, not - * vc->remote.nbma. - */ - netlink_update_binding(ifp, &addr, &lladdr); - } - } else { - state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state - : NUD_FAILED; - nhrp_cache_set_used(c, state == NUD_REACHABLE); - } -} - -static int netlink_route_recv(struct thread *t) -{ - uint8_t buf[ZNL_BUFFER_SIZE]; - int fd = THREAD_FD(t); - struct zbuf payload, zb; - struct nlmsghdr *n; - - zbuf_init(&zb, buf, sizeof(buf), 0); - while (zbuf_recv(&zb, fd) > 0) { - while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) { - debugf(NHRP_DEBUG_KERNEL, - "Netlink: Received msg_type %u, msg_flags %u", - n->nlmsg_type, n->nlmsg_flags); - switch (n->nlmsg_type) { - case RTM_GETNEIGH: - case RTM_NEWNEIGH: - case RTM_DELNEIGH: - netlink_neigh_msg(n, &payload); - break; - } - } - } - - thread_add_read(master, netlink_route_recv, 0, fd, NULL); - - return 0; + nhrp_send_zebra_nbr(proto, nbma, ifp); } static void netlink_log_register(int fd, int group) @@ -265,47 +149,64 @@ void netlink_set_nflog_group(int nlgroup) } } -void netlink_init(void) +void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) { - netlink_req_fd = znl_open(NETLINK_ROUTE, 0); - if (netlink_req_fd < 0) - return; + union sockunion addr = {}, lladdr = {}; + struct interface *ifp; + int state, ndm_state; + struct nhrp_cache *c; + struct zapi_neigh_ip api = {}; - netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH); - if (netlink_listen_fd < 0) + zclient_neigh_ip_decode(zclient->ibuf, &api); + if (api.ip_in.ipa_type == AF_UNSPEC) return; + sockunion_family(&addr) = api.ip_in.ipa_type; + memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr, + family2addrsize(api.ip_in.ipa_type)); - thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd, NULL); -} + sockunion_family(&lladdr) = api.ip_out.ipa_type; + if (api.ip_out.ipa_type != AF_UNSPEC) + memcpy((uint8_t *)sockunion_get_addr(&lladdr), + &api.ip_out.ip.addr, + family2addrsize(api.ip_out.ipa_type)); -int netlink_configure_arp(unsigned int ifindex, int pf) -{ - struct nlmsghdr *n; - struct ndtmsg *ndtm; - struct rtattr *rta; - struct zbuf *zb = zbuf_alloc(512); - int r; - - n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE); - ndtm = znl_push(zb, sizeof(*ndtm)); - *ndtm = (struct ndtmsg){ - .ndtm_family = pf, - }; + ifp = if_lookup_by_index(api.index, vrf_id); + ndm_state = api.ndm_state; - znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache", - 10); - - rta = znl_rta_nested_push(zb, NDTA_PARMS); - znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex); - znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1); - znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0); - znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0); - znl_rta_nested_complete(zb, rta); - - znl_nlmsg_complete(zb, n); - r = zbuf_send(zb, netlink_req_fd); - zbuf_recv(zb, netlink_req_fd); - zbuf_free(zb); + if (!ifp) + return; + c = nhrp_cache_get(ifp, &addr, 0); + if (!c) + return; + debugf(NHRP_DEBUG_KERNEL, + "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u", + (cmd == ZEBRA_NHRP_NEIGH_GET) + ? "who-has" + : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh" + : "del-neigh", + &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type); + if (cmd == ZEBRA_NHRP_NEIGH_GET) { + if (c->cur.type >= NHRP_CACHE_CACHED) { + nhrp_cache_set_used(c, 1); + debugf(NHRP_DEBUG_KERNEL, + "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU", + &addr, ifp->name, &c->cur.remote_nbma_natoa, + &c->cur.peer->vc->remote.nbma, &lladdr); + /* In case of shortcuts, nbma is given by lladdr, not + * vc->remote.nbma. + */ + netlink_update_binding(ifp, &addr, &lladdr); + } + } else { + state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state + : ZEBRA_NEIGH_STATE_FAILED; + nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE); + } +} - return r; +void netlink_init(void) +{ + netlink_req_fd = znl_open(NETLINK_ROUTE, 0); + if (netlink_req_fd < 0) + return; } diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index a6880054fd..f6d89b141a 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -298,6 +298,7 @@ void nhrp_interface_update(struct interface *ifp) if (!if_ad->configured) { os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi)); + nhrp_send_zebra_configure_arp(ifp, afi2family(afi)); if_ad->configured = 1; nhrp_interface_update_address(ifp, afi, 1); } diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index b78bf92784..9dfaf073d8 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -34,7 +34,6 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) struct zbuf extpl; union sockunion cie_nbma, cie_nbma_nhs, cie_proto, cie_proto_nhs, *proto; - char buf[64]; int ok = 0, holdtime; unsigned short mtu = 0; @@ -78,10 +77,8 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) &cie_proto)) { nifp->nat_nbma = cie_nbma; debugf(NHRP_DEBUG_IF, - "%s: NAT detected, real NBMA address: %s", - ifp->name, - sockunion2str(&nifp->nbma, buf, - sizeof(buf))); + "%s: NAT detected, real NBMA address: %pSU", + ifp->name, &nifp->nbma); } break; case NHRP_EXTENSION_RESPONDER_ADDRESS: diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 199f3332d2..a44190d292 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -192,10 +192,10 @@ static void *nhrp_peer_create(void *data) return p; } -static void do_peer_hash_free(struct hash_bucket *hb, - void *arg __attribute__((__unused__))) +static void do_peer_hash_free(void *hb_data) { - struct nhrp_peer *p = hb->data; + struct nhrp_peer *p = (struct nhrp_peer *)hb_data; + nhrp_peer_check_delete(p); } @@ -207,9 +207,10 @@ void nhrp_peer_interface_del(struct interface *ifp) nifp->peer_hash ? nifp->peer_hash->count : 0); if (nifp->peer_hash) { - hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL); + hash_clean(nifp->peer_hash, do_peer_hash_free); assert(nifp->peer_hash->count == 0); hash_free(nifp->peer_hash); + nifp->peer_hash = NULL; } } @@ -422,7 +423,7 @@ static void nhrp_process_nat_extension(struct nhrp_packet_parser *pp, if (!sockunion_cmp(proto, &cie_proto)) { debugf(NHRP_DEBUG_COMMON, - "\tcie_nbma for proto %pSU is %pSU", + "cie_nbma for proto %pSU is %pSU", proto, cie_nbma); break; } diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 7a4c57b5d4..23fa0771ef 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -79,6 +79,24 @@ static void nhrp_route_update_zebra(const struct prefix *p, } } +static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER : + ZEBRA_NHRP_NEIGH_UNREGISTER, + vrf_id); + stream_putw(s, afi); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} + void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) { struct route_node *rn; @@ -344,6 +362,8 @@ static void nhrp_zebra_connected(struct zclient *zclient) ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); + nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true); + nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true); } void nhrp_zebra_init(void) @@ -357,7 +377,9 @@ void nhrp_zebra_init(void) zclient->interface_address_delete = nhrp_interface_address_delete; zclient->redistribute_route_add = nhrp_route_read; zclient->redistribute_route_del = nhrp_route_read; - + zclient->neighbor_added = nhrp_neighbor_operation; + zclient->neighbor_removed = nhrp_neighbor_operation; + zclient->neighbor_get = nhrp_neighbor_operation; zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs); } @@ -370,8 +392,47 @@ static void nhrp_table_node_cleanup(struct route_table *table, XFREE(MTYPE_NHRP_ROUTE, node->info); } +void nhrp_send_zebra_configure_arp(struct interface *ifp, int family) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) { + debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready", + __func__); + return; + } + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, + ZEBRA_CONFIGURE_ARP, + ifp->vrf_id); + stream_putc(s, family); + stream_putl(s, ifp->ifindex); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} + +void nhrp_send_zebra_nbr(union sockunion *in, + union sockunion *out, + struct interface *ifp) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return; + s = zclient->obuf; + stream_reset(s); + zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD : + ZEBRA_NEIGH_IP_DEL, in, out, + ifp); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} + void nhrp_zebra_terminate(void) { + nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false); + nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false); zclient_stop(zclient); zclient_free(zclient); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index e4afb22f80..136f855dfc 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -88,7 +88,12 @@ static inline int notifier_active(struct notifier_list *l) void nhrp_zebra_init(void); void nhrp_zebra_terminate(void); - +void nhrp_send_zebra_configure_arp(struct interface *ifp, int family); +void nhrp_send_zebra_nbr(union sockunion *in, + union sockunion *out, + struct interface *ifp); +void nhrp_send_zebra_configure_arp(struct interface *ifp, + int family); struct zbuf; struct nhrp_vc; struct nhrp_cache; @@ -326,6 +331,7 @@ int nhrp_interface_up(ZAPI_CALLBACK_ARGS); int nhrp_interface_down(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS); +void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS); void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn); diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 9b117ddf0d..c21e01601c 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -470,10 +470,44 @@ static void vici_register_event(struct vici_conn *vici, const char *name) vici_submit(vici, obuf); } +static bool vici_charon_filepath_done; +static bool vici_charon_not_found; + +static char *vici_get_charon_filepath(void) +{ + static char buff[1200]; + FILE *fp; + char *ptr; + char line[1024]; + + if (vici_charon_filepath_done) + return (char *)buff; + fp = popen("ipsec --piddir", "r"); + if (!fp) { + if (!vici_charon_not_found) { + flog_err(EC_NHRP_SWAN, + "VICI: Failed to retrieve charon file path"); + vici_charon_not_found = true; + } + return NULL; + } + /* last line of output is used to get vici path */ + while (fgets(line, sizeof(line), fp) != NULL) { + ptr = strchr(line, '\n'); + if (ptr) + *ptr = '\0'; + snprintf(buff, sizeof(buff), "%s/charon.vici", line); + } + pclose(fp); + vici_charon_filepath_done = true; + return buff; +} + static int vici_reconnect(struct thread *t) { struct vici_conn *vici = THREAD_ARG(t); int fd; + char *file_path; vici->t_reconnect = NULL; if (vici->fd >= 0) @@ -481,6 +515,11 @@ static int vici_reconnect(struct thread *t) fd = sock_open_unix(VICI_SOCKET); if (fd < 0) { + file_path = vici_get_charon_filepath(); + if (file_path) + fd = sock_open_unix(file_path); + } + if (fd < 0) { debugf(NHRP_DEBUG_VICI, "%s: failure connecting VICI socket: %s", __func__, strerror(errno)); diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c index a23526af48..43ce974817 100644 --- a/nhrpd/zbuf.c +++ b/nhrpd/zbuf.c @@ -27,7 +27,7 @@ struct zbuf *zbuf_alloc(size_t size) { struct zbuf *zb; - zb = XMALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size); + zb = XCALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size); zbuf_init(zb, zb + 1, size, 0); zb->allocated = 1; diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample deleted file mode 100644 index 0a6ddb7137..0000000000 --- a/ospf6d/ospf6d.conf.sample +++ /dev/null @@ -1,52 +0,0 @@ -! -! Zebra configuration saved from vty -! 2003/11/28 00:49:49 -! -hostname ospf6d@plant -password zebra -log stdout -service advanced-vty -! -debug ospf6 neighbor state -! -interface fxp0 - ipv6 ospf6 cost 1 - ipv6 ospf6 hello-interval 10 - ipv6 ospf6 dead-interval 40 - ipv6 ospf6 retransmit-interval 5 - ipv6 ospf6 priority 0 - ipv6 ospf6 transmit-delay 1 - ipv6 ospf6 instance-id 0 -! -interface lo0 - ipv6 ospf6 cost 1 - ipv6 ospf6 hello-interval 10 - ipv6 ospf6 dead-interval 40 - ipv6 ospf6 retransmit-interval 5 - ipv6 ospf6 priority 1 - ipv6 ospf6 transmit-delay 1 - ipv6 ospf6 instance-id 0 -! -router ospf6 - router-id 255.1.1.1 - redistribute static route-map static-ospf6 - interface fxp0 area 0.0.0.0 -! -access-list access4 permit 127.0.0.1/32 -! -ipv6 access-list access6 permit 3ffe:501::/32 -ipv6 access-list access6 permit 2001:200::/48 -ipv6 access-list access6 permit ::1/128 -! -ipv6 prefix-list test-prefix seq 1000 deny any -! -route-map static-ospf6 permit 10 - match ipv6 address prefix-list test-prefix - set metric-type type-2 - set metric 2000 -! -line vty - access-class access4 - ipv6 access-class access6 - exec-timeout 0 0 -! diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 788b532a90..5ccae5b279 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -5,7 +5,6 @@ if OSPF6D noinst_LIBRARIES += ospf6d/libospf6.a sbin_PROGRAMS += ospf6d/ospf6d -dist_examples_DATA += ospf6d/ospf6d.conf.sample vtysh_scan += \ ospf6d/ospf6_abr.c \ ospf6d/ospf6_asbr.c \ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 6829c4a347..6e4bc7abf1 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -694,6 +694,13 @@ static int ospf_if_delete_hook(struct interface *ifp) struct route_node *rn; rc = ospf_opaque_del_if(ifp); + /* + * This function must be called before `route_table_finish` due to + * BFD integration need to iterate over the interface neighbors to + * remove all registrations. + */ + ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp)); + route_table_finish(IF_OIFS(ifp)); for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) @@ -701,7 +708,6 @@ static int ospf_if_delete_hook(struct interface *ifp) ospf_del_if_params(ifp, rn->info); route_table_finish(IF_OIFS_PARAMS(ifp)); - ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp)); XFREE(MTYPE_OSPF_IF_INFO, ifp->info); return rc; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a1dac641d7..2d06e6884d 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7865,10 +7865,9 @@ DEFUN (ip_ospf_message_digest_key, } key_id = strtol(keyid, NULL, 10); - if (ospf_crypt_key_lookup(params->auth_crypt, key_id) != NULL) { - vty_out(vty, "OSPF: Key %d already exists\n", key_id); - return CMD_WARNING; - } + + /* Remove existing key, if any */ + ospf_crypt_key_delete(params->auth_crypt, key_id); ck = ospf_crypt_key_new(); ck->key_id = (uint8_t)key_id; @@ -11711,6 +11710,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) /* Router Dead Interval print. */ if (OSPF_IF_PARAM_CONFIGURED(params, v_wait) + && params->is_v_wait_set && params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) { vty_out(vty, " ip ospf dead-interval "); diff --git a/ospfd/ospfd.conf.sample b/ospfd/ospfd.conf.sample deleted file mode 100644 index 0e8ac67bba..0000000000 --- a/ospfd/ospfd.conf.sample +++ /dev/null @@ -1,13 +0,0 @@ -! -*- ospf -*- -! -! OSPFd sample configuration file -! -! -hostname ospfd -password zebra -!enable password please-set-at-here -! -!router ospf -! network 192.168.1.0/24 area 0 -! -log stdout diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 63610e38d8..f592a9eec8 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -5,7 +5,6 @@ if OSPFD noinst_LIBRARIES += ospfd/libfrrospf.a sbin_PROGRAMS += ospfd/ospfd -dist_examples_DATA += ospfd/ospfd.conf.sample vtysh_scan += \ ospfd/ospf_bfd.c \ ospfd/ospf_dump.c \ diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h index 654d089cbc..d0af674ff9 100644 --- a/pathd/path_pcep.h +++ b/pathd/path_pcep.h @@ -84,7 +84,7 @@ DECLARE_MTYPE(PCEP); struct pcep_config_group_opts { char name[64]; - char tcp_md5_auth[TCP_MD5SIG_MAXKEYLEN]; + char tcp_md5_auth[PCEP_MD5SIG_MAXKEYLEN]; struct ipaddr source_ip; short source_port; bool draft07; diff --git a/pathd/pathd.conf.sample b/pathd/pathd.conf.sample deleted file mode 100644 index 9fe7d2d6e3..0000000000 --- a/pathd/pathd.conf.sample +++ /dev/null @@ -1,41 +0,0 @@ -! Default pathd configuration sample -! -password frr -log stdout - -segment-routing - traffic-eng - segment-list test1 - index 10 mpls label 123 - index 20 mpls label 456 - ! - segment-list test2 - index 10 mpls label 321 - index 20 mpls label 654 - ! - policy color 1 endpoint 1.1.1.1 - name one - binding-sid 100 - candidate-path preference 100 name test1 explicit segment-list test1 - candidate-path preference 200 name test2 explicit segment-list test2 - ! - policy color 2 endpoint 2.2.2.2 - name two - binding-sid 101 - candidate-path preference 100 name def explicit segment-list test2 - candidate-path preference 200 name dyn dynamic - bandwidth 12345 - metric bound abc 16 required - metric te 10 - ! - ! - pcep - pcc-peer PCE1 - address ip 127.0.0.1 - sr-draft07 - ! - pcc - peer PCE1 - ! - ! -! diff --git a/pathd/subdir.am b/pathd/subdir.am index b4501214bf..38df326489 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -5,7 +5,6 @@ if PATHD noinst_LIBRARIES += pathd/libpath.a sbin_PROGRAMS += pathd/pathd -dist_examples_DATA += pathd/pathd.conf.sample vtysh_scan += $(top_srcdir)/pathd/path_cli.c vtysh_daemons += pathd # TODO add man page @@ -22,7 +21,6 @@ pathd_libpath_a_SOURCES = \ pathd/path_cli.c \ pathd/path_debug.c \ pathd/path_errors.c \ - pathd/path_main.c \ pathd/path_nb.c \ pathd/path_nb_config.c \ pathd/path_nb_state.c \ @@ -50,7 +48,9 @@ noinst_HEADERS += \ pathd/pathd.h \ # end -pathd_pathd_SOURCES = pathd/path_main.c +pathd_pathd_SOURCES = \ + pathd/path_main.c \ + # end nodist_pathd_pathd_SOURCES = \ yang/frr-pathd.yang.c \ # end diff --git a/pbrd/pbrd.conf.sample b/pbrd/pbrd.conf.sample deleted file mode 100644 index c9e7dce01f..0000000000 --- a/pbrd/pbrd.conf.sample +++ /dev/null @@ -1,19 +0,0 @@ -! Sample pbrd configuration file -! -! A quick example of what a pbr configuration might look like -! -! -log stdout -! -! nexthop-group TEST -! nexthop 4.5.6.7 -! nexthop 5.6.7.8 -! ! -! pbr-map BLUE seq 100 -! match dst-ip 9.9.9.0/24 -! match src-ip 10.10.10.0/24 -! set nexthop-group TEST -! ! -! int swp1 -! pbr-policy BLUE -! diff --git a/pbrd/subdir.am b/pbrd/subdir.am index 7ad071af3b..bbe3f2ab71 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -5,7 +5,6 @@ if PBRD noinst_LIBRARIES += pbrd/libpbr.a sbin_PROGRAMS += pbrd/pbrd -dist_examples_DATA += pbrd/pbrd.conf.sample vtysh_scan += \ pbrd/pbr_vty.c \ pbrd/pbr_debug.c \ diff --git a/pceplib/pcep.h b/pceplib/pcep.h index 278ab9d5dc..b5d02c7e62 100644 --- a/pceplib/pcep.h +++ b/pceplib/pcep.h @@ -28,12 +28,10 @@ #endif #if defined(linux) || defined(GNU_LINUX) -//#include <netinet/in.h> + #define ipv6_u __in6_u #else -// bsd family -#define TCP_MD5SIG_MAXKEYLEN 80 -//#include <netinet/in.h> +/* bsd family */ #define ipv6_u __u6_addr #ifdef __FreeBSD__ #include <sys/endian.h> @@ -45,4 +43,12 @@ #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> + +/* Cross-compilation seems to have trouble finding this */ +#if defined(TCP_MD5SIG_MAXKEYLEN) +#define PCEP_MD5SIG_MAXKEYLEN TCP_MD5SIG_MAXKEYLEN +#else +#define PCEP_MD5SIG_MAXKEYLEN 80 +#endif + #endif diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c index 967f138143..37f3353f76 100644 --- a/pceplib/pcep_msg_tlvs_encoding.c +++ b/pceplib/pcep_msg_tlvs_encoding.c @@ -25,6 +25,15 @@ * Encoding and decoding for PCEP Object TLVs. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __FreeBSD__ +#include <sys/endian.h> +#else +#include <endian.h> +#endif /* __FreeBSD__ */ #include <stdlib.h> #include <string.h> diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c index 1a702a8b63..d263f64f39 100644 --- a/pceplib/pcep_pcc.c +++ b/pceplib/pcep_pcc.c @@ -53,7 +53,7 @@ struct cmd_line_args { char dest_ip_str[MAX_DST_IP_STR]; short src_tcp_port; short dest_tcp_port; - char tcp_md5_str[TCP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */ + char tcp_md5_str[PCEP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */ bool is_ipv6; bool eventpoll; /* poll for pcep_event's, or use callback (default) */ }; diff --git a/pceplib/pcep_session_logic.h b/pceplib/pcep_session_logic.h index a082ec66da..9cdec5250f 100644 --- a/pceplib/pcep_session_logic.h +++ b/pceplib/pcep_session_logic.h @@ -122,7 +122,7 @@ typedef struct pcep_configuration_ { struct pcep_versioning *pcep_msg_versioning; - char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN]; + char tcp_authentication_str[PCEP_MD5SIG_MAXKEYLEN]; bool is_tcp_auth_md5; /* true: RFC 2385, false: RFC 5925 */ } pcep_configuration; diff --git a/pceplib/pcep_socket_comm.h b/pceplib/pcep_socket_comm.h index 797ffda860..89d2492914 100644 --- a/pceplib/pcep_socket_comm.h +++ b/pceplib/pcep_socket_comm.h @@ -91,9 +91,9 @@ typedef struct pcep_socket_comm_session_ { int received_bytes; bool close_after_write; void *external_socket_data; /* used for external socket infra */ - char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN - + 1]; /* should be used with is_tcp_auth_md5 - flag */ + /* should be used with is_tcp_auth_md5 flag */ + char tcp_authentication_str[PCEP_MD5SIG_MAXKEYLEN + 1]; + bool is_tcp_auth_md5; /* flag to distinguish between rfc 2385 (md5) and rfc 5925 (tcp-ao) */ diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c index 6b650f6823..57e1d16e91 100644 --- a/pceplib/test/pcep_msg_tlvs_test.c +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -21,6 +21,15 @@ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __FreeBSD__ +#include <sys/endian.h> +#else +#include <endian.h> +#endif /* __FreeBSD__ */ #include <stdlib.h> #include <CUnit/CUnit.h> diff --git a/pimd/pimd.conf.sample b/pimd/pimd.conf.sample deleted file mode 100644 index de1da6b838..0000000000 --- a/pimd/pimd.conf.sample +++ /dev/null @@ -1,40 +0,0 @@ -! -! pimd sample configuration file -! -hostname quagga-pimd-router -password zebra -!enable password zebra -! -!log file pimd.log -log stdout -! -line vty - exec-timeout 60 -! -!debug igmp -!debug pim -!debug pim zebra -! -ip multicast-routing -! -! ! You may want to enable ssmpingd for troubleshooting -! ! See http://www.venaas.no/multicast/ssmping/ -! ! -! ip ssmpingd 1.1.1.1 -! ip ssmpingd 2.2.2.2 -! -! ! HINTS: -! ! - Enable "ip pim ssm" on the interface directly attached to the -! ! multicast source host (if this is the first-hop router) -! ! - Enable "ip pim ssm" on pim-routers-facing interfaces -! ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces -! ! - In order to inject IGMPv3 local membership information in the -! ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on -! ! the same interface; otherwise PIM won't advertise -! ! IGMPv3-learned membership to other PIM routers -! -interface eth0 - ip pim ssm - ip igmp - -! -x- diff --git a/pimd/subdir.am b/pimd/subdir.am index 717f4782f8..9910642ffa 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -7,7 +7,6 @@ noinst_LIBRARIES += pimd/libpim.a sbin_PROGRAMS += pimd/pimd bin_PROGRAMS += pimd/mtracebis noinst_PROGRAMS += pimd/test_igmpv3_join -dist_examples_DATA += pimd/pimd.conf.sample vtysh_scan += pimd/pim_cmd.c vtysh_daemons += pimd man8 += $(MANBUILD)/frr-pimd.8 diff --git a/python/clippy/elf.py b/python/clippy/elf.py index 4ed334f0c4..02cb2e38b3 100644 --- a/python/clippy/elf.py +++ b/python/clippy/elf.py @@ -162,7 +162,10 @@ class ELFDissectData(object): for field in parent._efields[self.elfclass]: if field[0] == fieldname: break - offset += struct.calcsize(field[1]) + spec = field[1] + if spec == 'P': + spec = 'I' if self.elfclass == 32 else 'Q' + offset += struct.calcsize(spec) else: raise AttributeError('%r not found in %r.fields' % (fieldname, parent)) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index b6d7ab2416..47c6ad41af 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -456,6 +456,7 @@ ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr %endif install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr +install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr install -d -m750 %{buildroot}%{rundir} @@ -641,7 +642,7 @@ fi %files -%doc */*.sample* COPYING +%doc COPYING %doc doc/mpls %doc README.md /usr/share/yang/*.yang @@ -654,9 +655,6 @@ fi %dir %attr(750,root,root) %{_localstatedir}/log/frr %dir %attr(750,root,root) %{rundir} %endif -%if 0%{?vty_group:1} - %attr(750,%{frr_user},%{vty_group}) %{configdir}/vtysh.conf.sample -%endif %{_infodir}/frr.info.gz %{_mandir}/man*/* %{_sbindir}/zebra diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample deleted file mode 100644 index e11bf0bb23..0000000000 --- a/ripd/ripd.conf.sample +++ /dev/null @@ -1,22 +0,0 @@ -! -*- rip -*- -! -! RIPd sample configuration file -! -hostname ripd -password zebra -! -! debug rip events -! debug rip packet -! -router rip -! network 11.0.0.0/8 -! network eth0 -! route 10.0.0.0/8 -! distribute-list private-only in eth0 -! -!access-list private-only permit 10.0.0.0/8 -!access-list private-only deny any -! -!log file ripd.log -! -log stdout diff --git a/ripd/subdir.am b/ripd/subdir.am index 09d5590329..99979bff0d 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -5,7 +5,6 @@ if RIPD noinst_LIBRARIES += ripd/librip.a sbin_PROGRAMS += ripd/ripd -dist_examples_DATA += ripd/ripd.conf.sample vtysh_scan += \ ripd/rip_cli.c \ ripd/rip_debug.c \ diff --git a/ripngd/ripngd.conf.sample b/ripngd/ripngd.conf.sample deleted file mode 100644 index 28f08c399a..0000000000 --- a/ripngd/ripngd.conf.sample +++ /dev/null @@ -1,20 +0,0 @@ -! -*- rip -*- -! -! RIPngd sample configuration file -! -hostname ripngd -password zebra -! -! debug ripng events -! debug ripng packet -! -! -router ripng -! network sit1 -! route 3ffe:506::0/32 -! distribute-list local-only out sit1 -! -!ipv6 access-list local-only permit 3ffe:506::0/32 -!ipv6 access-list local-only deny any -! -log stdout diff --git a/ripngd/subdir.am b/ripngd/subdir.am index 8d370f1b5d..9d8d27d4cc 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -50,5 +50,3 @@ ripngd_ripngd_SOURCES = \ nodist_ripngd_ripngd_SOURCES = \ yang/frr-ripngd.yang.c \ # end - -dist_examples_DATA += ripngd/ripngd.conf.sample diff --git a/sharpd/sharpd.conf.sample b/sharpd/sharpd.conf.sample deleted file mode 100644 index d1cc19a51f..0000000000 --- a/sharpd/sharpd.conf.sample +++ /dev/null @@ -1,6 +0,0 @@ -! Default sharpd configuration sample -! -! There are no `default` configuration commands for sharpd -! all commands are at the view or enable level. -! -log stdout diff --git a/sharpd/subdir.am b/sharpd/subdir.am index d161eb6327..acf4fe5d00 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -5,7 +5,6 @@ if SHARPD noinst_LIBRARIES += sharpd/libsharp.a sbin_PROGRAMS += sharpd/sharpd -dist_examples_DATA += sharpd/sharpd.conf.sample vtysh_scan += sharpd/sharp_vty.c vtysh_daemons += sharpd man8 += $(MANBUILD)/frr-sharpd.8 diff --git a/staticd/staticd.conf.sample b/staticd/staticd.conf.sample deleted file mode 100644 index 3b64eb9c90..0000000000 --- a/staticd/staticd.conf.sample +++ /dev/null @@ -1,5 +0,0 @@ -! Default staticd configuration sample -! -log stdout -! -! ip route 4.5.6.7/32 10.10.10.10 diff --git a/staticd/subdir.am b/staticd/subdir.am index a0ae2569cb..62969a0a2a 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -5,7 +5,6 @@ if STATICD noinst_LIBRARIES += staticd/libstatic.a sbin_PROGRAMS += staticd/staticd -dist_examples_DATA += staticd/staticd.conf.sample vtysh_scan += staticd/static_vty.c vtysh_daemons += staticd man8 += $(MANBUILD)/frr-staticd.8 diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index c858571254..c10e32ad0a 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -346,9 +346,9 @@ def test_converge_protocols(): print("Show that v4 routes are right\n") v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i) - expected = net["r%s" % i].cmd( - "sort {} 2> /dev/null".format(v4_routesFile) - ).rstrip() + expected = ( + net["r%s" % i].cmd("sort {} 2> /dev/null".format(v4_routesFile)).rstrip() + ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( @@ -379,9 +379,9 @@ def test_converge_protocols(): print("Show that v6 routes are right\n") v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i) - expected = net["r%s" % i].cmd( - "sort {} 2> /dev/null".format(v6_routesFile) - ).rstrip() + expected = ( + net["r%s" % i].cmd("sort {} 2> /dev/null".format(v6_routesFile)).rstrip() + ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( diff --git a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py index 400e7e9bf5..75506d1a51 100644 --- a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py +++ b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py @@ -45,6 +45,10 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo + +pytestmark = [pytest.mark.bgpd] + + total_ebgp_peers = 20 ##################################################### diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py index dfe6a8074d..fffcbbd0ef 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py @@ -67,6 +67,10 @@ from lib.topolog import logger from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/ebgp_ecmp_topo2.json".format(CWD) diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py index 2bde52af1d..342a0a4b2f 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py @@ -67,6 +67,10 @@ from lib.topolog import logger from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/ibgp_ecmp_topo2.json".format(CWD) diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index 2744920272..f389632b1e 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -35,7 +35,7 @@ import json import platform from functools import partial -pytestmark = [pytest.mark.pimd] +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py index db4eab9d3d..b830e16b9a 100755 --- a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -505,8 +505,10 @@ def test_r1_mplsvpn_VrfTable(): associated_int = r1_snmp.get( "mplsL3VpnVrfAssociatedInterfaces.{}".format(snmp_str_to_oid("VRF-a")) ) - assertmsg = "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format( - associated_int + assertmsg = ( + "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format( + associated_int + ) ) assert associated_int == "3", assertmsg diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index 222478f12d..320e6d430c 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -42,13 +42,11 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo -l3mdev_accept = 0 -krel = "" - class BGPEVPNTopo(Topo): "Test topology builder" @@ -73,8 +71,6 @@ class BGPEVPNTopo(Topo): def setup_module(mod): "Sets up the pytest environment" - global l3mdev_accept - global krel tgen = Topogen(BGPEVPNTopo, mod.__name__) tgen.start_topology() @@ -90,18 +86,13 @@ def setup_module(mod): ) return pytest.skip("Skipping BGP EVPN RT5 NETNS Test. Kernel not supported") - l3mdev_accept = 1 - logger.info("setting net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)) - # create VRF vrf-101 on R1 and R2 # create loop101 cmds_vrflite = [ - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), "ip link add {}-vrf-101 type vrf table 101", "ip ru add oif {}-vrf-101 table 101", "ip ru add iif {}-vrf-101 table 101", "ip link set dev {}-vrf-101 up", - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), "ip link add loop101 type dummy", "ip link set dev loop101 master {}-vrf-101", "ip link set dev loop101 up", @@ -139,6 +130,7 @@ def setup_module(mod): logger.info("result: " + output) router = tgen.gears["r2"] + adjust_router_l3mdev(tgen, "r2") for cmd in cmds_vrflite: logger.info("cmd to r2: " + cmd.format("r2")) output = router.run(cmd.format("r2")) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py index aa99ebf6d0..b70626fcce 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py @@ -137,7 +137,7 @@ from lib.common_config import ( kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, - required_linux_kernel_version + required_linux_kernel_version, ) # Reading the data from JSON File for topology and configuration creation @@ -1329,20 +1329,22 @@ def test_BGP_GR_TC_4_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -1802,10 +1804,11 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info("Restart BGPd on R2 ") kill_router_daemons(tgen, "r2", ["bgpd"]) @@ -1823,10 +1826,11 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -2108,20 +2112,22 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2140,10 +2146,11 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -2469,20 +2476,22 @@ def test_BGP_GR_TC_20_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2755,10 +2764,10 @@ def test_BGP_GR_TC_31_1_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info("[Phase 4] : R1 is about to come up now ") start_router_daemons(tgen, "r1", ["bgpd"]) @@ -3237,10 +3246,12 @@ def test_BGP_GR_TC_9_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3248,10 +3259,10 @@ def test_BGP_GR_TC_9_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3281,10 +3292,11 @@ def test_BGP_GR_TC_9_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -3416,10 +3428,12 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3427,10 +3441,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3452,10 +3466,11 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -3675,10 +3690,12 @@ def test_BGP_GR_TC_43_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) protocol = "bgp" result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False @@ -3983,10 +4000,12 @@ def test_BGP_GR_TC_44_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) @@ -5011,10 +5030,10 @@ def test_BGP_GR_TC_48_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) dut = "r2" peer = "r1" @@ -5025,17 +5044,19 @@ def test_BGP_GR_TC_48_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) step("Bring up BGP on R1 and remove Peer-level GR config from R1") @@ -5394,17 +5415,19 @@ def BGP_GR_TC_52_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) step("Bring up BGP on R2 and remove Peer-level GR config from R1") diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index c7dca72570..9438b90ef8 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -136,7 +136,7 @@ from lib.common_config import ( kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, - required_linux_kernel_version + required_linux_kernel_version, ) # Reading the data from JSON File for topology and configuration creation @@ -557,10 +557,11 @@ def test_BGP_GR_TC_3_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info( "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER) @@ -703,10 +704,11 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info( "Waiting for selection deferral timer({} sec).. ".format( @@ -733,10 +735,11 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -1470,35 +1473,39 @@ def test_BGP_GR_18_p1(request): dut = "r6" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r6: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes dut = "r2" result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -1959,18 +1966,20 @@ def test_BGP_GR_chaos_29_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1..") @@ -2212,10 +2221,12 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) if addr_type == "ipv6": @@ -2227,10 +2238,12 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") @@ -2411,27 +2424,30 @@ def test_BGP_GR_chaos_34_2_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, "r3", "r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2568,10 +2584,11 @@ def test_BGP_GR_chaos_34_1_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 3] : Kill BGPd daemon on R1..") @@ -2587,18 +2604,20 @@ def test_BGP_GR_chaos_34_1_p1(request): # Verifying BGP RIB routes input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 @@ -2772,27 +2791,30 @@ def test_BGP_GR_chaos_32_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r5: EOR is set to TRUE\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2898,10 +2920,11 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon @@ -2964,10 +2987,11 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -3119,18 +3143,20 @@ def test_BGP_GR_chaos_30_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r3"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -3532,10 +3558,10 @@ def BGP_GR_TC_7_p1(request): dut = "r1" input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) @@ -3709,10 +3735,11 @@ def test_BGP_GR_TC_23_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes received from router R1 dut = "r1" @@ -3833,18 +3860,20 @@ def test_BGP_GR_20_p1(request): dut = "r3" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 diff --git a/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py index 47cc0eb39d..0c7e84a5a3 100755 --- a/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py +++ b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py @@ -30,6 +30,9 @@ sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") from lib.ltemplate import * +pytestmark = [pytest.mark.bgpd, pytest.mark.ldpd, pytest.mark.ospfd] + + def test_check_linux_vrf(): CliOnFail = None # For debugging, uncomment the next line diff --git a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py index 783e746418..cd845be296 100644 --- a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py +++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py @@ -46,6 +46,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class BGPIPV6RTADVTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 1c3c51f68e..5d97537bd0 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -84,6 +84,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.ltemplate import ltemplateRtrCmd +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo @@ -145,26 +146,12 @@ class ThisTestTopo(Topo): switch[1].add_link(tgen.gears["r3"], nodeif="r3-eth1") -l3mdev_accept = 0 - - def ltemplatePreRouterStartHook(): - global l3mdev_accept cc = ltemplateRtrCmd() krel = platform.release() tgen = get_topogen() logger.info("pre router-start hook, kernel=" + krel) - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - logger.info("setting net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)) # check for mpls if tgen.hasmpls != True: logger.info("MPLS not available, skipping setup") @@ -187,10 +174,11 @@ def ltemplatePreRouterStartHook(): "ip ru add oif {0}-cust1 table 10", "ip ru add iif {0}-cust1 table 10", "ip link set dev {0}-cust1 up", - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), ] for rtr in rtrs: - router = tgen.gears[rtr] + # adjust handling of VRF traffic + adjust_router_l3mdev(tgen, rtr) + for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) cc.doCmd(tgen, rtr, "ip link set dev {0}-eth4 master {0}-cust1".format(rtr)) @@ -229,9 +217,11 @@ def ltemplatePreRouterStartHook(): "ip ru add oif {0}-cust2 table 20", "ip ru add iif {0}-cust2 table 20", "ip link set dev {0}-cust2 up", - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), ] for rtr in rtrs: + # adjust handling of VRF traffic + adjust_router_l3mdev(tgen, rtr) + for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) cc.doCmd(tgen, rtr, "ip link set dev {0}-eth0 master {0}-cust2".format(rtr)) 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 7c154ecd15..650ba20b8c 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 @@ -1,6 +1,7 @@ from lib.lutil import luCommand -from customize import l3mdev_accept +from lib.common_config import kernel_requires_l3mdev_adjustment +l3mdev_accept = kernel_requires_l3mdev_adjustment() l3mdev_rtrs = ["r1", "r3", "r4", "ce4"] for rtr in l3mdev_rtrs: luCommand(rtr, "sysctl net.ipv4.tcp_l3mdev_accept", " = \d*", "none", "") diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py index 8e5ffe10be..84d9c48f35 100644 --- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -598,10 +598,12 @@ def test_large_community_lists_with_rmap_apply_and_remove(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_4, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "largeCommunity is still present after deleting route-map \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) @@ -899,10 +901,10 @@ def test_large_community_lists_with_rmap_set_none(request): dut = "r6" for adt in ADDR_TYPES: result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "Community-list is still present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "Community-list is still present \n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) @@ -2238,10 +2240,10 @@ def test_large_community_lists_with_rmap_match_regex(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_7, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "largeCommunity is still present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "largeCommunity is still present \n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py index d550c38a2f..d1745674f0 100644 --- a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py +++ b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py @@ -45,6 +45,10 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo + +pytestmark = [pytest.mark.bgpd] + + # Basic scenario for BGP-LU. Nodes are directly connected. # Node 3 is advertising many routes to 2, which advertises them # as BGP-LU to 1; this way we get routes with actual labels, as diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index 464d6eb475..5ecaee2ece 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -508,10 +508,10 @@ def test_ambiguous_overlapping_addresses_in_different_vrfs_p0(request): ) result = verify_rib(tgen, addr_type, dut, input_dict_1, tag=500, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are present with tag value 500 \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "Routes are present with tag value 500 \n Error: {}".format(tc_name, result) + ) logger.info("Expected Behavior: {}".format(result)) step( @@ -1147,10 +1147,12 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_1, metric=123, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are present with metric value 123 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected Behavior: {}".format(result)) result = verify_rib(tgen, addr_type, dut, input_dict_2, metric=123) @@ -1161,10 +1163,12 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, metric=0, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are present with metric value 0 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected Behavior: {}".format(result)) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 10cf1c6ae8..c8d1330122 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -102,6 +102,10 @@ from lib.topolog import logger from lib.bgp import clear_bgp, verify_bgp_rib, create_router_bgp, verify_bgp_convergence from lib.topojson import build_config_from_json, build_topo_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_multi_vrf_topo2.json".format(CWD) @@ -2218,16 +2222,20 @@ def test_restart_bgpd_daemon_p1(request): } result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are still present in VRF RED_A and RED_B \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are still present in VRF BLUE_A and BLUE_B \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Bring up BGPd daemon on R1.") start_router_daemons(tgen, "r1", ["bgpd"]) diff --git a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py index 7c7a8b87ed..21dc725793 100644 --- a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py @@ -39,6 +39,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class TemplateTopo(Topo): def build(self, *_args, **_opts): tgen = get_topogen(self) diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index 4764ff8945..2a98cb341d 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -86,6 +86,10 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/bgp_recursive_route_ebgp_multi_hop.json".format(CWD) try: @@ -365,10 +369,11 @@ def test_recursive_routes_iBGP_peer_p1(request): protocol="bgp", expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure the same static route on R2 again") dut = "r2" @@ -486,10 +491,11 @@ def test_recursive_routes_iBGP_peer_p1(request): result = verify_rib( tgen, addr_type, "r2", input_dict_4, protocol="bgp", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -598,10 +604,11 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Shut interface on R2 that has IP from the subnet as BGP next-hop") intf_r2_r4 = topo["routers"]["r2"]["links"]["r4"]["interface"] @@ -676,10 +683,11 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -1622,10 +1630,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that once eBGP multi-hop is removed, BGP session goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add ebgp-multihop command on R3 again") for addr_type in ADDR_TYPES: @@ -1663,10 +1672,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that BGP session goes down, when update-source is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add update-source command on R1 again") for addr_type in ADDR_TYPES: @@ -1715,18 +1725,20 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) sleep(3) step("Verify that BGP session goes down, when static route is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add static route on R3 again") for addr_type in ADDR_TYPES: @@ -1768,10 +1780,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): sleep(3) step("Verify that BGP neighborship between R1 and R3 goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) intf_r1_r3 = topo["routers"]["r1"]["links"]["r3"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_r3, True) @@ -2087,10 +2100,11 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure multipath-relax command on R4") result = create_router_bgp(tgen, topo, maxpath_relax) @@ -2147,10 +2161,11 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Re-configure maximum-path 2 command on R4") input_dict_8 = { @@ -2338,10 +2353,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "configured but not peer routers" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("configure same password on R2 and R3") for routerN in ["r2", "r3"]: @@ -2368,10 +2384,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "strings are in CAPs on R2 and R3" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Configure same password on R2 and R3 without CAPs") for routerN in ["r2", "r3"]: @@ -2395,10 +2412,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): step("Verify if password is removed from R1, both sessions go down again") result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Configure alphanumeric password on R1 and peer routers R2,R3") for bgp_neighbor in ["r2", "r3"]: diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py index 88935ae4d1..dffe24f3a0 100644 --- a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py @@ -44,6 +44,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class TemplateTopo(Topo): def build(self, *_args, **_opts): tgen = get_topogen(self) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index b99f1a7418..291a6e7c3a 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -498,6 +498,7 @@ def disable_route_map_to_prefer_global_next_hop(tgen, topo): # ##################################################### + def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): """ TC5_FUNC_5: @@ -762,9 +763,7 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): for addr_type in ADDR_TYPES: - step( - "On router R1 delete static routes in vrf ISR to LOOPBACK_1" - ) + step("On router R1 delete static routes in vrf ISR to LOOPBACK_1") input_routes_r1 = { "r1": { @@ -772,7 +771,7 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): { "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], "next_hop": (intf_r2_r1[addr_type]).split("/")[0], - "delete": True + "delete": True, } ] } diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py index 97d98415db..92ee8513e1 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py @@ -42,6 +42,7 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo @@ -71,22 +72,6 @@ def setup_module(mod): router_list = tgen.routers() logger.info("Testing with VRF Lite support") - krel = platform.release() - - # May need to adjust handling of vrf traffic depending on kernel version - l3mdev_accept = 0 - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - logger.info( - "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept) - ) cmds = [ "ip link add {0}-cust1 type vrf table 1001", @@ -99,15 +84,8 @@ def setup_module(mod): for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) - output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") - logger.info( - "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output) - ) - - if l3mdev_accept: - output = tgen.net[rname].cmd( - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) - ) + # adjust handling of vrf traffic + adjust_router_l3mdev(tgen, rname) for rname, router in router_list.items(): router.load_config( diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 7ad5d8c9ab..cf64956bfd 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -11,6 +11,7 @@ from lib.topotest import json_cmp_result from lib.topotest import g_extra_config as topotest_extra_config from lib.topolog import logger + def pytest_addoption(parser): """ Add topology-only option to the topology tester. This option makes pytest @@ -143,9 +144,7 @@ def pytest_configure(config): vtysh_on_error = config.getoption("--vtysh-on-error") topotest_extra_config["vtysh_on_error"] = vtysh_on_error - topotest_extra_config["pause_after"] = ( - pause_after or shell or vtysh - ) + topotest_extra_config["pause_after"] = pause_after or shell or vtysh topotest_extra_config["topology_only"] = config.getoption("--topology-only") @@ -177,9 +176,11 @@ def pytest_runtest_makereport(item, call): else: error = True # Handle assert failures - parent._previousfailed = item # pylint: disable=W0212 + parent._previousfailed = item # pylint: disable=W0212 logger.error( - 'assert failed at "{}/{}": {}'.format(modname, item.name, call.excinfo.value) + 'assert failed at "{}/{}": {}'.format( + modname, item.name, call.excinfo.value + ) ) # (topogen) Set topology error to avoid advancing in the test. @@ -188,7 +189,6 @@ def pytest_runtest_makereport(item, call): # This will cause topogen to report error on `routers_have_failure`. tgen.set_error("{}/{}".format(modname, item.name)) - if error and topotest_extra_config["shell_on_error"]: for router in tgen.routers(): pause = True diff --git a/tests/topotests/isis-snmp/test_isis_snmp.py b/tests/topotests/isis-snmp/test_isis_snmp.py index 1bcd0eefc6..07f3335e23 100755 --- a/tests/topotests/isis-snmp/test_isis_snmp.py +++ b/tests/topotests/isis-snmp/test_isis_snmp.py @@ -124,7 +124,6 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["r3"]) - def setup_module(mod): "Sets up the pytest environment" @@ -148,20 +147,24 @@ def setup_module(mod): # Don't start the following in the CE nodes if router.name[0] == "r": router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)), + TopoRouter.RD_ISIS, + os.path.join(CWD, "{}/isisd.conf".format(rname)), "-M snmp", ) router.load_config( - TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), + TopoRouter.RD_LDP, + os.path.join(CWD, "{}/ldpd.conf".format(rname)), ) router.load_config( - TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap", ) # After loading the configurations, this function loads configured daemons. tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -169,6 +172,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def router_compare_json_output(rname, command, reference): "Compare router JSON output" @@ -184,6 +188,7 @@ def router_compare_json_output(rname, command, reference): assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg + def generate_oid(numoids, index1, index2): if numoids == 1: oid = "{}".format(index1) @@ -200,7 +205,9 @@ def test_isis_convergence(): router_compare_json_output( rname, "show yang operational-data /frr-interface:lib isisd", - "show_yang_interface_isis_adjacencies.ref") + "show_yang_interface_isis_adjacencies.ref", + ) + def test_r1_scalar_snmp(): "Wait for protocol convergence" @@ -213,26 +220,26 @@ def test_r1_scalar_snmp(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid('isisSysVersion', "one(1)") - assert r1_snmp.test_oid('isisSysLevelType', "level1and2(3)") - assert r1_snmp.test_oid('isisSysID',"00 00 00 00 00 01") - assert r1_snmp.test_oid('isisSysMaxPathSplits',"32") - assert r1_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") - assert r1_snmp.test_oid('isisSysAdminState',"on(1)") - assert r1_snmp.test_oid('isisSysMaxAge',"1200 seconds") - assert r1_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + assert r1_snmp.test_oid("isisSysVersion", "one(1)") + assert r1_snmp.test_oid("isisSysLevelType", "level1and2(3)") + assert r1_snmp.test_oid("isisSysID", "00 00 00 00 00 01") + assert r1_snmp.test_oid("isisSysMaxPathSplits", "32") + assert r1_snmp.test_oid("isisSysMaxLSPGenInt", "900 seconds") + assert r1_snmp.test_oid("isisSysAdminState", "on(1)") + assert r1_snmp.test_oid("isisSysMaxAge", "1200 seconds") + assert r1_snmp.test_oid("isisSysProtSupported", "07 5 6 7") r2 = tgen.net.get("r2") r2_snmp = SnmpTester(r2, "2.2.2.2", "public", "2c") - - assert r2_snmp.test_oid('isisSysVersion', "one(1)") - assert r2_snmp.test_oid('isisSysLevelType', "level1and2(3)") - assert r2_snmp.test_oid('isisSysID',"00 00 00 00 00 02") - assert r2_snmp.test_oid('isisSysMaxPathSplits',"32") - assert r2_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") - assert r2_snmp.test_oid('isisSysAdminState',"on(1)") - assert r2_snmp.test_oid('isisSysMaxAge',"1200 seconds") - assert r2_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + + assert r2_snmp.test_oid("isisSysVersion", "one(1)") + assert r2_snmp.test_oid("isisSysLevelType", "level1and2(3)") + assert r2_snmp.test_oid("isisSysID", "00 00 00 00 00 02") + assert r2_snmp.test_oid("isisSysMaxPathSplits", "32") + assert r2_snmp.test_oid("isisSysMaxLSPGenInt", "900 seconds") + assert r2_snmp.test_oid("isisSysAdminState", "on(1)") + assert r2_snmp.test_oid("isisSysMaxAge", "1200 seconds") + assert r2_snmp.test_oid("isisSysProtSupported", "07 5 6 7") circtable_test = { @@ -245,7 +252,8 @@ circtable_test = { "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)", "inactive(1)"], "isisCircSmallHellos": ["false(2)", "false(2)", "false(2)"], "isisCirc3WayEnabled": ["false(2)", "false(2)", "false(2)"], - } +} + def test_r1_isisCircTable(): tgen = get_topogen() @@ -256,9 +264,9 @@ def test_r1_isisCircTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(1,1,0)) - oids.append(generate_oid(1,2,0)) - oids.append(generate_oid(1,3,0)) + oids.append(generate_oid(1, 1, 0)) + oids.append(generate_oid(1, 2, 0)) + oids.append(generate_oid(1, 3, 0)) # check items for item in circtable_test.keys(): @@ -267,14 +275,26 @@ def test_r1_isisCircTable(): ) assert r1_snmp.test_oid_walk(item, circtable_test[item], oids), assertmsg + circleveltable_test = { "isisCircLevelMetric": ["10", "10", "10", "10"], "isisCircLevelWideMetric": ["10", "10", "0", "0"], "isisCircLevelISPriority": ["64", "64", "64", "64"], "isisCircLevelHelloMultiplier": ["10", "10", "10", "10"], - "isisCircLevelHelloTimer": ["3000 milliseconds", "3000 milliseconds", "3000 milliseconds", "3000 milliseconds"], - "isisCircLevelMinLSPRetransInt": ["1 seconds", "1 seconds", "0 seconds", "0 seconds"], - } + "isisCircLevelHelloTimer": [ + "3000 milliseconds", + "3000 milliseconds", + "3000 milliseconds", + "3000 milliseconds", + ], + "isisCircLevelMinLSPRetransInt": [ + "1 seconds", + "1 seconds", + "0 seconds", + "0 seconds", + ], +} + def test_r1_isislevelCircTable(): tgen = get_topogen() @@ -285,10 +305,10 @@ def test_r1_isislevelCircTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(2,1,"area")) - oids.append(generate_oid(2,2,"area")) - oids.append(generate_oid(2,3,"area")) - oids.append(generate_oid(2,3,"domain")) + oids.append(generate_oid(2, 1, "area")) + oids.append(generate_oid(2, 2, "area")) + oids.append(generate_oid(2, 3, "area")) + oids.append(generate_oid(2, 3, "domain")) # check items for item in circleveltable_test.keys(): @@ -316,6 +336,7 @@ adjtable_down_test = { "isisISAdjNeighPriority": ["64"], } + def test_r1_isisAdjTable(): "check ISIS Adjacency Table" tgen = get_topogen() @@ -324,11 +345,11 @@ def test_r1_isisAdjTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(2,1,1)) - oids.append(generate_oid(2,2,1)) + oids.append(generate_oid(2, 1, 1)) + oids.append(generate_oid(2, 2, 1)) oids_down = [] - oids_down.append(generate_oid(2,1,1)) + oids_down.append(generate_oid(2, 1, 1)) # check items for item in adjtable_test.keys(): @@ -337,7 +358,6 @@ def test_r1_isisAdjTable(): ) assert r1_snmp.test_oid_walk(item, adjtable_test[item], oids), assertmsg - # shutdown interface and one adjacency should be removed "check ISIS adjacency is removed when interface is shutdown" r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nshutdown") @@ -347,7 +367,9 @@ def test_r1_isisAdjTable(): assertmsg = "{} should be {} oids {} full dict {}:".format( item, adjtable_down_test[item], oids_down, r1_snmp.walk(item) ) - assert r1_snmp.test_oid_walk(item, adjtable_down_test[item], oids_down), assertmsg + assert r1_snmp.test_oid_walk( + item, adjtable_down_test[item], oids_down + ), assertmsg # no shutdown interface and adjacency should be restored r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nno shutdown") diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json index 8e3cdc7bd6..1a6fe6d5c6 100644 --- a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json +++ b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json @@ -5,73 +5,73 @@ { "vertex": "r1" } - ], + ], "ipv6": [ { "vertex": "r1" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r1" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r1(4)", + "type": "IP internal", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", + "interface": "r1-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r1(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" } - ], + ], "ipv6": [ { "vertex": "r1" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r1(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", + "interface": "r1-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r1(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "internal", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP6", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" } ] diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json index 72022a8167..a77f7977f9 100644 --- a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json +++ b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json @@ -5,76 +5,76 @@ { "vertex": "r2" } - ], + ], "ipv6": [ { "vertex": "r2" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r2" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r2(4)", + "type": "IP internal", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", + "interface": "r2-eth0", + "metric": "10", + "next-hop": "r4", + "parent": "r2(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" } - ], + ], "ipv6": [ { "vertex": "r2" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r2(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" - }, + }, { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", + "interface": "r2-eth0", + "metric": "10", + "next-hop": "r4", + "parent": "r2(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r4", - "metric": "internal", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP6", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" } ] } } -}
\ No newline at end of file +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json index 62b895766e..1e5d331965 100644 --- a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json +++ b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json @@ -4,126 +4,126 @@ "ipv4": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r3(4)", + "type": "IP internal", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "30", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" } - ], + ], "ipv6": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP6", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "30", - "parent": "r3-eth1", - "type": "IP6", + "interface": "r3-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r3(4)", + "type": "IP internal", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth0", - "type": "IP", + "interface": "r3-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" } - ], + ], "ipv6": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r3" } ] diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json index 0d69550cad..34f5ac9ca4 100644 --- a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json +++ b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json @@ -4,126 +4,126 @@ "ipv4": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r4(4)", + "type": "IP internal", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "30", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" } - ], + ], "ipv6": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP6", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "30", - "parent": "r4-eth1", - "type": "IP6", + "interface": "r4-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r4(4)", + "type": "IP internal", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth0", + "metric": "10", + "next-hop": "r2", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r2" - }, + }, { - "interface": "r2", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth0", - "type": "IP", + "interface": "r4-eth0", + "metric": "20", + "next-hop": "r2", + "parent": "r2(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" } - ], + ], "ipv6": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" - }, + }, { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth0", + "metric": "10", + "next-hop": "r2", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r2" } ] diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json index b4ed6a069d..ace56536e9 100644 --- a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json +++ b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json @@ -4,121 +4,121 @@ "ipv4": [ { "vertex": "r5" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r5(4)", + "type": "IP internal", "vertex": "10.0.10.0/24" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r5(4)", + "type": "IP internal", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth1", + "metric": "10", + "next-hop": "r4", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" } - ], + ], "ipv6": [ { "vertex": "r5" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth1", + "metric": "10", + "next-hop": "r4", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r3", - "metric": "internal", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP6", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r4", - "metric": "internal", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP6", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" } ] - }, + }, "level-2": { - "ipv4": [], + "ipv4": [], "ipv6": [] } } -}
\ No newline at end of file +} diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py index ae904ba69e..b7fe0c2ddb 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -41,12 +41,29 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.topotest import iproute2_is_vrf_capable -from lib.common_config import required_linux_kernel_version +from lib.common_config import ( + required_linux_kernel_version, + adjust_router_l3mdev, +) from mininet.topo import Topo pytestmark = [pytest.mark.isisd] +VERTEX_TYPE_LIST = [ + "pseudo_IS", + "pseudo_TE-IS", + "IS", + "TE-IS", + "ES", + "IP internal", + "IP external", + "IP TE", + "IP6 internal", + "IP6 external", + "UNKNOWN", +] + class ISISTopo1(Topo): "Simple two layer ISIS vrf topology" @@ -93,22 +110,6 @@ def setup_module(mod): tgen.start_topology() logger.info("Testing with VRF Lite support") - krel = platform.release() - - # May need to adjust handling of vrf traffic depending on kernel version - l3mdev_accept = 0 - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - logger.info( - "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept) - ) cmds = [ "ip link add {0}-cust1 type vrf table 1001", @@ -122,15 +123,9 @@ def setup_module(mod): # create VRF rx-cust1 and link rx-eth0 to rx-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) - output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") - logger.info( - "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output) - ) - if l3mdev_accept: - output = tgen.net[rname].cmd( - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) - ) + # adjust handling of vrf traffic + adjust_router_l3mdev(tgen, rname) for rname, router in tgen.routers().items(): router.load_config( @@ -316,6 +311,7 @@ def parse_topology(lines, level): areas = {} area = None ipv = None + vertex_type_regex = "|".join(VERTEX_TYPE_LIST) for line in lines: area_match = re.match(r"Area (.+):", line) @@ -335,44 +331,57 @@ def parse_topology(lines, level): ipv = "ipv4" continue - item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) - if item_match is not None: + item_match = re.match( + r"([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)", line + ) + if ( + item_match is not None + and item_match.group(1) == "Vertex" + and item_match.group(2) == "Type" + and item_match.group(3) == "Metric" + and item_match.group(4) == "Next-Hop" + and item_match.group(5) == "Interface" + and item_match.group(6) == "Parent" + ): # Skip header - if ( - item_match.group(1) == "Vertex" - and item_match.group(2) == "Type" - and item_match.group(3) == "Metric" - and item_match.group(4) == "Next-Hop" - and item_match.group(5) == "Interface" - and item_match.group(6) == "Parent" - ): - continue + continue + item_match = re.match( + r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+) ([^\s]+) ([^\s]+)".format( + vertex_type_regex + ), + line, + ) + if item_match is not None: areas[area][level][ipv].append( { "vertex": item_match.group(1), "type": item_match.group(2), "metric": item_match.group(3), - "next-hop": item_match.group(4), - "interface": item_match.group(5), - "parent": item_match.group(6), + "next-hop": item_match.group(5), + "interface": item_match.group(6), + "parent": item_match.group(7), } ) continue - item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) + item_match = re.match( + r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+)".format(vertex_type_regex), + line, + ) + if item_match is not None: areas[area][level][ipv].append( { "vertex": item_match.group(1), "type": item_match.group(2), "metric": item_match.group(3), - "parent": item_match.group(4), + "parent": item_match.group(5), } ) continue - item_match = re.match(r"([^ ]+)", line) + item_match = re.match(r"([^\s]+)", line) if item_match is not None: areas[area][level][ipv].append({"vertex": item_match.group(1)}) continue diff --git a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py index 4144f9b261..f47d906157 100644 --- a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py @@ -141,15 +141,16 @@ def setup_module(mod): TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) router.load_config( - TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), - "-M snmp" + TopoRouter.RD_LDP, + os.path.join(CWD, "{}/ldpd.conf".format(rname)), + "-M snmp", ) router.load_config( - TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), - "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap" + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap", ) - tgen.start_router() @@ -199,7 +200,7 @@ def test_rib(): # Skip if previous fatal error condition is raised # TODO: disabling this check to avoid 'snmpd not running' errors - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -212,7 +213,7 @@ def test_ldp_adjacencies(): # Skip if previous fatal error condition is raised # TODO: disabling this check to avoid 'snmpd not running' errors - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -226,7 +227,7 @@ def test_ldp_neighbors(): tgen = get_topogen() # Skip if previous fatal error condition is raised - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -242,8 +243,8 @@ def test_r1_ldp_lsr_objects(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid('mplsLdpLsrId', "01 01 01 01") - assert r1_snmp.test_oid('mplsLdpLsrLoopDetectionCapable', 'none(1)') + assert r1_snmp.test_oid("mplsLdpLsrId", "01 01 01 01") + assert r1_snmp.test_oid("mplsLdpLsrLoopDetectionCapable", "none(1)") def test_r1_ldp_entity_table(): @@ -253,52 +254,31 @@ def test_r1_ldp_entity_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLdpId', ['1.1.1.1:0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityIndex', ['1']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityProtocolVersion', ['1']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityAdminStatus', ['enable(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityOperStatus', ['enabled(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTcpPort', ['646']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityUdpDscPort', ['646']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityMaxPduLength', ['4096 octets']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityKeepAliveHoldTimer', ['180 seconds']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityHelloHoldTimer', ['0 seconds']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityInitSessionThreshold', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelDistMethod', ['downstreamUnsolicited(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelRetentionMode', ['liberal(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityPathVectorLimit', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityHopCountLimit', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTransportAddrKind', ['loopback(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeer', ['true(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeerAddrType', ['ipv4(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeerAddr', ['01 01 01 01']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelType', ['generic(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityDiscontinuityTime', ['(0) 0:00:00.00']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStorageType', ['nonVolatile(3)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityRowStatus', ['createAndGo(4)']) + assert r1_snmp.test_oid_walk("mplsLdpEntityLdpId", ["1.1.1.1:0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityIndex", ["1"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityProtocolVersion", ["1"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityAdminStatus", ["enable(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityOperStatus", ["enabled(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTcpPort", ["646"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityUdpDscPort", ["646"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityMaxPduLength", ["4096 octets"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityKeepAliveHoldTimer", ["180 seconds"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityHelloHoldTimer", ["0 seconds"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityInitSessionThreshold", ["0"]) + assert r1_snmp.test_oid_walk( + "mplsLdpEntityLabelDistMethod", ["downstreamUnsolicited(2)"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityLabelRetentionMode", ["liberal(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityPathVectorLimit", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityHopCountLimit", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTransportAddrKind", ["loopback(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeer", ["true(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeerAddrType", ["ipv4(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeerAddr", ["01 01 01 01"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityLabelType", ["generic(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityDiscontinuityTime", ["(0) 0:00:00.00"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStorageType", ["nonVolatile(3)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityRowStatus", ["createAndGo(4)"]) def test_r1_ldp_entity_stats_table(): @@ -308,32 +288,23 @@ def test_r1_ldp_entity_stats_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionAttempts", ["0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionAttempts', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedNoHelloErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedAdErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedMaxPduErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedLRErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadLdpIdentifierErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadPduLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadMessageLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadTlvLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsMalformedTlvValueErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsKeepAliveTimerExpErrors', ['0']) + "mplsLdpEntityStatsSessionRejectedNoHelloErrors", ["0"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedAdErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedMaxPduErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedLRErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadLdpIdentifierErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadPduLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadMessageLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadTlvLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsMalformedTlvValueErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsKeepAliveTimerExpErrors", ["0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsShutdownReceivedNotifications', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsShutdownSentNotifications', ['0']) + "mplsLdpEntityStatsShutdownReceivedNotifications", ["0"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsShutdownSentNotifications", ["0"]) def test_r1_ldp_peer_table(): @@ -343,17 +314,16 @@ def test_r1_ldp_peer_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + assert r1_snmp.test_oid_walk("mplsLdpPeerLdpId", ["2.2.2.2:0", "3.3.3.3:0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpPeerLdpId', ['2.2.2.2:0', '3.3.3.3:0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerLabelDistMethod', - ['downstreamUnsolicited(2)', 'downstreamUnsolicited(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerPathVectorLimit', ['0', '0']) + "mplsLdpPeerLabelDistMethod", + ["downstreamUnsolicited(2)", "downstreamUnsolicited(2)"], + ) + assert r1_snmp.test_oid_walk("mplsLdpPeerPathVectorLimit", ["0", "0"]) + assert r1_snmp.test_oid_walk("mplsLdpPeerTransportAddrType", ["ipv4(1)", "ipv4(1)"]) assert r1_snmp.test_oid_walk( - 'mplsLdpPeerTransportAddrType', ['ipv4(1)', 'ipv4(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerTransportAddr', ['02 02 02 02', '03 03 03 03']) + "mplsLdpPeerTransportAddr", ["02 02 02 02", "03 03 03 03"] + ) def test_r1_ldp_session_table(): @@ -363,18 +333,20 @@ def test_r1_ldp_session_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk('mplsLdpSessionState', - ['operational(5)', 'operational(5)']) - assert r1_snmp.test_oid_walk('mplsLdpSessionRole', - ['passive(3)', 'passive(3)']) - assert r1_snmp.test_oid_walk('mplsLdpSessionProtocolVersion', - ['1', '1']) - assert r1_snmp.test_oid_walk('mplsLdpSessionKeepAliveTime', - ['180 seconds', '180 seconds']) - assert r1_snmp.test_oid_walk('mplsLdpSessionMaxPduLength', - ['4096 octets', '4096 octets']) - assert r1_snmp.test_oid_walk('mplsLdpSessionDiscontinuityTime', - ['(0) 0:00:00.00', '(0) 0:00:00.00']) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionState", ["operational(5)", "operational(5)"] + ) + assert r1_snmp.test_oid_walk("mplsLdpSessionRole", ["passive(3)", "passive(3)"]) + assert r1_snmp.test_oid_walk("mplsLdpSessionProtocolVersion", ["1", "1"]) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionKeepAliveTime", ["180 seconds", "180 seconds"] + ) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionMaxPduLength", ["4096 octets", "4096 octets"] + ) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionDiscontinuityTime", ["(0) 0:00:00.00", "(0) 0:00:00.00"] + ) def test_r1_ldp_session_stats_table(): @@ -384,10 +356,8 @@ def test_r1_ldp_session_stats_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk( - 'mplsLdpSessionStatsUnknownMesTypeErrors', ['0', '0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpSessionStatsUnknownTlvErrors', ['0', '0']) + assert r1_snmp.test_oid_walk("mplsLdpSessionStatsUnknownMesTypeErrors", ["0", "0"]) + assert r1_snmp.test_oid_walk("mplsLdpSessionStatsUnknownTlvErrors", ["0", "0"]) def test_r1_ldp_hello_adjacency_table(): @@ -397,12 +367,11 @@ def test_r1_ldp_hello_adjacency_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyIndex', - ['1', '2', '1']) - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyHoldTime', - ['15', '45', '15']) - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyType', - ['link(1)', 'targeted(2)', 'link(1)']) + assert r1_snmp.test_oid_walk("mplsLdpHelloAdjacencyIndex", ["1", "2", "1"]) + assert r1_snmp.test_oid_walk("mplsLdpHelloAdjacencyHoldTime", ["15", "45", "15"]) + assert r1_snmp.test_oid_walk( + "mplsLdpHelloAdjacencyType", ["link(1)", "targeted(2)", "link(1)"] + ) # Memory leak test template diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 83ee866636..d2212d1807 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -43,7 +43,7 @@ from lib.common_config import ( run_frr_cmd, FRRCFG_FILE, retry, - get_ipv6_linklocal_address + get_ipv6_linklocal_address, ) LOGDIR = "/tmp/topotests/" diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 2224b4f3a3..ead593d2ca 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -75,54 +75,54 @@ config_section = "topogen" # Debug logs for daemons DEBUG_LOGS = { "pimd": [ - 'debug msdp events', - 'debug msdp packets', - 'debug igmp events', - 'debug igmp trace', - 'debug mroute', - 'debug mroute detail', - 'debug pim events', - 'debug pim packets', - 'debug pim trace', - 'debug pim zebra', - 'debug pim bsm', - 'debug pim packets joins', - 'debug pim packets register', - 'debug pim nht' + "debug msdp events", + "debug msdp packets", + "debug igmp events", + "debug igmp trace", + "debug mroute", + "debug mroute detail", + "debug pim events", + "debug pim packets", + "debug pim trace", + "debug pim zebra", + "debug pim bsm", + "debug pim packets joins", + "debug pim packets register", + "debug pim nht", ], "bgpd": [ - 'debug bgp neighbor-events', - 'debug bgp updates', - 'debug bgp zebra', - 'debug bgp nht', - 'debug bgp neighbor-events', - 'debug bgp graceful-restart', - 'debug bgp update-groups', - 'debug bgp vpn leak-from-vrf', - 'debug bgp vpn leak-to-vrf', - 'debug bgp zebr', - 'debug bgp updates', - 'debug bgp nht', - 'debug bgp neighbor-events', - 'debug vrf' + "debug bgp neighbor-events", + "debug bgp updates", + "debug bgp zebra", + "debug bgp nht", + "debug bgp neighbor-events", + "debug bgp graceful-restart", + "debug bgp update-groups", + "debug bgp vpn leak-from-vrf", + "debug bgp vpn leak-to-vrf", + "debug bgp zebr", + "debug bgp updates", + "debug bgp nht", + "debug bgp neighbor-events", + "debug vrf", ], "zebra": [ - 'debug zebra events', - 'debug zebra rib', - 'debug zebra vxlan', - 'debug zebra nht' + "debug zebra events", + "debug zebra rib", + "debug zebra vxlan", + "debug zebra nht", ], "ospf": [ - 'debug ospf event', - 'debug ospf ism', - 'debug ospf lsa', - 'debug ospf nsm', - 'debug ospf nssa', - 'debug ospf packet all', - 'debug ospf sr', - 'debug ospf te', - 'debug ospf zebra', - ] + "debug ospf event", + "debug ospf ism", + "debug ospf lsa", + "debug ospf nsm", + "debug ospf nssa", + "debug ospf packet all", + "debug ospf sr", + "debug ospf te", + "debug ospf zebra", + ], } if config.has_option("topogen", "verbosity"): @@ -1155,10 +1155,8 @@ def create_debug_log_config(tgen, input_dict, build=False): log_file = debug_dict.setdefault("log_file", None) if log_file: - _log_file = os.path.join(LOGDIR, tgen.modname, - log_file) - debug_config.append("log file {} \n".\ - format(_log_file)) + _log_file = os.path.join(LOGDIR, tgen.modname, log_file) + debug_config.append("log file {} \n".format(_log_file)) if type(enable_logs) is list: for daemon in enable_logs: @@ -1178,10 +1176,9 @@ def create_debug_log_config(tgen, input_dict, build=False): for debug_log in debug_logs: debug_config.append("no {}".format(debug_log)) - result = create_common_configuration(tgen, router, - debug_config, - "debug_log_config", - build=build) + result = create_common_configuration( + tgen, router, debug_config, "debug_log_config", build=build + ) except InvalidCLIError: # Traceback errormsg = traceback.format_exc() @@ -3868,7 +3865,7 @@ def get_ipv6_linklocal_address(topo, node, intf): """ tgen = get_topogen() ext_nh = tgen.net[node].get_ipv6_linklocal() - req_nh = topo[node]['links'][intf]['interface'] + req_nh = topo[node]["links"][intf]["interface"] llip = None for llips in ext_nh: if llips[0] == req_nh: @@ -3876,8 +3873,9 @@ def get_ipv6_linklocal_address(topo, node, intf): logger.info("Link local ip found = %s", llip) return llip - errormsg = "Failed: Link local ip not found on router {}, "\ - "interface {}".format(node, intf) + errormsg = "Failed: Link local ip not found on router {}, " "interface {}".format( + node, intf + ) return errormsg @@ -4512,3 +4510,51 @@ def verify_ip_nht(tgen, input_dict): logger.debug("Exiting lib API: verify_ip_nht()") return False + + +def kernel_requires_l3mdev_adjustment(): + """ + Checks if the L3 master device needs to be adjusted to handle VRF traffic + based on kernel version. + + Returns + ------- + 1 or 0 + """ + + if version_cmp(platform.release(), "4.15") >= 0: + return 1 + return 0 + + +def adjust_router_l3mdev(tgen, router): + """ + Adjusts a routers L3 master device to handle VRF traffic depending on kernel + version. + + Parameters + ---------- + * `tgen` : tgen object + * `router` : router id to be configured. + + Returns + ------- + True + """ + + l3mdev_accept = kernel_requires_l3mdev_adjustment() + + logger.info( + "router {0}: setting net.ipv4.tcp_l3mdev_accept={1}".format( + router, l3mdev_accept + ) + ) + + output = tgen.net[router].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") + logger.info("router {0}: existing tcp_l3mdev_accept was {1}".format(router, output)) + + tgen.net[router].cmd( + "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) + ) + + return True diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 9f642411b5..04a12d0eec 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -344,9 +344,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= for lnk in input_dict[router]["links"].keys(): if "ospf" not in input_dict[router]["links"][lnk]: logger.debug( - "Router %s: ospf config is not present in" - "input_dict", - router + "Router %s: ospf config is not present in" "input_dict", router ) continue ospf_data = input_dict[router]["links"][lnk]["ospf"] diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 104b215078..2a46115850 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -54,6 +54,7 @@ from mininet.term import makeTerm g_extra_config = {} + def gdb_core(obj, daemon, corefiles): gdbcmds = """ info threads @@ -545,7 +546,6 @@ def iproute2_is_vrf_capable(): stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, - encoding="utf-8" ) iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] @@ -1346,15 +1346,9 @@ class Router(Node): # Run a command in a new window (gnome-terminal, screen, tmux, xterm) def runInWindow(self, cmd, title=None): topo_terminal = os.getenv("FRR_TOPO_TERMINAL") - if topo_terminal or ( - "TMUX" not in os.environ and "STY" not in os.environ - ): + if topo_terminal or ("TMUX" not in os.environ and "STY" not in os.environ): term = topo_terminal if topo_terminal else "xterm" - makeTerm( - self, - title=title if title else cmd, - term=term, - cmd=cmd) + makeTerm(self, title=title if title else cmd, term=term, cmd=cmd) else: nscmd = "sudo nsenter -m -n -t {} {}".format(self.pid, cmd) if "TMUX" in os.environ: @@ -1363,9 +1357,7 @@ class Router(Node): cmd = "{} {}".format(wcmd, nscmd) elif "STY" in os.environ: if os.path.exists( - "/run/screen/S-{}/{}".format( - os.environ['USER'], os.environ['STY'] - ) + "/run/screen/S-{}/{}".format(os.environ["USER"], os.environ["STY"]) ): wcmd = "screen" else: @@ -1373,7 +1365,6 @@ class Router(Node): cmd = "{} {}".format(wcmd, nscmd) self.cmd(cmd) - def startRouter(self, tgen=None): # Disable integrated-vtysh-config self.cmd( @@ -1460,7 +1451,7 @@ class Router(Node): def startRouterDaemons(self, daemons=None): "Starts all FRR daemons for this router." - gdb_breakpoints = g_extra_config["gdb_breakpoints"] + gdb_breakpoints = g_extra_config["gdb_breakpoints"] gdb_daemons = g_extra_config["gdb_daemons"] gdb_routers = g_extra_config["gdb_routers"] @@ -1521,12 +1512,10 @@ class Router(Node): if ( (gdb_routers or gdb_daemons) - and (not gdb_routers - or self.name in gdb_routers - or "all" in gdb_routers) - and (not gdb_daemons - or daemon in gdb_daemons - or "all" in gdb_daemons) + and ( + not gdb_routers or self.name in gdb_routers or "all" in gdb_routers + ) + and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons) ): if daemon == "snmpd": cmdopt += " -f " @@ -1547,7 +1536,6 @@ class Router(Node): self.cmd(" ".join([cmdenv, binary, cmdopt])) logger.info("{}: {} {} started".format(self, self.routertype, daemon)) - # Start Zebra first if "zebra" in daemons_list: start_daemon("zebra", "-s 90000000") diff --git a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py index 6b7180978e..cd398a5111 100644 --- a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py @@ -648,7 +648,11 @@ def test_BSR_CRP_with_blackhole_address_p1(request): input_dict = { "i1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_rp}]}, "l1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_lhr}]}, - "f1": {"static_routes": [{"network": CRP, "next_hop": next_hop_fhr, "delete": True}]}, + "f1": { + "static_routes": [ + {"network": CRP, "next_hop": next_hop_fhr, "delete": True} + ] + }, } result = create_static_routes(tgen, input_dict) @@ -692,10 +696,11 @@ def test_BSR_CRP_with_blackhole_address_p1(request): step("Verify if b1 chosen as BSR in l1") result = verify_pim_bsr(tgen, topo, "l1", BSR_IP_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b1 is not chosen as BSR in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b1 is not chosen as BSR in l1 \n Error: {}".format( tc_name, result - )) + ) state_after = verify_pim_interface_traffic(tgen, state_dict) assert isinstance( @@ -841,10 +846,12 @@ def test_new_router_fwd_p0(request): # Verify bsr state in l1 step("Verify no BSR in l1 as i1 would not forward the no-forward bsm") result = verify_pim_bsr(tgen, topo, "l1", bsr_ip, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "BSR data is present after no-forward bsm also \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) # unconfigure unicast bsm on f1-i1-eth2 step("unconfigure unicast bsm on f1-i1-eth2, will forward with only mcast") @@ -966,10 +973,11 @@ def test_int_bsm_config_p1(request): result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "Mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Mroutes are still present \n Error: {}".format( tc_name, result - )) + ) # unconfigure bsm processing on f1 on f1-i1-eth2 step("unconfigure bsm processing on f1 in f1-i1-eth2, will drop bsm") @@ -989,20 +997,21 @@ def test_int_bsm_config_p1(request): # Verify bsr state in i1 step("Verify if b1 is not chosen as BSR in i1") result = verify_pim_bsr(tgen, topo, "i1", bsr_ip, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b1 is chosen as BSR in i1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b1 is chosen as BSR in i1 \n Error: {}".format( tc_name, result - )) + ) # check if mroute still not installed because of rp not available step("check if mroute still not installed because of rp not available") result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed but rp not available \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "mroute installed but rp not available \n Error: {}".format(tc_name, result) + ) # configure bsm processing on i1 on f1-i1-eth2 step("configure bsm processing on f1 in f1-i1-eth2, will accept bsm") @@ -1464,10 +1473,11 @@ def test_BSM_timeout_p0(request): tgen, topo, "f1", group, rp_source="BSR", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "bsr has not aged out in f1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "bsr has not aged out in f1 \n Error: {}".format( tc_name, result - )) + ) # Verify RP mapping removed after hold timer expires group = "225.1.1.1/32" @@ -1491,20 +1501,23 @@ def test_BSM_timeout_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, src_addr, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "join state is up and join timer is running in l1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) # Verify ip mroute is not installed step("Verify mroute not installed in l1") result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) step("clear BSM database before moving to next case") clear_bsrp_data(tgen, topo) @@ -1657,10 +1670,11 @@ def test_iif_join_state_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) # Add back route for RP to make it reachable step("Add back route for RP to make it reachable") diff --git a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py index 5fc5e52518..199746d5f6 100644 --- a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py @@ -104,6 +104,10 @@ from lib.pim import ( from lib.topolog import logger from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.pimd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/mcast_pim_bsmp_02.json".format(CWD) try: @@ -454,10 +458,11 @@ def test_starg_mroute_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, wait=20, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) # Send BSM again to configure rp step("Add back RP by sending BSM from b1") @@ -807,10 +812,11 @@ def test_BSR_election_p0(request): # Verify bsr state in FHR step("Verify if b2 is not chosen as bsr in f1") result = verify_pim_bsr(tgen, topo, "f1", bsr_ip2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b2 is chosen as bsr in f1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b2 is chosen as bsr in f1 \n Error: {}".format( tc_name, result - )) + ) # Verify if b1 is still chosen as bsr step("Verify if b1 is still chosen as bsr in f1") diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py index 1c22654541..33f476de44 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py @@ -3487,11 +3487,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is still present after shut the link from " - "FHR to RP from RP node \n Error: {}".format( - tc_name, result - )) + "FHR to RP from RP node \n Error: {}".format(tc_name, result) + ) step(" No shut the link from FHR to RP from RP node") @@ -3638,11 +3638,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is still present after shut the link from " - "FHR to RP from FHR node \n Error: {}".format( - tc_name, result - )) + "FHR to RP from FHR node \n Error: {}".format(tc_name, result) + ) step(" No shut the link from FHR to RP from FHR node") diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py index 68b7849c2b..1081b764ac 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py @@ -490,10 +490,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "mroutes(S,G) are present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_upstream_iif( tgen, @@ -503,10 +505,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) for data in input_dict_starg: result = verify_ip_mroutes( @@ -518,10 +522,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "mroutes(*,G) are present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_upstream_iif( tgen, @@ -531,10 +537,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Configure default routes on c2") @@ -557,10 +565,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "RP info is unknown after removing static route from c2 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Verify (s,g) populated after adding default route ") @@ -787,10 +797,11 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( tc_name, result - )) + ) result = verify_upstream_iif( tgen, @@ -800,10 +811,11 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "upstream is still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "upstream is still present \n Error: {}".format( tc_name, result - )) + ) step("Configure default routes on all the nodes") @@ -840,10 +852,12 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "RP info is unknown after removing static route from c2 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Verify (s,g) populated after adding default route ") diff --git a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py index 1317ec67b4..e90230eb3b 100755 --- a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py @@ -423,10 +423,12 @@ def test_add_delete_static_RP_p0(request): dut = "r1" interface = "r1-r0-eth0" result = verify_igmp_groups(tgen, dut, interface, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: igmp group present without any IGMP join \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify show ip pim interface traffic without any IGMP join") state_dict = {"r1": {"r1-r2-eth1": ["pruneTx"]}} @@ -492,26 +494,29 @@ def test_add_delete_static_RP_p0(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: RP info present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: RP info present \n Error: {}".format( tc_name, result - )) + ) step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF interface present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF interface present \n Error: {}".format(tc_name, result) + ) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is up and join timer is running \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) @@ -521,10 +526,11 @@ def test_add_delete_static_RP_p0(request): step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present \n Error: {}".format( tc_name, result - )) + ) step("r1: Verify show ip pim interface traffic without any IGMP join") state_after = verify_pim_interface_traffic(tgen, state_dict) @@ -681,10 +687,12 @@ def test_SPT_RPT_path_same_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S, G) upstream join state is up and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r2-eth1" @@ -811,17 +819,19 @@ def test_not_reachable_static_RP_p0(request): "using show ip pim state" ) result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "OIL is not same and IIF is not cleared on R1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: upstream IIF should be unknown , verify using show ip pim" "upstream") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF is not unknown \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF is not unknown \n Error: {}".format(tc_name, result) + ) step( "r1: join state should not be joined and join timer should stop," @@ -830,10 +840,12 @@ def test_not_reachable_static_RP_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: join state is joined and timer is not stopped \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step( "r1: (*,G) prune is sent towards the RP interface, verify using" @@ -850,10 +862,12 @@ def test_not_reachable_static_RP_p0(request): step("r1: (*, G) cleared from mroute table using show ip mroute") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*, G) are not cleared from mroute table \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected behavior: {}".format(result)) # Uncomment next line for debugging @@ -920,10 +934,11 @@ def test_add_RP_after_join_received_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: rp-info is present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: rp-info is present \n Error: {}".format( tc_name, result - )) + ) step("joinTx value before join sent") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"]}} @@ -944,34 +959,38 @@ def test_add_RP_after_join_received_p1(request): step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IFF interface is present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IFF interface is present \n Error: {}".format(tc_name, result) + ) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is joined and timer is running \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: PIM state is up\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format( tc_name, result - )) + ) step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format( tc_name, result - )) + ) step("r1: Configure static RP") input_dict = { @@ -1095,33 +1114,37 @@ def test_reachable_static_RP_after_join_p0(request): step("r1 : Verify upstream IIF interface") iif = "r1-r2-eth1" result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF interface is present\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF interface is present\n Error: {}".format(tc_name, result) + ) step("r1 : Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is joined and timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1 : Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: PIM state is up\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format( tc_name, result - )) + ) step("r1 : Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format( tc_name, result - )) + ) step("r1: Make RP reachable") intf = "r1-r2-eth1" @@ -1362,10 +1385,12 @@ def test_send_join_on_higher_preffered_rp_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE, oif, rp_address_2, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: rp-info is present for group 225.1.1.1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step( "r1 : Verify RPF interface updated in mroute when higher preferred" @@ -1619,11 +1644,11 @@ def test_RP_configured_as_LHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S, G) upstream join state is joined and join" - " timer is running \n Error: {}".format( - tc_name, result - )) + " timer is running \n Error: {}".format(tc_name, result) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -1828,10 +1853,12 @@ def test_RP_configured_as_LHR_2_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2036,10 +2063,12 @@ def test_RP_configured_as_FHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2245,10 +2274,12 @@ def test_RP_configured_as_FHR_2_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2372,10 +2403,12 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2394,10 +2427,12 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2623,10 +2658,12 @@ def test_restart_pimd_process_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2791,10 +2828,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2813,10 +2852,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2932,10 +2973,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2952,10 +2995,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3132,10 +3177,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3154,10 +3201,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3224,10 +3273,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3399,10 +3450,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3421,10 +3474,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3491,10 +3546,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3513,10 +3570,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3643,30 +3702,36 @@ def test_shutdown_primary_path_p1(request): iif = "r1-r3-eth2" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes") dut = "r2" iif = "lo" oif = "r2-r3-eth1" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (*, G) ip mroutes") dut = "r3" iif = "r3-r2-eth1" oif = "r3-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: No shutdown the link from R1 to R3 from R3 node") dut = "r3" @@ -3826,20 +3891,24 @@ def test_delete_RP_shut_noshut_upstream_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) @@ -3949,20 +4018,24 @@ def test_delete_RP_shut_noshut_RP_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) diff --git a/tests/topotests/nhrp-topo/r1/nhrp4_cache.json b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json new file mode 100644 index 0000000000..6426a939be --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json @@ -0,0 +1,29 @@ +{ + "attr":{ + "entriesCount":2 + }, + "table":[ + { + "interface":"r1-gre0", + "type":"nhs", + "protocol":"10.255.255.2", + "nbma":"10.2.1.2", + "claimed_nbma":"10.2.1.2", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + }, + { + "interface":"r1-gre0", + "type":"local", + "protocol":"10.255.255.1", + "nbma":"10.1.1.1", + "claimed_nbma":"10.1.1.1", + "used":false, + "timeout":false, + "auth":false, + "identity":"-" + } + ] +} diff --git a/tests/topotests/nhrp-topo/r1/nhrp_route4.json b/tests/topotests/nhrp-topo/r1/nhrp_route4.json new file mode 100644 index 0000000000..68b5a6ece2 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrp_route4.json @@ -0,0 +1,25 @@ +{ + "10.255.255.2\/32":[ + { + "prefix":"10.255.255.2\/32", + "protocol":"nhrp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":10, + "metric":0, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-gre0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp-topo/r1/nhrpd.conf b/tests/topotests/nhrp-topo/r1/nhrpd.conf new file mode 100644 index 0000000000..04114bdbe6 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrpd.conf @@ -0,0 +1,10 @@ +log stdout debugging +debug nhrp all +interface r1-gre0 + ip nhrp holdtime 500 + ip nhrp shortcut + ip nhrp network-id 42 + ip nhrp nhs dynamic nbma 10.2.1.2 + ip nhrp registration no-unique + tunnel source r1-eth0 +exit diff --git a/tests/topotests/nhrp-topo/r1/zebra.conf b/tests/topotests/nhrp-topo/r1/zebra.conf new file mode 100644 index 0000000000..b45670fcb2 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/zebra.conf @@ -0,0 +1,12 @@ +interface r1-eth0 + ip address 10.1.1.1/24 +! +ip route 10.2.1.0/24 10.1.1.3 +interface r1-gre0 + ip address 10.255.255.1/32 + no link-detect + ipv6 nd suppress-ra +exit +interface r1-eth1 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/nhrp-topo/r2/nhrp4_cache.json b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json new file mode 100644 index 0000000000..34558e0c28 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json @@ -0,0 +1,29 @@ +{ + "attr":{ + "entriesCount":2 + }, + "table":[ + { + "interface":"r2-gre0", + "type":"local", + "protocol":"10.255.255.2", + "nbma":"10.2.1.2", + "claimed_nbma":"10.2.1.2", + "used":false, + "timeout":false, + "auth":false, + "identity":"-" + }, + { + "interface":"r2-gre0", + "type":"dynamic", + "protocol":"10.255.255.1", + "nbma":"10.1.1.1", + "claimed_nbma":"10.1.1.1", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + } + ] +} diff --git a/tests/topotests/nhrp-topo/r2/nhrp_route4.json b/tests/topotests/nhrp-topo/r2/nhrp_route4.json new file mode 100644 index 0000000000..7393cba893 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrp_route4.json @@ -0,0 +1,25 @@ +{ + "10.255.255.1\/32":[ + { + "prefix":"10.255.255.1\/32", + "protocol":"nhrp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":10, + "metric":0, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-gre0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp-topo/r2/nhrpd.conf b/tests/topotests/nhrp-topo/r2/nhrpd.conf new file mode 100644 index 0000000000..e4f6fb7445 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrpd.conf @@ -0,0 +1,10 @@ +debug nhrp all +log stdout debugging +nhrp nflog-group 1 +interface r2-gre0 + ip nhrp holdtime 500 + ip nhrp redirect + ip nhrp network-id 42 + ip nhrp registration no-unique + tunnel source r2-eth0 +exit diff --git a/tests/topotests/nhrp-topo/r2/zebra.conf b/tests/topotests/nhrp-topo/r2/zebra.conf new file mode 100644 index 0000000000..9f40d4d72e --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/zebra.conf @@ -0,0 +1,12 @@ +interface r2-eth0 + ip address 10.2.1.2/24 +! +ip route 10.1.1.0/24 10.2.1.3 +interface r2-gre0 + ip address 10.255.255.2/32 + no link-detect + ipv6 nd suppress-ra +! +interface r2-eth1 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/nhrp-topo/r3/zebra.conf b/tests/topotests/nhrp-topo/r3/zebra.conf new file mode 100644 index 0000000000..6d3d267978 --- /dev/null +++ b/tests/topotests/nhrp-topo/r3/zebra.conf @@ -0,0 +1,11 @@ +debug zebra kernel +debug zebra rib +debug zebra events +debug zebra packet +ip forwarding +interface r3-eth0 + ip address 10.1.1.3/24 +! +interface r3-eth1 + ip address 10.2.1.3/24 +exit diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.dot b/tests/topotests/nhrp-topo/test_nhrp_topo.dot new file mode 100644 index 0000000000..6b68fb398f --- /dev/null +++ b/tests/topotests/nhrp-topo/test_nhrp_topo.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo2"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:4::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + + r2 -- sw2 [label="eth1"]; + r3 -- sw2 [label="eth0"]; + + r2 -- sw3 [label="eth2"]; + r4 -- sw3 [label="eth0"]; +} diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.py b/tests/topotests/nhrp-topo/test_nhrp_topo.py new file mode 100644 index 0000000000..1687961f34 --- /dev/null +++ b/tests/topotests/nhrp-topo/test_nhrp_topo.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# +# test_nhrp_topo.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_nhrp_topo.py: Test the FRR/Quagga NHRP daemon +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class NHRPTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 3 routers. + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r3']) + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['r2']) + switch = tgen.add_switch('s4') + switch.add_link(tgen.gears['r1']) + + +def _populate_iface(): + tgen = get_topogen() + cmds_tot_hub = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.2.1.{1} remote 0.0.0.0', + 'ip link set dev {0}-gre0 up', + 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6'] + + cmds_tot = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.1.1.{1} remote 0.0.0.0', + 'ip link set dev {0}-gre0 up', + 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6'] + + for cmd in cmds_tot_hub: + input = cmd.format('r2', '2') + logger.info('input: '+cmd) + output = tgen.net['r2'].cmd(cmd.format('r2', '2')) + logger.info('output: '+output); + + for cmd in cmds_tot: + input = cmd.format('r1', '1') + logger.info('input: '+cmd) + output = tgen.net['r1'].cmd(cmd.format('r1', '1')) + logger.info('output: '+output); + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(NHRPTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + _populate_iface() + + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)), + ) + if rname in ('r1', 'r2'): + router.load_config( + TopoRouter.RD_NHRP, + os.path.join(CWD, '{}/nhrpd.conf'.format(rname)) + ) + + # Initialize all routers. + logger.info('Launching BGP, NHRP') + for name in router_list: + router = tgen.gears[name] + router.start() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_protocols_convergence(): + """ + Assert that all protocols have converged before checking for the NHRP + statuses as they depend on it. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Check IPv4 routing tables. + logger.info("Checking NHRP cache and IPv4 routes for convergence") + router_list = tgen.routers() + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + + json_file = '{}/{}/nhrp4_cache.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip nhrp cache json', expected) + _, result = topotest.run_and_expect(test_func, None, count=40, + wait=0.5) + + output = router.vtysh_cmd('show ip nhrp cache') + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + + json_file = '{}/{}/nhrp_route4.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip route nhrp json', expected) + _, result = topotest.run_and_expect(test_func, None, count=40, + wait=0.5) + + output = router.vtysh_cmd('show ip route nhrp') + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + logger.info('Dump neighbor information on {}-gre0'.format(rname)) + output = router.run('ip neigh show') + logger.info(output) + + +def test_nhrp_connection(): + "Assert that the NHRP peers can find themselves." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + pingrouter = tgen.gears['r1'] + logger.info('Check Ping IPv4 from R1 to R2 = 10.255.255.2)') + output = pingrouter.run('ping 10.255.255.2 -f -c 1000') + logger.info(output) + if '1000 packets transmitted, 1000 received' not in output: + assertmsg = 'expected ping IPv4 from R1 to R2 should be ok' + assert 0, assertmsg + else: + logger.info('Check Ping IPv4 from R1 to R2 OK') + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py index 57b93c3fd5..b6e5e14830 100644 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py @@ -86,6 +86,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" @@ -385,9 +386,7 @@ def test_rib_ipv4_step5(): pytest.skip(tgen.errors) logger.info("Disabling SR on rt6") - tgen.net["rt6"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "no segment-routing on"' - ) + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "router ospf" -c "no segment-routing on"') for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( @@ -652,7 +651,7 @@ def test_mpls_lib_step10(): # Expected changes: # -All commands should be rejected # -#def test_ospf_invalid_config_step11(): +# def test_ospf_invalid_config_step11(): # logger.info("Test (step 11): check if invalid configuration is rejected") # tgen = get_topogen() # diff --git a/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py index 1d69f5d699..32f9b3453e 100644 --- a/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py +++ b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py @@ -79,6 +79,7 @@ import pytest pytestmark = [pytest.mark.ospfd] + class OspfTeTopo(Topo): "Test topology builder" @@ -175,6 +176,7 @@ def setup_testcase(msg): # Note that all routers must discover the same Network Topology, so the same TED. + def test_step1(): "Step1: Check initial topology" @@ -190,12 +192,8 @@ def test_step2(): tgen = setup_testcase("Step2: Shutdown interface between r1 & r2") - tgen.net["r1"].cmd( - 'vtysh -c "conf t" -c "interface r1-eth1" -c "shutdown"' - ) - tgen.net["r2"].cmd( - 'vtysh -c "conf t" -c "interface r2-eth1" -c "shutdown"' - ) + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "shutdown"') + tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "shutdown"') for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step2.json") @@ -207,9 +205,7 @@ def test_step3(): tgen = setup_testcase("Step3: Disable Inter-AS on r3") - tgen.net["r3"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "no mpls-te inter-as"' - ) + tgen.net["r3"].cmd('vtysh -c "conf t" -c "router ospf" -c "no mpls-te inter-as"') for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step3.json") @@ -221,18 +217,14 @@ def test_step4(): tgen = setup_testcase("Step4: Enable Segment Routing on r1 & r2") - tgen.net["r1"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "segment-routing on"' - ) + tgen.net["r1"].cmd('vtysh -c "conf t" -c "router ospf" -c "segment-routing on"') tgen.net["r1"].cmd( 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 20000 23999"' ) tgen.net["r1"].cmd( 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 10.0.255.1/32 index 10"' ) - tgen.net["r2"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "segment-routing on"' - ) + tgen.net["r2"].cmd('vtysh -c "conf t" -c "router ospf" -c "segment-routing on"') tgen.net["r2"].cmd( 'vtysh -c "conf t" -c "router ospf" -c "segment-routing node-msd 16"' ) @@ -253,12 +245,8 @@ def test_step5(): tgen = setup_testcase("Step5: Re-enable interface between r1 & r2") - tgen.net["r1"].cmd( - 'vtysh -c "conf t" -c "interface r1-eth1" -c "no shutdown"' - ) - tgen.net["r2"].cmd( - 'vtysh -c "conf t" -c "interface r2-eth1" -c "no shutdown"' - ) + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "no shutdown"') + tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "no shutdown"') for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step5.json") @@ -291,9 +279,7 @@ def test_step7(): tgen = setup_testcase("Step7: Disable OSPF on r4") - tgen.net["r4"].cmd( - 'vtysh -c "conf t" -c "no router ospf"' - ) + tgen.net["r4"].cmd('vtysh -c "conf t" -c "no router ospf"') for rname in ["r1", "r2", "r3"]: compare_ted_json_output(tgen, rname, "ted_step7.json") diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py index 9117247ebd..42634ce906 100644 --- a/tests/topotests/ospf-topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py @@ -135,25 +135,35 @@ def test_wait_protocol_convergence(): * Full/DROther * Full/Backup """ - result = tgen.gears[router].vtysh_cmd('show ip ospf neighbor json', - isjson=True) - if topotest.json_cmp(result, {"neighbors": {neighbor: [ - {"state": "Full/DR"}]}}) is None: + result = tgen.gears[router].vtysh_cmd( + "show ip ospf neighbor json", isjson=True + ) + if ( + topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/DR"}]}} + ) + is None + ): return None - if topotest.json_cmp(result, {"neighbors": {neighbor: [ - {"state": "Full/DROther"}]}}) is None: + if ( + topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/DROther"}]}} + ) + is None + ): return None - return topotest.json_cmp(result, {"neighbors": {neighbor: [ - {"state": "Full/Backup"}]}}) + return topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/Backup"}]}} + ) - _, result = topotest.run_and_expect(run_command_and_expect, None, - count=130, wait=1) + _, result = topotest.run_and_expect( + run_command_and_expect, None, count=130, wait=1 + ) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg - def expect_ospfv3_neighbor_full(router, neighbor): "Wait until OSPFv3 convergence." logger.info("waiting OSPFv3 router '{}'".format(router)) diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.py b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py index 32aff05982..efc8565bb3 100644 --- a/tests/topotests/ospf6-topo2/test_ospf6_topo2.py +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py @@ -141,12 +141,19 @@ def test_ospf6_default_route(): topotest.router_json_cmp, tgen.gears[router], "show ipv6 ospf6 database inter-prefix detail json", - {"areaScopedLinkStateDb": [{ - "areaId": area, - "lsa": [{ - "prefix": prefix, - "metric": metric, - }]}]}, + { + "areaScopedLinkStateDb": [ + { + "areaId": area, + "lsa": [ + { + "prefix": prefix, + "metric": metric, + } + ], + } + ] + }, ) _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) assertmsg = '"{}" convergence failure'.format(router) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index cebe55b39c..c117fc6a72 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -249,17 +249,20 @@ def test_ospf_chaos_tc31_p1(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + result = verify_rib( + tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Bring up OSPFd daemon on R0.") start_router_daemons(tgen, "r0", ["ospfd"]) @@ -482,17 +485,20 @@ def test_ospf_chaos_tc34_p1(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + result = verify_rib( + tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Bring up staticd daemon on R0.") start_router_daemons(tgen, "r0", ["staticd"]) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index adf82a5e85..1aabc06db0 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -259,19 +259,21 @@ def test_ospf_ecmp_tc16_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) for intfr in range(1, 7): intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] @@ -326,10 +328,11 @@ def test_ospf_ecmp_tc16_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -342,10 +345,11 @@ def test_ospf_ecmp_tc16_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Re configure the static route in R0.") dut = "r0" @@ -432,10 +436,11 @@ def test_ospf_ecmp_tc17_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -448,10 +453,11 @@ def test_ospf_ecmp_tc17_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure the static route in R0.Change ECMP value to 2.") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py index c5230d6614..e6dc18a434 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py @@ -307,10 +307,11 @@ def test_ospf_lan_ecmp_tc18_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -323,10 +324,11 @@ def test_ospf_lan_ecmp_tc18_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index 2fbb27f4fc..d9b90a132a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -397,10 +397,11 @@ def test_ospf_lan_tc1_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_neighbor(tgen, topo, dut, lan=True, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r0: OSPF neighbors-hip is up \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r0: OSPF neighbors-hip is up \n Error: {}".format( tc_name, result - )) + ) step("No Shut interface on R0") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index b99ce6cfb8..7864d0307a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -332,18 +332,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are present in fib \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are present in fib \n Error: {}".format( tc_name, result - )) + ) step("Delete and reconfigure prefix list.") # Create ip prefix list @@ -383,18 +385,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) pfx_list = { "r0": { @@ -438,18 +442,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -496,18 +502,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step( "configure the route map with the same name that is used " @@ -523,18 +531,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) # Create route map routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}} @@ -545,18 +555,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Delete the route map.") # Create route map @@ -573,18 +585,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index fb6b28ce5b..1432a82b12 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -247,11 +247,11 @@ def test_ospf_redistribution_tc5_p0(request): if result is not True: break - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present after deleting ip address of newly " - "configured interface of R0 \n Error: {}".format( - tc_name, result - )) + "configured interface of R0 \n Error: {}".format(tc_name, result) + ) protocol = "ospf" result = verify_rib( @@ -264,11 +264,11 @@ def test_ospf_redistribution_tc5_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present in fib after deleting ip address of newly " - "configured interface of R0 \n Error: {}".format( - tc_name, result - )) + "configured interface of R0 \n Error: {}".format(tc_name, result) + ) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { @@ -370,11 +370,11 @@ def test_ospf_redistribution_tc6_p0(request): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present after deleting ip address of newly " - "configured loopback of R0 \n Error: {}".format( - tc_name, result - )) + "configured loopback of R0 \n Error: {}".format(tc_name, result) + ) protocol = "ospf" result = verify_rib( @@ -386,11 +386,11 @@ def test_ospf_redistribution_tc6_p0(request): next_hop=nh, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present in fib after deleting ip address of newly " - "configured loopback of R0 \n Error: {}".format( - tc_name, result - )) + "configured loopback of R0 \n Error: {}".format(tc_name, result) + ) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py index 74d609c57e..76e50beb5c 100644 --- a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -94,12 +94,14 @@ def setup_module(mod): tgen.start_router() + def teardown_module(_mod): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() + def test_converge_protocols(): "Wait for protocol convergence" @@ -110,19 +112,26 @@ def test_converge_protocols(): topotest.sleep(10, "Waiting for OSPF convergence") + def ospf_configure_suppress_fa(router_name, area): "Configure OSPF suppress-fa in router_name" tgen = get_topogen() router = tgen.gears[router_name] - router.vtysh_cmd("conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area)) + router.vtysh_cmd( + "conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area) + ) + def ospf_unconfigure_suppress_fa(router_name, area): "Remove OSPF suppress-fa in router_name" tgen = get_topogen() router = tgen.gears[router_name] - router.vtysh_cmd("conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area)) + router.vtysh_cmd( + "conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area) + ) + def ospf_get_lsa_type5(router_name): "Return a dict with link state id as key and forwarding addresses as value" @@ -141,7 +150,8 @@ def ospf_get_lsa_type5(router_name): result[lsa] = re1.group(1) return result -@pytest.fixture(scope='module', name='original') + +@pytest.fixture(scope="module", name="original") def test_ospf_set_suppress_fa(): "Test OSPF area [x] nssa suppress-fa" @@ -162,6 +172,7 @@ def test_ospf_set_suppress_fa(): # in the test_ospf_unset_supress_fa return initial + def test_ospf_unset_supress_fa(original): "Test OSPF no area [x] nssa suppress-fa" diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index dc4e29ebde..5d4950a70e 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -949,10 +949,11 @@ def static_routes_rmap_pfxlist_p0_tc7_ebgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, ("Testcase {} : Failed \n" - "routes are still present \n Error: {}".format( + assert ( + result4 is not True + ), "Testcase {} : Failed \n" "routes are still present \n Error: {}".format( tc_name, result4 - )) + ) step("vm4 should be present in FRR1") dut = "r1" diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 14db729195..09c437c3c4 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -947,10 +947,11 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, ("Testcase {} : Failed \n" - "routes are still present \n Error: {}".format( + assert ( + result4 is not True + ), "Testcase {} : Failed \n" "routes are still present \n Error: {}".format( tc_name, result4 - )) + ) step("vm4 should be present in FRR1") dut = "r1" diff --git a/tools/etc/frr/frr.conf b/tools/etc/frr/frr.conf index 61f7a65620..5ee6d15c91 100644 --- a/tools/etc/frr/frr.conf +++ b/tools/etc/frr/frr.conf @@ -1,3 +1,10 @@ -# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log -# in /var/log/frr/frr.log +# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log in +# /var/log/frr/frr.log +# +# Note: +# FRR's configuration shell, vtysh, dynamically edits the live, in-memory +# configuration while FRR is running. When instructed, vtysh will persist the +# live configuration to this file, overwriting its contents. If you want to +# avoid this, you can edit this file manually before starting FRR, or instruct +# vtysh to write configuration to a different file. log syslog informational diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index 96ae530894..dfa9b261c3 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -5,7 +5,6 @@ if VRRPD noinst_LIBRARIES += vrrpd/libvrrp.a sbin_PROGRAMS += vrrpd/vrrpd -# dist_examples_DATA += staticd/staticd.conf.sample vtysh_scan += vrrpd/vrrp_vty.c vtysh_daemons += vrrpd man8 += $(MANBUILD)/frr-vrrpd.8 diff --git a/vtysh/subdir.am b/vtysh/subdir.am index 86861b0390..5f7d854948 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -4,7 +4,6 @@ if VTYSH bin_PROGRAMS += vtysh/vtysh -dist_examples_DATA += vtysh/vtysh.conf.sample man1 += $(MANBUILD)/vtysh.1 endif diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 3764188292..75fee1d297 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2932,10 +2932,15 @@ DEFUN (vtysh_show_history, /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, - "show memory", + "show memory [" DAEMONS_LIST "]", SHOW_STR - "Memory statistics\n") + "Memory statistics\n" + DAEMONS_STR) { + if (argc == 3) + return show_one_daemon(vty, argv, argc - 1, + argv[argc - 1]->text); + return show_per_daemon(vty, argv, argc, "Memory statistics for %s:\n"); } @@ -3719,19 +3724,19 @@ DEFUN (no_vtysh_output_file, DEFUN(find, find_cmd, - "find REGEX", + "find REGEX...", "Find CLI command matching a regular expression\n" "Search pattern (POSIX regex)\n") { - char *pattern = argv[1]->arg; const struct cmd_node *node; const struct cmd_element *cli; vector clis; - regex_t exp = {}; - + char *pattern = argv_concat(argv, argc, 1); int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED); + XFREE(MTYPE_TMP, pattern); + if (cr != 0) { switch (cr) { case REG_BADBR: diff --git a/vtysh/vtysh.conf.sample b/vtysh/vtysh.conf.sample deleted file mode 100644 index 4e0a2beb44..0000000000 --- a/vtysh/vtysh.conf.sample +++ /dev/null @@ -1,7 +0,0 @@ -! -! Sample configuration file for vtysh. -! -!service integrated-vtysh-config -!hostname quagga-router -!username root nopassword -! diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 498d3e5f67..3414c764ce 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -342,6 +342,9 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(OPENFABRIC_NODE, line); else if (strncmp(line, "route-map", strlen("route-map")) == 0) config = config_get(RMAP_NODE, line); + else if (strncmp(line, "no route-map", strlen("no route-map")) + == 0) + config = config_get(RMAP_NODE, line); else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0) config = config_get(PBRMAP_NODE, line); else if (strncmp(line, "access-list", strlen("access-list")) diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 6ed3dadaae..c4eb78608b 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -364,6 +364,11 @@ module frr-route-map { description "Route map instance name"; } + leaf optimization-disabled { + type boolean; + default false; + description "Disables or enables the optimization"; + } list entry { key "sequence"; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index af2c251607..6aaf9d94f3 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1661,8 +1661,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) else if (IS_ZEBRA_IF_VXLAN(ifp)) zebra_l2_vxlanif_del(ifp); - if (!IS_ZEBRA_IF_VRF(ifp)) - if_delete_update(ifp); + if_delete_update(ifp); } return 0; diff --git a/zebra/interface.c b/zebra/interface.c index 3eeed9ac90..4b708496a1 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -898,7 +898,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp, * Remove and re-add any existing neighbor entry for this address, * since Netlink doesn't currently offer update message types. */ - kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id); + kernel_neigh_update(0, ifp->ifindex, (void *)&ipv4_ll.s_addr, mac, 6, + ns_id, AF_INET, true); /* Add new neighbor entry. * @@ -910,8 +911,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp, * they'll be useless to us. */ if (add) - kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6, - ns_id); + kernel_neigh_update(add, ifp->ifindex, (void *)&ipv4_ll.s_addr, + mac, 6, ns_id, AF_INET, true); memcpy(&zif->neigh_mac[0], &mac[0], 6); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index e71e662458..adb61023c1 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1335,6 +1335,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_VTEP_ADD: case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: return netlink_put_neigh_update_msg(bth, ctx); case DPLANE_OP_RULE_ADD: diff --git a/zebra/rt.h b/zebra/rt.h index 48f1df2868..daaa926a7d 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -68,8 +68,11 @@ kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx); #endif /* !HAVE_NETLINK */ -extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id); +extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla, + int llalen, ns_id_t ns_id, uint8_t family, + bool permanent); +extern int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, + bool reg); extern int kernel_interface_set_master(struct interface *master, struct interface *slave); @@ -78,6 +81,9 @@ extern int mpls_kernel_init(void); extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); +extern int kernel_configure_if_link(struct interface *ifp, + struct interface *link_ifp, ns_id_t ns_id); + /* * Southbound Initialization routines to get initial starting * state. diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 55e0775a8c..d2ec7da57c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -185,6 +185,10 @@ static uint16_t neigh_state_to_netlink(uint16_t dplane_state) state |= NUD_PROBE; if (dplane_state & DPLANE_NUD_INCOMPLETE) state |= NUD_INCOMPLETE; + if (dplane_state & DPLANE_NUD_PERMANENT) + state |= NUD_PERMANENT; + if (dplane_state & DPLANE_NUD_FAILED) + state |= NUD_FAILED; return state; } @@ -1537,10 +1541,10 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) routedesc, nl_msg_type_to_str(cmd), label); } -static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla, + int llalen, ns_id_t ns_id, uint8_t family, + bool permanent, uint8_t protocol) { - uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1556,15 +1560,24 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - req.ndm.ndm_family = AF_INET; - req.ndm.ndm_state = NUD_PERMANENT; + req.ndm.ndm_family = family; req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; + if (cmd == RTM_NEWNEIGH) { + if (!permanent) + req.ndm.ndm_state = NUD_REACHABLE; + else + req.ndm.ndm_state = NUD_PERMANENT; + } else + req.ndm.ndm_state = NUD_FAILED; nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol, sizeof(protocol)); - nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr); - nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + req.ndm.ndm_type = RTN_UNICAST; + nl_attr_put(&req.n, sizeof(req), NDA_DST, addr, + family2addrsize(family)); + if (lla) + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2679,11 +2692,12 @@ int netlink_nexthop_read(struct zebra_ns *zns) } -int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen, + ns_id_t ns_id, uint8_t family, bool permanent) { return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, - addr, lla, llalen, ns_id); + addr, lla, llalen, ns_id, family, permanent, + RTPROT_ZEBRA); } /** @@ -2694,7 +2708,9 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, * entry. * @ctx: Dataplane context * @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH) - * @mac: A neighbor cache link layer address + * @lla: A pointer to neighbor cache link layer address + * @llalen: Length of the pointer to neighbor cache link layer + * address * @ip: A neighbor cache n/w layer destination address * In the case of bridge FDB, this represnts the remote * VTEP IP. @@ -2706,18 +2722,18 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, * @state: NUD_* states * @data: data buffer pointer * @datalen: total amount of data buffer space + * @protocol: protocol information * * Return: 0 when the msg doesn't fit entirely in the buffer * otherwise the number of bytes written to buf. */ static ssize_t netlink_neigh_update_msg_encode( - const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac, - const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type, - uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy, + const struct zebra_dplane_ctx *ctx, int cmd, const void *lla, + int llalen, const struct ipaddr *ip, bool replace_obj, uint8_t family, + uint8_t type, uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy, uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data, - size_t datalen) + size_t datalen, uint8_t protocol) { - uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -2749,8 +2765,8 @@ static ssize_t netlink_neigh_update_msg_encode( sizeof(protocol))) return 0; - if (mac) { - if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6)) + if (lla) { + if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, lla, llalen)) return 0; } @@ -2814,12 +2830,17 @@ netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd, void *buf, size_t buflen) { struct ethaddr dst_mac = {.octet = {0}}; + int proto = RTPROT_ZEBRA; + + if (dplane_ctx_get_type(ctx) != 0) + proto = zebra2proto(dplane_ctx_get_type(ctx)); return netlink_neigh_update_msg_encode( - ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false, - PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, - false /*nfy*/, 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, - buf, buflen); + ctx, cmd, (const void *)&dst_mac, ETH_ALEN, + dplane_ctx_neigh_get_ipaddr(ctx), false, PF_BRIDGE, 0, NTF_SELF, + (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, false /*nfy*/, + 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, buf, buflen, + proto); } #ifndef NDA_RTA @@ -3185,6 +3206,10 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, uint32_t update_flags; bool nfy = false; uint8_t nfy_flags = 0; + int proto = RTPROT_ZEBRA; + + if (dplane_ctx_get_type(ctx) != 0) + proto = zebra2proto(dplane_ctx_get_type(ctx)); cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL ? RTM_NEWNEIGH : RTM_DELNEIGH; @@ -3251,9 +3276,10 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, } total = netlink_neigh_update_msg_encode( - ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true, - AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags, - false /*ext*/, 0 /*ext_flags*/, data, datalen); + ctx, cmd, (const void *)dplane_ctx_mac_get_addr(ctx), ETH_ALEN, + &vtep_ip, true, AF_BRIDGE, 0, flags, state, nhg_id, nfy, + nfy_flags, false /*ext*/, 0 /*ext_flags*/, data, datalen, + proto); return total; } @@ -3307,6 +3333,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) bool local_inactive; uint32_t ext_flags = 0; bool dp_static = false; + int l2_len = 0; + int cmd; ndm = NLMSG_DATA(h); @@ -3348,6 +3376,43 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID)) netlink_handle_5549(ndm, zif, ifp, &ip, true); + /* we send link layer information to client: + * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH + * - struct ipaddr ( for DEL and GET) + * - struct ethaddr mac; (for NEW) + */ + if (h->nlmsg_type == RTM_NEWNEIGH) + cmd = ZEBRA_NHRP_NEIGH_ADDED; + else if (h->nlmsg_type == RTM_GETNEIGH) + cmd = ZEBRA_NHRP_NEIGH_GET; + else if (h->nlmsg_type == RTM_DELNEIGH) + cmd = ZEBRA_NHRP_NEIGH_REMOVED; + else { + zlog_debug("%s(): unknown nlmsg type %u", __func__, + h->nlmsg_type); + return 0; + } + if (tb[NDA_LLADDR]) { + /* copy LLADDR information */ + l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]); + memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), l2_len); + } + if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) { + union sockunion link_layer_ipv4; + + if (l2_len) { + sockunion_family(&link_layer_ipv4) = AF_INET; + memcpy((void *)sockunion_get_addr(&link_layer_ipv4), + &mac, l2_len); + } else + sockunion_family(&link_layer_ipv4) = AF_UNSPEC; + zsend_nhrp_neighbor_notify(cmd, ifp, &ip, ndm->ndm_state, + &link_layer_ipv4); + } + + if (h->nlmsg_type == RTM_GETNEIGH) + return 0; + /* The neighbor is present on an SVI. From this, we locate the * underlying * bridge because we're only interested in neighbors on a VxLAN bridge. @@ -3615,7 +3680,8 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) int len; struct ndmsg *ndm; - if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH)) + if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH + || h->nlmsg_type == RTM_GETNEIGH)) return 0; /* Length validity. */ @@ -3656,19 +3722,42 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd, void *buf, size_t buflen) { const struct ipaddr *ip; - const struct ethaddr *mac; + const struct ethaddr *mac = NULL; + const struct ipaddr *link_ip = NULL; + const void *link_ptr = NULL; + char buf2[ETHER_ADDR_STRLEN]; + + int llalen; uint8_t flags; uint16_t state; uint8_t family; uint32_t update_flags; uint32_t ext_flags = 0; bool ext = false; + int proto = RTPROT_ZEBRA; + + if (dplane_ctx_get_type(ctx) != 0) + proto = zebra2proto(dplane_ctx_get_type(ctx)); ip = dplane_ctx_neigh_get_ipaddr(ctx); - mac = dplane_ctx_neigh_get_mac(ctx); - if (is_zero_mac(mac)) - mac = NULL; + if (dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_INSTALL + || dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_DELETE) { + link_ip = dplane_ctx_neigh_get_link_ip(ctx); + llalen = IPADDRSZ(link_ip); + link_ptr = (const void *)&(link_ip->ip.addr); + ipaddr2str(link_ip, buf2, sizeof(buf2)); + } else { + mac = dplane_ctx_neigh_get_mac(ctx); + llalen = ETH_ALEN; + link_ptr = (const void *)mac; + if (is_zero_mac(mac)) + mac = NULL; + if (mac) + prefix_mac2str(mac, buf2, sizeof(buf2)); + else + snprintf(buf2, sizeof(buf2), "null"); + } update_flags = dplane_ctx_neigh_get_update_flags(ctx); flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx)); state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx)); @@ -3682,7 +3771,7 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, */ if (update_flags & DPLANE_NEIGH_WAS_STATIC) ext = true; - } else { + } else if (!(update_flags & DPLANE_NEIGH_NO_EXTENSION)) { ext = true; /* local neigh */ if (update_flags & DPLANE_NEIGH_SET_STATIC) @@ -3690,15 +3779,63 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Tx %s family %s IF %s(%u) Neigh %pIA MAC %pEA flags 0x%x state 0x%x %sext_flags 0x%x", + "Tx %s family %s IF %s(%u) Neigh %pIA %s %s flags 0x%x state 0x%x %sext_flags 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(family), dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx), - ip, mac, flags, state, ext ? "ext " : "", ext_flags); + ip, link_ip ? "Link " : "MAC ", buf2, flags, state, + ext ? "ext " : "", ext_flags); return netlink_neigh_update_msg_encode( - ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state, - 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext, ext_flags, buf, - buflen); + ctx, cmd, link_ptr, llalen, ip, true, family, RTN_UNICAST, + flags, state, 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext, + ext_flags, buf, buflen, proto); +} + +static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx, + void *data, size_t datalen) +{ + struct { + struct nlmsghdr n; + struct ndtmsg ndtm; + char buf[]; + } *req = data; + struct rtattr *nest; + uint8_t family; + ifindex_t idx; + uint32_t val; + + if (datalen < sizeof(*req)) + return 0; + memset(req, 0, sizeof(*req)); + family = dplane_ctx_neightable_get_family(ctx); + idx = dplane_ctx_get_ifindex(ctx); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)); + req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE; + req->n.nlmsg_type = RTM_SETNEIGHTBL; + req->ndtm.ndtm_family = family; + + nl_attr_put(&req->n, datalen, NDTA_NAME, + family == AF_INET ? "arp_cache" : "ndisc_cache", 10); + nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS); + if (nest == NULL) + return 0; + if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx))) + return 0; + val = dplane_ctx_neightable_get_app_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val))) + return 0; + val = dplane_ctx_neightable_get_mcast_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val, + sizeof(val))) + return 0; + val = dplane_ctx_neightable_get_ucast_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val, + sizeof(val))) + return 0; + nl_attr_nest_end(&req->n, nest); + + return NLMSG_ALIGN(req->n.nlmsg_len); } static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, @@ -3710,9 +3847,11 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, case DPLANE_OP_NEIGH_INSTALL: case DPLANE_OP_NEIGH_UPDATE: case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_NEIGH_IP_INSTALL: ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); break; case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_NEIGH_IP_DELETE: ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); break; case DPLANE_OP_VTEP_ADD: @@ -3723,6 +3862,9 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + ret = netlink_neigh_table_update_ctx(ctx, buf, buflen); + break; default: ret = -1; } diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index a0f401c334..ada828d016 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -362,8 +362,14 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_SUCCESS; } -int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg) +{ + /* TODO */ + return 0; +} + +int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen, + ns_id_t ns_id, uint8_t family, bool permanent) { /* TODO */ return 0; @@ -388,6 +394,12 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_SUCCESS; } +int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp, + ns_id_t ns_id) +{ + return 0; +} + extern int kernel_interface_set_master(struct interface *master, struct interface *slave) { diff --git a/zebra/subdir.am b/zebra/subdir.am index 6a582f6901..80ea9ac7b8 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -4,7 +4,6 @@ if ZEBRA sbin_PROGRAMS += zebra/zebra -dist_examples_DATA += zebra/zebra.conf.sample vtysh_scan += \ zebra/debug.c \ zebra/interface.c \ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index b482914418..e854d7ff3a 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -974,6 +974,37 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } +void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4) +{ + struct stream *s; + struct listnode *node, *nnode; + struct zserv *client; + afi_t afi; + union sockunion ip; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Notifying Neighbor entry (%u)", + __PRETTY_FUNCTION__, cmd); + + sockunion_family(&ip) = ipaddr_family(ipaddr); + afi = family2afi(sockunion_family(&ip)); + memcpy((char *)sockunion_get_addr(&ip), &ipaddr->ip.addr, + family2addrsize(sockunion_family(&ip))); + + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], ifp->vrf_id)) + continue; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + zclient_neigh_ip_encode(s, cmd, &ip, link_layer_ipv4, ifp); + stream_putw_at(s, 0, stream_get_endp(s)); + zserv_send_message(client, s); + } +} + + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, vrf_id_t vrf_id) @@ -2277,6 +2308,7 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf)); vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); } } @@ -3167,6 +3199,97 @@ stream_failure: return; } + +static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS) +{ + afi_t afi; + + STREAM_GETW(msg, afi); + if (afi <= AFI_UNSPEC || afi >= AFI_MAX) { + zlog_warn( + "Invalid AFI %u while registering for neighbors notifications", + afi); + goto stream_failure; + } + vrf_bitmap_set(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); +stream_failure: + return; +} + +static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS) +{ + afi_t afi; + + STREAM_GETW(msg, afi); + if (afi <= AFI_UNSPEC || afi >= AFI_MAX) { + zlog_warn( + "Invalid AFI %u while unregistering from neighbor notifications", + afi); + goto stream_failure; + } + vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf)); +stream_failure: + return; +} + +static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + uint8_t fam; + ifindex_t idx; + struct interface *ifp; + + s = msg; + STREAM_GETC(s, fam); + if (fam != AF_INET && fam != AF_INET6) + return; + STREAM_GETL(s, idx); + ifp = if_lookup_by_index_per_ns(zvrf->zns, idx); + if (!ifp) + return; + dplane_neigh_table_update(ifp, fam, 1, 0, 0); +stream_failure: + return; +} + +static inline void zebra_neigh_ip_add(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_neigh_ip api = {}; + int ret; + const struct interface *ifp; + + s = msg; + ret = zclient_neigh_ip_decode(s, &api); + if (ret < 0) + return; + ifp = if_lookup_by_index(api.index, zvrf_id(zvrf)); + if (!ifp) + return; + dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_INSTALL, ifp, &api.ip_out, + &api.ip_in, api.ndm_state, client->proto); +} + + +static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_neigh_ip api = {}; + int ret; + struct interface *ifp; + + s = msg; + ret = zclient_neigh_ip_decode(s, &api); + if (ret < 0) + return; + ifp = if_lookup_by_index(api.index, zvrf_id(zvrf)); + if (!ifp) + return; + dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_DELETE, ifp, &api.ip_out, + &api.ip_in, api.ndm_state, client->proto); +} + + static inline void zread_iptable(ZAPI_HANDLER_ARGS) { struct zebra_pbr_iptable *zpi = @@ -3352,6 +3475,11 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request, [ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh, [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh, + [ZEBRA_NEIGH_IP_ADD] = zebra_neigh_ip_add, + [ZEBRA_NEIGH_IP_DEL] = zebra_neigh_ip_del, + [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register, + [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister, + [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp, }; /* diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index ca471f8d98..0beb3cc100 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -104,6 +104,9 @@ extern int zsend_label_manager_connect_response(struct zserv *client, extern int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint, char *name, int status); +extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample deleted file mode 100644 index 03042eb083..0000000000 --- a/zebra/zebra.conf.sample +++ /dev/null @@ -1,23 +0,0 @@ -! -*- zebra -*- -! -! zebra sample configuration file -! -hostname Router -password zebra -enable password zebra -! -! Interface's description. -! -!interface lo -! description test of desc. -! -!interface sit0 -! multicast - -! -! Static default route sample. -! -!ip route 0.0.0.0/0 203.181.89.241 -! - -!log file zebra.log diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 18fe0a7e85..c8ee8f9051 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -220,13 +220,26 @@ struct dplane_mac_info { */ struct dplane_neigh_info { struct ipaddr ip_addr; - struct ethaddr mac; + union { + struct ethaddr mac; + struct ipaddr ip_addr; + } link; uint32_t flags; uint16_t state; uint32_t update_flags; }; /* + * Neighbor Table + */ +struct dplane_neigh_table { + uint8_t family; + uint32_t app_probes; + uint32_t ucast_probes; + uint32_t mcast_probes; +}; + +/* * Policy based routing rule info for the dataplane */ struct dplane_ctx_rule { @@ -313,6 +326,7 @@ struct zebra_dplane_ctx { struct zebra_pbr_ipset_entry entry; struct zebra_pbr_ipset_info info; } ipset_entry; + struct dplane_neigh_table neightable; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -452,6 +466,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_ipset_entry_in; _Atomic uint32_t dg_ipset_entry_errors; + _Atomic uint32_t dg_neightable_in; + _Atomic uint32_t dg_neightable_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -496,12 +513,11 @@ static enum zebra_dplane_result mac_update_common( vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, bool sticky, uint32_t nhg_id, uint32_t update_flags); -static enum zebra_dplane_result neigh_update_internal( - enum dplane_op_e op, - const struct interface *ifp, - const struct ethaddr *mac, - const struct ipaddr *ip, - uint32_t flags, uint16_t state, uint32_t update_flags); +static enum zebra_dplane_result +neigh_update_internal(enum dplane_op_e op, const struct interface *ifp, + const void *link, int link_family, + const struct ipaddr *ip, uint32_t flags, uint16_t state, + uint32_t update_flags, int protocol); /* * Public APIs @@ -669,6 +685,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_RULE_UPDATE: case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: case DPLANE_OP_NONE: case DPLANE_OP_IPSET_ADD: case DPLANE_OP_IPSET_DELETE: @@ -677,6 +695,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + break; case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: if (ctx->u.iptable.interface_name_list) { @@ -950,6 +970,15 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_IPSET_ENTRY_DELETE: ret = "IPSET_ENTRY_DELETE"; break; + case DPLANE_OP_NEIGH_IP_INSTALL: + ret = "NEIGH_IP_INSTALL"; + break; + case DPLANE_OP_NEIGH_IP_DELETE: + ret = "NEIGH_IP_DELETE"; + break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + ret = "NEIGH_TABLE_UPDATE"; + break; } return ret; @@ -1711,11 +1740,18 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( return &(ctx->u.neigh.ip_addr); } +const struct ipaddr * +dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return &(ctx->u.neigh.link.ip_addr); +} + const struct ethaddr *dplane_ctx_neigh_get_mac( const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.neigh.mac); + return &(ctx->u.neigh.link.mac); } uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx) @@ -1978,6 +2014,37 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr) return ptr->status; } +uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.family; +} + +uint32_t +dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.app_probes; +} + +uint32_t +dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.ucast_probes; +} + +uint32_t +dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.mcast_probes; +} + /* * End of interface extra info accessors */ @@ -3436,6 +3503,41 @@ enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp, } /* + * API to configure link local with either MAC address or IP information + */ +enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op, + const struct interface *ifp, + struct ipaddr *link_ip, + struct ipaddr *ip, + uint32_t ndm_state, int protocol) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + uint16_t state = 0; + uint32_t update_flags; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + char buf1[PREFIX_STRLEN], buf2[PREFIX_STRLEN]; + + ipaddr2str(link_ip, buf1, sizeof(buf1)); + ipaddr2str(ip, buf2, sizeof(buf2)); + zlog_debug("init link ctx %s: ifp %s, ip %s link %s", + dplane_op2str(op), ifp->name, buf1, buf2); + } + if (ndm_state == ZEBRA_NEIGH_STATE_REACHABLE) + state = DPLANE_NUD_REACHABLE; + else if (ndm_state == ZEBRA_NEIGH_STATE_FAILED) + state = DPLANE_NUD_FAILED; + + update_flags = DPLANE_NEIGH_NO_EXTENSION; + + result = neigh_update_internal(op, ifp, (const void *)link_ip, + ipaddr_family(link_ip), ip, 0, state, + update_flags, protocol); + + return result; +} + +/* * Enqueue local mac add (or update). */ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp, @@ -3584,9 +3686,9 @@ enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp, if (was_static) update_flags |= DPLANE_NEIGH_WAS_STATIC; - result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, - ifp, mac, ip, flags, DPLANE_NUD_NOARP, - update_flags); + result = neigh_update_internal( + DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET, + ip, flags, DPLANE_NUD_NOARP, update_flags, 0); return result; } @@ -3618,9 +3720,9 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp, if (set_router) ntf |= DPLANE_NTF_ROUTER; - result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, - ifp, mac, ip, ntf, - state, update_flags); + result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp, + (const void *)mac, AF_ETHERNET, ip, ntf, + state, update_flags, 0); return result; } @@ -3636,8 +3738,8 @@ enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp, update_flags |= DPLANE_NEIGH_REMOTE; - result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, - ifp, NULL, ip, 0, 0, update_flags); + result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL, + AF_ETHERNET, ip, 0, 0, update_flags, 0); return result; } @@ -3660,8 +3762,8 @@ enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp, SET_IPADDR_V4(&addr); addr.ipaddr_v4 = *ip; - result = neigh_update_internal(DPLANE_OP_VTEP_ADD, - ifp, &mac, &addr, 0, 0, 0); + result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac, + AF_ETHERNET, &addr, 0, 0, 0, 0); return result; } @@ -3685,8 +3787,9 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp, SET_IPADDR_V4(&addr); addr.ipaddr_v4 = *ip; - result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, - ifp, &mac, &addr, 0, 0, 0); + result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp, + (const void *)&mac, AF_ETHERNET, &addr, + 0, 0, 0, 0); return result; } @@ -3696,8 +3799,65 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp, { enum zebra_dplane_result result; - result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, ip, - DPLANE_NTF_USE, DPLANE_NUD_INCOMPLETE, 0); + result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, + AF_ETHERNET, ip, DPLANE_NTF_USE, + DPLANE_NUD_INCOMPLETE, 0, 0); + + return result; +} + +enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, + const uint8_t family, + const uint32_t app_probes, + const uint32_t ucast_probes, + const uint32_t mcast_probes) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret; + struct zebra_dplane_ctx *ctx = NULL; + struct zebra_ns *zns; + enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("set neigh ctx %s: ifp %s, family %s", + dplane_op2str(op), ifp->name, family2str(family)); + } + + ctx = dplane_ctx_alloc(); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + ctx->zd_vrf_id = ifp->vrf_id; + + zns = zebra_ns_lookup(ifp->vrf_id); + dplane_ctx_ns_init(ctx, zns, false); + + strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); + ctx->zd_ifindex = ifp->ifindex; + + /* Init the neighbor-specific data area */ + memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable)); + + ctx->u.neightable.family = family; + ctx->u.neightable.app_probes = app_probes; + ctx->u.neightable.ucast_probes = ucast_probes; + ctx->u.neightable.mcast_probes = mcast_probes; + + /* Enqueue for processing on the dplane pthread */ + ret = dplane_update_enqueue(ctx); + + /* Increment counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + /* Error counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } return result; } @@ -3706,27 +3866,43 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp, * Common helper api for neighbor updates */ static enum zebra_dplane_result -neigh_update_internal(enum dplane_op_e op, - const struct interface *ifp, - const struct ethaddr *mac, - const struct ipaddr *ip, - uint32_t flags, uint16_t state, - uint32_t update_flags) +neigh_update_internal(enum dplane_op_e op, const struct interface *ifp, + const void *link, const int link_family, + const struct ipaddr *ip, uint32_t flags, uint16_t state, + uint32_t update_flags, int protocol) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; int ret; struct zebra_dplane_ctx *ctx = NULL; struct zebra_ns *zns; + const struct ethaddr *mac = NULL; + const struct ipaddr *link_ip = NULL; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) - zlog_debug("init neigh ctx %s: ifp %s, mac %pEA, ip %pIA", - dplane_op2str(op), ifp->name, mac, ip); + if (link_family == AF_ETHERNET) + mac = (const struct ethaddr *)link; + else + link_ip = (const struct ipaddr *)link; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + char buf1[PREFIX_STRLEN]; + + buf1[0] = '\0'; + if (link_family == AF_ETHERNET) + prefix_mac2str(mac, buf1, sizeof(buf1)); + else + ipaddr2str(link_ip, buf1, sizeof(buf1)); + zlog_debug("init neigh ctx %s: ifp %s, %s %s, ip %pIA", + dplane_op2str(op), ifp->name, + link_family == AF_ETHERNET ? "mac " : "link ", + buf1, ip); + } ctx = dplane_ctx_alloc(); ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; ctx->zd_vrf_id = ifp->vrf_id; + dplane_ctx_set_type(ctx, protocol); zns = zebra_ns_lookup(ifp->vrf_id); dplane_ctx_ns_init(ctx, zns, false); @@ -3739,7 +3915,10 @@ neigh_update_internal(enum dplane_op_e op, ctx->u.neigh.ip_addr = *ip; if (mac) - ctx->u.neigh.mac = *mac; + ctx->u.neigh.link.mac = *mac; + else if (link_ip) + ctx->u.neigh.link.ip_addr = *link_ip; + ctx->u.neigh.flags = flags; ctx->u.neigh.state = state; ctx->u.neigh.update_flags = update_flags; @@ -4048,6 +4227,13 @@ int dplane_show_helper(struct vty *vty, bool detailed) memory_order_relaxed); vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming); vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors, + memory_order_relaxed); + vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming); + vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs); return CMD_SUCCESS; } @@ -4433,6 +4619,8 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_VTEP_ADD: case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf, sizeof(buf)); @@ -4485,6 +4673,13 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_op2str(dplane_ctx_get_op(ctx)), ipent.unique, ctx); } break; + + case DPLANE_OP_NEIGH_TABLE_UPDATE: + zlog_debug("Dplane neigh table op %s, ifp %s, family %s", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifname(ctx), + family2str(dplane_ctx_neightable_get_family(ctx))); + break; } } @@ -4568,6 +4763,8 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_VTEP_ADD: case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors, 1, memory_order_relaxed); @@ -4604,6 +4801,13 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) memory_order_relaxed); break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_neightable_errors, 1, + memory_order_relaxed); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 4913ca251f..8d51d93cd4 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -165,6 +165,12 @@ enum dplane_op_e { DPLANE_OP_IPSET_DELETE, DPLANE_OP_IPSET_ENTRY_ADD, DPLANE_OP_IPSET_ENTRY_DELETE, + + /* LINK LAYER IP address update */ + DPLANE_OP_NEIGH_IP_INSTALL, + DPLANE_OP_NEIGH_IP_DELETE, + + DPLANE_OP_NEIGH_TABLE_UPDATE, }; /* @@ -184,6 +190,8 @@ enum dplane_op_e { #define DPLANE_NUD_NOARP 0x04 #define DPLANE_NUD_PROBE 0x08 #define DPLANE_NUD_INCOMPLETE 0x10 +#define DPLANE_NUD_PERMANENT 0x20 +#define DPLANE_NUD_FAILED 0x40 /* MAC update flags - dplane_mac_info.update_flags */ #define DPLANE_MAC_REMOTE (1 << 0) @@ -196,6 +204,7 @@ enum dplane_op_e { #define DPLANE_NEIGH_WAS_STATIC (1 << 1) #define DPLANE_NEIGH_SET_STATIC (1 << 2) #define DPLANE_NEIGH_SET_INACTIVE (1 << 3) +#define DPLANE_NEIGH_NO_EXTENSION (1 << 4) #define DPLANE_BR_PORT_NON_DF (1 << 0) @@ -458,6 +467,8 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( const struct zebra_dplane_ctx *ctx); const struct ethaddr *dplane_ctx_neigh_get_mac( const struct zebra_dplane_ctx *ctx); +const struct ipaddr * +dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx); uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx); @@ -507,6 +518,15 @@ dplane_ctx_get_br_port_sph_filters(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx); +/* Accessors for neighbor table information */ +uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx); + /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); @@ -585,6 +605,16 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp, const struct connected *ifc); /* + * Link layer operations for the dataplane. + */ +enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op, + const struct interface *ifp, + struct ipaddr *link_ip, + struct ipaddr *ip, + uint32_t ndm_state, + int protocol); + +/* * Enqueue evpn mac operations for the dataplane. */ enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp, @@ -656,6 +686,15 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp, enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp, const struct ipaddr *ip); +/* + * Enqueue a neighbor table parameter set + */ +enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, + const uint8_t family, + const uint32_t app_probes, + const uint32_t ucast_probes, + const uint32_t mcast_probes); + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 12ed024a66..7edf022892 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2898,6 +2898,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NEIGH_INSTALL: case DPLANE_OP_NEIGH_UPDATE: case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: case DPLANE_OP_VTEP_ADD: case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_RULE_ADD: @@ -2912,6 +2914,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_DELETE: case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: break; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ffe4be8557..82a0e6d015 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3924,10 +3924,13 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_NEIGH_INSTALL: case DPLANE_OP_NEIGH_UPDATE: case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: case DPLANE_OP_VTEP_ADD: case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); diff --git a/zebra/zserv.c b/zebra/zserv.c index 6c5eebe6fe..f89b6fe478 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -638,6 +638,7 @@ static void zserv_client_free(struct zserv *client) vrf_bitmap_free(client->redist_default[afi]); vrf_bitmap_free(client->ridinfo[afi]); + vrf_bitmap_free(client->nhrp_neighinfo[afi]); } /* @@ -760,6 +761,7 @@ static struct zserv *zserv_client_create(int sock) client->redist[afi][i] = vrf_bitmap_init(); client->redist_default[afi] = vrf_bitmap_init(); client->ridinfo[afi] = vrf_bitmap_init(); + client->nhrp_neighinfo[afi] = vrf_bitmap_init(); } /* Add this client to linked list. */ diff --git a/zebra/zserv.h b/zebra/zserv.h index c60799b8ba..203670ac1d 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -137,6 +137,9 @@ struct zserv { /* Router-id information. */ vrf_bitmap_t ridinfo[AFI_MAX]; + /* Router-id information. */ + vrf_bitmap_t nhrp_neighinfo[AFI_MAX]; + bool notify_owner; /* Indicates if client is synchronous. */ |
