diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c91a2ab6bd..cff050a9ef 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1692,6 +1692,58 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, return route_change; } +/* + * If the local route was not selected evict it and tell zebra to re-add + * the best remote dest. + * + * Typically a local path added by zebra is expected to be selected as + * best. In which case when a remote path wins as best (later) + * evpn_route_select_install itself evicts the older-local-best path. + * + * However if bgp's add and zebra's add cross paths (race condition) it + * is possible that the local path is no longer the "older" best path. + * It is a path that was never designated as best and hence requires + * additional handling to prevent bgp from injecting and holding on to a + * non-best local path. + */ +static void evpn_cleanup_local_non_best_route(struct bgp *bgp, + struct bgpevpn *vpn, + struct bgp_node *rn, + struct bgp_path_info *local_pi) +{ + struct bgp_path_info *tmp_pi; + struct bgp_path_info *curr_select = NULL; + uint8_t flags = 0; + char buf[PREFIX_STRLEN]; + + /* local path was not picked as the winner; kick it out */ + if (bgp_debug_zebra(NULL)) { + zlog_debug("evicting local evpn prefix %s as remote won", + prefix2str(&rn->p, buf, sizeof(buf))); + } + evpn_delete_old_local_route(bgp, vpn, rn, local_pi); + bgp_path_info_reap(rn, local_pi); + + /* tell zebra to re-add the best remote path */ + for (tmp_pi = rn->info; tmp_pi; tmp_pi = tmp_pi->next) { + if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) { + curr_select = tmp_pi; + break; + } + } + if (curr_select && + curr_select->type == ZEBRA_ROUTE_BGP + && curr_select->sub_type == BGP_ROUTE_IMPORTED) { + if (curr_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (curr_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, + curr_select->attr->nexthop, flags, + mac_mobility_seqnum(curr_select->attr)); + } +} + /* * Create or update EVPN route (of type based on prefix) for specified VNI * and schedule for processing. @@ -1754,10 +1806,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, assert(pi); attr_new = pi->attr; + /* lock ri to prevent freeing in evpn_route_select_install */ + bgp_path_info_lock(pi); /* Perform route selection; this is just to set the flags correctly * as local route in the VNI always wins. */ evpn_route_select_install(bgp, vpn, rn); + /* + * If the new local route was not selected evict it and tell zebra + * to re-add the best remote dest. BGP doesn't retain non-best local + * routes. + */ + if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { + route_change = 0; + evpn_cleanup_local_non_best_route(bgp, vpn, rn, pi); + } + bgp_path_info_unlock(pi); + bgp_unlock_node(rn); /* If this is a new route or some attribute has changed, export the @@ -1928,8 +1993,10 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* Delete route entry in the VNI route table. This can just be removed. */ delete_evpn_route_entry(bgp, afi, safi, rn, &pi); - if (pi) + if (pi) { bgp_path_info_reap(rn, pi); + evpn_route_select_install(bgp, vpn, rn); + } bgp_unlock_node(rn); return 0; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 29f9f64cca..aa5eabeade 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3195,7 +3195,7 @@ DEFUN (no_bgp_evpn_advertise_type5, */ DEFUN(show_bgp_l2vpn_evpn_vni, show_bgp_l2vpn_evpn_vni_cmd, - "show bgp l2vpn evpn vni [(1-16777215)] [json]", + "show bgp l2vpn evpn vni [" CMD_VNI_RANGE "] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3623,7 +3623,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi, * Display per-VNI EVPN routing table. */ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, - "show bgp l2vpn evpn route vni (1-16777215) [ | vtep A.B.C.D>] [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " [ | vtep A.B.C.D>] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3696,7 +3696,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, */ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, show_bgp_l2vpn_evpn_route_vni_macip_cmd, - "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " mac WORD [ip WORD] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3766,7 +3766,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, */ DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast, show_bgp_l2vpn_evpn_route_vni_multicast_cmd, - "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " multicast A.B.C.D [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -4019,7 +4019,7 @@ DEFUN(test_withdraw_evpn_type4_route, } ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd, - "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR + "show bgp evpn vni [" CMD_VNI_RANGE "]", SHOW_STR BGP_STR EVPN_HELP_STR "Show VNI\n" "VNI number\n") @@ -4060,7 +4060,7 @@ ALIAS_HIDDEN( ALIAS_HIDDEN( show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd, - "show bgp evpn route vni (1-16777215) [ | vtep A.B.C.D>]", + "show bgp evpn route vni " CMD_VNI_RANGE " [ | vtep A.B.C.D>]", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4073,7 +4073,7 @@ ALIAS_HIDDEN( ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, show_bgp_evpn_route_vni_macip_cmd, - "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", + "show bgp evpn route vni " CMD_VNI_RANGE " mac WORD [ip WORD]", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4085,7 +4085,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast, show_bgp_evpn_route_vni_multicast_cmd, - "show bgp evpn route vni (1-16777215) multicast A.B.C.D", + "show bgp evpn route vni " CMD_VNI_RANGE " multicast A.B.C.D", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4108,7 +4108,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd, DEFUN_NOSH (bgp_evpn_vni, bgp_evpn_vni_cmd, - "vni (1-16777215)", + "vni " CMD_VNI_RANGE, "VXLAN Network Identifier\n" "VNI number\n") { @@ -4134,7 +4134,7 @@ DEFUN_NOSH (bgp_evpn_vni, DEFUN (no_bgp_evpn_vni, no_bgp_evpn_vni_cmd, - "no vni (1-16777215)", + "no vni " CMD_VNI_RANGE, NO_STR "VXLAN Network Identifier\n" "VNI number\n") diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4542d0ec27..8ae74a008c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -453,6 +453,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, char exist_buf[PATH_ADDPATH_STR_BUFFER]; uint32_t new_mm_seq; uint32_t exist_mm_seq; + int nh_cmp; *paths_eq = 0; @@ -545,6 +546,28 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_mm_seq); return 0; } + + /* + * if sequence numbers are the same path with the lowest IP + * wins + */ + nh_cmp = bgp_path_info_nexthop_cmp(new, exist); + if (nh_cmp < 0) { + if (debug) + zlog_debug( + "%s: %s wins over %s due to same MM seq %u and lower IP %s", + pfx_buf, new_buf, exist_buf, new_mm_seq, + inet_ntoa(new->attr->nexthop)); + return 1; + } + if (nh_cmp > 0) { + if (debug) + zlog_debug( + "%s: %s loses to %s due to same MM seq %u and higher IP %s", + pfx_buf, new_buf, exist_buf, new_mm_seq, + inet_ntoa(new->attr->nexthop)); + return 0; + } } /* 1. Weight check. */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 60a4e994c9..f7c4175383 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3438,7 +3438,7 @@ DEFUN (no_match_evpn_route_type, DEFUN (match_evpn_vni, match_evpn_vni_cmd, - "match evpn vni (1-16777215)", + "match evpn vni " CMD_VNI_RANGE, MATCH_STR EVPN_HELP_STR "Match VNI\n" @@ -3450,7 +3450,7 @@ DEFUN (match_evpn_vni, DEFUN (no_match_evpn_vni, no_match_evpn_vni_cmd, - "no match evpn vni (1-16777215)", + "no match evpn vni " CMD_VNI_RANGE, NO_STR MATCH_STR EVPN_HELP_STR diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 948cc8518c..c57cd38151 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -822,6 +822,87 @@ DEFUN_HIDDEN (no_bgp_multiple_instance, return CMD_SUCCESS; } +DEFUN_HIDDEN (bgp_local_mac, + bgp_local_mac_cmd, + "bgp local-mac vni " CMD_VNI_RANGE " mac WORD seq (0-4294967295)", + BGP_STR + "Local MAC config\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "local mac\n" + "mac address\n" + "mac-mobility sequence\n" + "seq number\n") +{ + int rv; + vni_t vni; + struct ethaddr mac; + struct ipaddr ip; + uint32_t seq; + struct bgp *bgp; + + vni = strtoul(argv[3]->arg, NULL, 10); + if (!prefix_str2mac(argv[5]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + memset(&ip, 0, sizeof(ip)); + seq = strtoul(argv[7]->arg, NULL, 10); + + bgp = bgp_get_default(); + if (!bgp) { + vty_out(vty, "Default BGP instance is not there\n"); + return CMD_WARNING; + } + + rv = bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, 0 /* flags */, seq); + if (rv < 0) { + vty_out(vty, "Internal error\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN_HIDDEN (no_bgp_local_mac, + no_bgp_local_mac_cmd, + "no bgp local-mac vni " CMD_VNI_RANGE " mac WORD", + NO_STR + BGP_STR + "Local MAC config\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "local mac\n" + "mac address\n") +{ + int rv; + vni_t vni; + struct ethaddr mac; + struct ipaddr ip; + struct bgp *bgp; + + vni = strtoul(argv[4]->arg, NULL, 10); + if (!prefix_str2mac(argv[6]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + memset(&ip, 0, sizeof(ip)); + + bgp = bgp_get_default(); + if (!bgp) { + vty_out(vty, "Default BGP instance is not there\n"); + return CMD_WARNING; + } + + rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); + if (rv < 0) { + vty_out(vty, "Internal error\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + #if (CONFDATE > 20190601) CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco") CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG") @@ -12593,6 +12674,10 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_config_type_cmd); install_element(CONFIG_NODE, &no_bgp_config_type_cmd); + /* "bgp local-mac" hidden commands. */ + install_element(CONFIG_NODE, &bgp_local_mac_cmd); + install_element(CONFIG_NODE, &no_bgp_local_mac_cmd); + /* bgp route-map delay-timer commands. */ install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd); install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd); diff --git a/lib/command.h b/lib/command.h index 873ecdda98..11514fd5e8 100644 --- a/lib/command.h +++ b/lib/command.h @@ -378,6 +378,7 @@ struct cmd_node { #define WATCHFRR_STR "watchfrr information\n" #define ZEBRA_STR "Zebra information\n" +#define CMD_VNI_RANGE "(1-16777215)" #define CONF_BACKUP_EXT ".sav" /* Command warnings. */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 35f719fa54..cd78551cb4 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1458,7 +1458,7 @@ DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, } #endif -DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni (1-16777215)", +DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni " CMD_VNI_RANGE, "VXLAN Network Identifier\n" "VNI number\n") { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 4fff376377..263cb3d22c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -68,9 +68,6 @@ static void vty_show_ip_route_summary(struct vty *vty, static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table); -/* VNI range as per RFC 7432 */ -#define CMD_VNI_RANGE "(1-16777215)" - DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, "ip multicast rpf-lookup-mode ", diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0bc1ea50bb..d372d3e832 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -148,8 +148,7 @@ static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr); static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, uint8_t flags, uint32_t seq); -static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, - uint8_t flags); +static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr); static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); @@ -2305,6 +2304,7 @@ static int zvni_remote_neigh_update(zebra_vni_t *zvni, UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); + ZEBRA_NEIGH_SET_ACTIVE(n); n->r_vtep_ip = zmac->fwd_info.r_vtep_ip; } @@ -2407,7 +2407,7 @@ static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) &wctx->r_vtep_ip))) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { zvni_mac_send_del_to_client(wctx->zvni->vni, - &mac->macaddr, mac->flags); + &mac->macaddr); } if (wctx->uninstall) @@ -2494,18 +2494,10 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, /* * Inform BGP about local MAC deletion. */ -static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, - uint8_t mac_flags) +static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr) { - uint8_t flags = 0; - - if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); - - return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, - 0, ZEBRA_MACIP_DEL); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */, + 0 /* seq */, ZEBRA_MACIP_DEL); } /* @@ -4304,6 +4296,10 @@ static void process_remote_macip_add(vni_t vni, } } + /* Remove local MAC from BGP. */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + zvni_mac_send_del_to_client(zvni->vni, macaddr); + /* Set "auto" and "remote" forwarding info. */ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); @@ -4324,6 +4320,7 @@ static void process_remote_macip_add(vni_t vni, /* Install the entry. */ zvni_mac_install(zvni, mac); + } /* Update seq number. */ @@ -4522,6 +4519,13 @@ static void process_remote_macip_del(vni_t vni, } else { if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zvni_process_neigh_on_remote_mac_del(zvni, mac); + /* + * the remote sequence number in the auto mac entry + * needs to be reset to 0 as the mac entry may have + * been removed on all VTEPs (including + * the originating one) + */ + mac->rem_seq = 0; /* If all remote neighbors referencing a remote MAC * go away, we need to uninstall the MAC. @@ -5730,7 +5734,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, ifp->ifindex, vni); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); + zvni_mac_send_del_to_client(zvni->vni, macaddr); /* * If there are no neigh associated with the mac delete the mac @@ -5841,7 +5845,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zvni_process_neigh_on_local_mac_del(zvni, mac); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); + zvni_mac_send_del_to_client(zvni->vni, macaddr); /* * If there are no neigh associated with the mac delete the mac