diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c178844cc9bc..ec5fa7b74dbe 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4163,6 +4163,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, switch (nh_afi) { case AFI_IP: switch (safi) { + case SAFI_RTC: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4196,6 +4197,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, break; case AFI_IP6: switch (safi) { + case SAFI_RTC: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4311,6 +4313,12 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, case SAFI_ENCAP: assert(!"Please add proper encoding of SAFI_ENCAP"); break; + case SAFI_RTC: + stream_putc(s, p->prefixlen); + stream_putl(s, p->u.prefix_rtc.origin_as); + stream_put(s, &p->u.prefix_rtc.route_target, + PSIZE(p->prefixlen) - 4); + break; } } @@ -4349,6 +4357,8 @@ size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, case SAFI_FLOWSPEC: size = ((struct prefix_fs *)p)->prefix.prefixlen; break; + case SAFI_RTC: + size = p->prefixlen; } return size; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index fc54babaa360..3ff6ed9e554d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -42,6 +42,7 @@ #include "bgpd/bgp_trace.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_packet.h" +#include "bgpd/bgp_rtc.h" /* * Definitions and external declarations. @@ -547,8 +548,10 @@ static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn, /* Already mapped. */ return; - if (!irt) + if (!irt) { irt = import_rt_new(bgp, &eval_tmp); + bgp_rtc_add_static(bgp, eval, BGP_RTC_MAX_PREFIXLEN); + } /* Add VNI to the hash list for this RT. */ listnode_add(irt->vnis, vpn); @@ -559,11 +562,12 @@ static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn, * VNIs for this RT, then the RT hash is deleted. */ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, - struct irt_node *irt) + struct irt_node *irt, struct ecommunity_val *eval) { /* Delete VNI from hash list for this RT. */ listnode_delete(irt->vnis, vpn); if (!listnode_head(irt->vnis)) { + bgp_rtc_remove_static(bgp, eval, BGP_RTC_MAX_PREFIXLEN); import_rt_free(bgp, irt); } } @@ -6191,7 +6195,7 @@ void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn) irt = lookup_import_rt(bgp, &eval_tmp); if (irt) - unmap_vni_from_rt(bgp, vpn, irt); + unmap_vni_from_rt(bgp, vpn, irt, eval); } } } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 42ba54ab7bca..2f432abb4bfa 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1537,6 +1537,12 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) } } + /* Reset the rtc-plist */ + if (peer->rtc_plist != NULL) { + prefix_list_delete(peer->rtc_plist); + peer->rtc_plist = NULL; + } + /* Reset keepalive and holdtime */ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) { peer->v_keepalive = peer->keepalive; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 945076709c5c..42b4c2cfa4ce 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -201,6 +201,12 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, "capabilityErrorMultiProtocolSafi", "flowspec"); break; + case SAFI_RTC: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolSafi", + "rtc"); + break; case SAFI_UNSPEC: case SAFI_MAX: json_object_int_add( @@ -250,6 +256,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, case SAFI_EVPN: vty_out(vty, "SAFI EVPN"); break; + case SAFI_RTC: + vty_out(vty, "SAFI RTC"); + break; case SAFI_UNSPEC: case SAFI_MAX: vty_out(vty, "SAFI Unknown %d ", @@ -1475,19 +1484,20 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, error. */ if (*mp_capability && !CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { - if (!peer->afc_nego[AFI_IP][SAFI_UNICAST] - && !peer->afc_nego[AFI_IP][SAFI_MULTICAST] - && !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] - && !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] - && !peer->afc_nego[AFI_IP][SAFI_ENCAP] - && !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] - && !peer->afc_nego[AFI_IP6][SAFI_UNICAST] - && !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - && !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] - && !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - && !peer->afc_nego[AFI_IP6][SAFI_ENCAP] - && !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { + if (!peer->afc_nego[AFI_IP][SAFI_UNICAST] && + !peer->afc_nego[AFI_IP][SAFI_MULTICAST] && + !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] && + !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && + !peer->afc_nego[AFI_IP][SAFI_ENCAP] && + !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] && + !peer->afc_nego[AFI_IP][SAFI_RTC] && + !peer->afc_nego[AFI_IP6][SAFI_UNICAST] && + !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && + !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] && + !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && + !peer->afc_nego[AFI_IP6][SAFI_ENCAP] && + !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] && + !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { flog_err(EC_BGP_PKT_OPEN, "%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities", peer->host); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2a2c9bdba996..4ed289dbaf50 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -50,6 +50,7 @@ #include "bgpd/bgp_keepalives.h" #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_trace.h" +#include "bgpd/bgp_rtc.h" DEFINE_HOOK(bgp_packet_dump, (struct peer *peer, uint8_t type, bgp_size_t size, @@ -351,6 +352,8 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); case SAFI_FLOWSPEC: return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw); + case SAFI_RTC: + return bgp_nlri_parse_rtc(peer, attr, packet, mp_withdraw); } return BGP_NLRI_PARSE_ERROR; } @@ -2146,6 +2149,7 @@ static int bgp_open_receive(struct peer_connection *connection, peer->afc[AFI_IP][SAFI_LABELED_UNICAST]; peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] = peer->afc[AFI_IP][SAFI_FLOWSPEC]; + peer->afc_nego[AFI_IP][SAFI_RTC] = peer->afc[AFI_IP][SAFI_RTC]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 982f64a86004..73148f19caa7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-or-later /* BGP routing information * Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro * Copyright (C) 2016 Job Snijders @@ -75,6 +74,7 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_pbr.h" +#include "bgpd/bgp_rtc.h" #include "bgpd/bgp_route_clippy.c" @@ -2515,6 +2515,14 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_otc_egress(peer, attr)) return false; + /* RTC-Filtering */ + if (peer->afc[AFI_IP][SAFI_RTC]) { + /* The update group should only have one peer */ + onlypeer = SUBGRP_PFIRST(subgrp)->peer; + if (bgp_rtc_filter(onlypeer, attr, p)) + return false; + } + if (filter->advmap.update_type == UPDATE_TYPE_WITHDRAW && filter->advmap.aname && route_map_lookup_by_name(filter->advmap.aname)) { @@ -3549,6 +3557,7 @@ static void bgp_lu_handle_label_allocation(struct bgp *bgp, CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) { bgp_unregister_for_label(dest); } + } static struct interface * @@ -6634,6 +6643,11 @@ static void bgp_nexthop_reachability_check(afi_t afi, safi_t safi, struct bgp *bgp, struct bgp *bgp_nexthop) { + if (safi == SAFI_RTC) { + bgp_unlink_nexthop(bpi); + + bgp_path_info_set_flag(dest, bpi, BGP_PATH_VALID); + } /* Nexthop reachability check. */ if (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)) { @@ -6665,12 +6679,12 @@ static void bgp_nexthop_reachability_check(afi_t afi, safi_t safi, } } -static struct bgp_static *bgp_static_new(void) +struct bgp_static *bgp_static_new(void) { return XCALLOC(MTYPE_BGP_STATIC, sizeof(struct bgp_static)); } -static void bgp_static_free(struct bgp_static *bgp_static) +void bgp_static_free(struct bgp_static *bgp_static) { XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); route_map_counter_decrement(bgp_static->rmap.map); @@ -12036,6 +12050,69 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa return CMD_SUCCESS; } +int bgp_show_table_rtc(struct vty *vty, struct bgp *bgp, safi_t safi, + struct bgp_table *table, enum bgp_show_type type, + void *output_arg, uint16_t show_flags); +int bgp_show_table_rtc(struct vty *vty, struct bgp *bgp, safi_t safi, + struct bgp_table *table, enum bgp_show_type type, + void *output_arg, uint16_t show_flags) +{ + struct bgp_dest *dest, *next; + unsigned long output_cum = 0; + unsigned long total_cum = 0; + struct bgp_table *itable; + bool show_msg; + bool use_json = !!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + + show_msg = (!use_json && type == bgp_show_type_normal); + + for (dest = bgp_table_top(table); dest; dest = next) { + struct prefix local_p = {}; + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + local_p = *dest_p; + + next = bgp_route_next(dest); + + itable = bgp_dest_get_bgp_table_info(dest); + if (itable != NULL) { + + struct bgp_path_info *pi = + bgp_dest_get_bgp_path_info(dest); + struct ecommunity *ecom = ecommunity_parse( + local_p.u.prefix_rtc.route_target, 8, true); + char *ecomstr = ecommunity_ecom2str( + ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); + vty_out(vty, + "Prefix: \n\tRoute Target: %s/%u\n\tOrigin-as: %u\n", + ecomstr, local_p.prefixlen, + local_p.u.prefix_rtc.origin_as); + XFREE(MTYPE_ECOMMUNITY_STR, ecomstr); + ecommunity_unintern(&ecom); + route_vty_out_detail_header(vty, bgp, dest, &local_p, + NULL, AFI_IP, safi, NULL, + false); + route_vty_out_detail(vty, bgp, dest, &local_p, pi, + AFI_IP, safi, RPKI_NOT_BEING_USED, + NULL); + if (next == NULL) + show_msg = false; + } + } + if (show_msg) { + if (output_cum == 0) + vty_out(vty, "No BGP prefixes displayed, %ld exist\n", + total_cum); + else + vty_out(vty, + "\nDisplayed %ld routes and %ld total paths\n", + output_cum, total_cum); + } else { + if (use_json && output_cum == 0) + vty_out(vty, "{}\n"); + } + return CMD_SUCCESS; +} + int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd_match, enum bgp_show_type type, void *output_arg, @@ -12481,6 +12558,7 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: + case SAFI_RTC: case SAFI_FLOWSPEC: case SAFI_MAX: return NULL; @@ -16153,7 +16231,28 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, p = bgp_dest_get_prefix(dest); - vty_out(vty, " network %pFX", p); + if (safi == SAFI_RTC) { + /* Only prefixes with a length of more than 48 have the + * type and subtype field set. If those aren't set + * ecommunity_ecom2str returns just UNK: */ + if (p->prefixlen >= 48) { + struct ecommunity *ecom = ecommunity_parse( + (unsigned char *)&p->u.prefix_rtc + .route_target, + 8, false); + char *b = ecommunity_ecom2str( + ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt %s", b); + ecommunity_unintern(&ecom); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + vty_out(vty, " rt 0:0"); + } + vty_out(vty, "/%d", p->prefixlen); + } else { + vty_out(vty, " network %pFX", p); + } if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) vty_out(vty, " label-index %u", diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 5b433b555813..639f74543898 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -787,6 +787,8 @@ extern int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, uint32_t label_index, int evpn_type, const char *esi, const char *gwip, const char *ethtag, const char *routermac); +extern struct bgp_static *bgp_static_new(void); +extern void bgp_static_free(struct bgp_static *bgp_static); /* this is primarily for MPLS-VPN */ extern void bgp_update(struct peer *peer, const struct prefix *p, @@ -800,6 +802,12 @@ extern void bgp_withdraw(struct peer *peer, const struct prefix *p, int sub_type, struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels); +extern void bgp_static_update(struct bgp *bgp, const struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, + safi_t safi); +extern void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd); + /* for bgp_nexthop and bgp_damp */ extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi, afi_t afi, safi_t safi); diff --git a/bgpd/bgp_rtc.c b/bgpd/bgp_rtc.c new file mode 100644 index 000000000000..96c8f6de4399 --- /dev/null +++ b/bgpd/bgp_rtc.c @@ -0,0 +1,205 @@ +#include "bgpd/bgp_rtc.h" +#include "bgpd/bgp_debug.h" +#include "bgp_route.h" + +int bgp_nlri_parse_rtc(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, bool withdraw) +{ + uint8_t *pnt = packet->nlri; + uint8_t *lim = packet->nlri + packet->length; + int psize = 0; + /* Iterate over all received prefixes */ + for (; pnt < lim; pnt += psize) { + struct prefix p = {0}; + p.prefixlen = *pnt++; + if (p.prefixlen > BGP_RTC_MAX_PREFIXLEN || p.prefixlen < 32) { + zlog_err("SAFI_RTC parse error. Invalid prefixlen: %u", + p.prefixlen); + return BGP_NLRI_PARSE_ERROR; + } + p.family = AF_RTC; + psize = PSIZE(p.prefixlen); + if (pnt + psize > lim) { + zlog_err("SAFI_RTC parse error."); + return BGP_NLRI_PARSE_ERROR; + } + + /* Mask the value according to the prefixlen */ + for (int j = p.prefixlen; j < psize * 8; j++) { + pnt[j / 8] &= ~(1 << (j % 8)); + } + + p.u.prefix_rtc.origin_as = ntohl(*(uint32_t *)pnt); + + memcpy(&p.u.prefix_rtc.route_target, pnt + 4, psize - 4); + + if (withdraw) { + if (prefix_bgp_rtc_set(peer->host, &p, PREFIX_PERMIT, 0)) { + zlog_info("Withdrawn prefix %pFX is not in RTC prefix-list", + &p); + } + peer->rtc_plist = + prefix_list_get(AFI_IP, 0, 1, peer->host); + bgp_withdraw(peer, &p, 0, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + NULL, 0); + } else { + prefix_bgp_rtc_set(peer->host, &p, PREFIX_PERMIT, 1); + peer->rtc_plist = + prefix_list_get(AFI_IP, 0, 1, peer->host); + bgp_update(peer, &p, 0, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + NULL, 0, 0, NULL); + } + } + bgp_announce_route(peer, AFI_L2VPN, SAFI_EVPN, false); + return BGP_NLRI_PARSE_OK; +} + +int bgp_rtc_filter(struct peer *peer, struct attr *attr, const struct prefix *p) +{ + struct ecommunity *ecom = bgp_attr_get_ecommunity(attr); + if (ecom == NULL) { + return false; + } + + /* Build prefix to compare with */ + struct prefix cmp; + cmp.family = AF_RTC; + cmp.prefixlen = BGP_RTC_MAX_PREFIXLEN; + cmp.u.prefix_rtc.origin_as = peer->as; + + uint8_t *pnt; + uint8_t sub_type = 0; + for (uint32_t i = 0; i < ecom->size; i++) { + /* Retrieve value field */ + pnt = ecom->val + (i * ecom->unit_size); + + sub_type = *++pnt; + + if (sub_type == ECOMMUNITY_ROUTE_TARGET) { + if (peer->rtc_plist == NULL) { + if (BGP_DEBUG(update, UPDATE_OUT)) { + zlog_debug( + "Filtered prefix %pFX because RTC prefix-list does not exist", p); + } + return true; + } + memcpy(&cmp.u.prefix_rtc.route_target, + ecom->val + (i * ecom->unit_size), + ECOMMUNITY_SIZE); + if (prefix_list_apply_ext(peer->rtc_plist, NULL, &cmp, + true) == PREFIX_DENY) { + if (BGP_DEBUG(update, UPDATE_OUT)) { + zlog_debug( + "Filtered prefix %pFX because of RTC prefix-list", p); + } + return true; + } + } + } + return false; +} + +int bgp_rtc_static_from_str(struct vty *vty, struct bgp *bgp, const char *str, + bool add) +{ + struct ecommunity *ecom = NULL; + int plen = BGP_RTC_MAX_PREFIXLEN; + char *pnt; + char *cp; + + /* Find slash inside string. */ + pnt = strchr(str, '/'); + + /* String doesn't contain slash. */ + if (pnt == NULL) { + ecom = ecommunity_str2com(str, ECOMMUNITY_ROUTE_TARGET, 0); + if (ecom == NULL) { + vty_out(vty, "%% Can't parse ecommunity %s\n", str); + return CMD_WARNING_CONFIG_FAILED; + } + } else { + cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); + memcpy(cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ecom = ecommunity_str2com(cp, ECOMMUNITY_ROUTE_TARGET, 0); + + XFREE(MTYPE_TMP, cp); + if (ecom == NULL) { + vty_out(vty, "%% Can't parse ecommunity %s\n", str); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get prefix length. */ + plen = (uint8_t)atoi(++pnt); + if (plen > BGP_RTC_MAX_PREFIXLEN) { + ecommunity_free(&ecom); + vty_out(vty, "%% Invalid prefix length %d\n", plen); + return CMD_WARNING_CONFIG_FAILED; + } + } + if (add) + bgp_rtc_add_static(bgp, (struct ecommunity_val *)ecom->val, + plen); + else + bgp_rtc_remove_static(bgp, (struct ecommunity_val *)ecom->val, + plen); + + ecommunity_free(&ecom); + return CMD_SUCCESS; +} + +void bgp_rtc_add_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen) +{ + struct prefix prefix = {0}; + struct bgp_dest *dest; + struct bgp_static *bgp_static; + prefix.family = AF_RTC; + prefix.prefixlen = prefixlen; + prefix.u.prefix_rtc.origin_as = bgp->as; + memcpy(prefix.u.prefix_rtc.route_target, eval, PSIZE(prefixlen) - 4); + dest = bgp_node_get(bgp->route[AFI_IP][SAFI_RTC], &prefix); + + if (bgp_dest_has_bgp_path_info_data(dest)) { + bgp_dest_unlock_node(dest); + } else { + bgp_static = bgp_static_new(); + bgp_static->backdoor = 0; + bgp_static->valid = 0; + bgp_static->igpmetric = 0; + bgp_static->igpnexthop.s_addr = INADDR_ANY; + bgp_static->label = MPLS_INVALID_LABEL; + bgp_static->label_index = BGP_INVALID_LABEL_INDEX; + + bgp_dest_set_bgp_static_info(dest, bgp_static); + + bgp_static->valid = 1; + bgp_static_update(bgp, &prefix, bgp_static, AFI_IP, SAFI_RTC); + } +} + +void bgp_rtc_remove_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen) +{ + struct prefix prefix = {0}; + struct bgp_dest *dest; + struct bgp_static *bgp_static; + prefix.family = AF_RTC; + prefix.prefixlen = prefixlen; + prefix.u.prefix_rtc.origin_as = bgp->as; + memcpy(prefix.u.prefix_rtc.route_target, eval, PSIZE(prefixlen) - 4); + dest = bgp_node_get(bgp->route[AFI_IP][SAFI_RTC], &prefix); + + if (dest) { + bgp_static_withdraw(bgp, &prefix, AFI_IP, SAFI_RTC, NULL); + + bgp_static = bgp_dest_get_bgp_static_info(dest); + if (bgp_static != NULL) + bgp_static_free(bgp_static); + bgp_dest_set_bgp_static_info(dest, NULL); + bgp_dest_unlock_node(dest); + bgp_dest_unlock_node(dest); + } +} \ No newline at end of file diff --git a/bgpd/bgp_rtc.h b/bgpd/bgp_rtc.h new file mode 100644 index 000000000000..3fa0b786e0f7 --- /dev/null +++ b/bgpd/bgp_rtc.h @@ -0,0 +1,23 @@ +#ifndef BGP_RTC_H +#define BGP_RTC_H +#include +#include +#include +#include "bgpd.h" +#include "bgp_attr.h" +#include "bgp_ecommunity.h" +#include "vty.h" +#include "lib/prefix.h" + +#define BGP_RTC_MAX_PREFIXLEN 96 + +extern int bgp_nlri_parse_rtc(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, bool withdraw); +extern int bgp_rtc_filter(struct peer *peer, struct attr *attr, const struct prefix *p); +extern void bgp_rtc_add_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen); +extern void bgp_rtc_remove_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen); +int bgp_rtc_static_from_str(struct vty *vty, struct bgp *bgp, const char *str, + bool add); +#endif /* BGP_RTC_H */ \ No newline at end of file diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index b717793a4568..6194f15d6a9a 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -139,6 +139,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); dst->cap = src->cap; + dst->afc[AFI_IP][SAFI_RTC] = src->afc[AFI_IP][SAFI_RTC]; dst->af_cap[afi][safi] = src->af_cap[afi][safi]; dst->afc_nego[afi][safi] = src->afc_nego[afi][safi]; dst->orf_plist[afi][safi] = src->orf_plist[afi][safi]; @@ -438,6 +439,13 @@ static unsigned int updgrp_hash_key_make(const void *p) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)) key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2), key); + + if (afi == AFI_L2VPN && safi == SAFI_EVPN && + peer->afc[AFI_IP][SAFI_RTC]) { + key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2), + key); + } + /* * Multiple sessions with the same neighbor should get their own * update-group if they have different roles. @@ -514,6 +522,10 @@ static unsigned int updgrp_hash_key_make(const void *p) PEER_CAP_ORF_PREFIX_SM_RCV), (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)); + + zlog_debug("%pBP Update Group Hash: RTC: %u", peer, + peer->afc[AFI_IP][SAFI_RTC]); + zlog_debug( "%pBP Update Group Hash: local role: %u AIGP: %d SOO: %s", peer, peer->local_role, @@ -655,6 +667,11 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) !sockunion_same(&pe1->connection->su, &pe2->connection->su)) return false; + if (afi == AFI_L2VPN && safi == SAFI_EVPN && + (pe1->afc[AFI_IP][SAFI_RTC] != pe2->afc[AFI_IP][SAFI_RTC])) { + return false; + } + return true; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c9c7b8049644..4711aa7f283b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -65,6 +65,7 @@ #include "bgpd/bgp_mac.h" #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_conditional_adv.h" +#include "bgpd/bgp_rtc.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif @@ -181,6 +182,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV4_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV4_NODE; + case SAFI_RTC: + return BGP_RTC_NODE; case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -201,6 +204,7 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV6_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV6_NODE; + case SAFI_RTC: case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -236,6 +240,8 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi) return "IPv4 Encap"; if (safi == SAFI_FLOWSPEC) return "IPv4 Flowspec"; + if (safi == SAFI_RTC) + return "IPv4 RT-Constraint"; } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) return "IPv6 Unicast"; @@ -278,6 +284,8 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi) return "ipv4Encap"; if (safi == SAFI_FLOWSPEC) return "ipv4Flowspec"; + if (safi == SAFI_RTC) + return "ipv4Rtc"; } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) return "ipv6Unicast"; @@ -416,6 +424,9 @@ safi_t bgp_node_safi(struct vty *vty) case BGP_FLOWSPECV6_NODE: safi = SAFI_FLOWSPEC; break; + case BGP_RTC_NODE: + safi = SAFI_RTC; + break; default: safi = SAFI_UNICAST; break; @@ -480,6 +491,8 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_LABELED_UNICAST; else if (strmatch(safi_str, "flowspec")) safi = SAFI_FLOWSPEC; + else if (strmatch(safi_str, "rt-constraint")) + safi = SAFI_RTC; return safi; } @@ -546,6 +559,8 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) return "ipv4-labeled-unicast"; case SAFI_FLOWSPEC: return "ipv4-flowspec"; + case SAFI_RTC: + return "rt-constraint"; case SAFI_UNSPEC: case SAFI_EVPN: case SAFI_MAX: @@ -566,6 +581,7 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) return "ipv6-labeled-unicast"; case SAFI_FLOWSPEC: return "ipv6-flowspec"; + case SAFI_RTC: case SAFI_UNSPEC: case SAFI_EVPN: case SAFI_MAX: @@ -581,6 +597,7 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: case SAFI_ENCAP: case SAFI_LABELED_UNICAST: + case SAFI_RTC: case SAFI_FLOWSPEC: case SAFI_UNSPEC: case SAFI_MAX: @@ -10274,6 +10291,26 @@ static int vpn_policy_getdirs(struct vty *vty, const char *dstr, int *dodir) return CMD_SUCCESS; } +/* For testing purpose, static route of RTC. */ +DEFUN(rtc_network, rtc_network_cmd, "rt WORD", + "Add a route-target to announce\n" + "Specify the route-target e.g 65000:100/96\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return bgp_rtc_static_from_str(vty, bgp, argv[1]->arg, true); +} + + +/* For testing purpose, static route of RTC. */ +DEFUN(no_rtc_network, no_rtc_network_cmd, "no rt WORD", + NO_STR + "Remove a route-target no longer to announce\n" + "Specify the route-target e.g 65000:100/96\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return bgp_rtc_static_from_str(vty, bgp, argv[2]->arg, false); +} + DEFPY (af_rt_vpn_imexport, af_rt_vpn_imexport_cmd, "[no] vpn $direction_str RTLIST...", @@ -10831,6 +10868,15 @@ DEFUN_NOSH (address_family_evpn, return CMD_SUCCESS; } +DEFUN_NOSH(address_family_rtc, address_family_rtc_cmd, + "address-family ipv4 rt-constraint", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vty->node = BGP_RTC_NODE; + return CMD_SUCCESS; +} + DEFUN_NOSH (bgp_segment_routing_srv6, bgp_segment_routing_srv6_cmd, "segment-routing srv6", @@ -10965,13 +11011,12 @@ DEFUN_NOSH (exit_address_family, "exit-address-family", "Exit from Address Family configuration mode\n") { - if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE - || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE - || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE - || vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE - || vty->node == BGP_EVPN_NODE - || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || + vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || + vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE || + vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE || + vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE || + vty->node == BGP_FLOWSPECV6_NODE || vty->node == BGP_RTC_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -19248,6 +19293,8 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, vty_frame(vty, "ipv4 encap"); else if (safi == SAFI_FLOWSPEC) vty_frame(vty, "ipv4 flowspec"); + if (safi == SAFI_RTC) + vty_frame(vty, "ipv4 rt-constraint"); } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) vty_frame(vty, "ipv6 unicast"); @@ -19873,6 +19920,8 @@ int bgp_config_write(struct vty *vty) /* EVPN configuration. */ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_RTC); + hook_call(bgp_inst_config_write, bgp, vty); #ifdef ENABLE_BGP_VNC @@ -19997,6 +20046,13 @@ static struct cmd_node bgp_srv6_node = { .prompt = "%s(config-router-srv6)# ", }; +static struct cmd_node bgp_rtc_node = { + .name = "bgp rt-constraint", + .node = BGP_RTC_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-rtc)# ", +}; + static void community_list_vty(void); static void bgp_ac_peergroup(vector comps, struct cmd_token *token) @@ -20311,6 +20367,7 @@ void bgp_vty_init(void) install_node(&bgp_flowspecv4_node); install_node(&bgp_flowspecv6_node); install_node(&bgp_srv6_node); + install_node(&bgp_rtc_node); /* Install default VTY commands to new nodes. */ install_default(BGP_NODE); @@ -20327,6 +20384,7 @@ void bgp_vty_init(void) install_default(BGP_EVPN_NODE); install_default(BGP_EVPN_VNI_NODE); install_default(BGP_SRV6_NODE); + install_default(BGP_RTC_NODE); /* "global bgp inq-limit command */ install_element(CONFIG_NODE, &bgp_inq_limit_cmd); @@ -20481,6 +20539,13 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element(BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &no_rtc_network_cmd); + install_element(BGP_RTC_NODE, &rtc_network_cmd); + install_element(BGP_RTC_NODE, &bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + + /* "timers bgp" commands. */ install_element(BGP_NODE, &bgp_timers_cmd); install_element(BGP_NODE, &no_bgp_timers_cmd); @@ -20709,6 +20774,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &neighbor_activate_cmd); + install_element(BGP_RTC_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element(BGP_NODE, &no_neighbor_activate_hidden_cmd); @@ -20723,6 +20789,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_activate_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group" set commands. */ install_element(BGP_NODE, &neighbor_set_peer_group_cmd); @@ -20737,6 +20804,8 @@ void bgp_vty_init(void) &neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_set_peer_group_hidden_cmd); + install_element(BGP_RTC_NODE, &neighbor_set_peer_group_hidden_cmd); + /* "no neighbor peer-group unset" commands. */ install_element(BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -20751,6 +20820,7 @@ void bgp_vty_init(void) &no_neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_set_peer_group_hidden_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_set_peer_group_hidden_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element(BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd); @@ -20781,6 +20851,8 @@ void bgp_vty_init(void) &no_neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element(BGP_RTC_NODE, &neighbor_soft_reconfiguration_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd); @@ -20804,6 +20876,8 @@ void bgp_vty_init(void) install_element(BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd); + install_element(BGP_RTC_NODE, &neighbor_attr_unchanged_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_attr_unchanged_cmd); @@ -20836,6 +20910,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd); + install_element(BGP_RTC_NODE, &neighbor_nexthop_self_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor next-hop-self force" commands. */ install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd); @@ -20884,6 +20960,8 @@ void bgp_vty_init(void) &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element(BGP_RTC_NODE, &neighbor_nexthop_self_force_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_nexthop_self_force_cmd); /* "neighbor as-override" commands. */ install_element(BGP_NODE, &neighbor_as_override_hidden_cmd); @@ -21016,6 +21094,18 @@ void bgp_vty_init(void) &neighbor_remove_private_as_all_replace_as_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_RTC_NODE, &neighbor_remove_private_as_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_remove_private_as_cmd); + install_element(BGP_RTC_NODE, &neighbor_remove_private_as_all_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_remove_private_as_all_cmd); + install_element(BGP_RTC_NODE, + &neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_RTC_NODE, + &no_neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_RTC_NODE, + &neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_RTC_NODE, + &no_neighbor_remove_private_as_all_replace_as_cmd); /* "neighbor send-community" commands.*/ install_element(BGP_NODE, &neighbor_send_community_hidden_cmd); @@ -21063,6 +21153,10 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &neighbor_ecommunity_rpki_cmd); install_element(BGP_VPNV4_NODE, &neighbor_ecommunity_rpki_cmd); install_element(BGP_VPNV6_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_RTC_NODE, &neighbor_send_community_cmd); + install_element(BGP_RTC_NODE, &neighbor_send_community_type_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_send_community_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd); @@ -21100,6 +21194,8 @@ void bgp_vty_init(void) &no_neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_reflector_client_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd); @@ -21128,6 +21224,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_server_client_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_server_client_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_server_client_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor disable-addpath-rx" commands. */ install_element(BGP_IPV4_NODE, &neighbor_disable_addpath_rx_cmd); @@ -21309,6 +21407,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_capability_orf_prefix_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_capability_orf_prefix_cmd); /* "neighbor capability dynamic" commands.*/ install_element(BGP_NODE, &neighbor_capability_dynamic_cmd); @@ -21451,6 +21551,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_distribute_list_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element(BGP_NODE, &neighbor_prefix_list_hidden_cmd); @@ -21475,6 +21577,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd); @@ -21499,6 +21602,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_filter_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_filter_list_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element(BGP_NODE, &neighbor_route_map_hidden_cmd); @@ -21525,6 +21630,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd); @@ -21545,6 +21651,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + install_element(BGP_RTC_NODE, &neighbor_unsuppress_map_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor advertise-map" commands. */ install_element(BGP_NODE, &bgp_condadv_period_cmd); @@ -21673,6 +21781,15 @@ void bgp_vty_init(void) install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_maximum_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element(BGP_RTC_NODE, + &neighbor_maximum_prefix_threshold_warning_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element(BGP_RTC_NODE, + &neighbor_maximum_prefix_threshold_restart_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_maximum_prefix_cmd); /* "neighbor allowas-in" */ install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd); @@ -21695,6 +21812,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd); + install_element(BGP_RTC_NODE, &neighbor_allowas_in_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_allowas_in_cmd); /* neighbor accept-own */ install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd); @@ -21747,6 +21866,8 @@ void bgp_vty_init(void) install_element(BGP_NODE, &address_family_evpn_cmd); + install_element(BGP_NODE, &address_family_rtc_cmd); + /* "exit-address-family" command. */ install_element(BGP_IPV4_NODE, &exit_address_family_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); @@ -21759,6 +21880,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); + install_element(BGP_RTC_NODE, &exit_address_family_cmd); /* BGP retain all route-target */ install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a88de651f50c..c3ac4f8e9cca 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2143,6 +2143,8 @@ void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_FLOWSPEC], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_RTC], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_MULTICAST], @@ -4554,6 +4556,7 @@ bool peer_active(struct peer *peer) || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP][SAFI_FLOWSPEC] + || peer->afc[AFI_IP][SAFI_RTC] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] @@ -4568,19 +4571,20 @@ bool peer_active(struct peer *peer) /* If peer is negotiated at least one address family return 1. */ bool peer_active_nego(struct peer *peer) { - if (peer->afc_nego[AFI_IP][SAFI_UNICAST] - || peer->afc_nego[AFI_IP][SAFI_MULTICAST] - || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] - || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] - || peer->afc_nego[AFI_IP][SAFI_ENCAP] - || peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] - || peer->afc_nego[AFI_IP6][SAFI_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc_nego[AFI_IP6][SAFI_ENCAP] - || peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) + if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || + peer->afc_nego[AFI_IP][SAFI_MULTICAST] || + peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] || + peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || + peer->afc_nego[AFI_IP][SAFI_ENCAP] || + peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] || + peer->afc_nego[AFI_IP][SAFI_RTC] || + peer->afc_nego[AFI_IP6][SAFI_UNICAST] || + peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || + peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || + peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || + peer->afc_nego[AFI_IP6][SAFI_ENCAP] || + peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] || + peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) return true; return false; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7f1b82d9c763..a7965acf7678 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -89,6 +89,7 @@ enum bgp_af_index { BGP_AF_IPV6_LBL_UNICAST, BGP_AF_IPV4_FLOWSPEC, BGP_AF_IPV6_FLOWSPEC, + BGP_AF_RTC, BGP_AF_MAX }; @@ -1753,6 +1754,9 @@ struct peer { /* ORF Prefix-list */ struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; + /* Route Target Constrain list */ + struct prefix_list *rtc_plist; + /* Text description of last attribute rcvd */ char rcvd_attr_str[BUFSIZ]; @@ -2584,6 +2588,8 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV4_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV4_FLOWSPEC; + case SAFI_RTC: + return BGP_AF_RTC; case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2604,6 +2610,7 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV6_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV6_FLOWSPEC; + case SAFI_RTC: case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2621,6 +2628,7 @@ static inline int afindex(afi_t afi, safi_t safi) case SAFI_ENCAP: case SAFI_FLOWSPEC: case SAFI_UNSPEC: + case SAFI_RTC: case SAFI_MAX: return BGP_AF_MAX; } @@ -2644,13 +2652,13 @@ static inline int peer_group_active(struct peer *peer) /* If peer is negotiated at least one address family return 1. */ static inline int peer_afi_active_nego(const struct peer *peer, afi_t afi) { - if (peer->afc_nego[afi][SAFI_UNICAST] - || peer->afc_nego[afi][SAFI_MULTICAST] - || peer->afc_nego[afi][SAFI_LABELED_UNICAST] - || peer->afc_nego[afi][SAFI_MPLS_VPN] - || peer->afc_nego[afi][SAFI_ENCAP] - || peer->afc_nego[afi][SAFI_FLOWSPEC] - || peer->afc_nego[afi][SAFI_EVPN]) + if (peer->afc_nego[afi][SAFI_UNICAST] || + peer->afc_nego[afi][SAFI_MULTICAST] || + peer->afc_nego[afi][SAFI_LABELED_UNICAST] || + peer->afc_nego[afi][SAFI_MPLS_VPN] || + peer->afc_nego[afi][SAFI_ENCAP] || + peer->afc_nego[afi][SAFI_FLOWSPEC] || + peer->afc_nego[afi][SAFI_EVPN] || peer->afc_nego[afi][SAFI_RTC]) return 1; return 0; } @@ -2660,17 +2668,18 @@ static inline int peer_group_af_configured(struct peer_group *group) { struct peer *peer = group->conf; - if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] - || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] - || peer->afc[AFI_IP][SAFI_FLOWSPEC] - || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] - || peer->afc[AFI_IP6][SAFI_UNICAST] - || peer->afc[AFI_IP6][SAFI_MULTICAST] - || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] - || peer->afc[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc[AFI_IP6][SAFI_ENCAP] - || peer->afc[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc[AFI_L2VPN][SAFI_EVPN]) + if (peer->afc[AFI_IP][SAFI_UNICAST] || + peer->afc[AFI_IP][SAFI_MULTICAST] || + peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || + peer->afc[AFI_IP][SAFI_FLOWSPEC] || + peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || + peer->afc[AFI_IP][SAFI_RTC] || peer->afc[AFI_IP6][SAFI_UNICAST] || + peer->afc[AFI_IP6][SAFI_MULTICAST] || + peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || + peer->afc[AFI_IP6][SAFI_MPLS_VPN] || + peer->afc[AFI_IP6][SAFI_ENCAP] || + peer->afc[AFI_IP6][SAFI_FLOWSPEC] || + peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 2afcb2f45c8c..4b3cce0b9513 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -217,6 +217,7 @@ void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(!"Passed in safi should be impossible"); } @@ -3802,6 +3803,7 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: /* not expected */ flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi); @@ -4046,6 +4048,7 @@ static void rfapiProcessPeerDownRt(struct peer *peer, case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: /* Suppress uninitialized variable warning */ rt = NULL; diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index 146e0d18b549..fcfad22631ba 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -237,6 +237,7 @@ void rfapiMonitorExtraFlush(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(0); } @@ -305,6 +306,7 @@ void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(0); } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 6d6fad00745f..1442066de7e2 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -67,6 +67,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_routemap.c \ bgpd/bgp_routemap_nb.c \ bgpd/bgp_routemap_nb_config.c \ + bgpd/bgp_rtc.c \ bgpd/bgp_script.c \ bgpd/bgp_table.c \ bgpd/bgp_updgrp.c \ @@ -148,6 +149,7 @@ noinst_HEADERS += \ bgpd/bgp_rd.h \ bgpd/bgp_regex.h \ bgpd/bgp_rpki.h \ + bgpd/bgp_rtc.h \ bgpd/bgp_route.h \ bgpd/bgp_routemap_nb.h \ bgpd/bgp_script.h \ diff --git a/lib/command.h b/lib/command.h index cb105c656c18..397aa7de9ab7 100644 --- a/lib/command.h +++ b/lib/command.h @@ -184,6 +184,7 @@ enum node_type { RPKI_VRF_NODE, /* RPKI node for VRF */ PIM_NODE, /* PIM protocol mode */ PIM6_NODE, /* PIM protocol for IPv6 mode */ + BGP_RTC_NODE, /* BGP-RTC configuration node */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 39042d39ab9a..3db081b534c3 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -1120,10 +1120,10 @@ static int lib_prefix_list_create(struct nb_cb_create_args *args) name = yang_dnode_get_string(args->dnode, "name"); switch (type) { case 0: /* ipv4 */ - pl = prefix_list_get(AFI_IP, 0, name); + pl = prefix_list_get(AFI_IP, 0, 0, name); break; case 1: /* ipv6 */ - pl = prefix_list_get(AFI_IP6, 0, name); + pl = prefix_list_get(AFI_IP6, 0, 0, name); break; } diff --git a/lib/iana_afi.h b/lib/iana_afi.h index b9c19cc3d549..5cec59928b10 100644 --- a/lib/iana_afi.h +++ b/lib/iana_afi.h @@ -36,6 +36,7 @@ typedef enum { IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, IANA_SAFI_MPLS_VPN = 128, + IANA_SAFI_RTC = 132, /* BGP-RTC RFC 4684 */ IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; @@ -94,6 +95,8 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_LABELED_UNICAST; case IANA_SAFI_FLOWSPEC: return SAFI_FLOWSPEC; + case IANA_SAFI_RTC: + return SAFI_RTC; case IANA_SAFI_RESERVED: return SAFI_MAX; } @@ -118,6 +121,8 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_LABELED_UNICAST; case SAFI_FLOWSPEC: return IANA_SAFI_FLOWSPEC; + case SAFI_RTC: + return IANA_SAFI_RTC; case SAFI_UNSPEC: case SAFI_MAX: return IANA_SAFI_RESERVED; diff --git a/lib/plist.c b/lib/plist.c index 2cfaa7d81d27..db502f877a75 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -28,6 +28,7 @@ DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table"); #define PLC_BITS 8 #define PLC_LEN (1 << PLC_BITS) #define PLC_MAXLEVELV4 2 /* /24 for IPv4 */ +#define PLC_MAXLEVELRTC 3 /* /96 for RTC */ #define PLC_MAXLEVELV6 4 /* /48 for IPv6 */ #define PLC_MAXLEVEL 4 /* max(v4,v6) */ @@ -58,6 +59,10 @@ struct prefix_master { /* number of bytes that have a trie level */ size_t trie_depth; + /* value to return if a prefix_list is empty and we are trying to get a + * match */ + enum prefix_list_type empty_action; + struct plist_head str; }; static int prefix_list_compare_func(const struct prefix_list *a, @@ -67,26 +72,36 @@ DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item, /* Static structure of IPv4 prefix_list's master. */ static struct prefix_master prefix_master_ipv4 = { - NULL, NULL, NULL, PLC_MAXLEVELV4, + NULL, NULL, NULL, PLC_MAXLEVELV4, PREFIX_PERMIT, }; /* Static structure of IPv6 prefix-list's master. */ static struct prefix_master prefix_master_ipv6 = { - NULL, NULL, NULL, PLC_MAXLEVELV6, + NULL, NULL, NULL, PLC_MAXLEVELV6, PREFIX_PERMIT, }; /* Static structure of BGP ORF prefix_list's master. */ static struct prefix_master prefix_master_orf_v4 = { - NULL, NULL, NULL, PLC_MAXLEVELV4, + NULL, NULL, NULL, PLC_MAXLEVELV4, PREFIX_PERMIT, }; /* Static structure of BGP ORF prefix_list's master. */ static struct prefix_master prefix_master_orf_v6 = { - NULL, NULL, NULL, PLC_MAXLEVELV6, + NULL, NULL, NULL, PLC_MAXLEVELV6, PREFIX_PERMIT, +}; + +/* Satic structure of BGP Route target constrain prefix_list's master. */ +static struct prefix_master prefix_master_rtc = { + NULL, NULL, NULL, PLC_MAXLEVELRTC, PREFIX_DENY, }; -static struct prefix_master *prefix_master_get(afi_t afi, int orf) +static struct prefix_master *prefix_master_get(afi_t afi, int orf, int rtc) { + if (orf && rtc) + return NULL; + + if (rtc) + return &prefix_master_rtc; if (afi == AFI_IP) return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4; if (afi == AFI_IP6) @@ -114,7 +129,7 @@ static int prefix_list_compare_func(const struct prefix_list *a, } /* Lookup prefix_list from list of prefix_list by name. */ -static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, +static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, int rtc, const char *name) { struct prefix_list *plist, lookup; @@ -123,7 +138,7 @@ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, if (name == NULL) return NULL; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return NULL; @@ -135,12 +150,12 @@ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, struct prefix_list *prefix_list_lookup(afi_t afi, const char *name) { - return prefix_list_lookup_do(afi, 0, name); + return prefix_list_lookup_do(afi, 0, 0, name); } struct prefix_list *prefix_bgp_orf_lookup(afi_t afi, const char *name) { - return prefix_list_lookup_do(afi, 1, name); + return prefix_list_lookup_do(afi, 1, 0, name); } static struct prefix_list *prefix_list_new(void) @@ -172,13 +187,13 @@ void prefix_list_entry_free(struct prefix_list_entry *pentry) /* Insert new prefix list to list of prefix_list. Each prefix_list is sorted by the name. */ -static struct prefix_list *prefix_list_insert(afi_t afi, int orf, +static struct prefix_list *prefix_list_insert(afi_t afi, int orf, int rtc, const char *name) { struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return NULL; @@ -194,14 +209,15 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf, return plist; } -struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name) +struct prefix_list *prefix_list_get(afi_t afi, int orf, int rtc, + const char *name) { struct prefix_list *plist; - plist = prefix_list_lookup_do(afi, orf, name); + plist = prefix_list_lookup_do(afi, orf, rtc, name); if (plist == NULL) - plist = prefix_list_insert(afi, orf, name); + plist = prefix_list_insert(afi, orf, rtc, name); return plist; } @@ -789,7 +805,7 @@ enum prefix_list_type prefix_list_apply_ext( if (plist->count == 0) { if (which) *which = NULL; - return PREFIX_PERMIT; + return plist->master->empty_action; } depth = plist->master->trie_depth; @@ -1074,7 +1090,7 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name, int64_t seqnum = 0; json_object *json = NULL; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return CMD_WARNING; @@ -1185,7 +1201,7 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name, int ret; struct prefix p; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return CMD_WARNING; @@ -1456,6 +1472,41 @@ struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist, return s; } +int prefix_bgp_rtc_set(char *name, struct prefix *p, int permit, int set) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + + plist = prefix_list_get(AFI_IP, 0, 1, name); + if (!plist) { + return CMD_WARNING_CONFIG_FAILED; + } + + + if (set) { + pentry = prefix_list_entry_make( + p, (permit ? PREFIX_PERMIT : PREFIX_DENY), -1, 0, 0, + false); + + if (prefix_entry_dup_check(plist, pentry)) { + prefix_list_entry_free(pentry); + return CMD_WARNING_CONFIG_FAILED; + } + prefix_list_entry_add(plist, pentry); + } else { + pentry = prefix_list_entry_lookup( + plist, p, (permit ? PREFIX_PERMIT : PREFIX_DENY), -1, 0, + 0); + + if (!pentry) + return CMD_WARNING_CONFIG_FAILED; + + prefix_list_entry_delete(plist, pentry, 0); + } + + return CMD_SUCCESS; +} int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, int permit, int set) @@ -1474,7 +1525,7 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128)) orfp->le = 0; - plist = prefix_list_get(afi, 1, name); + plist = prefix_list_get(afi, 1, 0, name); if (!plist) return CMD_WARNING_CONFIG_FAILED; @@ -1589,12 +1640,12 @@ int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, return plist->count; } -static void prefix_list_reset_afi(afi_t afi, int orf) +static void prefix_list_reset_afi(afi_t afi, int orf, int rtc) { struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return; @@ -1618,7 +1669,7 @@ static void plist_autocomplete_afi(afi_t afi, vector comps, struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return; @@ -1693,6 +1744,7 @@ void prefix_list_init(void) plist_init(&prefix_master_orf_v4.str); plist_init(&prefix_master_ipv6.str); plist_init(&prefix_master_orf_v6.str); + plist_init(&prefix_master_rtc.str); cmd_variable_handler_register(plist_var_handlers); @@ -1702,8 +1754,9 @@ void prefix_list_init(void) void prefix_list_reset(void) { - prefix_list_reset_afi(AFI_IP, 0); - prefix_list_reset_afi(AFI_IP6, 0); - prefix_list_reset_afi(AFI_IP, 1); - prefix_list_reset_afi(AFI_IP6, 1); + prefix_list_reset_afi(AFI_IP, 0, 0); + prefix_list_reset_afi(AFI_IP6, 0, 0); + prefix_list_reset_afi(AFI_IP, 1, 0); + prefix_list_reset_afi(AFI_IP6, 1, 0); + prefix_list_reset_afi(AFI_IP, 0, 1); } diff --git a/lib/plist.h b/lib/plist.h index f31d8e879270..52f6a3774378 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -68,10 +68,12 @@ extern struct stream *prefix_bgp_orf_entry(struct stream *, uint8_t, uint8_t); extern int prefix_bgp_orf_set(char *, afi_t, struct orf_prefix *, int, int); extern void prefix_bgp_orf_remove_all(afi_t, char *); + +int prefix_bgp_rtc_set(char *name, struct prefix *p, int permit, int set); extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, bool use_json); -extern struct prefix_list *prefix_list_get(afi_t afi, int orf, +extern struct prefix_list *prefix_list_get(afi_t afi, int orf, int rtc, const char *name); extern void prefix_list_delete(struct prefix_list *plist); extern int64_t prefix_new_seq_get(struct prefix_list *plist); diff --git a/lib/prefix.c b/lib/prefix.c index 2485c3e61bdd..254d317a79d5 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -174,6 +174,8 @@ const char *safi2str(safi_t safi) return "labeled-unicast"; case SAFI_FLOWSPEC: return "flowspec"; + case SAFI_RTC: + return "rtc"; case SAFI_UNSPEC: case SAFI_MAX: return "unknown"; @@ -347,6 +349,9 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.prefix_flowspec.ptr = (uintptr_t)temp; memcpy((void *)dest->u.prefix_flowspec.ptr, (void *)src->u.prefix_flowspec.ptr, len); + } else if (src->family == AF_RTC) { + memcpy(&dest->u.prefix_rtc, &src->u.prefix_rtc, + sizeof(struct rtc_info)); } else { flog_err(EC_LIB_DEVELOPMENT, "prefix_copy(): Unknown address family %d", @@ -436,6 +441,10 @@ int prefix_same(union prefixconstptr up1, union prefixconstptr up2) p2->u.prefix_flowspec.prefixlen)) return 1; } + if (p1->family == AF_RTC) + if (!memcmp(&p1->u.prefix_rtc, &p2->u.prefix_rtc, + sizeof(struct rtc_info))) + return 1; } return 0; } @@ -567,6 +576,8 @@ const char *prefix_family_str(union prefixconstptr pu) return "ether"; if (p->family == AF_EVPN) return "evpn"; + if (p->family == AF_RTC) + return "rtc"; return "unspec"; } @@ -1116,6 +1127,10 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) strlcpy(str, "FS prefix", size); break; + case AF_RTC: + strlcpy(str, "RTC prefix", size); + break; + default: strlcpy(str, "UNK prefix", size); break; diff --git a/lib/prefix.h b/lib/prefix.h index 2d679d06224f..957689a0aa7e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -125,6 +125,11 @@ struct evpn_addr { #define prefix_addr u._prefix_addr }; +struct rtc_info { + uint32_t origin_as; + uint8_t route_target[8]; +}; + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -158,6 +163,10 @@ struct evpn_addr { #define AF_FLOWSPEC (AF_MAX + 2) #endif +#if !defined(AF_RTC) +#define AF_RTC (AF_MAX + 3) +#endif + struct flowspec_prefix { uint8_t family; uint16_t prefixlen; /* length in bytes */ @@ -181,6 +190,7 @@ struct prefix { uint32_t val32[4]; uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ + struct rtc_info prefix_rtc; /* AF_RTC */ struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ } u __attribute__((aligned(8))); }; @@ -227,6 +237,13 @@ struct prefix_evpn { struct evpn_addr prefix __attribute__((aligned(8))); }; +struct prefix_rtc { + uint8_t family; + uint16_t prefixlen; + struct rtc_info prefix __attribute__((aligned(8))); +}; + + static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp) { if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) @@ -294,6 +311,7 @@ union prefixptr { uniontype(prefixptr, struct prefix_evpn, evp) uniontype(prefixptr, struct prefix_fs, fs) uniontype(prefixptr, struct prefix_rd, rd) + uniontype(prefixptr, struct prefix_rtc, rtc) } TRANSPARENT_UNION; union prefixconstptr { @@ -303,6 +321,7 @@ union prefixconstptr { uniontype(prefixconstptr, const struct prefix_evpn, evp) uniontype(prefixconstptr, const struct prefix_fs, fs) uniontype(prefixconstptr, const struct prefix_rd, rd) + uniontype(prefixconstptr, const struct prefix_rtc, rtc) } TRANSPARENT_UNION; /* clang-format on */ @@ -658,6 +677,7 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr) #pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *) #pragma FRR printfrr_ext "%pFX" (struct prefix_fs *) #pragma FRR printfrr_ext "%pRDP" (struct prefix_rd *) +#pragma FRR printfrr_ext "%pRTC"(struct prefix_rtc *) /* RD with AS4B with dot and dot+ format */ #pragma FRR printfrr_ext "%pRDD" (struct prefix_rd *) #pragma FRR printfrr_ext "%pRDE" (struct prefix_rd *) diff --git a/lib/zebra.h b/lib/zebra.h index 15a54f6cdf61..e042396cbfb7 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -259,7 +259,8 @@ typedef enum { SAFI_EVPN = 5, SAFI_LABELED_UNICAST = 6, SAFI_FLOWSPEC = 7, - SAFI_MAX = 8 + SAFI_RTC = 8, /* BGP-RTC RFC 4684 */ + SAFI_MAX = 9, } safi_t; #define FOREACH_AFI_SAFI(afi, safi) \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c43e1909e3e1..e483b1a575a1 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1466,6 +1466,13 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; +static struct cmd_node bgp_rtc_node = { + .name = "bgp rtc", + .node = BGP_RTC_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-rtc)# ", +}; + static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", .node = BGP_VNC_DEFAULTS_NODE, @@ -1813,6 +1820,14 @@ DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, address_family_rtc, address_family_rtc_cmd, + "address-family ipv4 rt-constraint", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + vty->node = BGP_RTC_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast, address_family_ipv4_multicast_cmd, "address-family ipv4 multicast", "Enter Address Family command mode\n" @@ -2485,13 +2500,12 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit", DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { - if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE - || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE - || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE - || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE - || vty->node == BGP_EVPN_NODE - || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || + vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || + vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || + vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE || + vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE || + vty->node == BGP_FLOWSPECV6_NODE || vty->node == BGP_RTC_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -4939,6 +4953,7 @@ void vtysh_init_vty(void) install_node(&bgp_vnc_l2_group_node); install_node(&bgp_evpn_node); install_node(&bgp_evpn_vni_node); + install_node(&bgp_rtc_node); install_node(&rpki_node); install_node(&bmp_node); install_node(&bgp_srv6_node); @@ -5106,6 +5121,12 @@ void vtysh_init_vty(void) install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); + install_element(BGP_NODE, &address_family_rtc_cmd); + install_element(BGP_RTC_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_RTC_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_RTC_NODE, &vtysh_end_all_cmd); + install_element(BGP_RTC_NODE, &exit_address_family_cmd); + install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); diff --git a/yang/frr-bgp-common-multiprotocol.yang b/yang/frr-bgp-common-multiprotocol.yang index c22bdf996473..72e9d0197d5b 100644 --- a/yang/frr-bgp-common-multiprotocol.yang +++ b/yang/frr-bgp-common-multiprotocol.yang @@ -204,5 +204,15 @@ submodule frr-bgp-common-multiprotocol { description "IPv6 flowspec configuration options."; } + + container ipv4-rtc { + when "derived-from-or-self(../afi-safi-name, 'frr-rt:ipv4-rtc')" { + description + "Include this container for ipv4-rtc specific + configuration."; + } + description + "IPv4 RTC configuration options."; + } } } diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang index b34fd43e78de..07ed4bcc765c 100644 --- a/yang/frr-bgp.yang +++ b/yang/frr-bgp.yang @@ -819,6 +819,17 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1090,6 +1101,16 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1366,4 +1387,14 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } } diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang index b304c241a41c..78abef168068 100644 --- a/yang/frr-routing.yang +++ b/yang/frr-routing.yang @@ -172,6 +172,13 @@ module frr-routing { } + identity ipv4-rtc { + base afi-safi-type; + description + "This identity represents the ipv4-rtc address family."; + } + + identity control-plane-protocol { description "Base identity from which control-plane protocol identities are