Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bgpd : backpressure - Handle BGP-Zebra(EPVN) Install evt Creation #15624

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 130 additions & 56 deletions bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,28 +892,31 @@ 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;
static struct in_addr zero_remote_vtep_ip;
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)) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug(
"%s: No zebra instance to talk to, not installing remote macip",
__func__);
return 0;
return ZCLIENT_SEND_SUCCESS;
}

if (!esi)
Expand Down Expand Up @@ -979,32 +982,34 @@ 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)) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug(
"%s: No zebra instance to talk to, not installing remote vtep",
__func__);
return 0;
return ZCLIENT_SEND_SUCCESS;
}

s = zclient->obuf;
Expand All @@ -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);

Expand All @@ -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);
}

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1348,18 +1350,21 @@ 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);
}

return ret;
}

/* 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(
Expand All @@ -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;
}
Expand Down Expand Up @@ -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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this check is supposed to fix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Background: Basically the function evpn_route_select_install() is called even when bgp does down. We don't want to add this logic of adding to new fifo when we are doing the cleanup because we sometimes get to a point where the table gets deleted before we get to process items from the new fifo and when we do, we crash.

So this check is basically saying if the function is called via cleanup, don't add the new logic. Add it only when we don't do any cleanup.

In case of Non evpn (regular v4/v6), we have a clear demarcation where bgp_cleanup_routes() is called only while cleanup and we invoke bgp_zebra_withdraw and not the new logic.

Same logic is applied here but since these can be called by either cleanup or regular updates, we are separating it out

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);
Expand Down Expand Up @@ -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
Expand All @@ -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. */
Expand Down Expand Up @@ -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);
}
}

/*
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions bgpd/bgp_evpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading
Loading