Skip to content

Commit

Permalink
Merge pull request #14614 from opensourcerouting/feature/bgpd_handle_…
Browse files Browse the repository at this point in the history
…orf_capability_via_dynamic_capability

bgpd: Handle ORF capability using dynamic capabilities
  • Loading branch information
donaldsharp authored Oct 19, 2023
2 parents 2775d22 + 2c0c11f commit 6278888
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 33 deletions.
17 changes: 8 additions & 9 deletions bgpd/bgp_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,15 +340,14 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi,
peer->host, afi, safi, type, mode);
}

static const struct message orf_type_str[] = {
{ORF_TYPE_RESERVED, "Reserved"},
{ORF_TYPE_PREFIX, "Prefixlist"},
{0}};

static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"},
{ORF_MODE_SEND, "Send"},
{ORF_MODE_BOTH, "Both"},
{0}};
const struct message orf_type_str[] = { { ORF_TYPE_RESERVED, "Reserved" },
{ ORF_TYPE_PREFIX, "Prefixlist" },
{ 0 } };

const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" },
{ ORF_MODE_SEND, "Send" },
{ ORF_MODE_BOTH, "Both" },
{ 0 } };

static int bgp_capability_orf_entry(struct peer *peer,
struct capability_header *hdr)
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_open.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,7 @@ extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
bool use_json, json_object *json_neigh);
extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length);
extern const struct message capcode_str[];
extern const struct message orf_type_str[];
extern const struct message orf_mode_str[];

#endif /* _QUAGGA_BGP_OPEN_H */
195 changes: 193 additions & 2 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,8 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
uint32_t gr_restart_time;
uint8_t addpath_afi_safi_count = 0;
bool adv_addpath_tx = false;
unsigned long number_of_orfs_p;
uint8_t number_of_orfs = 0;
const char *capability = lookup_msg(capcode_str, capability_code,
"Unknown");

Expand Down Expand Up @@ -1458,8 +1460,78 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi2str(pkt_safi));

break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_ORF:
/* Convert AFI, SAFI to values for packet. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);

stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_ORF);
cap_len = stream_get_endp(s);
stream_putc(s, 0);

stream_putw(s, pkt_afi); /* Address Family Identifier */
stream_putc(s, 0); /* Reserved */
stream_putc(s,
pkt_safi); /* Subsequent Address Family Identifier */

number_of_orfs_p =
stream_get_endp(s); /* Number of ORFs pointer */
stream_putc(s, 0); /* Number of ORFs */

/* Address Prefix ORF */
if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_SM) ||
CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_RM)) {
stream_putc(s, ORF_TYPE_PREFIX);

if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_SM) &&
CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_RM)) {
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_ADV);
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_RM_ADV);
stream_putc(s, ORF_MODE_BOTH);
} else if (CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_ORF_PREFIX_SM)) {
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_ADV);
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_RM_ADV);
stream_putc(s, ORF_MODE_SEND);
} else {
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_RM_ADV);
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_ADV);
stream_putc(s, ORF_MODE_RECEIVE);
}
number_of_orfs++;
} else {
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_ADV);
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_RM_ADV);
}

/* Total Number of ORFs. */
stream_putc_at(s, number_of_orfs_p, number_of_orfs);

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 %s for afi/safi: %s/%s",
peer,
action == CAPABILITY_ACTION_SET
? "Advertising"
: "Removing",
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
Expand Down Expand Up @@ -3044,6 +3116,123 @@ static void bgp_dynamic_capability_addpath(uint8_t *pnt, int action,
}
}

static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
{
uint8_t *data = pnt + 3;
uint8_t *end = data + hdr->length;
size_t len = end - data;

struct capability_mp_data mpc;
uint8_t num;
iana_afi_t pkt_afi;
afi_t afi;
iana_safi_t pkt_safi;
safi_t safi;
uint8_t type;
uint8_t mode;
uint16_t sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
uint16_t rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
int i;

if (data + CAPABILITY_CODE_ORF_LEN > end) {
flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
"ORF: Received invalid length %zu, less than %d", len,
CAPABILITY_CODE_ORF_LEN);
return;
}

/* ORF Entry header */
memcpy(&mpc, data, sizeof(mpc));
data += sizeof(mpc);
num = *data++;
pkt_afi = ntohs(mpc.afi);
pkt_safi = mpc.safi;

/* Convert AFI, SAFI to internal values, check. */
if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
zlog_info("%pBP Addr-family %d/%d not supported. Ignoring the ORF capability",
peer, pkt_afi, pkt_safi);
return;
}

/* validate number field */
if (CAPABILITY_CODE_ORF_LEN + (num * 2) > hdr->length) {
zlog_info("%pBP ORF Capability entry length error, Cap length %u, num %u",
peer, hdr->length, num);
return;
}

if (action == CAPABILITY_ACTION_UNSET) {
UNSET_FLAG(peer->af_cap[afi][safi], sm_cap);
UNSET_FLAG(peer->af_cap[afi][safi], rm_cap);
return;
}

for (i = 0; i < num; i++) {
if (data + 1 > end) {
flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH,
"%pBP ORF Capability entry length (type) error, Cap length %u, num %u",
peer, hdr->length, num);
return;
}
type = *data++;

if (data + 1 > end) {
flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH,
"%pBP ORF Capability entry length (mode) error, Cap length %u, num %u",
peer, hdr->length, num);
return;
}
mode = *data++;

/* ORF Mode error check */
switch (mode) {
case ORF_MODE_BOTH:
case ORF_MODE_SEND:
case ORF_MODE_RECEIVE:
break;
default:
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP Addr-family %d/%d has ORF type/mode %d/%d not supported",
peer, afi, safi, type, mode);
continue;
}

if (!((afi == AFI_IP && safi == SAFI_UNICAST) ||
(afi == AFI_IP && safi == SAFI_MULTICAST) ||
(afi == AFI_IP6 && safi == SAFI_UNICAST))) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP Addr-family %d/%d unsupported AFI/SAFI received",
peer, afi, safi);
continue;
}

if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP OPEN has %s ORF capability as %s for afi/safi: %s/%s",
peer, lookup_msg(orf_type_str, type, NULL),
lookup_msg(orf_mode_str, mode, NULL),
iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));

switch (mode) {
case ORF_MODE_BOTH:
SET_FLAG(peer->af_cap[afi][safi], sm_cap);
SET_FLAG(peer->af_cap[afi][safi], rm_cap);
break;
case ORF_MODE_SEND:
SET_FLAG(peer->af_cap[afi][safi], sm_cap);
UNSET_FLAG(peer->af_cap[afi][safi], rm_cap);
break;
case ORF_MODE_RECEIVE:
SET_FLAG(peer->af_cap[afi][safi], rm_cap);
UNSET_FLAG(peer->af_cap[afi][safi], sm_cap);
break;
}
}
}

static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
Expand Down Expand Up @@ -3401,8 +3590,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ADDPATH:
bgp_dynamic_capability_addpath(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
Expand Down
70 changes: 48 additions & 22 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -5831,24 +5831,37 @@ DEFUN (neighbor_capability_orf_prefix,
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
int ret;

peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;

if (strmatch(argv[idx_send_recv]->text, "send"))
return peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM);
if (strmatch(argv[idx_send_recv]->text, "send")) {
ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_SET);
return ret;
}

if (strmatch(argv[idx_send_recv]->text, "receive"))
return peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
if (strmatch(argv[idx_send_recv]->text, "receive")) {
ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_SET);
return ret;
}

if (strmatch(argv[idx_send_recv]->text, "both"))
return peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM)
| peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
if (strmatch(argv[idx_send_recv]->text, "both")) {
ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM) |
peer_af_flag_set_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_SET);
return ret;
}

return CMD_WARNING_CONFIG_FAILED;
}
Expand Down Expand Up @@ -5883,24 +5896,37 @@ DEFUN (no_neighbor_capability_orf_prefix,
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
int ret;

peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;

if (strmatch(argv[idx_send_recv]->text, "send"))
return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM);
if (strmatch(argv[idx_send_recv]->text, "send")) {
ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_UNSET);
return ret;
}

if (strmatch(argv[idx_send_recv]->text, "receive"))
return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
if (strmatch(argv[idx_send_recv]->text, "receive")) {
ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_UNSET);
return ret;
}

if (strmatch(argv[idx_send_recv]->text, "both"))
return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM)
| peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
if (strmatch(argv[idx_send_recv]->text, "both")) {
ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_SM) |
peer_af_flag_unset_vty(vty, peer_str, afi, safi,
PEER_FLAG_ORF_PREFIX_RM);
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
CAPABILITY_ACTION_UNSET);
return ret;
}

return CMD_WARNING_CONFIG_FAILED;
}
Expand Down
22 changes: 22 additions & 0 deletions bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4979,6 +4979,16 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
else if (flag == PEER_FLAG_ORF_PREFIX_RM)
peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;

/* We should not reset the session if
* dynamic capability is enabled and we
* are changing the ORF prefix flags.
*/
if ((CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) &&
(flag == PEER_FLAG_ORF_PREFIX_RM ||
flag == PEER_FLAG_ORF_PREFIX_SM))
action.type = peer_change_none;

peer_change_action(peer, afi, safi, action.type);
}
}
Expand Down Expand Up @@ -5039,6 +5049,18 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
member->last_reset =
PEER_DOWN_CAPABILITY_CHANGE;

/* We should not reset the session if
* dynamic capability is enabled and we
* are changing the ORF prefix flags.
*/
if ((CHECK_FLAG(peer->cap,
PEER_CAP_DYNAMIC_RCV) &&
CHECK_FLAG(peer->cap,
PEER_CAP_DYNAMIC_ADV)) &&
(flag == PEER_FLAG_ORF_PREFIX_RM ||
flag == PEER_FLAG_ORF_PREFIX_SM))
action.type = peer_change_none;

peer_change_action(member, afi, safi,
action.type);
}
Expand Down
2 changes: 2 additions & 0 deletions tests/topotests/bgp_dynamic_capability/r1/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ router bgp 65001
neighbor 192.168.1.2 addpath-tx-all-paths
exit-address-family
!
ip prefix-list r2 seq 5 permit 10.10.10.10/32
!
Loading

0 comments on commit 6278888

Please sign in to comment.