From: Rajasekar Raja Date: Thu, 15 Feb 2024 19:23:51 +0000 (-0800) Subject: bgpd : backpressure - Handle BGP-Zebra(EPVN) Install evt Creation X-Git-Tag: base_10.1~200^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=a07df6f7548f6bd1b92acbb7a10c3823de33fe5f;p=matthieu%2Ffrr.git bgpd : backpressure - Handle BGP-Zebra(EPVN) Install evt Creation Current changes deals with EVPN routes installation to zebra. In evpn_route_select_install() we invoke evpn_zebra_install/uninstall which sends zclient_send_message(). This is a continuation of code changes (similar to ccfe452763d16c432fa81fd20e805bec819b345e) but to handle evpn part of the code. Ticket: #3390099 Signed-off-by: Rajasekar Raja --- diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a846484f0e..e142ff6a34 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -892,11 +892,10 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, /* * Add (update) or delete MACIP from zebra. */ -static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - const struct ethaddr *mac, - struct in_addr remote_vtep_ip, int add, - uint8_t flags, uint32_t seq, esi_t *esi) +static enum zclient_send_status bgp_zebra_send_remote_macip( + struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add, + uint8_t flags, uint32_t seq, esi_t *esi) { struct stream *s; uint16_t ipa_len; @@ -904,8 +903,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, bool esi_valid; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -913,7 +916,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote macip", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (!esi) @@ -979,24 +982,26 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, esi); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* * Add (update) or delete remote VTEP from zebra. */ -static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - int flood_control, int add) +static enum zclient_send_status +bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, int flood_control, + int add) { struct stream *s; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -1004,7 +1009,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote vtep", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } s = zclient->obuf; @@ -1021,7 +1026,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, EC_BGP_VTEP_INVALID, "Bad remote IP when trying to %s remote VTEP for VNI %u", add ? "ADD" : "DEL", (vpn ? vpn->vni : 0)); - return -1; + return ZCLIENT_SEND_FAILURE; } stream_putl(s, flood_control); @@ -1034,10 +1039,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* @@ -1263,14 +1265,14 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) } /* Install EVPN route into zebra. */ -static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi) +enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi) { - int ret; uint8_t flags; int flood_control = VXLAN_FLOOD_DISABLED; uint32_t seq; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { flags = 0; @@ -1348,6 +1350,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, flood_control = VXLAN_FLOOD_DISABLED; break; } + ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1); } @@ -1355,11 +1358,13 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, } /* Uninstall EVPN route from zebra. */ -static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi, bool is_sync) +enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi, + bool is_sync) { - int ret; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip( @@ -1374,7 +1379,7 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p); else ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, - VXLAN_FLOOD_DISABLED, 0); + VXLAN_FLOOD_DISABLED, 0); return ret; } @@ -1465,12 +1470,18 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { - if (bgp_zebra_has_route_changed(old_select)) - ret = evpn_zebra_install( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select); + if (bgp_zebra_has_route_changed(old_select)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + old_select); + else + bgp_zebra_route_install(dest, old_select, bgp, + true, vpn, false); + } + UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -1502,10 +1513,14 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(new_select->attr))) { - ret = evpn_zebra_install( - bgp, vpn, - (struct prefix_evpn *)bgp_dest_get_prefix(dest), - new_select); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix(dest), + new_select); + else + bgp_zebra_route_install(dest, new_select, bgp, true, + vpn, false); /* If an old best existed and it was a "local" route, the only * reason @@ -1522,13 +1537,19 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, evpn_delete_old_local_route(bgp, vpn, dest, old_select, new_select); } else { - if (old_select && old_select->type == ZEBRA_ROUTE_BGP - && old_select->sub_type == BGP_ROUTE_IMPORTED) - ret = evpn_zebra_uninstall( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select, false); + if (old_select && old_select->type == ZEBRA_ROUTE_BGP && + old_select->sub_type == BGP_ROUTE_IMPORTED) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || + CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN)) + evpn_zebra_uninstall(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + old_select, false); + else + bgp_zebra_route_install(dest, old_select, bgp, + false, vpn, false); + } } /* Clear any route change flags. */ @@ -2062,9 +2083,19 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp, if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && (curr_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(curr_select->attr))) - evpn_zebra_install(bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix(dest), - curr_select); + if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && + (curr_select->sub_type == BGP_ROUTE_IMPORTED || + bgp_evpn_attr_is_sync(curr_select->attr))) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + curr_select); + else + bgp_zebra_route_install(dest, curr_select, bgp, + true, vpn, false); + } } /* @@ -2245,8 +2276,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, p, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_uninstall(bgp, vpn, p, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } bgp_path_info_unlock(pi); @@ -2512,8 +2551,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, &evp, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + (void)evpn_zebra_uninstall(bgp, vpn, + &evp, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } @@ -2795,7 +2843,22 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) delete_all_type2_routes(bgp, vpn); build_evpn_type3_prefix(&p, vpn->originator_ip); + + /* + * To handle the following scenario: + * - Say, the new zebra announce fifo list has few vni Evpn prefixes yet + * to be sent to zebra. + * - At this point if we have triggers like "no advertise-all-vni" or + * "networking restart", where a vni is going down. + * + * Perform the below + * 1) send withdraw routes to zebra immediately in case it is installed. + * 2) before we blow up the vni table, we need to walk the list and + * pop all the dest whose za_vpn points to this vni. + */ + SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); ret = delete_evpn_route(bgp, vpn, &p); + UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); if (ret) return ret; @@ -6262,6 +6325,17 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, */ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { + struct bgp_dest *dest = NULL; + + while (zebra_announce_count(&bm->zebra_announce_head)) { + dest = zebra_announce_pop(&bm->zebra_announce_head); + if (dest->za_vpn == vpn) { + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } else + zebra_announce_add_tail(&bm->zebra_announce_head, dest); + } + bgp_evpn_remote_ip_hash_destroy(vpn); bgp_evpn_vni_es_cleanup(vpn); bgpevpn_unlink_from_l3vni(vpn); diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index c641a64f62..11a6f45dd0 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -186,4 +186,12 @@ extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi); extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi); +extern enum zclient_send_status evpn_zebra_install(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi); +extern enum zclient_send_status +evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, struct bgp_path_info *pi, + bool is_sync); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d88c52d1f6..601b8e91ba 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -45,13 +45,14 @@ static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es); static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp, struct bgp_evpn_es *es); -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret); +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, struct bgp_evpn_es *es, struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref); -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr); + bool esr); static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es); static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es); static struct bgp_evpn_es_evi * @@ -94,6 +95,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, struct bgp_dest *dest) { int ret = 0; + int zret = 0; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; struct bgp_path_info *old_select; /* old best */ @@ -120,7 +122,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop, true /*esr*/, old_select->attr->df_alg, - old_select->attr->df_pref); + old_select->attr->df_pref, &zret); } UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -149,7 +151,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, && new_select->sub_type == BGP_ROUTE_IMPORTED) { bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop, true /*esr */, new_select->attr->df_alg, - new_select->attr->df_pref); + new_select->attr->df_pref, &zret); } else { if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_IMPORTED) @@ -447,7 +449,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, attr->mp_nexthop_global_in); } - /* Return back the route entry. */ + /* Return back th*e route entry. */ *ri = tmp_pi; return 0; } @@ -1371,23 +1373,28 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es, } /* Send the remote ES to zebra for NHG programming */ -static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool add) +static enum zclient_send_status +bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool add) { struct bgp_evpn_es *es = es_vtep->es; struct stream *s; uint32_t flags = 0; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("No zebra instance, not installing remote es %s", es->esi_str); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) @@ -1418,12 +1425,12 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, return zclient_send_message(zclient); } -static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, - bool param_change) +static enum zclient_send_status bgp_evpn_es_vtep_re_eval_active( + struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, bool param_change) { bool old_active; bool new_active; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); /* currently we need an active EVI reference to use the VTEP as @@ -1445,7 +1452,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, es_vtep->df_alg, es_vtep->df_pref); /* send remote ES to zebra */ - bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); + ret = bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); /* The NHG is updated first for efficient failover handling. * Note the NHG can be de-activated while there are bgp @@ -1457,13 +1464,14 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, /* queue up the es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(es_vtep->es); } + + return ret; } -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, - struct bgp_evpn_es *es, - struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref) +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret) { struct bgp_evpn_es_vtep *es_vtep; bool param_change = false; @@ -1490,15 +1498,17 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, ++es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + *zret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); return es_vtep; } -static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool esr) +static enum zclient_send_status +bgp_evpn_es_vtep_do_del(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool esr) { bool param_change = false; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str, @@ -1515,18 +1525,25 @@ static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, --es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + ret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); bgp_evpn_es_vtep_free(es_vtep); + + return ret; } -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr) +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, + struct bgp_evpn_es *es, + struct in_addr vtep_ip, + bool esr) { struct bgp_evpn_es_vtep *es_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip); if (es_vtep) - bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + ret = bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + + return ret; } /********************** ES MAC-IP paths ************************************* @@ -3399,12 +3416,14 @@ static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find( /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and * EAD-per-EVI routes are rxed from it. */ -static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_evi_vtep *evi_vtep) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, + struct bgp_evpn_es_evi_vtep *evi_vtep) { bool old_active; bool new_active; uint32_t ead_activity_flags; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); @@ -3425,7 +3444,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); if (old_active == new_active) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s evi %u vtep %pI4 %s", @@ -3434,24 +3453,27 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active ? "active" : "inactive"); /* add VTEP to parent es */ - if (new_active) - evi_vtep->es_vtep = bgp_evpn_es_vtep_add( - bgp, evi_vtep->es_evi->es, evi_vtep->vtep_ip, - false /*esr*/, 0, 0); - else { + if (new_active) { + evi_vtep->es_vtep = + bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es, + evi_vtep->vtep_ip, false /*esr*/, + 0, 0, &ret); + } else { if (evi_vtep->es_vtep) { - bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, - false /*esr*/); + ret = bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, + false /*esr*/); evi_vtep->es_vtep = NULL; } } /* queue up the parent es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es); + + return ret; } -static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_add(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; @@ -3475,18 +3497,19 @@ static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, else SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + return bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); } -static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_del(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip); if (!evi_vtep) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("del es %s evi %u vtep %pI4 %s", @@ -3503,8 +3526,10 @@ static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, else UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + ret = bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); bgp_evpn_es_evi_vtep_free(evi_vtep); + + return ret; } /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */ @@ -3780,18 +3805,20 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni) /* Add remote ES-EVI entry. This is actually the remote VTEP add and the * ES-EVI is implicity created on first VTEP's reference. */ -int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_add(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; const esi_t *esi = &p->prefix.ead_addr.esi; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("add remote %s es %s evi %u vtep %pI4", @@ -3808,27 +3835,29 @@ int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, es_evi = bgp_evpn_es_evi_new(es, vpn); ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_add(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + return ret; } /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the * parent es-evi freed up implicitly in last VTEP's deref. */ -int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_del(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug( @@ -3847,7 +3876,7 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } es_evi = bgp_evpn_es_evi_find(es, vpn); if (!es_evi) { @@ -3860,14 +3889,15 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_del(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + + return ret; } /* If a VNI is being deleted we need to force del all remote VTEPs */ diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index cebabb9fd0..5d393c37a2 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -418,10 +418,12 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi); extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni); extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni); -extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); -extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); extern void bgp_evpn_mh_init(void); extern void bgp_evpn_mh_finish(void); void bgp_evpn_vni_es_init(struct bgpevpn *vpn); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 88baa53510..1f26736b55 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3402,9 +3402,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_IMPORTED)) - bgp_zebra_route_install(dest, old_select, - bgp, true); + bgp, true, NULL, + false); } } @@ -3522,9 +3522,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, if (old_select && is_route_parent_evpn(old_select)) bgp_zebra_route_install(dest, old_select, bgp, - false); + false, NULL, false); - bgp_zebra_route_install(dest, new_select, bgp, true); + bgp_zebra_route_install(dest, new_select, bgp, true, + NULL, false); } else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP @@ -3533,7 +3534,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, || old_select->sub_type == BGP_ROUTE_IMPORTED)) bgp_zebra_route_install(dest, old_select, bgp, - false); + false, NULL, false); } } @@ -4430,7 +4431,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) /* remove from RIB previous entry */ - bgp_zebra_route_install(dest, pi, bgp, false); + bgp_zebra_route_install(dest, pi, bgp, false, NULL, + false); } if (peer->sort == BGP_PEER_EBGP) { diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 95705d2470..130f5ca749 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -78,6 +78,8 @@ struct bgp_dest { struct zebra_announce_item zai; struct bgp_path_info *za_bgp_pi; + struct bgpevpn *za_vpn; + bool za_is_sync; uint64_t version; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 04d520a923..95c89869a2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1687,12 +1687,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && - (pi->type == ZEBRA_ROUTE_BGP && (pi->sub_type == BGP_ROUTE_NORMAL || pi->sub_type == BGP_ROUTE_IMPORTED))) - - bgp_zebra_route_install(dest, pi, bgp, true); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } /* Announce routes of any bgp subtype of a table to zebra */ @@ -1714,7 +1713,8 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && pi->type == ZEBRA_ROUTE_BGP) - bgp_zebra_route_install(dest, pi, bgp, true); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, @@ -1767,6 +1767,7 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, #define ZEBRA_ANNOUNCEMENTS_LIMIT 1000 static void bgp_handle_route_announcements_to_zebra(struct event *e) { + bool is_evpn = false; uint32_t count = 0; struct bgp_dest *dest = NULL; struct bgp_table *table = NULL; @@ -1781,6 +1782,8 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) table = bgp_dest_table(dest); install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", @@ -1788,17 +1791,38 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) table->bgp->name_pretty, dest, dest->flags); if (install) { - status = bgp_zebra_announce_actual(dest, dest->za_bgp_pi, - table->bgp); + if (is_evpn) + status = + evpn_zebra_install(table->bgp, + dest->za_vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + dest->za_bgp_pi); + else + status = bgp_zebra_announce_actual(dest, + dest->za_bgp_pi, + table->bgp); UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); } else { - status = bgp_zebra_withdraw_actual(dest, dest->za_bgp_pi, - table->bgp); + if (is_evpn) + status = evpn_zebra_uninstall( + table->bgp, dest->za_vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix(dest), + dest->za_bgp_pi, false); + else + status = bgp_zebra_withdraw_actual(dest, + dest->za_bgp_pi, + table->bgp); + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); } bgp_path_info_unlock(dest->za_bgp_pi); dest->za_bgp_pi = NULL; + dest->za_vpn = NULL; bgp_dest_unlock_node(dest); if (status == ZCLIENT_SEND_BUFFERED) @@ -1852,8 +1876,16 @@ static void bgp_zebra_buffer_write_ready(void) * withdrawn. */ void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, - struct bgp *bgp, bool install) + struct bgp *bgp, bool install, struct bgpevpn *vpn, + bool is_sync) { + bool is_evpn = false; + struct bgp_table *table = NULL; + + table = bgp_dest_table(dest); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; + /* * BGP is installing this route and bgp has been configured * to suppress announcements until the route has been installed @@ -1863,7 +1895,7 @@ void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, if (BGP_SUPPRESS_FIB_ENABLED(bgp)) SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - if (bgp->main_zebra_update_hold) + if (bgp->main_zebra_update_hold && !is_evpn) return; } else { UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); @@ -1873,7 +1905,7 @@ void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, * Don't try to install if we're not connected to Zebra or Zebra doesn't * know of this instance. */ - if (!bgp_install_info_to_zebra(bgp)) + if (!bgp_install_info_to_zebra(bgp) && !is_evpn) return; if (!CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL) && @@ -1893,7 +1925,7 @@ void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, dest->za_bgp_pi = info; } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { assert(dest->za_bgp_pi); - if (install) + if (install & !is_evpn) bgp_zebra_withdraw_actual(dest, dest->za_bgp_pi, bgp); bgp_path_info_unlock(dest->za_bgp_pi); @@ -1901,6 +1933,11 @@ void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, dest->za_bgp_pi = info; } + if (is_evpn) { + dest->za_vpn = vpn; + dest->za_is_sync = is_sync; + } + if (install) { UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); @@ -1931,7 +1968,8 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && (pi->type == ZEBRA_ROUTE_BGP)) - bgp_zebra_route_install(dest, pi, bgp, false); + bgp_zebra_route_install(dest, pi, bgp, false, + NULL, false); } } } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 9c033197f7..ef296b963c 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -30,7 +30,8 @@ extern int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, extern int bgp_if_update_all(void); extern void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *path, struct bgp *bgp, - bool install); + bool install, struct bgpevpn *vpn, + bool is_sync); extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi); /* Announce routes of any bgp subtype of a table to zebra */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index c0fefd53ba..e882a181b5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -530,6 +530,7 @@ struct bgp { #define BGP_FLAG_SOFT_VERSION_CAPABILITY (1ULL << 35) #define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36) #define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37) +#define BGP_FLAG_VNI_DOWN (1ULL << 38) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance.