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");
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:
}
}
+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)
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:
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;
}
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;
}