Hello BIRD maintainers,

I would like to report that BIRD does not currently implement RFC 8538
(Notification
Message Support for BGP Graceful Restart). This is not a protocol violation
— RFC
8538 is an optional extension that a speaker may choose not to implement.
However,
the lack of N-bit advertisement and Hard Reset handling limits
interoperability with
implementations that do support RFC 8538 (e.g., FRR, Cisco IOS-XR, Junos).

## Summary

RFC 8538 extends RFC 4724 Graceful Restart with three mechanisms:

1. **N-bit** (Notification bit, 0x4000 in the 16-bit Restart Flags + Time
field,
   i.e., 0x40 in the first byte): A speaker that is willing to send and
receive
   NOTIFICATION messages under RFC 8538 semantics MUST advertise this bit.
Only
   when both peers have advertised the N-bit is RFC 8538 behavior active.

2. **Hard Reset** (CEASE/subcode=9): When N-bit is mutually negotiated and a
   session teardown is intended to be unconditional (routes must be flushed
   immediately), the sender wraps applicable CEASE notifications inside a
   Hard Reset outer envelope (code=6, subcode=9, data=original
notification).

3. **Soft notification handling**: When N-bit is negotiated and a non-CEASE
   notification is sent/received, routes are retained in stale state (GR
hold)
   to allow a GR-style recovery, instead of being immediately withdrawn.

BIRD 2.x implements RFC 4724 base Graceful Restart but has no code for any
of the
above RFC 8538 behaviors.

## Affected Version

```text
BIRD version 2.0.7
```

Static code analysis also confirms the absence in the current development
tree.

## Observed Behavior

### Test 1 — N-bit not advertised in OPEN

A Python BGP peer connected to BIRD 2.0.7 with `graceful restart yes;
graceful
restart time 120;` and captured BIRD's OPEN message. The Graceful Restart
capability
(type=64) contained:

```text
Raw GR capability data: 0x007800010100
  16-bit Restart Flags + Time field: 0x0078
    Restart Flags nibble (bits 15-12): 0x0
      R-bit (0x8000 / bit 15): False
      N-bit (0x4000 / bit 14, RFC 8538): False   ← not set
    Restart Time (bits 11-0): 120s
  Per-AF: IPv4 unicast, F-bit=0
```

The N-bit (0x4000 in the 16-bit field, 0x40 in the first byte) is not set.
BIRD's
only defined GR restart flag is `BGP_GRF_RESTART` (0x80, the R-bit). There
is no
definition or code path for the RFC 8538 N-bit.

### Test 2 — CEASE not wrapped as Hard Reset

After session establishment, `birdc disable gr_test` triggered an admin
shutdown.
BIRD sent:

```text
NOTIFICATION: code=6 (CEASE), subcode=2 (Administrative Shutdown)
Data: (none)
```

This is a raw CEASE/AdminShutdown. RFC 8538 recommends that, when the N-bit
has been
exchanged, CEASE subcodes such as Administrative Shutdown be wrapped as
Hard Reset
(code=6, subcode=9) so the peer immediately flushes preserved routes.

## Expected Behavior

RFC 8538 is an optional extension, so BIRD is not required to implement it.
However,
if BIRD intends to support RFC 8538, the expected behavior would be:

1. Provide a configuration knob to advertise the N-bit (0x4000) in the GR
   capability when the operator enables RFC 8538 notification mode.

2. When the N-bit has been mutually negotiated and an admin shutdown
occurs, use
   Hard Reset encapsulation:
   ```text
   NOTIFICATION: code=6 (CEASE), subcode=9 (Hard Reset)
   Data: [original code=6][original subcode=2]
   ```

3. When receiving a non-CEASE notification from a peer that negotiated the
N-bit,
   retain the peer's routes in stale state instead of immediately
withdrawing them,
   enabling GR-style recovery from notification-triggered session drops.

## Source-Level Analysis

In `proto/bgp/packets.c`, `bgp_write_capabilities()` builds the GR
capability:

```c
if (caps->gr_aware)
{
  *buf++ = 64;               /* Capability 64: Support for graceful restart
*/
  *buf++ = 0;                /* length, filled later */
  data = buf;

  put_u16(buf, caps->gr_time);
  buf[0] |= caps->gr_flags;  /* only BGP_GRF_RESTART (0x80) defined */
  buf += 2;
  ...
}
```

`caps->gr_flags` is set in `bgp_prepare_capabilities()`:

```c
caps->gr_flags = p->p.gr_recovery ? BGP_GRF_RESTART : 0;
```

`BGP_GRF_RESTART` is defined as `0x80` (R-bit). The N-bit (`0x40` in the
first byte,
`0x4000` in the 16-bit field) is not defined anywhere in BIRD's source.

`bgp_create_notification()` writes NOTIFICATION messages directly:

```c
buf[0] = conn->notify_code;
buf[1] = conn->notify_subcode;
memcpy(buf+2, conn->notify_data, conn->notify_size);
return buf + 2 + conn->notify_size;
```

There is no Hard Reset wrapping, no N-bit negotiation check, and no
soft-notification
route-retention logic anywhere in the BIRD source.

## Comparison with FRR

FRR bgpd fully implements RFC 8538 (`bgp_open.h`):

```c
#define GRACEFUL_RESTART_R_BIT 0x8000
#define GRACEFUL_RESTART_N_BIT 0x4000   /* RFC 8538 */
```

In OPEN construction:
```c
SET_FLAG(gr_restart_time, GRACEFUL_RESTART_N_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
```

Negotiation check:
```c
bool bgp_has_graceful_restart_notification(struct peer *peer) {
    return CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) &&
           CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
}
```

Because BIRD never advertises the N-bit,
`bgp_has_graceful_restart_notification()`
always returns false on the FRR side for BIRD peers. Both implementations
correctly
fall back to RFC 4724 base GR behavior: this is an interoperability
limitation, not a
negotiated RFC 8538 failure.

## Dynamic Verification

Verified against BIRD 2.0.7 using a Python BGP peer that:
- Advertised the N-bit (0x4000) in its own OPEN to offer RFC 8538 to BIRD
- Parsed BIRD's OPEN response for the N-bit
- Triggered admin shutdown via `birdc` and captured BIRD's outgoing
NOTIFICATION

```text
TEST 1 (N-bit in OPEN)       : N_BIT_NOT_SET
  GR data 0x0078... → Restart Flags nibble = 0x0 → N-bit absent
TEST 2 (Hard Reset on CEASE) : CEASE_RAW
  NOTIFICATION code=6/sub=2 (AdminShutdown) — not wrapped as Hard Reset

RESULT: BIRD does NOT implement RFC 8538
```

## Impact

There is no current security or operational impact in BIRD-only or BIRD-FRR
deployments, because the N-bit is never mutually negotiated and both sides
fall back to standard RFC 4724 GR behavior.

The forward-looking concern is: if BIRD adds N-bit advertisement in the
future
without also implementing Hard Reset and soft-notification semantics,
sessions
with RFC 8538-capable peers could exhibit asymmetric teardown. Specifically:
- BIRD sends a raw CEASE/AdminShutdown (no Hard Reset envelope)
- The RFC 8538 peer interprets this as a soft GR event and retains stale
routes
  for the full restart timer window, instead of flushing them immediately

This would be a behavioral surprise for operators who configure BIRD as an
RFC 8538
peer in a mixed-vendor network.

## Suggested Fix

If RFC 8538 support is planned:

1. Define the N-bit flag:
   ```c
   #define BGP_GRF_NOTIFICATION 0x40   /* RFC 8538 N-bit, 0x4000 in 16-bit
field */
   ```

2. Add a configuration knob and set the bit in `bgp_prepare_capabilities()`
when
   the operator enables GR notification mode.

3. Implement Hard Reset wrapping in the NOTIFICATION send path when N-bit
is active.

4. On NOTIFICATION receive, when N-bit has been negotiated and the
notification is
   not a Hard Reset, retain peer routes (stale hold) instead of immediate
withdrawal.

Best regards.

Reply via email to