@@ -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
887934void subgroup_default_originate (struct update_subgroup * subgrp , bool withdraw )
0 commit comments