Skip to content

bgpd allows Dynamic Capability SET/UNSET storms to trigger repeated route announce/clear churn #22352

@xinzheliu2000

Description

@xinzheliu2000

Description

bgpd can be driven into repeated route announce/clear processing by an established BGP peer that rapidly toggles Dynamic Capability messages.

When Dynamic Capability is enabled for a peer, FRR accepts BGP CAPABILITY messages in the Established state. For Multi-Protocol capability changes, the parser updates the negotiated AFI/SAFI state and immediately triggers route processing:

Dynamic Capability SET MP(afi/safi)
  -> peer->afc_recv[afi][safi] = 1
  -> peer->afc_nego[afi][safi] = 1
  -> bgp_announce_route(peer, afi, safi, false)

Dynamic Capability UNSET MP(afi/safi)
  -> peer->afc_recv[afi][safi] = 0
  -> peer->afc_nego[afi][safi] = 0
  -> bgp_clear_route(peer, afi, safi)

There does not appear to be a rate limit, cooldown, or per-peer maximum change counter for these Dynamic Capability SET/UNSET operations.

As a result, an established peer can repeatedly toggle an AFI/SAFI capability and cause continuous route announce/clear churn without tearing down the BGP session.

This can consume control-plane CPU and create route update churn, especially on peers with large RIBs.

Version

FRRouting 10.6.1

How to reproduce

Enable Dynamic Capability for a BGP neighbor.

Example configuration pattern:

router bgp 65001
 neighbor 192.XXX.XXX.2 remote-as 65002
 neighbor 192.XXX.XXX.2 capability dynamic
 !
 address-family ipv4 unicast
  neighbor 192.XXX.XXX.2 activate
 exit-address-family
 !
 address-family ipv6 unicast
  neighbor 192.XXX.XXX.2 activate
 exit-address-family

Establish the BGP session with a peer that also advertises Dynamic Capability.

Then, from the established peer, repeatedly send BGP CAPABILITY messages that toggle Multi-Protocol capability for one AFI/SAFI, while another AFI/SAFI remains negotiated.

Example message sequence:

SET   MP(IPv6 unicast)
UNSET MP(IPv6 unicast)
SET   MP(IPv6 unicast)
UNSET MP(IPv6 unicast)
...

The peer should keep at least one other AFI/SAFI active, for example IPv4 unicast, so the session remains Established while IPv6 unicast is toggled.

Relevant packet-level structure:

BGP message type:
  CAPABILITY

Dynamic Capability payload:
  action = SET or UNSET
  code   = MP capability
  data   = AFI/SAFI tuple

Example logical sequence:

1. BGP session reaches Established.
2. Dynamic Capability has been negotiated.
3. Peer sends SET MP(IPv6 unicast).
4. FRR calls bgp_announce_route(peer, IPv6, unicast, false).
5. Peer sends UNSET MP(IPv6 unicast).
6. FRR calls bgp_clear_route(peer, IPv6, unicast).
7. Steps 3-6 can be repeated without session teardown.

Logs

Example debug-level behavior expected during testing:

CAPABILITY has action: SET, code: MP, length 4
CAPABILITY has Advertising MultiProtocol CAP for afi/safi: IPv6/unicast

CAPABILITY has action: UNSET, code: MP, length 4
CAPABILITY has Removing MultiProtocol CAP for afi/safi: IPv6/unicast

The important observation is that the session remains Established and the CAPABILITY messages do not trigger a NOTIFICATION or FSM reset.

Relevant code path:

bgpd/bgp_packet.c
  bgp_capability_receive()
    -> verifies Dynamic Capability was negotiated
    -> verifies peer is Established
    -> bgp_capability_msg_parse()

bgpd/bgp_packet.c
  bgp_capability_msg_parse()
    -> CAPABILITY_CODE_MP
       -> SET   calls bgp_announce_route()
       -> UNSET calls bgp_clear_route()
    -> returns BGP_PACKET_NOOP

The function returns:

return BGP_PACKET_NOOP;

so no FSM action is taken after the capability change.

Expected behavior

Dynamic Capability SET/UNSET messages should not allow an established peer to cause unbounded route announce/clear churn.

Expected behavior:

1. Dynamic Capability changes should be rate limited per peer.
2. Repeated SET/UNSET toggles for the same AFI/SAFI should have a cooldown.
3. Excessive capability changes should be ignored, delayed, or cause the peer to be reset.
4. Route announce/clear work should not be repeatedly triggered without throttling.
5. One peer should not be able to continuously consume control-plane resources through capability toggling.

For example, after one MP capability change for an AFI/SAFI, further changes for the same AFI/SAFI could be suppressed or delayed for a configured interval.

Actual behavior

FRR processes each accepted Dynamic Capability SET/UNSET message immediately.

Observed code behavior for MP capability SET:

if (action == CAPABILITY_ACTION_SET) {
    peer->afc_recv[afi][safi] = 1;
    if (peer->afc[afi][safi]) {
        peer->afc_nego[afi][safi] = 1;
        bgp_announce_route(peer, afi, safi, false);
    }
}

Observed code behavior for MP capability UNSET:

peer->afc_recv[afi][safi] = 0;
peer->afc_nego[afi][safi] = 0;

if (peer_active_nego(peer))
    bgp_clear_route(peer, afi, safi);
else
    goto done;

The parser then returns:

return BGP_PACKET_NOOP;

This allows the session to remain Established while repeated capability changes trigger repeated route processing.

There does not appear to be a per-peer rate limit, cooldown, or violation counter around this path.

Additional context

Impact

Type: Control-plane resource exhaustion / route churn
Affected daemon: bgpd
Attacker position: Established BGP peer
Required configuration: Dynamic Capability enabled for the peer
Default exposure: Lower, because Dynamic Capability is not enabled by default
Impact: CPU usage, route announce/withdraw churn, update-group churn, possible instability for other peers

A small amount of input can trigger much larger work in bgpd.

Example amplification pattern:

Small input:
  SET MP(afi/safi)
  UNSET MP(afi/safi)

Large internal work:
  bgp_announce_route()
  bgp_clear_route()
  route table walks
  update generation
  withdraw generation
  best-path/update-group side effects

On a router with a large RIB, repeatedly toggling an AFI/SAFI can cause significant route processing and UPDATE generation while the BGP session remains established.

Checklist

  • I have searched the open issues for this bug.
  • I have not included sensitive information in this report.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions