Skip to content

Commit

Permalink
Merge pull request FRRouting#14285 from opensourcerouting/feature/gra…
Browse files Browse the repository at this point in the history
…ceful_restart_dynamic_capability

bgpd: Handle Graceful Restart capability using dynamic capabilities
  • Loading branch information
riw777 authored Sep 5, 2023
2 parents 9770c83 + 14e3452 commit 92515dc
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 5 deletions.
158 changes: 156 additions & 2 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
unsigned long cap_len;
uint16_t len;
uint32_t gr_restart_time;

if (!peer_established(peer))
return;
Expand Down Expand Up @@ -1268,9 +1269,64 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
: "Removing",
iana_afi2str(pkt_afi), iana_safi2str(pkt_safi));
break;
case CAPABILITY_CODE_RESTART:
if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) &&
!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
return;

SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_RESTART);
cap_len = stream_get_endp(s);
stream_putc(s, 0);
gr_restart_time = peer->bgp->restart_time;

if (peer->bgp->t_startup) {
SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV);
}

if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_GRACEFUL_NOTIFICATION)) {
SET_FLAG(gr_restart_time, GRACEFUL_RESTART_N_BIT);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
}

stream_putw(s, gr_restart_time);

if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
FOREACH_AFI_SAFI (afi, safi) {
if (!peer->afc[afi][safi])
continue;

bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
&pkt_safi);
stream_putw(s, pkt_afi);
stream_putc(s, pkt_safi);
if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_GR_PRESERVE_FWD))
stream_putc(s, GRACEFUL_RESTART_F_BIT);
else
stream_putc(s, 0);
}
}

/* Software Version capability Len. */
len = stream_get_endp(s) - cap_len - 1;
stream_putc_at(s, cap_len, len);

if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP sending CAPABILITY has %s Graceful-Restart CAP for afi/safi: %s/%s",
peer,
action == CAPABILITY_ACTION_SET
? "Advertising"
: "Removing",
iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));

break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_ORF:
case CAPABILITY_CODE_RESTART:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ADDPATH:
Expand Down Expand Up @@ -2753,6 +2809,93 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
return BGP_PACKET_NOOP;
}

static void bgp_dynamic_capability_graceful_restart(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
{
#define GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE 4
uint16_t gr_restart_flag_time;
uint8_t *data = pnt + 3;
uint8_t *end = pnt + hdr->length;
size_t len = end - data;

if (action == CAPABILITY_ACTION_SET) {
if (len < sizeof(gr_restart_flag_time)) {
zlog_err("%pBP: Received invalid Graceful-Restart capability length %d",
peer, hdr->length);
return;
}

SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV);
ptr_get_be16(data, &gr_restart_flag_time);
data += sizeof(gr_restart_flag_time);

if (CHECK_FLAG(gr_restart_flag_time, GRACEFUL_RESTART_R_BIT))
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV);
else
UNSET_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV);

if (CHECK_FLAG(gr_restart_flag_time, GRACEFUL_RESTART_N_BIT))
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV);
else
UNSET_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV);

UNSET_FLAG(gr_restart_flag_time, 0xF000);
peer->v_gr_restart = gr_restart_flag_time;

while (data + GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE <=
end) {
afi_t afi;
safi_t safi;
iana_afi_t pkt_afi;
iana_safi_t pkt_safi;
struct graceful_restart_af graf;

memcpy(&graf, data, sizeof(graf));
pkt_afi = ntohs(graf.afi);
pkt_safi = safi_int2iana(graf.safi);

/* Convert AFI, SAFI to internal values, check. */
if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi,
&safi)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP: Addr-family %s/%s(afi/safi) not supported. Ignore the Graceful Restart capability for this AFI/SAFI",
peer, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
} else if (!peer->afc[afi][safi]) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP: Addr-family %s/%s(afi/safi) not enabled. Ignore the Graceful Restart capability",
peer, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
} else {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP: Address family %s is%spreserved",
peer,
get_afi_safi_str(afi, safi,
false),
CHECK_FLAG(peer->af_cap[afi]
[safi],
PEER_CAP_RESTART_AF_PRESERVE_RCV)
? " "
: " not ");

SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_RESTART_AF_RCV);
if (CHECK_FLAG(graf.flag,
GRACEFUL_RESTART_F_BIT))
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_RESTART_AF_PRESERVE_RCV);
}

data += GRACEFUL_RESTART_CAPABILITY_PER_AFI_SAFI_SIZE;
}
} else {
UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV);
}
}

/**
* Parse BGP CAPABILITY message for peer.
*
Expand Down Expand Up @@ -2886,9 +3029,20 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
return BGP_Stop;
}
break;
case CAPABILITY_CODE_RESTART:
if ((hdr->length - 2) % 4) {
zlog_err("%pBP: Received invalid Graceful-Restart capability length %d",
peer, hdr->length);
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}

bgp_dynamic_capability_graceful_restart(pnt, action,
hdr, peer);
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_ORF:
case CAPABILITY_CODE_RESTART:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ADDPATH:
Expand Down
23 changes: 23 additions & 0 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -3066,9 +3066,17 @@ DEFUN (bgp_graceful_restart_restart_time,
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
uint32_t restart;
struct listnode *node, *nnode;
struct peer *peer;

restart = strtoul(argv[idx_number]->arg, NULL, 10);
bgp->restart_time = restart;

for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
CAPABILITY_CODE_RESTART,
CAPABILITY_ACTION_SET);

return CMD_SUCCESS;
}

Expand Down Expand Up @@ -3119,8 +3127,16 @@ DEFUN (no_bgp_graceful_restart_restart_time,
"Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
struct listnode *node, *nnode;
struct peer *peer;

bgp->restart_time = BGP_DEFAULT_RESTART_TIME;

for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
CAPABILITY_CODE_RESTART,
CAPABILITY_ACTION_UNSET);

return CMD_SUCCESS;
}

Expand Down Expand Up @@ -3175,12 +3191,19 @@ DEFPY (bgp_graceful_restart_notification,
"Indicate Graceful Restart support for BGP NOTIFICATION messages\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
struct listnode *node, *nnode;
struct peer *peer;

if (no)
UNSET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);
else
SET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION);

for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
CAPABILITY_CODE_RESTART,
CAPABILITY_ACTION_SET);

return CMD_SUCCESS;
}

Expand Down
9 changes: 6 additions & 3 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,10 @@ The following functionality is provided by graceful restart:
1. The feature allows the restarting router to indicate to the helping peer the
routes it can preserve in its forwarding plane during control plane restart
by sending graceful restart capability in the OPEN message sent during
session establishment.
session establishment. Graceful restart notification flag and/or restart
time can also be changed during the dynamic BGP capabilities. If using
dynamic capabilities, no session reset is required, thus it's very useful
to increase restart time before doing a software upgrade or so.
2. The feature allows helping router to advertise to all other peers the routes
received from the restarting router which are preserved in the forwarding
plane of the restarting router during control plane restart.
Expand Down Expand Up @@ -2160,8 +2163,8 @@ Using AS Path in Route Map
Remove some AS numbers from the AS_PATH of the BGP path's NLRI. Removed AS
numbers are conformant with the regex defined in as-path access-list WORD.
The no form of this command removes this set operation from the route-map.


.. _bgp-communities-attribute:

Communities Attribute
Expand Down
1 change: 1 addition & 0 deletions tests/topotests/bgp_dynamic_capability/r1/bgpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
!
router bgp 65001
no bgp ebgp-requires-policy
bgp graceful-restart
neighbor 192.168.1.2 remote-as external
neighbor 192.168.1.2 timers 1 3
neighbor 192.168.1.2 timers connect 1
Expand Down
1 change: 1 addition & 0 deletions tests/topotests/bgp_dynamic_capability/r2/bgpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
!debug bgp neighbor
!
router bgp 65002
bgp graceful-restart
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as external
neighbor 192.168.1.1 timers 1 3
Expand Down
Loading

0 comments on commit 92515dc

Please sign in to comment.