Merge pull request #17229 from donaldsharp/bgp_update_optimizations

Optimizations and problem fixing for large scale ecmp from bgp
This commit is contained in:
Donatas Abraitis 2024-10-25 09:57:07 +03:00 committed by GitHub
commit ba3836c4e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 91 additions and 44 deletions

View File

@ -297,6 +297,8 @@ static struct aspath *aspath_new(enum asnotation_mode asnotation)
as = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath)); as = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
as->asnotation = asnotation; as->asnotation = asnotation;
as->count = 0;
return as; return as;
} }
@ -399,6 +401,11 @@ unsigned int aspath_count_confeds(struct aspath *aspath)
} }
unsigned int aspath_count_hops(const struct aspath *aspath) unsigned int aspath_count_hops(const struct aspath *aspath)
{
return aspath->count;
}
static unsigned int aspath_count_hops_internal(const struct aspath *aspath)
{ {
int count = 0; int count = 0;
struct assegment *seg = aspath->segments; struct assegment *seg = aspath->segments;
@ -708,6 +715,7 @@ struct aspath *aspath_dup(struct aspath *aspath)
else else
new->str[0] = '\0'; new->str[0] = '\0';
new->count = aspath->count;
return new; return new;
} }
@ -729,6 +737,7 @@ static void *aspath_hash_alloc(void *arg)
new->str_len = aspath->str_len; new->str_len = aspath->str_len;
new->json = aspath->json; new->json = aspath->json;
new->asnotation = aspath->asnotation; new->asnotation = aspath->asnotation;
new->count = aspath->count;
return new; return new;
} }
@ -856,6 +865,8 @@ struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit,
if (assegments_parse(s, length, &as.segments, use32bit) < 0) if (assegments_parse(s, length, &as.segments, use32bit) < 0)
return NULL; return NULL;
as.count = aspath_count_hops_internal(&as);
/* If already same aspath exist then return it. */ /* If already same aspath exist then return it. */
find = hash_get(ashash, &as, aspath_hash_alloc); find = hash_get(ashash, &as, aspath_hash_alloc);
@ -1032,7 +1043,7 @@ static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath,
asset->as[asset->length - 1] = as; asset->as[asset->length - 1] = as;
} }
aspath->count = aspath_count_hops_internal(aspath);
return asset; return asset;
} }
@ -1113,6 +1124,8 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
assegment_normalise(aspath->segments); assegment_normalise(aspath->segments);
aspath_str_update(aspath, false); aspath_str_update(aspath, false);
aspath->count = aspath_count_hops_internal(aspath);
return aspath; return aspath;
} }
@ -1268,6 +1281,7 @@ struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
} }
aspath_str_update(new, false); aspath_str_update(new, false);
new->count = aspath_count_hops_internal(new);
return new; return new;
} }
@ -1293,6 +1307,8 @@ struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
} }
aspath_str_update(new, false); aspath_str_update(new, false);
new->count = aspath_count_hops_internal(new);
return new; return new;
} }
@ -1315,6 +1331,8 @@ struct aspath *aspath_replace_all_asn(struct aspath *aspath, as_t our_asn)
} }
aspath_str_update(new, false); aspath_str_update(new, false);
new->count = aspath_count_hops_internal(new);
return new; return new;
} }
@ -1341,6 +1359,8 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn,
} }
aspath_str_update(new, false); aspath_str_update(new, false);
new->count = aspath_count_hops_internal(new);
return new; return new;
} }
@ -1413,6 +1433,7 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn)
if (!aspath->refcnt) if (!aspath->refcnt)
aspath_free(aspath); aspath_free(aspath);
aspath_str_update(new, false); aspath_str_update(new, false);
new->count = aspath_count_hops_internal(new);
return new; return new;
} }
@ -1469,6 +1490,7 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2)
last->next = as2->segments; last->next = as2->segments;
as2->segments = new; as2->segments = new;
aspath_str_update(as2, false); aspath_str_update(as2, false);
as2->count = aspath_count_hops_internal(as2);
return as2; return as2;
} }
@ -1486,6 +1508,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
if (as2->segments == NULL) { if (as2->segments == NULL) {
as2->segments = assegment_dup_all(as1->segments); as2->segments = assegment_dup_all(as1->segments);
aspath_str_update(as2, false); aspath_str_update(as2, false);
as2->count = aspath_count_hops_internal(as2);
return as2; return as2;
} }
@ -1506,6 +1529,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
if (!as2->segments) { if (!as2->segments) {
as2->segments = assegment_dup_all(as1->segments); as2->segments = assegment_dup_all(as1->segments);
aspath_str_update(as2, false); aspath_str_update(as2, false);
as2->count = aspath_count_hops_internal(as2);
return as2; return as2;
} }
@ -1551,6 +1575,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
* the inbetween AS_SEQUENCE of seg2 in the process * the inbetween AS_SEQUENCE of seg2 in the process
*/ */
aspath_str_update(as2, false); aspath_str_update(as2, false);
as2->count = aspath_count_hops_internal(as2);
return as2; return as2;
} else { } else {
/* AS_SET merge code is needed at here. */ /* AS_SET merge code is needed at here. */
@ -1662,6 +1687,7 @@ struct aspath *aspath_filter_exclude(struct aspath *source,
lastseg = newseg; lastseg = newseg;
} }
aspath_str_update(newpath, false); aspath_str_update(newpath, false);
newpath->count = aspath_count_hops_internal(newpath);
/* We are happy returning even an empty AS_PATH, because the /* We are happy returning even an empty AS_PATH, because the
* administrator * administrator
* might expect this very behaviour. There's a mean to avoid this, if * might expect this very behaviour. There's a mean to avoid this, if
@ -1680,6 +1706,7 @@ struct aspath *aspath_filter_exclude_all(struct aspath *source)
newpath = aspath_new(source->asnotation); newpath = aspath_new(source->asnotation);
aspath_str_update(newpath, false); aspath_str_update(newpath, false);
newpath->count = aspath_count_hops_internal(newpath);
/* We are happy returning even an empty AS_PATH, because the /* We are happy returning even an empty AS_PATH, because the
* administrator * administrator
* might expect this very behaviour. There's a mean to avoid this, if * might expect this very behaviour. There's a mean to avoid this, if
@ -1767,6 +1794,7 @@ struct aspath *aspath_filter_exclude_acl(struct aspath *source,
aspath_str_update(source, false); aspath_str_update(source, false);
source->count = aspath_count_hops_internal(source);
/* We are happy returning even an empty AS_PATH, because the /* We are happy returning even an empty AS_PATH, because the
* administrator * administrator
* might expect this very behaviour. There's a mean to avoid this, if * might expect this very behaviour. There's a mean to avoid this, if
@ -1805,6 +1833,7 @@ static struct aspath *aspath_add_asns(struct aspath *aspath, as_t asno,
} }
aspath_str_update(aspath, false); aspath_str_update(aspath, false);
aspath->count = aspath_count_hops_internal(aspath);
return aspath; return aspath;
} }
@ -1896,6 +1925,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
if (!hops) { if (!hops) {
newpath = aspath_dup(as4path); newpath = aspath_dup(as4path);
aspath_str_update(newpath, false); aspath_str_update(newpath, false);
/* dup sets the count properly */
return newpath; return newpath;
} }
@ -1957,6 +1987,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
aspath_free(newpath); aspath_free(newpath);
mergedpath->segments = assegment_normalise(mergedpath->segments); mergedpath->segments = assegment_normalise(mergedpath->segments);
aspath_str_update(mergedpath, false); aspath_str_update(mergedpath, false);
mergedpath->count = aspath_count_hops_internal(mergedpath);
if (BGP_DEBUG(as4, AS4)) if (BGP_DEBUG(as4, AS4))
zlog_debug("[AS4] result of synthesizing is %s", zlog_debug("[AS4] result of synthesizing is %s",
@ -2027,8 +2058,10 @@ struct aspath *aspath_delete_confed_seq(struct aspath *aspath)
seg = next; seg = next;
} }
if (removed_confed_segment) if (removed_confed_segment) {
aspath_str_update(aspath, false); aspath_str_update(aspath, false);
aspath->count = aspath_count_hops_internal(aspath);
}
return aspath; return aspath;
} }

View File

@ -59,6 +59,7 @@ struct aspath {
and AS path regular expression match. */ and AS path regular expression match. */
char *str; char *str;
unsigned short str_len; unsigned short str_len;
uint32_t count;
/* AS notation used by string expression of AS path */ /* AS notation used by string expression of AS path */
enum asnotation_mode asnotation; enum asnotation_mode asnotation;

View File

@ -178,6 +178,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
EVENT_OFF(going_away->t_delayopen); EVENT_OFF(going_away->t_delayopen);
EVENT_OFF(going_away->t_connect_check_r); EVENT_OFF(going_away->t_connect_check_r);
EVENT_OFF(going_away->t_connect_check_w); EVENT_OFF(going_away->t_connect_check_w);
EVENT_OFF(going_away->t_stop_with_notify);
EVENT_OFF(keeper->t_routeadv); EVENT_OFF(keeper->t_routeadv);
EVENT_OFF(keeper->t_connect); EVENT_OFF(keeper->t_connect);
EVENT_OFF(keeper->t_delayopen); EVENT_OFF(keeper->t_delayopen);
@ -1475,6 +1476,8 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection)
EVENT_OFF(connection->t_connect_check_r); EVENT_OFF(connection->t_connect_check_r);
EVENT_OFF(connection->t_connect_check_w); EVENT_OFF(connection->t_connect_check_w);
EVENT_OFF(connection->t_stop_with_notify);
/* Stop all timers. */ /* Stop all timers. */
EVENT_OFF(connection->t_start); EVENT_OFF(connection->t_start);
EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_connect);
@ -3032,3 +3035,10 @@ void bgp_peer_gr_flags_update(struct peer *peer)
} }
} }
} }
void bgp_event_stop_with_notify(struct event *event)
{
struct peer_connection *connection = EVENT_ARG(event);
bgp_stop_with_notify(connection, BGP_NOTIFY_SEND_HOLD_ERR, 0);
}

View File

@ -109,6 +109,7 @@ enum bgp_fsm_state_progress {
extern void bgp_fsm_nht_update(struct peer_connection *connection, extern void bgp_fsm_nht_update(struct peer_connection *connection,
struct peer *peer, bool has_valid_nexthops); struct peer *peer, bool has_valid_nexthops);
extern void bgp_event(struct event *event); extern void bgp_event(struct event *event);
extern void bgp_event_stop_with_notify(struct event *event);
extern int bgp_event_update(struct peer_connection *connection, extern int bgp_event_update(struct peer_connection *connection,
enum bgp_fsm_events event); enum bgp_fsm_events event);
extern enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection); extern enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection);

View File

@ -122,12 +122,12 @@ static void bgp_packet_add(struct peer_connection *connection,
peer->last_sendq_ok = monotime(NULL); peer->last_sendq_ok = monotime(NULL);
stream_fifo_push(connection->obuf, s); stream_fifo_push(connection->obuf, s);
}
delta = monotime(NULL) - peer->last_sendq_ok; delta = monotime(NULL) - peer->last_sendq_ok;
if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
holdtime = atomic_load_explicit(&peer->holdtime, holdtime = atomic_load_explicit(&peer->holdtime, memory_order_relaxed);
memory_order_relaxed);
else else
holdtime = peer->bgp->default_holdtime; holdtime = peer->bgp->default_holdtime;
@ -144,21 +144,17 @@ static void bgp_packet_add(struct peer_connection *connection,
if (!holdtime) { if (!holdtime) {
/* no holdtime, do nothing. */ /* no holdtime, do nothing. */
} else if (delta > sendholdtime) { } else if (delta > sendholdtime) {
flog_err( flog_err(EC_BGP_SENDQ_STUCK_PROPER,
EC_BGP_SENDQ_STUCK_PROPER,
"%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session", "%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session",
peer, sendholdtime); peer, sendholdtime);
bgp_stop_with_notify(connection, event_add_event(bm->master, bgp_event_stop_with_notify, connection, 0,
BGP_NOTIFY_SEND_HOLD_ERR, 0); &connection->t_stop_with_notify);
} else if (delta > (intmax_t)holdtime && } else if (delta > (intmax_t)holdtime && monotime(NULL) - peer->last_sendq_warn > 5) {
monotime(NULL) - peer->last_sendq_warn > 5) { flog_warn(EC_BGP_SENDQ_STUCK_WARN,
flog_warn(
EC_BGP_SENDQ_STUCK_WARN,
"%pBP has not made any SendQ progress for 1 holdtime (%us), peer overloaded?", "%pBP has not made any SendQ progress for 1 holdtime (%us), peer overloaded?",
peer, holdtime); peer, holdtime);
peer->last_sendq_warn = monotime(NULL); peer->last_sendq_warn = monotime(NULL);
} }
}
} }
static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi, static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi,

View File

@ -1133,9 +1133,9 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
/* 4. AS path length check. */ /* 4. AS path length check. */
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) { if (!CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) {
int exist_hops = aspath_count_hops(existattr->aspath); int exist_hops = aspath_count_hops(existattr->aspath);
int exist_confeds = aspath_count_confeds(existattr->aspath);
if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED)) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_CONFED)) {
int exist_confeds = aspath_count_confeds(existattr->aspath);
int aspath_hops; int aspath_hops;
aspath_hops = aspath_count_hops(newattr->aspath); aspath_hops = aspath_count_hops(newattr->aspath);
@ -4676,10 +4676,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* will not be interned. In which case, it is ok to update the * will not be interned. In which case, it is ok to update the
* attr->evpn_overlay, so that, this can be stored in adj_in. * attr->evpn_overlay, so that, this can be stored in adj_in.
*/ */
if ((afi == AFI_L2VPN) && evpn) if (evpn) {
if (afi == AFI_L2VPN)
bgp_attr_set_evpn_overlay(attr, evpn); bgp_attr_set_evpn_overlay(attr, evpn);
else else
evpn_overlay_free(evpn); evpn_overlay_free(evpn);
}
bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
} }
@ -4855,10 +4857,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* attr->evpn_overlay with evpn directly. Instead memcpy * attr->evpn_overlay with evpn directly. Instead memcpy
* evpn to new_atr.evpn_overlay before it is interned. * evpn to new_atr.evpn_overlay before it is interned.
*/ */
if (soft_reconfig && (afi == AFI_L2VPN) && evpn) if (soft_reconfig && evpn) {
if (afi == AFI_L2VPN)
bgp_attr_set_evpn_overlay(&new_attr, evpn); bgp_attr_set_evpn_overlay(&new_attr, evpn);
else else
evpn_overlay_free(evpn); evpn_overlay_free(evpn);
}
/* Apply incoming route-map. /* Apply incoming route-map.
* NB: new_attr may now contain newly allocated values from route-map * NB: new_attr may now contain newly allocated values from route-map

View File

@ -1223,6 +1223,8 @@ struct peer_connection {
struct event *t_process_packet; struct event *t_process_packet;
struct event *t_process_packet_error; struct event *t_process_packet_error;
struct event *t_stop_with_notify;
union sockunion su; union sockunion su;
#define BGP_CONNECTION_SU_UNSPEC(connection) \ #define BGP_CONNECTION_SU_UNSPEC(connection) \
(connection->su.sa.sa_family == AF_UNSPEC) (connection->su.sa.sa_family == AF_UNSPEC)

View File

@ -932,7 +932,7 @@ static int netlink_recv_msg(struct nlsock *nl, struct msghdr *msg)
} while (status == -1 && errno == EINTR); } while (status == -1 && errno == EINTR);
if (status == -1) { if (status == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EMSGSIZE)
return 0; return 0;
flog_err(EC_ZEBRA_RECVMSG_OVERRUN, "%s recvmsg overrun: %s", flog_err(EC_ZEBRA_RECVMSG_OVERRUN, "%s recvmsg overrun: %s",
nl->name, safe_strerror(errno)); nl->name, safe_strerror(errno));