diff options
36 files changed, 1376 insertions, 666 deletions
diff --git a/bgpd/bgp_community_alias.c b/bgpd/bgp_community_alias.c index 6e510a0a04..f770ebdd5d 100644 --- a/bgpd/bgp_community_alias.c +++ b/bgpd/bgp_community_alias.c @@ -152,3 +152,32 @@ const char *bgp_community2alias(char *community) return community; } + +static int bgp_community_alias_vector_walker(struct hash_bucket *bucket, + void *data) +{ + vector *comps = data; + struct community_alias *alias = bucket->data; + + vector_set(*comps, XSTRDUP(MTYPE_COMPLETION, alias->alias)); + + return 1; +} + +static void bgp_community_alias_cmd_completion(vector comps, + struct cmd_token *token) +{ + hash_walk(bgp_ca_alias_hash, bgp_community_alias_vector_walker, &comps); +} + +static const struct cmd_variable_handler community_alias_handlers[] = { + {.varname = "alias_name", + .completions = bgp_community_alias_cmd_completion}, + {.tokenname = "ALIAS_NAME", + .completions = bgp_community_alias_cmd_completion}, + {.completions = NULL}}; + +void bgp_community_alias_command_completion_setup(void) +{ + cmd_variable_handler_register(community_alias_handlers); +} diff --git a/bgpd/bgp_community_alias.h b/bgpd/bgp_community_alias.h index c84119a0d6..ab8ed06ee6 100644 --- a/bgpd/bgp_community_alias.h +++ b/bgpd/bgp_community_alias.h @@ -42,5 +42,6 @@ extern void bgp_ca_community_delete(struct community_alias *ca); extern void bgp_ca_alias_delete(struct community_alias *ca); extern int bgp_community_alias_write(struct vty *vty); extern const char *bgp_community2alias(char *community); +extern void bgp_community_alias_command_completion_setup(void); #endif /* FRR_BGP_COMMUNITY_ALIAS_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index bd45314350..e9cbf22882 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3663,7 +3663,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (aspath_loop_check(attr->aspath, peer->change_local_as) > aspath_loop_count) { peer->stat_pfx_aspath_loop++; - reason = "as-path contains our own AS A;"; + reason = "as-path contains our own AS;"; goto filtered; } } @@ -9519,14 +9519,18 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, static void damp_route_vty_out(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, afi_t afi, safi_t safi, bool use_json, - json_object *json) + json_object *json_paths) { - struct attr *attr; + struct attr *attr = path->attr; int len; char timebuf[BGP_UPTIME_LEN]; + json_object *json_path = NULL; + + if (use_json) + json_path = json_object_new_object(); /* short status lead text */ - route_vty_short_status_out(vty, path, p, json); + route_vty_short_status_out(vty, path, p, json_path); /* print prefix and mask */ if (!use_json) { @@ -9534,147 +9538,125 @@ static void damp_route_vty_out(struct vty *vty, const struct prefix *p, route_vty_out_route(path->net, p, vty, NULL, false); else vty_out(vty, "%*s", 17, " "); - } - len = vty_out(vty, "%s", path->peer->host); - len = 17 - len; - if (len < 1) { - if (!use_json) + len = vty_out(vty, "%s", path->peer->host); + len = 17 - len; + + if (len < 1) vty_out(vty, "\n%*s", 34, " "); - } else { - if (use_json) - json_object_int_add(json, "peerHost", len); else vty_out(vty, "%*s", len, " "); - } - if (use_json) - bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi, - safi, use_json, json); - else vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi, safi, - use_json, json)); - - /* Print attribute */ - attr = path->attr; + use_json, NULL)); - /* Print aspath */ - if (attr->aspath) { - if (use_json) - json_object_string_add(json, "asPath", - attr->aspath->str); - else + if (attr->aspath) aspath_print_vty(vty, "%s", attr->aspath, " "); - } - /* Print origin */ - if (use_json) - json_object_string_add(json, "origin", - bgp_origin_str[attr->origin]); - else vty_out(vty, "%s", bgp_origin_str[attr->origin]); - if (!use_json) vty_out(vty, "\n"); + } else { + bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi, + safi, use_json, json_path); + + if (attr->aspath) + json_object_string_add(json_path, "asPath", + attr->aspath->str); + + json_object_string_add(json_path, "origin", + bgp_origin_str[attr->origin]); + json_object_string_add(json_path, "peerHost", path->peer->host); + + json_object_array_add(json_paths, json_path); + } } /* flap route */ static void flap_route_vty_out(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, afi_t afi, safi_t safi, bool use_json, - json_object *json) + json_object *json_paths) { - struct attr *attr; + struct attr *attr = path->attr; struct bgp_damp_info *bdi; char timebuf[BGP_UPTIME_LEN]; int len; + json_object *json_path = NULL; if (!path->extra) return; + if (use_json) + json_path = json_object_new_object(); + bdi = path->extra->damp_info; /* short status lead text */ - route_vty_short_status_out(vty, path, p, json); + route_vty_short_status_out(vty, path, p, json_path); - /* print prefix and mask */ if (!use_json) { if (!display) route_vty_out_route(path->net, p, vty, NULL, false); else vty_out(vty, "%*s", 17, " "); - } - len = vty_out(vty, "%s", path->peer->host); - len = 16 - len; - if (len < 1) { - if (!use_json) + len = vty_out(vty, "%s", path->peer->host); + len = 16 - len; + if (len < 1) vty_out(vty, "\n%*s", 33, " "); - } else { - if (use_json) - json_object_int_add(json, "peerHost", len); else vty_out(vty, "%*s", len, " "); - } - len = vty_out(vty, "%d", bdi->flap); - len = 5 - len; - if (len < 1) { - if (!use_json) + len = vty_out(vty, "%d", bdi->flap); + len = 5 - len; + if (len < 1) vty_out(vty, " "); - } else { - if (use_json) - json_object_int_add(json, "bdiFlap", len); else vty_out(vty, "%*s", len, " "); - } - if (use_json) - peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, use_json, - json); - else vty_out(vty, "%s ", peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0, NULL)); - if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) - && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { - if (use_json) - bgp_damp_reuse_time_vty(vty, path, timebuf, - BGP_UPTIME_LEN, afi, safi, - use_json, json); - else + if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) + && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi, - safi, use_json, json)); - } else { - if (!use_json) + safi, use_json, NULL)); + else vty_out(vty, "%*s ", 8, " "); - } - - /* Print attribute */ - attr = path->attr; - /* Print aspath */ - if (attr->aspath) { - if (use_json) - json_object_string_add(json, "asPath", - attr->aspath->str); - else + if (attr->aspath) aspath_print_vty(vty, "%s", attr->aspath, " "); - } - /* Print origin */ - if (use_json) - json_object_string_add(json, "origin", - bgp_origin_str[attr->origin]); - else vty_out(vty, "%s", bgp_origin_str[attr->origin]); - if (!use_json) vty_out(vty, "\n"); + } else { + json_object_string_add(json_path, "peerHost", path->peer->host); + json_object_int_add(json_path, "bdiFlap", bdi->flap); + + peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, use_json, + json_path); + + if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) + && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) + bgp_damp_reuse_time_vty(vty, path, timebuf, + BGP_UPTIME_LEN, afi, safi, + use_json, json_path); + + if (attr->aspath) + json_object_string_add(json_path, "asPath", + attr->aspath->str); + + json_object_string_add(json_path, "origin", + bgp_origin_str[attr->origin]); + + json_object_array_add(json_paths, json_path); + } } static void route_vty_out_advertised_to(struct vty *vty, struct peer *peer, @@ -12196,7 +12178,7 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, |route-filter-translated-v4] [exact-match]\ |rpki <invalid|valid|notfound>\ |version (1-4294967295)\ - |alias WORD\ + |alias ALIAS_NAME\ ] [json$uj [detail$detail] | wide$wide]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 576ced3473..dfdfab79a5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1565,7 +1565,7 @@ void cli_show_router_bgp_router_id(struct vty *vty, struct lyd_node *dnode, } DEFPY(bgp_community_alias, bgp_community_alias_cmd, - "[no$no] bgp community alias WORD$community WORD$alias", + "[no$no] bgp community alias WORD$community ALIAS_NAME$alias_name", NO_STR BGP_STR "Add community specific parameters\n" "Create an alias for a community\n" @@ -1585,7 +1585,7 @@ DEFPY(bgp_community_alias, bgp_community_alias_cmd, memset(&ca1, 0, sizeof(ca1)); memset(&ca2, 0, sizeof(ca2)); strlcpy(ca1.community, community, sizeof(ca1.community)); - strlcpy(ca1.alias, alias, sizeof(ca1.alias)); + strlcpy(ca1.alias, alias_name, sizeof(ca1.alias)); lookup_community = bgp_ca_community_lookup(&ca1); lookup_alias = bgp_ca_alias_lookup(&ca1); @@ -20970,4 +20970,6 @@ void community_alias_vty(void) /* Community-list. */ install_element(CONFIG_NODE, &bgp_community_alias_cmd); + + bgp_community_alias_command_completion_setup(); } diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index ac17328325..6b5a008761 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -401,6 +401,22 @@ Route Selection paths learned from any of eBGP, iBGP, or confederation neighbors will be multipath if they are otherwise considered equal cost. +.. clicmd:: maximum-paths (1-128) + + Sets the maximum-paths value used for ecmp calculations for this + bgp instance in EBGP. The maximum value listed, 128, can be limited by + the ecmp cli for bgp or if the daemon was compiled with a lower + ecmp value. This value can also be set in ipv4/ipv6 unicast/labeled + unicast to only affect those particular afi/safi's. + +.. clicmd:: maximum-paths ibgp (1-128) [equal-cluster-length] + + Sets the maximum-paths value used for ecmp calculations for this + bgp instance in IBGP. The maximum value listed, 128, can be limited by + the ecmp cli for bgp or if the daemon was compiled with a lower + ecmp value. This value can also be set in ipv4/ipv6 unicast/labeled + unicast to only affect those particular afi/safi's. + .. _bgp-distance: Administrative Distance Metrics diff --git a/lib/route_types.txt b/lib/route_types.txt index c48391545d..77639070c9 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -1,4 +1,4 @@ -# Canonical Zserv route types information registry for Quagga. +# Canonical Zserv route types information registry for FRR. # # Used to construct route_types.c and route_types.h # @@ -60,7 +60,7 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 0, 0, 0, "PIM", pimd ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, 1, "EIGRP", eigrpd ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, 1, "NHRP", nhrpd # HSLS and OLSR both are AFI independent (so: 1, 1), however -# we want to disable for them for general Quagga distribution. +# we want to disable for them for general FRR distribution. # This at least makes it trivial for users of these protocols # to 'switch on' redist support (direct numeric entry remaining # possible). diff --git a/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf index 633d1832fd..293b38c7e8 100644 --- a/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf +++ b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf @@ -17,6 +17,7 @@ route-map DEF permit 10 ! router bgp 1 bgp log-neighbor-changes + bgp conditional-advertisement timer 5 no bgp ebgp-requires-policy neighbor 10.10.10.2 remote-as 2 ! diff --git a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf index c6147fe658..82525fac64 100644 --- a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf +++ b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf @@ -32,6 +32,7 @@ route-map RMAP-2 deny 10 ! router bgp 2 bgp log-neighbor-changes + bgp conditional-advertisement timer 5 no bgp ebgp-requires-policy neighbor 10.10.10.1 remote-as 1 neighbor 10.10.20.3 remote-as 3 diff --git a/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf index 2f4f5068d8..f389f309a6 100644 --- a/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf +++ b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf @@ -1,6 +1,7 @@ ! router bgp 3 bgp log-neighbor-changes + bgp conditional-advertisement timer 5 no bgp ebgp-requires-policy neighbor 10.10.20.2 remote-as 2 ! diff --git a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py index 086bad6481..fd5bb38b98 100755 --- a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py +++ b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py @@ -365,6 +365,10 @@ def test_ip_pe1_learn(): "run the IP learn test for PE1" tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + host1 = tgen.gears["host1"] pe1 = tgen.gears["PE1"] pe2 = tgen.gears["PE2"] @@ -380,6 +384,10 @@ def test_ip_pe2_learn(): "run the IP learn test for PE2" tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + host2 = tgen.gears["host2"] pe1 = tgen.gears["PE1"] pe2 = tgen.gears["PE2"] diff --git a/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json b/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json index 14842da326..dd412708bb 100644 --- a/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json +++ b/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json @@ -41,7 +41,10 @@ "neighbor": { "e1": { "dest_link": { - "r1": {} + "r1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -55,7 +58,10 @@ "neighbor": { "e1": { "dest_link": { - "r1": {} + "r1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -106,7 +112,10 @@ "neighbor": { "e1": { "dest_link": { - "r2-link1": {} + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -120,7 +129,10 @@ "neighbor": { "e1": { "dest_link": { - "r2-link1": {} + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -140,7 +152,10 @@ "neighbor": { "e1": { "dest_link": { - "r2-link2": {} + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -154,7 +169,10 @@ "neighbor": { "e1": { "dest_link": { - "r2-link2": {} + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -222,7 +240,10 @@ "neighbor": { "r1": { "dest_link": { - "e1": {} + "e1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -233,7 +254,10 @@ "neighbor": { "r1": { "dest_link": { - "e1": {} + "e1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -262,7 +286,10 @@ "neighbor": { "r2": { "dest_link": { - "e1-link1": {} + "e1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -273,7 +300,10 @@ "neighbor": { "r2": { "dest_link": { - "e1-link1": {} + "e1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -302,7 +332,10 @@ "neighbor": { "r2": { "dest_link": { - "e1-link2": {} + "e1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -313,7 +346,10 @@ "neighbor": { "r2": { "dest_link": { - "e1-link2": {} + "e1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -342,6 +378,8 @@ "d1": { "dest_link": { "e1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, "deactivate": "ipv4" } } @@ -349,6 +387,8 @@ "d2": { "dest_link": { "e1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, "deactivate": "ipv4" } } @@ -412,6 +452,8 @@ "e1": { "dest_link": { "d1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, "deactivate": "ipv4" } } @@ -442,7 +484,10 @@ "neighbor": { "r3": { "dest_link": { - "d1": {} + "d1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -453,7 +498,10 @@ "neighbor": { "r3": { "dest_link": { - "d1": {} + "d1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -482,7 +530,10 @@ "neighbor": { "r4": { "dest_link": { - "d1-link1": {} + "d1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -493,7 +544,10 @@ "neighbor": { "r4": { "dest_link": { - "d1-link1": {} + "d1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -522,7 +576,10 @@ "neighbor": { "r4": { "dest_link": { - "d1-link2": {} + "d1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -533,7 +590,10 @@ "neighbor": { "r4": { "dest_link": { - "d1-link2": {} + "d1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -590,7 +650,9 @@ "e1": { "dest_link": { "d2-link1": { - "deactivate": "ipv4" + "deactivate": "ipv4", + "keepalivetimer": 1, + "holddowntimer": 3 } } } @@ -620,7 +682,10 @@ "neighbor": { "r3": { "dest_link": { - "d2": {} + "d2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -631,7 +696,10 @@ "neighbor": { "r3": { "dest_link": { - "d2": {} + "d2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -660,7 +728,10 @@ "neighbor": { "r4": { "dest_link": { - "d2-link1": {} + "d2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -671,7 +742,10 @@ "neighbor": { "r4": { "dest_link": { - "d2-link1": {} + "d2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -700,7 +774,10 @@ "neighbor": { "r4": { "dest_link": { - "d2-link2": {} + "d2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -711,7 +788,10 @@ "neighbor": { "r4": { "dest_link": { - "d2-link2": {} + "d2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -755,12 +835,18 @@ "neighbor": { "d1": { "dest_link": { - "r3": {} + "r3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r3": {} + "r3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -771,12 +857,18 @@ "neighbor": { "d1": { "dest_link": { - "r3": {} + "r3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r3": {} + "r3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -814,12 +906,18 @@ "neighbor": { "d1": { "dest_link": { - "r4-link1": {} + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r4-link1": {} + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -830,12 +928,18 @@ "neighbor": { "d1": { "dest_link": { - "r4-link1": {} + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r4-link1": {} + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -852,12 +956,18 @@ "neighbor": { "d1": { "dest_link": { - "r4-link2": {} + "r4-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r4-link2": {} + "r4-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -868,12 +978,18 @@ "neighbor": { "d1": { "dest_link": { - "r4-link2": {} + "r4-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } }, "d2": { "dest_link": { - "r4-link2": {} + "r4-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } } } } @@ -885,3 +1001,4 @@ } } } + diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index a236a916b5..2f1f67439f 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -44,6 +44,7 @@ from lib.common_config import ( FRRCFG_FILE, retry, get_ipv6_linklocal_address, + get_frr_ipv6_linklocal ) LOGDIR = "/tmp/topotests/" @@ -265,6 +266,11 @@ def __create_bgp_global(tgen, input_dict, router, build=False): config_data.append("bgp router-id {}".format(router_id)) config_data.append("no bgp network import-check") + bgp_peer_grp_data = bgp_data.setdefault("peer-group", {}) + + if "peer-group" in bgp_data and bgp_peer_grp_data: + peer_grp_data = __create_bgp_peer_group(tgen, bgp_peer_grp_data, router) + config_data.extend(peer_grp_data) bst_path = bgp_data.setdefault("bestpath", None) if bst_path: @@ -380,6 +386,7 @@ def __create_bgp_unicast_neighbor( addr_data = addr_dict["unicast"] if addr_data: config_data.append("address-family {} unicast".format(addr_type)) + advertise_network = addr_data.setdefault("advertise_networks", []) for advertise_network_dict in advertise_network: network = advertise_network_dict["network"] @@ -404,14 +411,29 @@ def __create_bgp_unicast_neighbor( config_data.append(cmd) + import_cmd = addr_data.setdefault("import", {}) + if import_cmd: + try: + if import_cmd["delete"]: + config_data.append("no import vrf {}".format(import_cmd["vrf"])) + except KeyError: + config_data.append("import vrf {}".format(import_cmd["vrf"])) + max_paths = addr_data.setdefault("maximum_paths", {}) if max_paths: ibgp = max_paths.setdefault("ibgp", None) ebgp = max_paths.setdefault("ebgp", None) + del_cmd = max_paths.setdefault("delete", False) if ibgp: - config_data.append("maximum-paths ibgp {}".format(ibgp)) + if del_cmd: + config_data.append("no maximum-paths ibgp {}".format(ibgp)) + else: + config_data.append("maximum-paths ibgp {}".format(ibgp)) if ebgp: - config_data.append("maximum-paths {}".format(ebgp)) + if del_cmd: + config_data.append("no maximum-paths {}".format(ebgp)) + else: + config_data.append("maximum-paths {}".format(ebgp)) aggregate_addresses = addr_data.setdefault("aggregate_address", []) for aggregate_address in aggregate_addresses: @@ -649,6 +671,38 @@ def __create_l2vpn_evpn_address_family( return config_data +def __create_bgp_peer_group(topo, input_dict, router): + """ + Helper API to create neighbor specific configuration + + Parameters + ---------- + * `topo` : json file data + * `input_dict` : Input dict data, required when configuring from testcase + * `router` : router id to be configured + """ + config_data = [] + logger.debug("Entering lib API: __create_bgp_peer_group()") + + for grp, grp_dict in input_dict.items(): + config_data.append("neighbor {} peer-group".format(grp)) + neigh_cxt = "neighbor {} ".format(grp) + update_source = grp_dict.setdefault("update-source", None) + remote_as = grp_dict.setdefault("remote-as", None) + capability = grp_dict.setdefault("capability", None) + if update_source: + config_data.append("{} update-source {}".format(neigh_cxt, update_source)) + + if remote_as: + config_data.append("{} remote-as {}".format(neigh_cxt, remote_as)) + + if capability: + config_data.append("{} capability {}".format(neigh_cxt, capability)) + + logger.debug("Exiting lib API: __create_bgp_peer_group()") + return config_data + + def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): """ Helper API to create neighbor specific configuration @@ -660,10 +714,9 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): * `input_dict` : Input dict data, required when configuring from testcase * `router` : router id to be configured """ - config_data = [] logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) - + tgen = get_topogen() bgp_data = input_dict["address_family"] neigh_data = bgp_data[addr_type]["unicast"]["neighbor"] @@ -672,35 +725,91 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): nh_details = topo[name] if "vrfs" in topo[router] or type(nh_details["bgp"]) is list: - remote_as = nh_details["bgp"][0]["local_as"] + for vrf_data in nh_details["bgp"]: + if "vrf" in nh_details["links"][dest_link] and "vrf" in vrf_data: + if nh_details["links"][dest_link]["vrf"] == vrf_data["vrf"]: + remote_as = vrf_data["local_as"] + break + else: + if "vrf" not in vrf_data: + remote_as = vrf_data["local_as"] + break + else: remote_as = nh_details["bgp"]["local_as"] update_source = None - if dest_link in nh_details["links"].keys(): - ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0] - # Loopback interface - if "source_link" in peer and peer["source_link"] == "lo": - update_source = topo[router]["links"]["lo"][addr_type].split("/")[0] + if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered": + ip_addr = nh_details["links"][dest_link]["peer-interface"] + elif "neighbor_type" in peer and peer["neighbor_type"] == "link-local": + intf = topo[name]["links"][dest_link]["interface"] + ip_addr = get_frr_ipv6_linklocal(tgen, name, intf) + elif dest_link in nh_details["links"].keys(): + try: + ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0] + except KeyError: + intf = topo[name]["links"][dest_link]["interface"] + ip_addr = get_frr_ipv6_linklocal(tgen, name, intf) + if "delete" in peer and peer["delete"]: + neigh_cxt = "no neighbor {}".format(ip_addr) + config_data.append("{}".format(neigh_cxt)) + return config_data + else: + neigh_cxt = "neighbor {}".format(ip_addr) - neigh_cxt = "neighbor {}".format(ip_addr) + if "peer-group" in peer: + config_data.append( + "neighbor {} interface peer-group {}".format( + ip_addr, peer["peer-group"] + ) + ) + + # Loopback interface + if "source_link" in peer: + if peer["source_link"] == "lo": + update_source = topo[router]["links"]["lo"][addr_type].split("/")[0] + else: + update_source = topo[router]["links"][peer["source_link"]][ + "interface" + ] + if "peer-group" not in peer: + if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered": + config_data.append( + "{} interface remote-as {}".format(neigh_cxt, remote_as) + ) + elif add_neigh: + config_data.append("{} remote-as {}".format(neigh_cxt, remote_as)) - if add_neigh: - config_data.append("{} remote-as {}".format(neigh_cxt, remote_as)) if addr_type == "ipv6": config_data.append("address-family ipv6 unicast") config_data.append("{} activate".format(neigh_cxt)) + if "neighbor_type" in peer and peer["neighbor_type"] == "link-local": + config_data.append( + "{} update-source {}".format( + neigh_cxt, nh_details["links"][dest_link]["peer-interface"] + ) + ) + config_data.append( + "{} interface {}".format( + neigh_cxt, nh_details["links"][dest_link]["peer-interface"] + ) + ) + disable_connected = peer.setdefault("disable_connected_check", False) keep_alive = peer.setdefault("keepalivetimer", 3) hold_down = peer.setdefault("holddowntimer", 10) password = peer.setdefault("password", None) no_password = peer.setdefault("no_password", None) + capability = peer.setdefault("capability", None) max_hop_limit = peer.setdefault("ebgp_multihop", 1) + graceful_restart = peer.setdefault("graceful-restart", None) graceful_restart_helper = peer.setdefault("graceful-restart-helper", None) graceful_restart_disable = peer.setdefault("graceful-restart-disable", None) + if capability: + config_data.append("{} capability {}".format(neigh_cxt, capability)) if update_source: config_data.append( @@ -718,7 +827,6 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): config_data.append( "{} timers {} {}".format(neigh_cxt, keep_alive, hold_down) ) - if graceful_restart: config_data.append("{} graceful-restart".format(neigh_cxt)) elif graceful_restart == False: @@ -768,7 +876,7 @@ def __create_bgp_unicast_address_family( config_data = [] logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) - + tgen = get_topogen() bgp_data = input_dict["address_family"] neigh_data = bgp_data[addr_type]["unicast"]["neighbor"] @@ -784,16 +892,34 @@ def __create_bgp_unicast_address_family( for destRouterLink, data in sorted(nh_details["links"].items()): if "type" in data and data["type"] == "loopback": if dest_link == destRouterLink: - ip_addr = nh_details["links"][destRouterLink][ - addr_type - ].split("/")[0] + ip_addr = ( + nh_details["links"][destRouterLink][addr_type] + .split("/")[0] + .lower() + ) # Physical interface else: - if dest_link in nh_details["links"].keys(): - - ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0] - if addr_type == "ipv4" and bgp_data["ipv6"]: + # check the neighbor type if un numbered nbr, use interface. + if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered": + ip_addr = nh_details["links"][dest_link]["peer-interface"] + elif "neighbor_type" in peer and peer["neighbor_type"] == "link-local": + intf = topo[peer_name]["links"][dest_link]["interface"] + ip_addr = get_frr_ipv6_linklocal(tgen, peer_name, intf) + elif dest_link in nh_details["links"].keys(): + try: + ip_addr = nh_details["links"][dest_link][addr_type].split("/")[ + 0 + ] + except KeyError: + intf = topo[peer_name]["links"][dest_link]["interface"] + ip_addr = get_frr_ipv6_linklocal(tgen, peer_name, intf) + if ( + addr_type == "ipv4" + and bgp_data["ipv6"] + and check_address_types("ipv6") + and "ipv6" in nh_details["links"][dest_link] + ): deactivate = nh_details["links"][dest_link]["ipv6"].split("/")[ 0 ] @@ -822,6 +948,7 @@ def __create_bgp_unicast_address_family( prefix_lists = peer.setdefault("prefix_lists", {}) route_maps = peer.setdefault("route_maps", {}) no_send_community = peer.setdefault("no_send_community", None) + capability = peer.setdefault("capability", None) allowas_in = peer.setdefault("allowas-in", None) # next-hop-self @@ -841,6 +968,11 @@ def __create_bgp_unicast_address_family( "no {} send-community {}".format(neigh_cxt, no_send_community) ) + # capability_ext_nh + if capability and addr_type == "ipv6": + config_data.append("address-family ipv4 unicast") + config_data.append("{} activate".format(neigh_cxt)) + if "allowas_in" in peer: allow_as_in = peer["allowas_in"] config_data.append("{} allowas-in {}".format(neigh_cxt, allow_as_in)) @@ -1067,33 +1199,37 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True): API will verify if BGP is converged with in the given time frame. Running "show bgp summary json" command and verify bgp neighbor state is established, + Parameters ---------- * `tgen`: topogen object * `topo`: input json file data * `dut`: device under test - * `expected` : expected results from API, by-default True Usage ----- # To veriry is BGP is converged for all the routers used in topology results = verify_bgp_convergence(tgen, topo, dut="r1") + Returns ------- errormsg(str) or True """ - logger.debug("Entering lib API: verify_bgp_convergence()") + result = False + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + tgen = get_topogen() for router, rnode in tgen.routers().items(): - if dut is not None and dut != router: + if 'bgp' not in topo['routers'][router]: continue - if "bgp" not in topo["routers"][router]: + if dut is not None and dut != router: continue logger.info("Verifying BGP Convergence on router %s:", router) - show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json", isjson=True) + show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json", + isjson=True) # Verifying output dictionary show_bgp_json is empty or not if not bool(show_bgp_json): errormsg = "BGP is not running" @@ -1115,100 +1251,6 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True): # To find neighbor ip type bgp_addr_type = bgp_data["address_family"] - if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type: - for addr_type in bgp_addr_type.keys(): - if not check_address_types(addr_type): - continue - total_peer = 0 - - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] - - for bgp_neighbor in bgp_neighbors: - total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"]) - - for addr_type in bgp_addr_type.keys(): - if not check_address_types(addr_type): - continue - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] - - no_of_peer = 0 - for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link in peer_data["dest_link"].keys(): - data = topo["routers"][bgp_neighbor]["links"] - if dest_link in data: - peer_details = peer_data["dest_link"][dest_link] - # for link local neighbors - if ( - "neighbor_type" in peer_details - and peer_details["neighbor_type"] == "link-local" - ): - neighbor_ip = get_ipv6_linklocal_address( - topo["routers"], bgp_neighbor, dest_link - ) - elif "source_link" in peer_details: - neighbor_ip = topo["routers"][bgp_neighbor][ - "links" - ][peer_details["source_link"]][addr_type].split( - "/" - )[ - 0 - ] - elif ( - "neighbor_type" in peer_details - and peer_details["neighbor_type"] == "unnumbered" - ): - neighbor_ip = data[dest_link]["peer-interface"] - else: - neighbor_ip = data[dest_link][addr_type].split("/")[ - 0 - ] - nh_state = None - - if addr_type == "ipv4": - if "ipv4Unicast" in show_bgp_json[vrf]: - ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][ - "peers" - ] - nh_state = ipv4_data[neighbor_ip]["state"] - else: - if "ipv6Unicast" in show_bgp_json[vrf]: - ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][ - "peers" - ] - nh_state = ipv6_data[neighbor_ip]["state"] - if nh_state == "Established": - no_of_peer += 1 - - if "l2vpn" in bgp_addr_type: - if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]: - if no_of_peer == total_peer: - logger.info( - "[DUT: %s] VRF: %s, BGP is Converged for %s address-family", - router, - vrf, - addr_type, - ) - else: - errormsg = ( - "[DUT: %s] VRF: %s, BGP is not converged for %s address-family" - % (router, vrf, addr_type) - ) - return errormsg - else: - if no_of_peer == total_peer: - logger.info( - "[DUT: %s] VRF: %s, BGP is Converged for %s address-family", - router, - vrf, - addr_type, - ) - else: - errormsg = ( - "[DUT: %s] VRF: %s, BGP is not converged for %s address-family" - % (router, vrf, addr_type) - ) - return errormsg - if "l2vpn" in bgp_addr_type: total_evpn_peer = 0 @@ -1224,46 +1266,120 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True): data = topo["routers"][bgp_neighbor]["links"] for dest_link in dest_link_dict.keys(): if dest_link in data: - peer_details = peer_data[_addr_type][dest_link] + peer_details = \ + peer_data[_addr_type][dest_link] - neighbor_ip = data[dest_link][_addr_type].split("/")[0] + neighbor_ip = \ + data[dest_link][_addr_type].split( + "/")[0] nh_state = None - if ( - "ipv4Unicast" in show_bgp_json[vrf] - or "ipv6Unicast" in show_bgp_json[vrf] - ): - errormsg = ( - "[DUT: %s] VRF: %s, " - "ipv4Unicast/ipv6Unicast" - " address-family present" - " under l2vpn" % (router, vrf) - ) + if "ipv4Unicast" in show_bgp_json[vrf] or \ + "ipv6Unicast" in show_bgp_json[vrf]: + errormsg = ("[DUT: %s] VRF: %s, " + "ipv4Unicast/ipv6Unicast" + " address-family present" + " under l2vpn" % (router, + vrf)) return errormsg - l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][ - "peers" - ] - nh_state = l2VpnEvpn_data[neighbor_ip]["state"] + l2VpnEvpn_data = \ + show_bgp_json[vrf]["l2VpnEvpn"][ + "peers"] + nh_state = \ + l2VpnEvpn_data[neighbor_ip]["state"] if nh_state == "Established": no_of_evpn_peer += 1 if no_of_evpn_peer == total_evpn_peer: - logger.info( - "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers", - router, - vrf, - ) + logger.info("[DUT: %s] VRF: %s, BGP is Converged for " + "epvn peers", router, vrf) + result = True else: - errormsg = ( - "[DUT: %s] VRF: %s, BGP is not converged " - "for evpn peers" % (router, vrf) - ) + errormsg = ("[DUT: %s] VRF: %s, BGP is not converged " + "for evpn peers" % (router, vrf)) return errormsg + else: + total_peer = 0 + for addr_type in bgp_addr_type.keys(): + if not check_address_types(addr_type): + continue - logger.debug("Exiting API: verify_bgp_convergence()") - return True + bgp_neighbors = \ + bgp_addr_type[addr_type]["unicast"]["neighbor"] + + for bgp_neighbor in bgp_neighbors: + total_peer += \ + len(bgp_neighbors[bgp_neighbor]["dest_link"]) + + no_of_peer = 0 + for addr_type in bgp_addr_type.keys(): + if not check_address_types(addr_type): + continue + bgp_neighbors = \ + bgp_addr_type[addr_type]["unicast"]["neighbor"] + + for bgp_neighbor, peer_data in bgp_neighbors.items(): + for dest_link in peer_data["dest_link"].\ + keys(): + data = \ + topo["routers"][bgp_neighbor]["links"] + if dest_link in data: + peer_details = \ + peer_data['dest_link'][dest_link] + # for link local neighbors + if "neighbor_type" in peer_details and \ + peer_details["neighbor_type"] == \ + 'link-local': + intf = topo["routers"][bgp_neighbor][ + "links"][dest_link]["interface"] + neighbor_ip = get_frr_ipv6_linklocal( + tgen, bgp_neighbor, intf) + elif "source_link" in peer_details: + neighbor_ip = \ + topo["routers"][bgp_neighbor][ + "links"][peer_details[ + 'source_link']][ + addr_type].\ + split("/")[0] + elif "neighbor_type" in peer_details and \ + peer_details["neighbor_type"] == \ + 'unnumbered': + neighbor_ip = \ + data[dest_link]["peer-interface"] + else: + neighbor_ip = \ + data[dest_link][addr_type].split( + "/")[0] + nh_state = None + neighbor_ip = neighbor_ip.lower() + if addr_type == "ipv4": + ipv4_data = show_bgp_json[vrf][ + "ipv4Unicast"]["peers"] + nh_state = \ + ipv4_data[neighbor_ip]["state"] + else: + ipv6_data = show_bgp_json[vrf][ + "ipv6Unicast"]["peers"] + if neighbor_ip in ipv6_data: + nh_state = \ + ipv6_data[neighbor_ip]["state"] + + if nh_state == "Established": + no_of_peer += 1 + + if no_of_peer == total_peer and no_of_peer > 0: + logger.info("[DUT: %s] VRF: %s, BGP is Converged", + router, vrf) + result = True + else: + errormsg = ("[DUT: %s] VRF: %s, BGP is not converged" + % (router, vrf)) + return errormsg + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return result @retry(retry_timeout=16) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 9e60e523d3..6a02e50127 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -497,7 +497,7 @@ def reset_config_on_routers(tgen, routerName=None): f.close() run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname) init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname) - command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}".format( + command = "/usr/lib/frr/frr-reload.py --test --test-reset --input {} {} > {}".format( run_cfg_file, init_cfg_file, dname ) result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE) @@ -527,37 +527,9 @@ def reset_config_on_routers(tgen, routerName=None): raise InvalidCLIError(out_data) raise InvalidCLIError("Unknown error in %s", output) - f = open(dname, "r") delta = StringIO() - delta.write("configure terminal\n") - t_delta = f.read() - - # Don't disable debugs - check_debug = True - - for line in t_delta.split("\n"): - line = line.strip() - if line == "Lines To Delete" or line == "===============" or not line: - continue - - if line == "Lines To Add": - check_debug = False - continue - - if line == "============" or not line: - continue - - # Leave debugs and log output alone - if check_debug: - if "debug" in line or "log file" in line: - continue - - delta.write(line) - delta.write("\n") - - f.close() - - delta.write("end\n") + with open(dname, "r") as f: + delta.write(f.read()) output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False) @@ -637,6 +609,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False): return True + def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): """ API to get the link local ipv6 address of a particular interface using @@ -669,38 +642,48 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): else: cmd = "show interface" - ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) - - # Fix newlines (make them all the same) - ifaces = ("\n".join(ifaces.splitlines()) + "\n").splitlines() - - interface = None - ll_per_if_count = 0 - for line in ifaces: - # Interface name - m = re_search("Interface ([a-zA-Z0-9-]+) is", line) - if m: - interface = m.group(1).split(" ")[0] - ll_per_if_count = 0 - - # Interface ip - m1 = re_search("inet6 (fe80[:a-fA-F0-9]+[/0-9]+)", line) - if m1: - local = m1.group(1) - ll_per_if_count += 1 - if ll_per_if_count > 1: - linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] - else: - linklocal += [[interface, local]] - - if linklocal: - if intf: - return [_linklocal[1] for _linklocal in linklocal if _linklocal[0] == intf][ - 0 - ].split("/")[0] - return linklocal - else: - errormsg = "Link local ip missing on router {}" + linklocal = [] + if vrf: + cmd = "show interface vrf {}".format(vrf) + else: + cmd = "show interface" + for chk_ll in range(0, 60): + sleep(1/4) + ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) + # Fix newlines (make them all the same) + ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() + + interface = None + ll_per_if_count = 0 + for line in ifaces: + # Interface name + m = re_search('Interface ([a-zA-Z0-9-]+) is', line) + if m: + interface = m.group(1).split(" ")[0] + ll_per_if_count = 0 + + # Interface ip + m1 = re_search('inet6 (fe80[:a-fA-F0-9]+[\/0-9]+)', + line) + if m1: + local = m1.group(1) + ll_per_if_count += 1 + if ll_per_if_count > 1: + linklocal += [["%s-%s" % + (interface, ll_per_if_count), local]] + else: + linklocal += [[interface, local]] + + try: + if linklocal: + if intf: + return [_linklocal[1] for _linklocal in linklocal if _linklocal[0]==intf][0].\ + split("/")[0] + return linklocal + except IndexError: + continue + + errormsg = "Link local ip missing on router {}".format(router) return errormsg @@ -1846,6 +1829,14 @@ def create_interfaces_cfg(tgen, topo, build=False): else: interface_data.append("ipv6 address {}".format(intf_addr)) + # Wait for vrf interfaces to get link local address once they are up + if not destRouterLink == 'lo' and 'vrf' in topo[c_router][ + 'links'][destRouterLink]: + vrf = topo[c_router]['links'][destRouterLink]['vrf'] + intf = topo[c_router]['links'][destRouterLink]['interface'] + ll = get_frr_ipv6_linklocal(tgen, c_router, intf=intf, + vrf = vrf) + if "ipv6-link-local" in data: intf_addr = c_data["links"][destRouterLink]["ipv6-link-local"] diff --git a/tools/frr-reload.py b/tools/frr-reload.py index eb8753fd08..9d41305ec3 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -2012,6 +2012,11 @@ if __name__ == "__main__": parser.add_argument( "--daemon", help="daemon for which want to replace the config", default="" ) + parser.add_argument( + "--test-reset", + action="store_true", + help="Used by topotest to not delete debug or log file commands", + ) args = parser.parse_args() @@ -2125,7 +2130,7 @@ if __name__ == "__main__": service_integrated_vtysh_config = False break - if not service_integrated_vtysh_config and not args.daemon: + if not args.test and not service_integrated_vtysh_config and not args.daemon: log.error( "'service integrated-vtysh-config' is not configured, this is required for 'service frr reload'" ) @@ -2153,35 +2158,56 @@ if __name__ == "__main__": running.load_from_show_running(args.daemon) (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) - lines_to_configure = [] if lines_to_del: - print("\nLines To Delete") - print("===============") + if not args.test_reset: + print("\nLines To Delete") + print("===============") for (ctx_keys, line) in lines_to_del: if line == "!": continue - cmd = "\n".join(lines_to_config(ctx_keys, line, True)) - lines_to_configure.append(cmd) + nolines = lines_to_config(ctx_keys, line, True) + + if args.test_reset: + # For topotests the original code stripped the lines, and ommitted blank lines + # after, do that here + nolines = [x.strip() for x in nolines] + # For topotests leave these lines in (don't delete them) + # [chopps: why is "log file" more special than other "log" commands?] + nolines = [x for x in nolines if "debug" not in x and "log file" not in x] + if not nolines: + continue + + cmd = "\n".join(nolines) print(cmd) if lines_to_add: - print("\nLines To Add") - print("============") + if not args.test_reset: + print("\nLines To Add") + print("============") for (ctx_keys, line) in lines_to_add: if line == "!": continue - cmd = "\n".join(lines_to_config(ctx_keys, line, False)) - lines_to_configure.append(cmd) + lines = lines_to_config(ctx_keys, line, False) + + if args.test_reset: + # For topotests the original code stripped the lines, and ommitted blank lines + # after, do that here + lines = [x.strip() for x in lines if x.strip()] + if not lines: + continue + + cmd = "\n".join(lines) print(cmd) elif args.reload: + lines_to_configure = [] # We will not be able to do anything, go ahead and exit(1) if not vtysh.is_config_available(): diff --git a/zebra/rib.h b/zebra/rib.h index b7ffb9ce8d..31d9dfd265 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -177,15 +177,16 @@ struct route_entry { /* meta-queue structure: * sub-queue 0: nexthop group objects - * sub-queue 1: connected - * sub-queue 2: kernel - * sub-queue 3: static - * sub-queue 4: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP - * sub-queue 5: iBGP, eBGP - * sub-queue 6: any other origin (if any) typically those that + * sub-queue 1: EVPN/VxLAN objects + * sub-queue 2: connected + * sub-queue 3: kernel + * sub-queue 4: static + * sub-queue 5: RIP, RIPng, OSPF, OSPF6, IS-IS, EIGRP, NHRP + * sub-queue 6: iBGP, eBGP + * sub-queue 7: any other origin (if any) typically those that * don't generate routes */ -#define MQ_SIZE 7 +#define MQ_SIZE 8 struct meta_queue { struct list *subq[MQ_SIZE]; uint32_t size; /* sum of lengths of all subqueues */ @@ -446,6 +447,36 @@ extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx); /* Enqueue incoming nhg from proto daemon for processing */ extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe); +/* Enqueue evpn route for processing */ +int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix); +int zebra_rib_queue_evpn_route_del(vrf_id_t vrf_id, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix); +/* Enqueue EVPN remote ES for processing */ +int zebra_rib_queue_evpn_rem_es_add(const esi_t *esi, + const struct in_addr *vtep_ip, + bool esr_rxed, uint8_t df_alg, + uint16_t df_pref); +int zebra_rib_queue_evpn_rem_es_del(const esi_t *esi, + const struct in_addr *vtep_ip); +/* Enqueue EVPN remote macip update for processing */ +int zebra_rib_queue_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, + const struct ipaddr *ip, + struct in_addr vtep_ip); +int zebra_rib_queue_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, + const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, + struct in_addr vtep_ip, + const esi_t *esi); +/* Enqueue VXLAN remote vtep update for processing */ +int zebra_rib_queue_evpn_rem_vtep_add(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip, + int flood_control); +int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip); + extern void meta_queue_free(struct meta_queue *mq); extern int zebra_rib_labeled_unicast(struct route_entry *re); extern struct route_table *rib_table_ipv6; diff --git a/zebra/rt.h b/zebra/rt.h index f79ddbe958..929a44ade7 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -93,10 +93,10 @@ extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, struct interface *br_if); extern void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid); + const struct ethaddr *mac, vlanid_t vid); extern void neigh_read(struct zebra_ns *zns); extern void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *ifp); -extern void neigh_read_specific_ip(struct ipaddr *ip, +extern void neigh_read_specific_ip(const struct ipaddr *ip, struct interface *vlan_if); extern void route_read(struct zebra_ns *zns); extern int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 38f8140db2..a64ec52dda 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3466,10 +3466,9 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, /* Request for MAC FDB for a specific MAC address in VLAN from the kernel */ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, - int family, - int type, + int family, int type, struct interface *br_if, - struct ethaddr *mac, + const struct ethaddr *mac, vlanid_t vid) { struct { @@ -3506,7 +3505,7 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid) + const struct ethaddr *mac, vlanid_t vid) { int ret = 0; struct zebra_dplane_info dp_info; @@ -3946,7 +3945,8 @@ int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) * read using netlink interface. */ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, - int type, struct ipaddr *ip, + int type, + const struct ipaddr *ip, ifindex_t ifindex) { struct { @@ -3983,8 +3983,8 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, return netlink_request(&zns->netlink_cmd, &req); } -int netlink_neigh_read_specific_ip(struct ipaddr *ip, - struct interface *vlan_if) +int netlink_neigh_read_specific_ip(const struct ipaddr *ip, + struct interface *vlan_if) { int ret = 0; struct zebra_ns *zns; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 4e41ff984b..93c06e555b 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -99,8 +99,9 @@ extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if); extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, - struct ethaddr *mac, uint16_t vid); -extern int netlink_neigh_read_specific_ip(struct ipaddr *ip, + const struct ethaddr *mac, + uint16_t vid); +extern int netlink_neigh_read_specific_ip(const struct ipaddr *ip, struct interface *vlan_if); extern vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index fbca47351d..f70b006acd 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -46,9 +46,9 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, } void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid) + const struct ethaddr *mac, vlanid_t vid) { -netlink_macfdb_read_specific_mac(zns, br_if, mac, vid); + netlink_macfdb_read_specific_mac(zns, br_if, mac, vid); } void neigh_read(struct zebra_ns *zns) @@ -61,7 +61,7 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) netlink_neigh_read_for_vlan(zns, vlan_if); } -void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +void neigh_read_specific_ip(const struct ipaddr *ip, struct interface *vlan_if) { netlink_neigh_read_specific_ip(ip, vlan_if); } diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index 74c6825ba1..594f7c2dd9 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -88,7 +88,7 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, } void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, - struct ethaddr *mac, vlanid_t vid) + const struct ethaddr *mac, vlanid_t vid) { } @@ -100,7 +100,7 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } -void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +void neigh_read_specific_ip(const struct ipaddr *ip, struct interface *vlan_if) { } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 8f2aa2fb09..a53e388062 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -682,6 +682,8 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, stream_put_in_addr(s, &addr); if (re) { + struct nexthop_group *nhg; + stream_putc(s, re->distance); stream_putl(s, re->metric); num = 0; @@ -689,15 +691,11 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, nump = stream_get_endp(s); /* reserve room for nexthop_num */ stream_putc(s, 0); - /* - * Only non-recursive routes are elegible to resolve the - * nexthop we are looking up. Therefore, we will just iterate - * over the top chain of nexthops. - */ - for (nexthop = re->nhe->nhg.nexthop; nexthop; - nexthop = nexthop->next) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + nhg = rib_get_fib_nhg(re); + for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { + if (rnh_nexthop_valid(re, nexthop)) num += zserv_encode_nexthop(s, nexthop); + } /* store nexthop_num */ stream_putc_at(s, nump, num); @@ -3655,8 +3653,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_ADVERTISE_ALL_VNI] = zebra_vxlan_advertise_all_vni, [ZEBRA_REMOTE_ES_VTEP_ADD] = zebra_evpn_proc_remote_es, [ZEBRA_REMOTE_ES_VTEP_DEL] = zebra_evpn_proc_remote_es, - [ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add, - [ZEBRA_REMOTE_VTEP_DEL] = zebra_vxlan_remote_vtep_del, + [ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add_zapi, + [ZEBRA_REMOTE_VTEP_DEL] = zebra_vxlan_remote_vtep_del_zapi, [ZEBRA_REMOTE_MACIP_ADD] = zebra_vxlan_remote_macip_add, [ZEBRA_REMOTE_MACIP_DEL] = zebra_vxlan_remote_macip_del, [ZEBRA_DUPLICATE_ADDR_DETECTION] = zebra_vxlan_dup_addr_detection, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 04411fa0d2..1217ed915a 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -3640,14 +3640,10 @@ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op, uint16_t state = 0; uint32_t update_flags; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char buf1[PREFIX_STRLEN], buf2[PREFIX_STRLEN]; + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("%s: init link ctx %s: ifp %s, link_ip %pIA ip %pIA", + __func__, dplane_op2str(op), ifp->name, link_ip, ip); - 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) diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 816f46bac9..2c9f1dca59 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -1330,10 +1330,12 @@ void zebra_evpn_cleanup_all(struct hash_bucket *bucket, void *arg) zebra_evpn_del(zevpn); } -static void -zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, - uint8_t flags, uint32_t seq, esi_t *esi) +static void zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, + const struct ethaddr *macaddr, + uint16_t ipa_len, + const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, + const esi_t *esi) { struct sync_mac_ip_ctx ctx; char ipbuf[INET6_ADDRSTRLEN]; @@ -1380,10 +1382,10 @@ zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr, /************************** remote mac-ip handling **************************/ /* Process a remote MACIP add from BGP. */ -void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, +void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, + uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, - struct in_addr vtep_ip, esi_t *esi) + struct in_addr vtep_ip, const esi_t *esi) { zebra_evpn_t *zevpn; zebra_vtep_t *zvtep; @@ -1447,18 +1449,19 @@ void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr, return; - if (process_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len, ipaddr, - &mac, vtep_ip, flags, seq, esi) + if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len, + ipaddr, &mac, vtep_ip, flags, seq, + esi) != 0) return; - process_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip, flags, - seq); + zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip, + flags, seq); } /* Process a remote MACIP delete from BGP. */ -void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, +void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, + uint16_t ipa_len, const struct ipaddr *ipaddr, struct in_addr vtep_ip) { zebra_evpn_t *zevpn; diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h index ee9e1406e4..774627a15d 100644 --- a/zebra/zebra_evpn.h +++ b/zebra/zebra_evpn.h @@ -204,12 +204,12 @@ int zebra_evpn_vtep_uninstall(zebra_evpn_t *zevpn, struct in_addr *vtep_ip); void zebra_evpn_handle_flooding_remote_vteps(struct hash_bucket *bucket, void *zvrf); void zebra_evpn_cleanup_all(struct hash_bucket *bucket, void *arg); -void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, +void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, + uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, - struct in_addr vtep_ip, esi_t *esi); -void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, + struct in_addr vtep_ip, const esi_t *esi); +void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, + uint16_t ipa_len, const struct ipaddr *ipaddr, struct in_addr vtep_ip); void zebra_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt); diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index fe3167dc29..cf2aa67269 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -986,8 +986,9 @@ void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) /* * Inform BGP about local MACIP. */ -int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, - struct ipaddr *ip, uint8_t flags, +int zebra_evpn_macip_send_msg_to_client(vni_t vni, + const struct ethaddr *macaddr, + const struct ipaddr *ip, uint8_t flags, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd) { @@ -1095,7 +1096,8 @@ static void *zebra_evpn_mac_alloc(void *p) /* * Add MAC entry. */ -zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr) +zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, + const struct ethaddr *macaddr) { zebra_mac_t tmp_mac; zebra_mac_t *mac = NULL; @@ -1254,7 +1256,8 @@ void zebra_evpn_mac_del_all(zebra_evpn_t *zevpn, int uninstall, int upd_client, /* * Look up MAC hash entry. */ -zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevpn, struct ethaddr *mac) +zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevpn, + const struct ethaddr *mac) { zebra_mac_t tmp; zebra_mac_t *pmac; @@ -1269,7 +1272,7 @@ zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevpn, struct ethaddr *mac) /* * Inform BGP about local MAC addition. */ -int zebra_evpn_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, +int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t mac_flags, uint32_t seq, struct zebra_evpn_es *es) { @@ -1303,7 +1306,7 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, /* * Inform BGP about local MAC deletion. */ -int zebra_evpn_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, +int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t flags, bool force) { if (!force) { @@ -1563,7 +1566,7 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac) static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_mac_t *mac, uint32_t seq, uint16_t ipa_len, - struct ipaddr *ipaddr, + const struct ipaddr *ipaddr, bool sync) { char ipbuf[INET6_ADDRSTRLEN]; @@ -1627,11 +1630,10 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, return true; } -zebra_mac_t * -zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, - uint8_t flags, uint32_t seq, esi_t *esi, - struct sync_mac_ip_ctx *ctx) +zebra_mac_t *zebra_evpn_proc_sync_mac_update( + zebra_evpn_t *zevpn, const struct ethaddr *macaddr, uint16_t ipa_len, + const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, + const esi_t *esi, struct sync_mac_ip_ctx *ctx) { zebra_mac_t *mac; bool inform_bgp = false; @@ -1958,11 +1960,13 @@ void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, zebra_evpn_print_mac_hash_detail(bucket, ctxt); } -int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, - struct ethaddr *macaddr, uint16_t ipa_len, - struct ipaddr *ipaddr, zebra_mac_t **macp, - struct in_addr vtep_ip, uint8_t flags, - uint32_t seq, esi_t *esi) +int zebra_evpn_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, + const struct ethaddr *macaddr, + uint16_t ipa_len, + const struct ipaddr *ipaddr, + zebra_mac_t **macp, struct in_addr vtep_ip, + uint8_t flags, uint32_t seq, + const esi_t *esi) { char buf1[INET6_ADDRSTRLEN]; bool sticky; @@ -2127,7 +2131,7 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, struct interface *ifp, - struct ethaddr *macaddr, vlanid_t vid, + const struct ethaddr *macaddr, vlanid_t vid, bool sticky, bool local_inactive, bool dp_static, zebra_mac_t *mac) { @@ -2447,8 +2451,8 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac, } int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, - struct ipaddr *ip, zebra_mac_t **macp, - struct ethaddr *macaddr, vlanid_t vlan_id, + const struct ipaddr *ip, zebra_mac_t **macp, + const struct ethaddr *macaddr, vlanid_t vlan_id, bool def_gw) { zebra_mac_t *mac; diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index fb162f1a93..e90082e50b 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -229,11 +229,14 @@ int zebra_evpn_rem_mac_uninstall(zebra_evpn_t *zevi, zebra_mac_t *mac, int zebra_evpn_rem_mac_install(zebra_evpn_t *zevi, zebra_mac_t *mac, bool was_static); void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevi, zebra_mac_t *mac); -zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevi, struct ethaddr *mac); -zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevi, struct ethaddr *macaddr); +zebra_mac_t *zebra_evpn_mac_lookup(zebra_evpn_t *zevi, + const struct ethaddr *mac); +zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevi, + const struct ethaddr *macaddr); int zebra_evpn_mac_del(zebra_evpn_t *zevi, zebra_mac_t *mac); -int zebra_evpn_macip_send_msg_to_client(uint32_t id, struct ethaddr *macaddr, - struct ipaddr *ip, uint8_t flags, +int zebra_evpn_macip_send_msg_to_client(uint32_t id, + const struct ethaddr *macaddr, + const struct ipaddr *ip, uint8_t flags, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd); void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json); @@ -246,38 +249,39 @@ void zebra_evpn_mac_send_add_del_to_client(zebra_mac_t *mac, bool old_bgp_ready, void zebra_evpn_mac_del_all(zebra_evpn_t *zevi, int uninstall, int upd_client, uint32_t flags); -int zebra_evpn_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, +int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t mac_flags, uint32_t seq, struct zebra_evpn_es *es); -int zebra_evpn_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, +int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, uint32_t flags, bool force); void zebra_evpn_send_mac_list_to_client(zebra_evpn_t *zevi); -zebra_mac_t * -zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevi, struct ethaddr *macaddr, - uint16_t ipa_len, struct ipaddr *ipaddr, - uint8_t flags, uint32_t seq, esi_t *esi, - struct sync_mac_ip_ctx *ctx); +zebra_mac_t *zebra_evpn_proc_sync_mac_update( + zebra_evpn_t *zevi, const struct ethaddr *macaddr, uint16_t ipa_len, + const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, + const esi_t *esi, struct sync_mac_ip_ctx *ctx); void zebra_evpn_sync_mac_del(zebra_mac_t *mac); void zebra_evpn_rem_mac_del(zebra_evpn_t *zevi, zebra_mac_t *mac); void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt); void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt); -int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, - struct ethaddr *macaddr, uint16_t ipa_len, - struct ipaddr *ipaddr, zebra_mac_t **macp, - struct in_addr vtep_ip, uint8_t flags, - uint32_t seq, esi_t *esi); +int zebra_evpn_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, + const struct ethaddr *macaddr, + uint16_t ipa_len, + const struct ipaddr *ipaddr, + zebra_mac_t **macp, struct in_addr vtep_ip, + uint8_t flags, uint32_t seq, + const esi_t *esi); int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, struct interface *ifp, - struct ethaddr *macaddr, vlanid_t vid, + const struct ethaddr *macaddr, vlanid_t vid, bool sticky, bool local_inactive, bool dp_static, zebra_mac_t *mac); int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac, bool clear_static); int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, - struct ipaddr *ip, zebra_mac_t **macp, - struct ethaddr *macaddr, vlanid_t vlan_id, + const struct ipaddr *ip, zebra_mac_t **macp, + const struct ethaddr *macaddr, vlanid_t vlan_id, bool def_gw); void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn); void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn); diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index d6ae92a03d..05947faf4f 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -1747,7 +1747,7 @@ static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1, RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp); /* Lookup ES */ -struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi) +struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi) { struct zebra_evpn_es tmp; @@ -1758,7 +1758,7 @@ struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi) /* A new local es is created when a local-es-id and sysmac is configured * against an interface. */ -static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi) +static struct zebra_evpn_es *zebra_evpn_es_new(const esi_t *esi) { struct zebra_evpn_es *es; @@ -2392,7 +2392,7 @@ static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid, return zebra_evpn_local_es_update(zif, &esi); } -static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip) +int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip) { char buf[ESI_STR_LEN]; struct zebra_evpn_es *es; @@ -2432,9 +2432,8 @@ static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp) zebra_evpn_es_remote_info_re_eval(esp); } -static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip, - bool esr_rxed, uint8_t df_alg, - uint16_t df_pref) +int zebra_evpn_remote_es_add(const esi_t *esi, struct in_addr vtep_ip, + bool esr_rxed, uint8_t df_alg, uint16_t df_pref) { char buf[ESI_STR_LEN]; struct zebra_evpn_es *es; @@ -2498,10 +2497,10 @@ void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS) : false; STREAM_GETC(s, df_alg); STREAM_GETW(s, df_pref); - zebra_evpn_remote_es_add(&esi, vtep_ip, esr_rxed, df_alg, - df_pref); + zebra_rib_queue_evpn_rem_es_add(&esi, &vtep_ip, esr_rxed, + df_alg, df_pref); } else { - zebra_evpn_remote_es_del(&esi, vtep_ip); + zebra_rib_queue_evpn_rem_es_del(&esi, &vtep_ip); } stream_failure: @@ -2542,7 +2541,7 @@ bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es) return true; } -bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi) +bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, const esi_t *esi) { struct zebra_evpn_es *es; @@ -3901,12 +3900,12 @@ void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS) if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("evpn remote nh %d %pIA rmac %pEA add", vrf_id, &nh, &rmac); - zebra_vxlan_evpn_vrf_route_add(vrf_id, &rmac, &nh, + zebra_rib_queue_evpn_route_add(vrf_id, &rmac, &nh, (struct prefix *)&dummy_prefix); } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("evpn remote nh %d %pIA del", vrf_id, &nh); - zebra_vxlan_evpn_vrf_route_del(vrf_id, &nh, + zebra_rib_queue_evpn_route_del(vrf_id, &nh, (struct prefix *)&dummy_prefix); } } diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 8861e80cee..a828056f1f 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -330,14 +330,17 @@ extern void zebra_evpn_es_show_detail(struct vty *vty, bool uj); extern void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi); extern void zebra_evpn_update_all_es(zebra_evpn_t *zevpn); extern void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS); +int zebra_evpn_remote_es_add(const esi_t *esi, struct in_addr vtep_ip, + bool esr_rxed, uint8_t df_alg, uint16_t df_pref); +int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip); extern void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail); extern void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail); extern void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac); extern bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, - struct zebra_evpn_es *es); -extern bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi); -extern struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi); + struct zebra_evpn_es *es); +extern bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, const esi_t *esi); +extern struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi); extern void zebra_evpn_interface_init(void); extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp); extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj); diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 4c7a1542fc..839e8d9ebc 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -204,7 +204,7 @@ static void *zebra_evpn_neigh_alloc(void *p) } static void zebra_evpn_local_neigh_ref_mac(zebra_neigh_t *n, - struct ethaddr *macaddr, + const struct ethaddr *macaddr, zebra_mac_t *mac, bool send_mac_update) { @@ -284,8 +284,8 @@ static void zebra_evpn_sync_neigh_dp_install(zebra_neigh_t *n, /* * Inform BGP about local neighbor addition. */ -int zebra_evpn_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr, +int zebra_evpn_neigh_send_add_to_client(vni_t vni, const struct ipaddr *ip, + const struct ethaddr *macaddr, zebra_mac_t *zmac, uint32_t neigh_flags, uint32_t seq) { @@ -497,7 +497,7 @@ static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n, } bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n, - struct ethaddr *macaddr, uint32_t seq, + const struct ethaddr *macaddr, uint32_t seq, bool sync) { uint32_t tmp_seq; @@ -543,8 +543,8 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n, * Add neighbor entry. */ static zebra_neigh_t *zebra_evpn_neigh_add(zebra_evpn_t *zevpn, - struct ipaddr *ip, - struct ethaddr *mac, + const struct ipaddr *ip, + const struct ethaddr *mac, zebra_mac_t *zmac, uint32_t n_flags) { zebra_neigh_t tmp_n; @@ -615,8 +615,8 @@ void zebra_evpn_sync_neigh_del(zebra_neigh_t *n) zebra_neigh_t * zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, - uint16_t ipa_len, struct ipaddr *ipaddr, - uint8_t flags, uint32_t seq, esi_t *esi, + uint16_t ipa_len, const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx) { struct interface *ifp = NULL; @@ -895,7 +895,8 @@ void zebra_evpn_neigh_del_all(zebra_evpn_t *zevpn, int uninstall, /* * Look up neighbor hash entry. */ -zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, struct ipaddr *ip) +zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, + const struct ipaddr *ip) { zebra_neigh_t tmp; zebra_neigh_t *n; @@ -1254,9 +1255,9 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, } int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, - struct ipaddr *ip, struct ethaddr *macaddr, - bool is_router, bool local_inactive, - bool dp_static) + const struct ipaddr *ip, + const struct ethaddr *macaddr, bool is_router, + bool local_inactive, bool dp_static) { struct zebra_vrf *zvrf; zebra_neigh_t *n = NULL; @@ -1596,7 +1597,8 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, } int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, - struct ipaddr *ip, struct ethaddr *macaddr, + const struct ipaddr *ip, + const struct ethaddr *macaddr, uint16_t state) { zebra_neigh_t *n = NULL; @@ -2046,10 +2048,11 @@ void zebra_evpn_print_dad_neigh_hash_detail(struct hash_bucket *bucket, zebra_evpn_print_neigh_hash_detail(bucket, ctxt); } -void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, - struct ipaddr *ipaddr, zebra_mac_t *mac, - struct in_addr vtep_ip, uint8_t flags, - uint32_t seq) +void zebra_evpn_neigh_remote_macip_add(zebra_evpn_t *zevpn, + struct zebra_vrf *zvrf, + const struct ipaddr *ipaddr, + zebra_mac_t *mac, struct in_addr vtep_ip, + uint8_t flags, uint32_t seq) { zebra_neigh_t *n; int update_neigh = 0; @@ -2240,7 +2243,8 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, zebra_neigh_t *n, - zebra_mac_t *mac, struct ipaddr *ipaddr) + zebra_mac_t *mac, + const struct ipaddr *ipaddr) { if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) && CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) @@ -2273,7 +2277,7 @@ void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn, } } -int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) +int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, const struct ipaddr *ip) { zebra_neigh_t *n; zebra_mac_t *zmac; @@ -2298,7 +2302,7 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) } /* If it is a remote entry, the kernel has aged this out or someone has - * deleted it, it needs to be re-installed as Quagga is the owner. + * deleted it, it needs to be re-installed as FRR is the owner. */ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { zebra_evpn_rem_neigh_install(zevpn, n, false /*was_static*/); diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h index 05156c1255..3735a833fd 100644 --- a/zebra/zebra_evpn_neigh.h +++ b/zebra/zebra_evpn_neigh.h @@ -217,26 +217,27 @@ int remote_neigh_count(zebra_mac_t *zmac); int zebra_evpn_rem_neigh_install(zebra_evpn_t *zevpn, zebra_neigh_t *n, bool was_static); void zebra_evpn_install_neigh_hash(struct hash_bucket *bucket, void *ctxt); -int zebra_evpn_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr, +int zebra_evpn_neigh_send_add_to_client(vni_t vni, const struct ipaddr *ip, + const struct ethaddr *macaddr, zebra_mac_t *zmac, uint32_t neigh_flags, uint32_t seq); int zebra_evpn_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, struct ethaddr *macaddr, uint32_t flags, int state, bool force); bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n, - struct ethaddr *macaddr, uint32_t seq, + const struct ethaddr *macaddr, uint32_t seq, bool sync); int zebra_evpn_neigh_del(zebra_evpn_t *zevpn, zebra_neigh_t *n); void zebra_evpn_sync_neigh_del(zebra_neigh_t *n); zebra_neigh_t * zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, - uint16_t ipa_len, struct ipaddr *ipaddr, - uint8_t flags, uint32_t seq, esi_t *esi, + uint16_t ipa_len, const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx); void zebra_evpn_neigh_del_all(zebra_evpn_t *zevpn, int uninstall, int upd_client, uint32_t flags); -zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, struct ipaddr *ip); +zebra_neigh_t *zebra_evpn_neigh_lookup(zebra_evpn_t *zevpn, + const struct ipaddr *ip); int zebra_evpn_rem_neigh_install(zebra_evpn_t *zevpn, zebra_neigh_t *n, bool was_static); @@ -251,11 +252,12 @@ void zebra_evpn_process_neigh_on_local_mac_change(zebra_evpn_t *zevpn, void zebra_evpn_process_neigh_on_remote_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *zmac); int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, - struct ipaddr *ip, struct ethaddr *macaddr, - bool is_router, bool local_inactive, - bool dp_static); + const struct ipaddr *ip, + const struct ethaddr *macaddr, bool is_router, + bool local_inactive, bool dp_static); int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, - struct ipaddr *ip, struct ethaddr *macaddr, + const struct ipaddr *ip, + const struct ethaddr *macaddr, uint16_t state); void zebra_evpn_send_neigh_to_client(zebra_evpn_t *zevpn); void zebra_evpn_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt); @@ -266,16 +268,18 @@ void zebra_evpn_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt); void zebra_evpn_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt); void zebra_evpn_print_dad_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt); -void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, - struct ipaddr *ipaddr, zebra_mac_t *mac, - struct in_addr vtep_ip, uint8_t flags, - uint32_t seq); +void zebra_evpn_neigh_remote_macip_add(zebra_evpn_t *zevpn, + struct zebra_vrf *zvrf, + const struct ipaddr *ipaddr, + zebra_mac_t *mac, struct in_addr vtep_ip, + uint8_t flags, uint32_t seq); int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip, zebra_mac_t *mac); void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, zebra_neigh_t *n, - zebra_mac_t *mac, struct ipaddr *ipaddr); -int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip); + zebra_mac_t *mac, + const struct ipaddr *ipaddr); +int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, const struct ipaddr *ip); #ifdef __cplusplus diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index af86263a16..46d5164127 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -453,8 +453,13 @@ static void *zebra_nhg_hash_alloc(void *arg) /* Mark duplicate nexthops in a group at creation time. */ nexthop_group_mark_duplicates(&(nhe->nhg)); - /* Add the ifp now if it's not a group or recursive and has ifindex */ - if (nhe->nhg.nexthop && nhe->nhg.nexthop->ifindex) { + /* + * Add the ifp now if it's not a group or recursive and has ifindex. + * + * A proto-owned ID is always a group. + */ + if (!PROTO_OWNED(nhe) && nhe->nhg.nexthop && !nhe->nhg.nexthop->next + && !nhe->nhg.nexthop->resolved && nhe->nhg.nexthop->ifindex) { struct interface *ifp = NULL; ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 12cc0b4e8a..c51dd759a6 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -56,13 +56,14 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_dplane.h" +#include "zebra/zebra_evpn_mh.h" DEFINE_MGROUP(ZEBRA, "zebra"); DEFINE_MTYPE(ZEBRA, RE, "Route Entry"); DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination"); DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object"); -DEFINE_MTYPE_STATIC(ZEBRA, WQ_NHG_WRAPPER, "WQ nhg wrapper"); +DEFINE_MTYPE_STATIC(ZEBRA, WQ_WRAPPER, "WQ wrapper"); /* * Event, list, and mutex for delivery of dataplane results @@ -74,7 +75,7 @@ static struct dplane_ctx_q rib_dplane_q; DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason), (rn, reason)); -/* Should we allow non Quagga processes to delete our routes */ +/* Should we allow non FRR processes to delete our routes */ extern int allow_delete; /* Each route type's string and default distance value. */ @@ -83,41 +84,44 @@ static const struct { uint8_t distance; uint8_t meta_q_map; } route_info[ZEBRA_ROUTE_MAX] = { - [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Uneeded for nhg's */, 0}, - [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 6}, - [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 2}, - [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 1}, - [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 3}, - [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 4}, - [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 4}, - [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 4}, - [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 4}, - [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 4}, - [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 5}, - [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 6}, - [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 4}, - [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 4}, - [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 6}, - [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 6}, - [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 3}, - [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 6}, - [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 5}, - [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 5}, - [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 5}, - [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 5}, - [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 5}, - [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 4}, - [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 6}, - [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 6}, - [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 6}, - [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 4}, - [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 6}, - [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 6}, + [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */, 0}, + [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, 7}, + [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, 3}, + [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, 2}, + [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, 4}, + [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, 5}, + [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, 5}, + [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, 5}, + [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, 5}, + [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, 5}, + [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */, 6}, + [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, 7}, + [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, 5}, + [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, 5}, + [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, 7}, + [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, 7}, + [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, 4}, + [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, 7}, + [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, 6}, + [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, 6}, + [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20, 6}, + [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, 6}, + [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20, 6}, + [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, 5}, + [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, 7}, + [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 7}, + [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 7}, + [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 5}, + [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 7}, + [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 7}, /* Any new route type added to zebra, should be mirrored here */ /* no entry/default: 150 */ }; +/* EVPN/VXLAN subqueue is number 1 */ +#define META_QUEUE_EVPN 1 + /* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update * from the OS, and an 'nhe' is a nhe update. */ @@ -132,6 +136,29 @@ struct wq_nhg_wrapper { #define WQ_NHG_WRAPPER_TYPE_CTX 0x01 #define WQ_NHG_WRAPPER_TYPE_NHG 0x02 +/* Wrapper structs for evpn/vxlan workqueue items. */ +struct wq_evpn_wrapper { + int type; + bool add_p; + vrf_id_t vrf_id; + bool esr_rxed; + uint8_t df_alg; + uint16_t df_pref; + uint32_t flags; + uint32_t seq; + esi_t esi; + vni_t vni; + struct ipaddr ip; + struct ethaddr macaddr; + struct prefix prefix; + struct in_addr vtep_ip; +}; + +#define WQ_EVPN_WRAPPER_TYPE_VRFROUTE 0x01 +#define WQ_EVPN_WRAPPER_TYPE_REM_ES 0x02 +#define WQ_EVPN_WRAPPER_TYPE_REM_MACIP 0x03 +#define WQ_EVPN_WRAPPER_TYPE_REM_VTEP 0x04 + /* %pRN is already a printer for route_nodes that just prints the prefix */ #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pZN" (struct route_node *) @@ -2316,6 +2343,62 @@ done: } /* + * Process a node from the EVPN/VXLAN subqueue. + */ +static void process_subq_evpn(struct listnode *lnode) +{ + struct wq_evpn_wrapper *w; + + /* In general, the list node points to a wrapper object + * holding the info necessary to make some update. + */ + w = listgetdata(lnode); + if (!w) + return; + + if (w->type == WQ_EVPN_WRAPPER_TYPE_VRFROUTE) { + if (w->add_p) + zebra_vxlan_evpn_vrf_route_add(w->vrf_id, &w->macaddr, + &w->ip, &w->prefix); + else + zebra_vxlan_evpn_vrf_route_del(w->vrf_id, &w->ip, + &w->prefix); + } else if (w->type == WQ_EVPN_WRAPPER_TYPE_REM_ES) { + if (w->add_p) + zebra_evpn_remote_es_add(&w->esi, w->ip.ipaddr_v4, + w->esr_rxed, w->df_alg, + w->df_pref); + else + zebra_evpn_remote_es_del(&w->esi, w->ip.ipaddr_v4); + } else if (w->type == WQ_EVPN_WRAPPER_TYPE_REM_MACIP) { + uint16_t ipa_len = 0; + + if (w->ip.ipa_type == IPADDR_V4) + ipa_len = IPV4_MAX_BYTELEN; + else if (w->ip.ipa_type == IPADDR_V6) + ipa_len = IPV6_MAX_BYTELEN; + + if (w->add_p) + zebra_evpn_rem_macip_add(w->vni, &w->macaddr, ipa_len, + &w->ip, w->flags, w->seq, + w->vtep_ip, &w->esi); + else + zebra_evpn_rem_macip_del(w->vni, &w->macaddr, ipa_len, + &w->ip, w->vtep_ip); + } else if (w->type == WQ_EVPN_WRAPPER_TYPE_REM_VTEP) { + if (w->add_p) + zebra_vxlan_remote_vtep_add(w->vrf_id, w->vni, + w->vtep_ip, w->flags); + else + zebra_vxlan_remote_vtep_del(w->vrf_id, w->vni, + w->vtep_ip); + } + + + XFREE(MTYPE_WQ_WRAPPER, w); +} + +/* * Process the nexthop-group workqueue subqueue */ static void process_subq_nhg(struct listnode *lnode) @@ -2355,8 +2438,7 @@ static void process_subq_nhg(struct listnode *lnode) /* Process incoming nhg update, probably from a proto daemon */ newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, nhe->zapi_instance, - nhe->zapi_session, - &nhe->nhg, 0); + nhe->zapi_session, &nhe->nhg, 0); /* Report error to daemon via ZAPI */ if (newnhe == NULL) @@ -2368,7 +2450,7 @@ static void process_subq_nhg(struct listnode *lnode) zebra_nhg_free(nhe); } - XFREE(MTYPE_WQ_NHG_WRAPPER, w); + XFREE(MTYPE_WQ_WRAPPER, w); } static void process_subq_route(struct listnode *lnode, uint8_t qindex) @@ -2411,9 +2493,9 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) route_unlock_node(rnode); } -/* Take a list of route_node structs and return 1, if there was a record - * picked from it and processed by rib_process(). Don't process more, - * than one RN record; operate only in the specified sub-queue. +/* + * Examine the specified subqueue; process one entry and return 1 if + * there is a node, return 0 otherwise. */ static unsigned int process_subq(struct list *subq, uint8_t qindex) { @@ -2422,7 +2504,9 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) if (!lnode) return 0; - if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map) + if (qindex == META_QUEUE_EVPN) + process_subq_evpn(lnode); + else if (qindex == route_info[ZEBRA_ROUTE_NHG].meta_q_map) process_subq_nhg(lnode); else process_subq_route(lnode, qindex); @@ -2432,7 +2516,7 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) return 1; } -/* Dispatch the meta queue by picking, processing and unlocking the next RN from +/* Dispatch the meta queue by picking and processing the next node from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and * data is pointed to the meta queue structure. */ @@ -2538,7 +2622,7 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) if (!ctx) return -1; - w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper)); + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_nhg_wrapper)); w->type = WQ_NHG_WRAPPER_TYPE_CTX; w->u.ctx = ctx; @@ -2564,7 +2648,7 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) if (!nhe) return -1; - w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper)); + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_nhg_wrapper)); w->type = WQ_NHG_WRAPPER_TYPE_NHG; w->u.nhe = nhe; @@ -2579,6 +2663,14 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) return 0; } +static int rib_meta_queue_evpn_add(struct meta_queue *mq, void *data) +{ + listnode_add(mq->subq[META_QUEUE_EVPN], data); + mq->size++; + + return 0; +} + static int mq_add_handler(void *data, int (*mq_add_func)(struct meta_queue *mq, void *data)) { @@ -2640,6 +2732,225 @@ int rib_queue_nhe_add(struct nhg_hash_entry *nhe) return mq_add_handler(nhe, rib_meta_queue_nhg_add); } +/* + * Enqueue evpn route for processing + */ +int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix) +{ + struct wq_evpn_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_VRFROUTE; + w->add_p = true; + w->vrf_id = vrf_id; + w->macaddr = *rmac; + w->ip = *vtep_ip; + w->prefix = *host_prefix; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: (%u)%pIA, host prefix %pFX enqueued", __func__, + vrf_id, vtep_ip, host_prefix); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +int zebra_rib_queue_evpn_route_del(vrf_id_t vrf_id, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix) +{ + struct wq_evpn_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_VRFROUTE; + w->add_p = false; + w->vrf_id = vrf_id; + w->ip = *vtep_ip; + w->prefix = *host_prefix; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: (%u)%pIA, host prefix %pFX enqueued", __func__, + vrf_id, vtep_ip, host_prefix); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +/* Enqueue EVPN remote ES for processing */ +int zebra_rib_queue_evpn_rem_es_add(const esi_t *esi, + const struct in_addr *vtep_ip, + bool esr_rxed, uint8_t df_alg, + uint16_t df_pref) +{ + struct wq_evpn_wrapper *w; + char buf[ESI_STR_LEN]; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_ES; + w->add_p = true; + w->esi = *esi; + w->ip.ipa_type = IPADDR_V4; + w->ip.ipaddr_v4 = *vtep_ip; + w->esr_rxed = esr_rxed; + w->df_alg = df_alg; + w->df_pref = df_pref; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: vtep %pI4, esi %s enqueued", __func__, vtep_ip, + esi_to_str(esi, buf, sizeof(buf))); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +int zebra_rib_queue_evpn_rem_es_del(const esi_t *esi, + const struct in_addr *vtep_ip) +{ + struct wq_evpn_wrapper *w; + char buf[ESI_STR_LEN]; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_ES; + w->add_p = false; + w->esi = *esi; + w->ip.ipa_type = IPADDR_V4; + w->ip.ipaddr_v4 = *vtep_ip; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + if (memcmp(esi, zero_esi, sizeof(esi_t)) != 0) + esi_to_str(esi, buf, sizeof(buf)); + else + strlcpy(buf, "-", sizeof(buf)); + + zlog_debug("%s: vtep %pI4, esi %s enqueued", __func__, vtep_ip, + buf); + } + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +/* + * Enqueue EVPN remote macip update for processing + */ +int zebra_rib_queue_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, + const struct ipaddr *ipaddr, + uint8_t flags, uint32_t seq, + struct in_addr vtep_ip, const esi_t *esi) +{ + struct wq_evpn_wrapper *w; + char buf[ESI_STR_LEN]; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_MACIP; + w->add_p = true; + w->vni = vni; + w->macaddr = *macaddr; + w->ip = *ipaddr; + w->flags = flags; + w->seq = seq; + w->vtep_ip = vtep_ip; + w->esi = *esi; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + if (memcmp(esi, zero_esi, sizeof(esi_t)) != 0) + esi_to_str(esi, buf, sizeof(buf)); + else + strlcpy(buf, "-", sizeof(buf)); + + zlog_debug("%s: mac %pEA, vtep %pI4, esi %s enqueued", __func__, + macaddr, &vtep_ip, buf); + } + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +int zebra_rib_queue_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, + const struct ipaddr *ip, + struct in_addr vtep_ip) +{ + struct wq_evpn_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_MACIP; + w->add_p = false; + w->vni = vni; + w->macaddr = *macaddr; + w->ip = *ip; + w->vtep_ip = vtep_ip; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: mac %pEA, vtep %pI4 enqueued", __func__, + macaddr, &vtep_ip); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +/* + * Enqueue remote VTEP address for processing + */ +int zebra_rib_queue_evpn_rem_vtep_add(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip, int flood_control) +{ + struct wq_evpn_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_VTEP; + w->add_p = true; + w->vrf_id = vrf_id; + w->vni = vni; + w->vtep_ip = vtep_ip; + w->flags = flood_control; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: vrf %u, vtep %pI4 enqueued", __func__, vrf_id, + &vtep_ip); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +int zebra_rib_queue_evpn_rem_vtep_del(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip) +{ + struct wq_evpn_wrapper *w; + + w = XCALLOC(MTYPE_WQ_WRAPPER, sizeof(struct wq_evpn_wrapper)); + + w->type = WQ_EVPN_WRAPPER_TYPE_REM_VTEP; + w->add_p = false; + w->vrf_id = vrf_id; + w->vni = vni; + w->vtep_ip = vtep_ip; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: vrf %u, vtep %pI4 enqueued", __func__, vrf_id, + &vtep_ip); + + return mq_add_handler(w, rib_meta_queue_evpn_add); +} + +/* Clean up the EVPN meta-queue list */ +static void evpn_meta_queue_free(struct list *l) +{ + struct listnode *node; + struct wq_evpn_wrapper *w; + + /* Free the node wrapper object, and the struct it wraps */ + while ((node = listhead(l)) != NULL) { + w = node->data; + node->data = NULL; + + XFREE(MTYPE_WQ_WRAPPER, w); + + list_delete_node(l, node); + } +} + /* Clean up the nhg meta-queue list */ static void nhg_meta_queue_free(struct list *l) { @@ -2656,7 +2967,7 @@ static void nhg_meta_queue_free(struct list *l) else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG) zebra_nhg_free(w->u.nhe); - XFREE(MTYPE_WQ_NHG_WRAPPER, w); + XFREE(MTYPE_WQ_WRAPPER, w); list_delete_node(l, node); } @@ -2688,6 +2999,8 @@ void meta_queue_free(struct meta_queue *mq) /* Some subqueues may need cleanup - nhgs for example */ if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map) nhg_meta_queue_free(mq->subq[i]); + else if (i == META_QUEUE_EVPN) + evpn_meta_queue_free(mq->subq[i]); list_delete(&mq->subq[i]); } @@ -2763,7 +3076,7 @@ rib_dest_t *zebra_rib_create_dest(struct route_node *rn) * dest is created on-demand by rib_link() and is kept around at least * as long as there are ribs hanging off it (@see rib_gc_dest()). * - * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): + * Refcounting (aka "locking" throughout the Zebra and FRR code): * * - route_nodes: refcounted by: * - dest attached to route_node: @@ -3518,7 +3831,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, &(tmp_nh->gate.ipv6), sizeof(struct in6_addr)); } - zebra_vxlan_evpn_vrf_route_del(re->vrf_id, + zebra_rib_queue_evpn_route_del(re->vrf_id, &vtep_ip, p); } } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 41d55c2e6c..017a4aae7f 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -598,8 +598,7 @@ static const int RNH_INVALID_NH_FLAGS = (NEXTHOP_FLAG_RECURSIVE | NEXTHOP_FLAG_DUPLICATE | NEXTHOP_FLAG_RNH_FILTERED); -static bool rnh_nexthop_valid(const struct route_entry *re, - const struct nexthop *nh) +bool rnh_nexthop_valid(const struct route_entry *re, const struct nexthop *nh) { return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE) diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 4897a6af30..24ee6d0bd9 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -64,6 +64,9 @@ extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family); +extern bool rnh_nexthop_valid(const struct route_entry *re, + const struct nexthop *nh); + /* UI control to avoid notifications if backup nexthop status changes */ void rnh_set_hide_backups(bool hide_p); bool rnh_get_hide_backups(void); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 2f3ea7475a..2b46929acb 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3820,10 +3820,6 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) uint16_t l = 0, ipa_len; char buf1[INET6_ADDRSTRLEN]; - memset(&macaddr, 0, sizeof(struct ethaddr)); - memset(&ip, 0, sizeof(struct ipaddr)); - memset(&vtep_ip, 0, sizeof(struct in_addr)); - s = msg; while (l < hdr->length) { @@ -3844,7 +3840,8 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) ipaddr2str(&ip, buf1, sizeof(buf1)) : "", &vtep_ip, zebra_route_string(client->proto)); - process_remote_macip_del(vni, &macaddr, ipa_len, &ip, vtep_ip); + /* Enqueue to workqueue for processing */ + zebra_rib_queue_evpn_rem_macip_del(vni, &macaddr, &ip, vtep_ip); } stream_failure: @@ -3870,10 +3867,6 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) esi_t esi; char esi_buf[ESI_STR_LEN]; - memset(&macaddr, 0, sizeof(struct ethaddr)); - memset(&ip, 0, sizeof(struct ipaddr)); - memset(&vtep_ip, 0, sizeof(struct in_addr)); - if (!EVPN_ENABLED(zvrf)) { zlog_debug("EVPN not enabled, ignoring remote MACIP ADD"); return; @@ -3882,6 +3875,7 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) s = msg; while (l < hdr->length) { + int res_length = zebra_vxlan_remote_macip_helper( true, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, &flags, &seq, &esi); @@ -3907,8 +3901,9 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) zebra_route_string(client->proto)); } - process_remote_macip_add(vni, &macaddr, ipa_len, &ip, - flags, seq, vtep_ip, &esi); + /* Enqueue to workqueue for processing */ + zebra_rib_queue_evpn_rem_macip_add(vni, &macaddr, &ip, flags, + seq, vtep_ip, &esi); } stream_failure: @@ -4204,27 +4199,23 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, /* * Handle message from client to delete a remote VTEP for an EVPN. */ -void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS) +void zebra_vxlan_remote_vtep_del_zapi(ZAPI_HANDLER_ARGS) { struct stream *s; unsigned short l = 0; vni_t vni; struct in_addr vtep_ip; - zebra_evpn_t *zevpn; - zebra_vtep_t *zvtep; - struct interface *ifp; - struct zebra_if *zif; if (!is_evpn_enabled()) { zlog_debug( - "%s: EVPN is not enabled yet we have received a vtep del command", + "%s: EVPN is not enabled yet we have received a VTEP DEL msg", __func__); return; } if (!EVPN_ENABLED(zvrf)) { - zlog_debug("Recv MACIP DEL for non-EVPN VRF %u", - zvrf_id(zvrf)); + zlog_debug("Recv VTEP DEL zapi for non-EVPN VRF %u", + zvrf_id(zvrf)); return; } @@ -4244,76 +4235,182 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS) l += 4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Recv VTEP_DEL %pI4 VNI %u from %s", + zlog_debug("Recv VTEP DEL %pI4 VNI %u from %s", &vtep_ip, vni, zebra_route_string(client->proto)); - /* Locate VNI hash entry - expected to exist. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Failed to locate VNI hash upon remote VTEP DEL, VNI %u", - vni); - continue; - } + /* Enqueue for processing */ + zebra_rib_queue_evpn_rem_vtep_del(zvrf_id(zvrf), vni, vtep_ip); + } - ifp = zevpn->vxlan_if; - if (!ifp) { +stream_failure: + return; +} + +/* + * Handle message from client to delete a remote VTEP for an EVPN. + */ +void zebra_vxlan_remote_vtep_del(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip) +{ + zebra_evpn_t *zevpn; + zebra_vtep_t *zvtep; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_vrf *zvrf; + + if (!is_evpn_enabled()) { + zlog_debug("%s: Can't process vtep del: EVPN is not enabled", + __func__); + return; + } + + zvrf = zebra_vrf_lookup_by_id(vrf_id); + if (!zvrf) + return; + + if (!EVPN_ENABLED(zvrf)) { + zlog_debug("Can't process VTEP DEL for non-EVPN VRF %u", + zvrf_id(zvrf)); + return; + } + + /* Locate VNI hash entry - expected to exist. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "VNI %u hash %p doesn't have intf upon remote VTEP DEL", - zevpn->vni, zevpn); - continue; - } - zif = ifp->info; + "Failed to locate VNI hash for remote VTEP DEL, VNI %u", + vni); + return; + } - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - continue; + ifp = zevpn->vxlan_if; + if (!ifp) { + zlog_debug( + "VNI %u hash %p doesn't have intf upon remote VTEP DEL", + zevpn->vni, zevpn); + return; + } + zif = ifp->info; - /* If the remote VTEP does not exist, there's nothing more to - * do. - * Otherwise, uninstall any remote MACs pointing to this VTEP - * and - * then, the VTEP entry itself and remove it. - */ - zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); - if (!zvtep) - continue; + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + /* If the remote VTEP does not exist, there's nothing more to + * do. + * Otherwise, uninstall any remote MACs pointing to this VTEP + * and then, the VTEP entry itself and remove it. + */ + zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); + if (!zvtep) + return; - zebra_evpn_vtep_uninstall(zevpn, &vtep_ip); - zebra_evpn_vtep_del(zevpn, zvtep); + zebra_evpn_vtep_uninstall(zevpn, &vtep_ip); + zebra_evpn_vtep_del(zevpn, zvtep); +} + +/* + * Handle message from client to add a remote VTEP for an EVPN. + */ +void zebra_vxlan_remote_vtep_add(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip, int flood_control) +{ + zebra_evpn_t *zevpn; + struct interface *ifp; + struct zebra_if *zif; + zebra_vtep_t *zvtep; + struct zebra_vrf *zvrf; + + if (!is_evpn_enabled()) { + zlog_debug("%s: EVPN not enabled: can't process a VTEP ADD", + __func__); + return; } -stream_failure: - return; + zvrf = zebra_vrf_lookup_by_id(vrf_id); + if (!zvrf) + return; + + if (!EVPN_ENABLED(zvrf)) { + zlog_debug("Can't process VTEP ADD for non-EVPN VRF %u", + zvrf_id(zvrf)); + return; + } + + /* Locate VNI hash entry - expected to exist. */ + zevpn = zebra_evpn_lookup(vni); + if (!zevpn) { + flog_err( + EC_ZEBRA_VTEP_ADD_FAILED, + "Failed to locate EVPN hash upon remote VTEP ADD, VNI %u", + vni); + return; + } + + ifp = zevpn->vxlan_if; + if (!ifp) { + flog_err( + EC_ZEBRA_VTEP_ADD_FAILED, + "VNI %u hash %p doesn't have intf upon remote VTEP ADD", + zevpn->vni, zevpn); + return; + } + + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); + if (zvtep) { + /* If the remote VTEP already exists check if + * the flood mode has changed + */ + if (zvtep->flood_control != flood_control) { + if (zvtep->flood_control == VXLAN_FLOOD_DISABLED) + /* old mode was head-end-replication but + * is no longer; get rid of the HER fdb + * entry installed before + */ + zebra_evpn_vtep_uninstall(zevpn, &vtep_ip); + zvtep->flood_control = flood_control; + zebra_evpn_vtep_install(zevpn, zvtep); + } + } else { + zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, flood_control); + if (zvtep) + zebra_evpn_vtep_install(zevpn, zvtep); + else + flog_err(EC_ZEBRA_VTEP_ADD_FAILED, + "Failed to add remote VTEP, VNI %u zevpn %p", + vni, zevpn); + } } /* * Handle message from client to add a remote VTEP for an EVPN. */ -void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) +void zebra_vxlan_remote_vtep_add_zapi(ZAPI_HANDLER_ARGS) { struct stream *s; unsigned short l = 0; vni_t vni; struct in_addr vtep_ip; - zebra_evpn_t *zevpn; - struct interface *ifp; - struct zebra_if *zif; int flood_control; - zebra_vtep_t *zvtep; if (!is_evpn_enabled()) { zlog_debug( - "%s: EVPN not enabled yet we received a vtep_add zapi call", + "%s: EVPN not enabled yet we received a VTEP ADD zapi msg", __func__); return; } if (!EVPN_ENABLED(zvrf)) { - zlog_debug("Recv MACIP ADD for non-EVPN VRF %u", - zvrf_id(zvrf)); + zlog_debug("Recv VTEP ADD zapi for non-EVPN VRF %u", + zvrf_id(zvrf)); return; } @@ -4328,62 +4425,13 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) l += IPV4_MAX_BYTELEN + 4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Recv VTEP_ADD %pI4 VNI %u flood %d from %s", - &vtep_ip, vni, flood_control, - zebra_route_string(client->proto)); - - /* Locate VNI hash entry - expected to exist. */ - zevpn = zebra_evpn_lookup(vni); - if (!zevpn) { - flog_err( - EC_ZEBRA_VTEP_ADD_FAILED, - "Failed to locate EVPN hash upon remote VTEP ADD, VNI %u", - vni); - continue; - } - - ifp = zevpn->vxlan_if; - if (!ifp) { - flog_err( - EC_ZEBRA_VTEP_ADD_FAILED, - "VNI %u hash %p doesn't have intf upon remote VTEP ADD", - zevpn->vni, zevpn); - continue; - } - - zif = ifp->info; - - /* If down or not mapped to a bridge, we're done. */ - if (!if_is_operative(ifp) || !zif->brslave_info.br_if) - continue; + zlog_debug("Recv VTEP ADD %pI4 VNI %u flood %d from %s", + &vtep_ip, vni, flood_control, + zebra_route_string(client->proto)); - zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); - if (zvtep) { - /* If the remote VTEP already exists check if - * the flood mode has changed - */ - if (zvtep->flood_control != flood_control) { - if (zvtep->flood_control - == VXLAN_FLOOD_DISABLED) - /* old mode was head-end-replication but - * is no longer; get rid of the HER fdb - * entry installed before - */ - zebra_evpn_vtep_uninstall(zevpn, - &vtep_ip); - zvtep->flood_control = flood_control; - zebra_evpn_vtep_install(zevpn, zvtep); - } - } else { - zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, - flood_control); - if (zvtep) - zebra_evpn_vtep_install(zevpn, zvtep); - else - flog_err(EC_ZEBRA_VTEP_ADD_FAILED, - "Failed to add remote VTEP, VNI %u zevpn %p", - vni, zevpn); - } + /* Enqueue for processing */ + zebra_rib_queue_evpn_rem_vtep_add(zvrf_id(zvrf), vni, vtep_ip, + flood_control); } stream_failure: @@ -4398,7 +4446,7 @@ stream_failure: * 3. vrr interface (MACVLAN) associated to a SVI * We advertise macip routes for an interface if it is associated to VxLan vlan */ -int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, +int zebra_vxlan_add_del_gw_macip(struct interface *ifp, const struct prefix *p, int add) { struct ipaddr ip; diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 24de8ff04e..915e987b6b 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -72,8 +72,12 @@ is_vxlan_flooding_head_end(void) /* ZAPI message handlers */ extern void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS); -extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS); -extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_remote_vtep_add_zapi(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_remote_vtep_del_zapi(ZAPI_HANDLER_ARGS); +void zebra_vxlan_remote_vtep_add(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip, int flood_control); +extern void zebra_vxlan_remote_vtep_del(vrf_id_t vrf_id, vni_t vni, + struct in_addr vtep_ip); extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS); @@ -157,8 +161,8 @@ extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json); extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json); extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, json_object *json_vrfs); -extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, - int add); +extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, + const struct prefix *p, int add); extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if); |
