Skip to content

Commit a20f14c

Browse files
authored
Merge pull request FRRouting#20325 from enkechen-panw/bgp-dup-fix
bgpd: fix bugs with suppress-duplicates
2 parents 68b79b1 + 5c29f55 commit a20f14c

File tree

5 files changed

+69
-41
lines changed

5 files changed

+69
-41
lines changed

bgpd/bgp_advertise.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash,
103103
struct bgp_advertise_attr ref;
104104
struct bgp_advertise_attr *baa;
105105

106-
ref.attr = bgp_attr_intern(attr);
106+
/* The attr is already intern'ed */
107+
ref.attr = attr;
107108
baa = (struct bgp_advertise_attr *)hash_get(
108109
hash, &ref, bgp_advertise_attr_hash_alloc);
109110
baa->refcnt++;

bgpd/bgp_advertise.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ struct bgp_adj_out {
6969

7070
uint32_t addpath_tx_id;
7171

72-
/* Attribute hash */
73-
uint32_t attr_hash;
74-
7572
/* Advertised attribute. */
7673
struct attr *attr;
7774

bgpd/bgp_packet.c

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,6 @@ void bgp_generate_updgrp_packets(struct event *event)
428428
uint32_t generated = 0;
429429
afi_t afi;
430430
safi_t safi;
431-
enum bgp_af_index index;
432431

433432
wpq = atomic_load_explicit(&peer->bgp->wpkt_quanta,
434433
memory_order_relaxed);
@@ -445,23 +444,8 @@ void bgp_generate_updgrp_packets(struct event *event)
445444
|| bgp_update_delay_active(peer->bgp))
446445
return;
447446

448-
if (peer->connection->t_routeadv) {
449-
/* If MRAI is running, we have to hint "adj-rib-out" to
450-
* ignore suppression of updates for this peer, because
451-
* if we don't, we will miss some updates that are very
452-
* quick (flapping/= del/add) during the MRAI wait time.
453-
*/
454-
for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
455-
paf = peer->peer_af_array[index];
456-
if (!paf)
457-
continue;
458-
459-
if (paf && paf->subgroup)
460-
SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
461-
}
462-
447+
if (peer->connection->t_routeadv)
463448
return;
464-
}
465449

466450
/*
467451
* Since the following is a do while loop
@@ -480,6 +464,8 @@ void bgp_generate_updgrp_packets(struct event *event)
480464
return;
481465

482466
do {
467+
enum bgp_af_index index;
468+
483469
s = NULL;
484470
for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
485471
paf = peer->peer_af_array[index];
@@ -529,12 +515,6 @@ void bgp_generate_updgrp_packets(struct event *event)
529515
*/
530516
if (!next_pkt || !next_pkt->buffer) {
531517
if (!paf->t_announce_route) {
532-
/* Make sure we supress BGP UPDATES
533-
* for normal processing later again.
534-
*/
535-
UNSET_FLAG(paf->subgroup->sflags,
536-
SUBGRP_STATUS_FORCE_UPDATES);
537-
538518
/* If route-refresh BoRR message was
539519
* already sent and we are done with
540520
* re-announcing tables for a decent

bgpd/bgp_route.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6633,12 +6633,15 @@ void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force)
66336633
* Ignore if subgroup doesn't exist (implies AF is not negotiated)
66346634
* or a refresh has already been triggered.
66356635
*/
6636-
if (!subgrp || paf->t_announce_route)
6636+
if (!subgrp)
66376637
return;
66386638

66396639
if (force)
66406640
SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
66416641

6642+
if (paf->t_announce_route)
6643+
return;
6644+
66426645
/*
66436646
* Start a timer to stagger/delay the announce. This serves
66446647
* two purposes - announcement can potentially be combined for

bgpd/bgp_updgrp_adv.c

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,16 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
544544
struct update_subgroup *subgrp, struct attr *attr,
545545
struct bgp_path_info *path)
546546
{
547-
struct bgp_adj_out *adj = NULL;
547+
struct bgp_adj_out *adj;
548548
struct bgp_advertise *adv;
549549
struct peer *peer;
550550
afi_t afi;
551551
safi_t safi;
552552
struct peer *adv_peer;
553553
struct peer_af *paf;
554554
struct bgp *bgp;
555-
uint32_t attr_hash = 0;
555+
struct attr *attr_new;
556+
bool debug;
556557

557558
peer = SUBGRP_PEER(subgrp);
558559
afi = SUBGRP_AFI(subgrp);
@@ -562,6 +563,8 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
562563
if (DISABLE_BGP_ANNOUNCE)
563564
return false;
564565

566+
debug = BGP_DEBUG(update, UPDATE_OUT);
567+
565568
/* Look for adjacency information. */
566569
adj = adj_lookup(
567570
dest, subgrp,
@@ -586,15 +589,18 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
586589
* at egress, neighbors will see duplicate UPDATES despite
587590
* the route wasn't changed actually.
588591
* Do not suppress BGP UPDATES for route-refresh.
592+
*
593+
* It's a duplicate UPDATE if the new attribute is the same as
594+
* the one that was sent out, or the one that has been queued.
589595
*/
590-
if (likely(CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)))
591-
attr_hash = attrhash_key_make(attr);
592-
593-
if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) &&
594-
attr_hash && adj->attr_hash == attr_hash &&
595-
bgp_labels_cmp(path->extra ? path->extra->labels : NULL,
596-
adj->labels)) {
597-
if (BGP_DEBUG(update, UPDATE_OUT)) {
596+
attr_new = bgp_attr_intern(attr);
597+
598+
if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES) &&
599+
!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) &&
600+
((attr_new == adj->attr) ||
601+
(adj->adv && adj->adv->baa && (attr_new == adj->adv->baa->attr))) &&
602+
bgp_labels_cmp(path->extra ? path->extra->labels : NULL, adj->labels)) {
603+
if (debug) {
598604
char attr_str[BUFSIZ] = {0};
599605

600606
bgp_dump_attr(attr, attr_str, sizeof(attr_str));
@@ -603,6 +609,22 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
603609
peer->host, dest, attr_str, afi2str(afi), safi2str(safi));
604610
}
605611

612+
/*
613+
* If this is a duplicate of the update that was sent out,
614+
* clean up the queued update, regardless whether it is a
615+
* withdraw or an advertisement.
616+
*/
617+
if (adj->adv && (attr_new == adj->attr)) {
618+
if (debug) {
619+
zlog_debug("%s delete queued UPDATE %pBD, afi=%s, safi=%s",
620+
peer->host, dest, afi2str(afi), safi2str(safi));
621+
}
622+
623+
bgp_advertise_clean_subgroup(subgrp, adj);
624+
}
625+
626+
bgp_attr_unintern(&attr_new);
627+
606628
/*
607629
* If BGP is skipping sending this value to it's peers
608630
* the version number should be updated just like it
@@ -632,9 +654,8 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
632654
/* bgp_path_info adj_out reference */
633655
adv->pathi = bgp_path_info_lock(path);
634656

635-
adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr);
657+
adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr_new);
636658
adv->adj = adj;
637-
adj->attr_hash = attr_hash;
638659
if (path->extra)
639660
adj->labels = bgp_labels_intern(path->extra->labels);
640661
else
@@ -643,6 +664,11 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
643664
/* Add new advertisement to advertisement attribute list. */
644665
bgp_advertise_add(adv->baa, adv);
645666

667+
if (debug) {
668+
zlog_debug("%s queue UPDATE %pBD, afi=%s, safi=%s", peer->host, dest, afi2str(afi),
669+
safi2str(safi));
670+
}
671+
646672
/*
647673
* If the update adv list is empty, trigger the member peers'
648674
* mrai timers so the socket writes can happen.
@@ -686,6 +712,9 @@ void bgp_adj_out_unset_subgroup(struct bgp_dest *dest,
686712
struct bgp_adj_out *adj;
687713
struct bgp_advertise *adv;
688714
bool trigger_write;
715+
afi_t afi;
716+
safi_t safi;
717+
struct peer *peer;
689718

690719
if (DISABLE_BGP_ANNOUNCE)
691720
return;
@@ -720,6 +749,15 @@ void bgp_adj_out_unset_subgroup(struct bgp_dest *dest,
720749
* announcement. */
721750
bgp_adv_fifo_add_tail(&subgrp->sync->withdraw, adv);
722751

752+
if (BGP_DEBUG(update, UPDATE_OUT)) {
753+
peer = SUBGRP_PEER(subgrp);
754+
afi = SUBGRP_AFI(subgrp);
755+
safi = SUBGRP_SAFI(subgrp);
756+
757+
zlog_debug("%s queue UPDATE (withdraw) %pBD, afi=%s, safi=%s",
758+
peer->host, dest, afi2str(afi), safi2str(safi));
759+
}
760+
723761
if (trigger_write)
724762
subgroup_trigger_write(subgrp);
725763
} else {
@@ -850,6 +888,7 @@ void subgroup_announce_route(struct update_subgroup *subgrp)
850888
struct bgp_dest *dest;
851889
struct bgp_table *table;
852890
struct peer *onlypeer;
891+
bool force_update;
853892

854893
if (update_subgroup_needs_refresh(subgrp)) {
855894
update_subgroup_set_needs_refresh(subgrp, 0);
@@ -865,15 +904,20 @@ void subgroup_announce_route(struct update_subgroup *subgrp)
865904
PEER_STATUS_ORF_WAIT_REFRESH))
866905
return;
867906

907+
force_update = !!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
908+
868909
if (SUBGRP_SAFI(subgrp) != SAFI_MPLS_VPN
869910
&& SUBGRP_SAFI(subgrp) != SAFI_ENCAP
870911
&& SUBGRP_SAFI(subgrp) != SAFI_EVPN)
871912
subgroup_announce_table(subgrp, NULL);
872913
else {
873914
struct bgp_table *rib = update_subgroup_rib(subgrp);
874915

875-
if (!rib)
916+
if (!rib) {
917+
if (force_update)
918+
UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
876919
return;
920+
}
877921

878922
for (dest = bgp_table_top(rib); dest; dest = bgp_route_next(dest)) {
879923
table = bgp_dest_get_bgp_table_info(dest);
@@ -882,6 +926,9 @@ void subgroup_announce_route(struct update_subgroup *subgrp)
882926
subgroup_announce_table(subgrp, table);
883927
}
884928
}
929+
930+
if (force_update)
931+
UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
885932
}
886933

887934
void subgroup_default_originate(struct update_subgroup *subgrp, bool withdraw)

0 commit comments

Comments
 (0)