Merge pull request #12248 from pguibert6WIND/bgpasdot

lib, bgp: add initial support for asdot format
This commit is contained in:
Russ White 2023-02-21 08:01:03 -05:00 committed by GitHub
commit ba755d35e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 7247 additions and 473 deletions

View File

@ -287,9 +287,13 @@ static struct assegment *assegment_normalise(struct assegment *head)
return head;
}
static struct aspath *aspath_new(void)
static struct aspath *aspath_new(enum asnotation_mode asnotation)
{
return XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
struct aspath *as;
as = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
as->asnotation = asnotation;
return as;
}
/* Free AS path structure. */
@ -537,8 +541,10 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
*
* This was changed to 10 after the well-known BGP assertion, which
* had hit some parts of the Internet in May of 2009.
* plain format : '4294967295 ' : 10 + 1
* astod format : '65535.65535 ': 11 + 1
*/
#define ASN_STR_LEN (10 + 1)
#define ASN_STR_LEN (11 + 1)
str_size = MAX(assegment_count_asns(seg, 0) * ASN_STR_LEN + 2 + 1,
ASPATH_STR_DEFAULT_LEN);
str_buf = XMALLOC(MTYPE_AS_STR, str_size);
@ -569,7 +575,7 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
/* We might need to increase str_buf, particularly if path has
* differing segments types, our initial guesstimate above will
* have been wrong. Need 10 chars for ASN, a separator each and
* have been wrong. Need 11 chars for ASN, a separator each and
* potentially two segment delimiters, plus a space between each
* segment and trailing zero.
*
@ -595,12 +601,11 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
/* write out the ASNs, with their separators, bar the last one*/
for (i = 0; i < seg->length; i++) {
if (make_json)
json_object_array_add(
jseg_list,
json_object_new_int64(seg->as[i]));
len += snprintf(str_buf + len, str_size - len, "%u",
seg->as[i]);
asn_asn2json_array(jseg_list, seg->as[i],
as->asnotation);
len += snprintfrr(str_buf + len, str_size - len,
ASN_FORMAT(as->asnotation),
&seg->as[i]);
if (i < (seg->length - 1))
len += snprintf(str_buf + len, str_size - len,
@ -691,6 +696,7 @@ struct aspath *aspath_dup(struct aspath *aspath)
new->str = XMALLOC(MTYPE_AS_STR, buflen);
new->str_len = aspath->str_len;
new->asnotation = aspath->asnotation;
/* copy the string data */
if (aspath->str_len > 0)
@ -718,6 +724,7 @@ static void *aspath_hash_alloc(void *arg)
new->str = aspath->str;
new->str_len = aspath->str_len;
new->json = aspath->json;
new->asnotation = aspath->asnotation;
return new;
}
@ -825,7 +832,8 @@ static int assegments_parse(struct stream *s, size_t length,
On error NULL is returned.
*/
struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit)
struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit,
enum asnotation_mode asnotation)
{
struct aspath as;
struct aspath *find;
@ -840,6 +848,7 @@ struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit)
return NULL;
memset(&as, 0, sizeof(as));
as.asnotation = asnotation;
if (assegments_parse(s, length, &as.segments, use32bit) < 0)
return NULL;
@ -1057,7 +1066,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
seg = assegment_append_asns(seg, seg1->as, match);
if (!aspath) {
aspath = aspath_new();
aspath = aspath_new(as1->asnotation);
aspath->segments = seg;
} else
prevseg->next = seg;
@ -1077,7 +1086,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
}
if (!aspath)
aspath = aspath_new();
aspath = aspath_new(as1->asnotation);
/* Make as-set using rest of all information. */
from = match;
@ -1521,7 +1530,7 @@ struct aspath *aspath_filter_exclude(struct aspath *source,
struct assegment *srcseg, *exclseg, *lastseg;
struct aspath *newpath;
newpath = aspath_new();
newpath = aspath_new(source->asnotation);
lastseg = NULL;
for (srcseg = source->segments; srcseg; srcseg = srcseg->next) {
@ -1751,7 +1760,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
newseg = assegment_append_asns(newseg, seg->as, cpasns);
if (!newpath) {
newpath = aspath_new();
newpath = aspath_new(aspath->asnotation);
newpath->segments = newseg;
} else
prevseg->next = newseg;
@ -1880,16 +1889,16 @@ static void aspath_segment_add(struct aspath *as, int type)
as->segments = new;
}
struct aspath *aspath_empty(void)
struct aspath *aspath_empty(enum asnotation_mode asnotation)
{
return aspath_parse(NULL, 0, 1); /* 32Bit ;-) */
return aspath_parse(NULL, 0, 1, asnotation); /* 32Bit ;-) */
}
struct aspath *aspath_empty_get(void)
{
struct aspath *aspath;
aspath = aspath_new();
aspath = aspath_new(bgp_get_asnotation(NULL));
aspath_make_str_count(aspath, false);
return aspath;
}
@ -1925,6 +1934,8 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
unsigned long *asno)
{
const char *p = buf;
as_t asval;
bool found = false;
/* Skip separators (space for sequences, ',' for sets). */
while (isspace((unsigned char)*p) || *p == ',')
@ -1961,30 +1972,18 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
return p;
}
/* Check actual AS value. */
if (isdigit((unsigned char)*p)) {
as_t asval;
*token = as_token_asval;
asval = (*p - '0');
p++;
while (isdigit((unsigned char)*p)) {
asval *= 10;
asval += (*p - '0');
p++;
}
asval = 0;
p = asn_str2asn_parse(p, &asval, &found);
if (found) {
*asno = asval;
return p;
}
/* There is no match then return unknown token. */
*token = as_token_unknown;
p++;
*token = as_token_asval;
} else
*token = as_token_unknown;
return p;
}
struct aspath *aspath_str2aspath(const char *str)
struct aspath *aspath_str2aspath(const char *str,
enum asnotation_mode asnotation)
{
enum as_token token = as_token_unknown;
unsigned short as_type;
@ -1992,7 +1991,7 @@ struct aspath *aspath_str2aspath(const char *str)
struct aspath *aspath;
int needtype;
aspath = aspath_new();
aspath = aspath_new(asnotation);
/* We start default type as AS_SEQUENCE. */
as_type = AS_SEQUENCE;
@ -2066,6 +2065,10 @@ bool aspath_cmp(const void *arg1, const void *arg2)
const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
if (((const struct aspath *)arg1)->asnotation !=
((const struct aspath *)arg2)->asnotation)
return false;
while (seg1 || seg2) {
int i;
if ((!seg1 && seg2) || (seg1 && !seg2))

View File

@ -57,6 +57,9 @@ struct aspath {
and AS path regular expression match. */
char *str;
unsigned short str_len;
/* AS notation used by string expression of AS path */
enum asnotation_mode asnotation;
};
#define ASPATH_STR_DEFAULT_LEN 32
@ -65,7 +68,9 @@ struct aspath {
extern void aspath_init(void);
extern void aspath_finish(void);
extern struct aspath *aspath_parse(struct stream *s, size_t length,
int use32bit);
int use32bit,
enum asnotation_mode asnotation);
extern struct aspath *aspath_dup(struct aspath *aspath);
extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2);
extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2);
@ -81,9 +86,10 @@ extern bool aspath_cmp_left(const struct aspath *aspath1,
extern bool aspath_cmp_left_confed(const struct aspath *as1,
const struct aspath *as2);
extern struct aspath *aspath_delete_confed_seq(struct aspath *aspath);
extern struct aspath *aspath_empty(void);
extern struct aspath *aspath_empty(enum asnotation_mode asnotation);
extern struct aspath *aspath_empty_get(void);
extern struct aspath *aspath_str2aspath(const char *str);
extern struct aspath *aspath_str2aspath(const char *str,
enum asnotation_mode asnotation);
extern void aspath_str_update(struct aspath *as, bool make_json);
extern void aspath_free(struct aspath *aspath);
extern struct aspath *aspath_intern(struct aspath *aspath);

View File

@ -1054,7 +1054,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
attr->origin = origin;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
attr->aspath = aspath_empty();
attr->aspath = aspath_empty(bgp->asnotation);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->tag = 0;
@ -1092,7 +1092,7 @@ struct attr *bgp_attr_aggregate_intern(
if (aspath)
attr.aspath = aspath_intern(aspath);
else
attr.aspath = aspath_empty();
attr.aspath = aspath_empty(bgp->asnotation);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
/* Next hop attribute. */
@ -1590,15 +1590,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
struct peer *const peer = args->peer;
const bgp_size_t length = args->length;
enum asnotation_mode asnotation;
asnotation = bgp_get_asnotation(
args->peer && args->peer->bgp ? args->peer->bgp : NULL);
/*
* peer with AS4 => will get 4Byte ASnums
* otherwise, will get 16 Bit
*/
attr->aspath = aspath_parse(
peer->curr, length,
CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
&& CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV));
attr->aspath =
aspath_parse(peer->curr, length,
CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) &&
CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV),
asnotation);
/* In case of IBGP, length will be zero. */
if (!attr->aspath) {
@ -1614,7 +1618,8 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
* such messages, conformant BGP speakers SHOULD use the "Treat-as-
* withdraw" error handling behavior as per [RFC7606].
*/
if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
if (peer->bgp && peer->bgp->reject_as_sets &&
aspath_check_as_sets(attr->aspath)) {
flog_err(EC_BGP_ATTR_MAL_AS_PATH,
"AS_SET and AS_CONFED_SET are deprecated from %pBP",
peer);
@ -1690,8 +1695,11 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
enum asnotation_mode asnotation;
*as4_path = aspath_parse(peer->curr, length, 1);
asnotation = bgp_get_asnotation(peer->bgp);
*as4_path = aspath_parse(peer->curr, length, 1, asnotation);
/* In case of IBGP, length will be zero. */
if (!*as4_path) {

View File

@ -86,7 +86,8 @@ static void attr_parse(struct stream *s, uint16_t len)
case BGP_ATTR_AS_PATH: {
struct aspath *aspath;
aspath = aspath_parse(s, length, 1);
aspath = aspath_parse(s, length, 1,
bgp_get_asnotation(NULL));
printf("ASPATH: %s\n", aspath->str);
aspath_free(aspath);
} break;

View File

@ -2635,6 +2635,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
char tag_buf[30];
char overlay_index_buf[INET6_ADDRSTRLEN + 14];
const struct prefix_evpn *evp;
int len = 0;
/* ' with addpath ID ' 17
* max strlen of uint32 + 10
@ -2688,11 +2689,15 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
}
}
if (prd)
snprintfrr(str, size, "RD %pRD %pFX%s%s%s %s %s", prd, pu.p,
if (prd) {
len += snprintfrr(str + len, size - len, "RD ");
len += snprintfrr(str + len, size - len,
BGP_RD_AS_FORMAT(bgp_get_asnotation(NULL)),
prd);
snprintfrr(str + len, size - len, " %pFX%s%s%s %s %s", pu.p,
overlay_index_buf, tag_buf, pathid_buf, afi2str(afi),
safi2str(safi));
else if (safi == SAFI_FLOWSPEC) {
} else if (safi == SAFI_FLOWSPEC) {
char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
const struct prefix_fs *fs = pu.fs;

View File

@ -5923,6 +5923,8 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn)
vpn->prd.prefixlen = 64;
snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id);
(void)str2prefix_rd(buf, &vpn->prd);
if (vpn->prd_pretty)
XFREE(MTYPE_BGP, vpn->prd_pretty);
UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
}
@ -6027,6 +6029,8 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
bf_release_index(bm->rd_idspace, vpn->rd_id);
hash_release(bgp->vni_svi_hash, vpn);
hash_release(bgp->vnihash, vpn);
if (vpn->prd_pretty)
XFREE(MTYPE_BGP, vpn->prd_pretty);
QOBJ_UNREG(vpn);
XFREE(MTYPE_BGP_EVPN, vpn);
}
@ -6238,13 +6242,14 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
ret = bgp_get_vty(&bgp_vrf, &as, vrf_id_to_name(vrf_id),
vrf_id == VRF_DEFAULT
? BGP_INSTANCE_TYPE_DEFAULT
: BGP_INSTANCE_TYPE_VRF);
? BGP_INSTANCE_TYPE_DEFAULT
: BGP_INSTANCE_TYPE_VRF,
NULL, ASNOTATION_UNDEFINED);
switch (ret) {
case BGP_ERR_AS_MISMATCH:
flog_err(EC_BGP_EVPN_AS_MISMATCH,
"BGP instance is already running; AS is %u",
as);
"BGP instance is already running; AS is %s",
bgp_vrf->as_pretty);
return -1;
case BGP_ERR_INSTANCE_MISMATCH:
flog_err(EC_BGP_EVPN_INSTANCE_MISMATCH,
@ -6660,6 +6665,9 @@ void bgp_evpn_cleanup(struct bgp *bgp)
list_delete(&bgp->vrf_import_rtl);
list_delete(&bgp->vrf_export_rtl);
list_delete(&bgp->l2vnis);
if (bgp->vrf_prd_pretty)
XFREE(MTYPE_BGP, bgp->vrf_prd_pretty);
}
/*

View File

@ -2395,7 +2395,8 @@ static void bgp_evpn_es_json_frag_fill(json_object *json_frags,
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
json_frag = json_object_new_object();
json_object_string_addf(json_frag, "rd", "%pRD", &es_frag->prd);
json_object_string_addf(json_frag, "rd", "%pRDP",
&es_frag->prd);
json_object_int_add(json_frag, "eviCount",
listcount(es_frag->es_evi_frag_list));
@ -2410,7 +2411,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty,
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
vty_out(vty, " %pRD EVIs: %d\n", &es_frag->prd,
vty_out(vty, " %pRDP EVIs: %d\n", &es_frag->prd,
listcount(es_frag->es_evi_frag_list));
}
}
@ -2524,7 +2525,7 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
json_object_string_add(json, "esi", es->esi_str);
if (es->es_base_frag)
json_object_string_addf(json, "rd", "%pRD",
json_object_string_addf(json, "rd", "%pRDP",
&es->es_base_frag->prd);
if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
@ -2562,7 +2563,7 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
vty_out(vty, "%-30s %-5s %-21pRD %-8d %s\n", es->esi_str,
vty_out(vty, "%-30s %-5s %-21pRDP %-8d %s\n", es->esi_str,
type_str, &es->es_base_frag->prd,
listcount(es->es_evi_list), vtep_str);
}
@ -2639,7 +2640,7 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
vty_out(vty, "ESI: %s\n", es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
vty_out(vty, " RD: %pRD\n", &es->es_base_frag->prd);
vty_out(vty, " RD: %pRDP\n", &es->es_base_frag->prd);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
if (es->flags & BGP_EVPNES_LOCAL)
vty_out(vty, " Local ES DF preference: %u\n",
@ -3958,7 +3959,8 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
json_object *json_types;
json_object_string_add(json, "esi", es_evi->es->esi_str);
json_object_int_add(json, "vni", es_evi->vpn->vni);
if (es_evi->vpn)
json_object_int_add(json, "vni", es_evi->vpn->vni);
if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
BGP_EVPNES_EVI_REMOTE)) {
@ -4002,13 +4004,18 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
struct bgp_evpn_es_evi *es_evi, json_object *json)
{
enum asnotation_mode mode;
mode = bgp_get_asnotation(es_evi->vpn->bgp_vrf);
if (json) {
json_object *json_flags;
/* Add the "brief" info first */
bgp_evpn_es_evi_show_entry(vty, es_evi, json);
if (es_evi->es_frag)
json_object_string_addf(json, "esFragmentRd", "%pRD",
json_object_string_addf(json, "esFragmentRd",
BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd);
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
json_flags = json_object_new_array();
@ -4032,9 +4039,12 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
vty_out(vty, "VNI: %d ESI: %s\n",
es_evi->vpn->vni, es_evi->es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
if (es_evi->es_frag)
vty_out(vty, " ES fragment RD: %pRD\n",
if (es_evi->es_frag) {
vty_out(vty, " ES fragment RD: ");
vty_out(vty, BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd);
vty_out(vty, "\n");
}
vty_out(vty, " Inconsistencies: %s\n",
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
"es-vtep-mismatch":"-");

View File

@ -76,6 +76,7 @@ struct bgpevpn {
/* RD for this VNI. */
struct prefix_rd prd;
char *prd_pretty;
/* Route type 3 field */
struct in_addr originator_ip;

View File

@ -374,7 +374,9 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_int_add(json, "vni", bgp_vrf->l3vni);
json_object_string_add(json, "type", "L3");
json_object_string_add(json, "inKernel", "True");
json_object_string_addf(json, "rd", "%pRD", &bgp_vrf->vrf_prd);
json_object_string_addf(json, "rd",
BGP_RD_AS_FORMAT(bgp_vrf->asnotation),
&bgp_vrf->vrf_prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&bgp_vrf->originator_ip);
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
@ -398,7 +400,10 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Type: %s\n", "L3");
vty_out(vty, " Tenant VRF: %s\n",
vrf_id_to_name(bgp_vrf->vrf_id));
vty_out(vty, " RD: %pRD\n", &bgp_vrf->vrf_prd);
vty_out(vty, " RD: ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp_vrf->asnotation),
&bgp_vrf->vrf_prd);
vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n",
&bgp_vrf->originator_ip);
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
@ -461,8 +466,10 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
struct bgp *bgp_evpn;
enum asnotation_mode asnotation;
bgp_evpn = bgp_get_evpn();
asnotation = bgp_get_asnotation(bgp_evpn);
if (json) {
json_import_rtl = json_object_new_array();
@ -471,7 +478,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_string_add(json, "type", "L2");
json_object_string_add(json, "inKernel",
is_vni_live(vpn) ? "True" : "False");
json_object_string_addf(json, "rd", "%pRD", &vpn->prd);
json_object_string_addf(
json, "rd", BGP_RD_AS_FORMAT(asnotation), &vpn->prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json, "mcastGroup", "%pI4",
@ -512,7 +520,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
vty_out(vty, " Type: %s\n", "L2");
vty_out(vty, " Tenant-Vrf: %s\n",
vrf_id_to_name(vpn->tenant_vrf_id));
vty_out(vty, " RD: %pRD\n", &vpn->prd);
vty_out(vty, " RD: ");
vty_out(vty, BGP_RD_AS_FORMAT(asnotation), &vpn->prd);
vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n", &vpn->originator_ip);
vty_out(vty, " Mcast group: %pI4\n", &vpn->mcast_grp);
if (!vpn->advertise_gw_macip &&
@ -991,7 +1001,9 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_object_string_add(json_vni, "inKernel", "True");
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&bgp->originator_ip);
json_object_string_addf(json_vni, "rd", "%pRD", &bgp->vrf_prd);
json_object_string_addf(json_vni, "rd",
BGP_RD_AS_FORMAT(bgp->asnotation),
&bgp->vrf_prd);
json_object_string_add(json_vni, "advertiseGatewayMacip",
"n/a");
json_object_string_add(json_vni, "advertiseSviMacIp", "n/a");
@ -1007,7 +1019,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_vni, "rmac",
prefix_mac2str(&bgp->rmac, buf2, sizeof(buf2)));
} else {
vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, bgp->l3vni, "L3",
vty_out(vty, "%-1s %-10u %-4s ", buf1, bgp->l3vni, "L3");
vty_out(vty, BGP_RD_AS_FORMAT_SPACE(bgp->asnotation),
&bgp->vrf_prd);
}
@ -1091,11 +1104,13 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
struct listnode *node, *nnode;
struct ecommunity *ecom;
struct bgp *bgp_evpn;
enum asnotation_mode asnotation;
vty = args[0];
json = args[1];
bgp_evpn = bgp_get_evpn();
asnotation = bgp_get_asnotation(bgp_evpn);
if (json) {
json_vni = json_object_new_object();
@ -1112,7 +1127,9 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "type", "L2");
json_object_string_add(json_vni, "inKernel",
is_vni_live(vpn) ? "True" : "False");
json_object_string_addf(json_vni, "rd", "%pRD", &vpn->prd);
json_object_string_addf(json_vni, "rd",
BGP_RD_AS_FORMAT(asnotation),
&vpn->prd);
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json_vni, "mcastGroup", "%pI4",
@ -1142,8 +1159,8 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "advertiseSviMacIp",
"Disabled");
} else {
vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, vpn->vni, "L2",
&vpn->prd);
vty_out(vty, "%-1s %-10u %-4s ", buf1, vpn->vni, "L2");
vty_out(vty, BGP_RD_AS_FORMAT_SPACE(asnotation), &vpn->prd);
}
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@ -1332,9 +1349,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
json,
"defaultLocPrf",
bgp->default_local_pref);
json_object_int_add(
json, "localAS",
bgp->as);
asn_asn2json(json, "localAS",
bgp->as,
bgp->asnotation);
} else {
if (option == SHOW_DISPLAY_TAGS)
vty_out(vty,
@ -2203,7 +2220,8 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Configure RD for VRF
*/
static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd,
const char *rd_pretty)
{
/* If we have already advertise type-5 routes with a diffrent RD, we
* have to delete and withdraw them firs
@ -2212,6 +2230,7 @@ static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
/* update RD */
memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
/* We have a new RD for VRF.
@ -2233,7 +2252,8 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
/* fall back to default RD */
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
if (bgp_vrf->vrf_prd_pretty)
XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty);
/* We have a new RD for VRF.
* Advertise all type-5 routes again with the new RD
*/
@ -2244,7 +2264,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
* Configure RD for a VNI (vty handler)
*/
static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_rd *rd)
struct prefix_rd *rd, const char *rd_pretty)
{
/* If the VNI is "live", we need to delete and withdraw this VNI's
* local routes with the prior RD first. Then, after updating RD,
@ -2255,6 +2275,7 @@ static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
/* update RD */
memcpy(&vpn->prd, rd, sizeof(struct prefix_rd));
vpn->prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
if (is_vni_live(vpn))
@ -2778,7 +2799,8 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
json_rd = json_object_new_object();
json_object_string_addf(json_rd, "rd", "%pRD", prd);
json_object_string_addf(json_rd, "rd",
BGP_RD_AS_FORMAT(bgp->asnotation), prd);
}
bgp_dest_unlock_node(rd_dest);
@ -2861,7 +2883,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
if (add_rd_to_json)
json_object_object_addf(json, json_rd, "%pRD", prd);
json_object_object_addf(
json, json_rd,
BGP_RD_AS_FORMAT(bgp->asnotation), prd);
else {
json_object_free(json_rd);
json_rd = NULL;
@ -2916,7 +2940,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
continue;
prefix_rd2str((struct prefix_rd *)rd_destp, rd_str,
sizeof(rd_str));
sizeof(rd_str), bgp->asnotation);
/* Construct an RT-2 from the user-supplied mac(ip),
* then search the l2vpn evpn table for it.
@ -3043,7 +3067,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
tbl_ver = table->version;
prefix_rd2str((struct prefix_rd *)rd_destp, rd_str,
sizeof(rd_str));
sizeof(rd_str), bgp->asnotation);
if (json)
json_rd = json_object_new_object();
@ -3460,7 +3484,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
if (is_vni_configured(vpn)) {
vty_out(vty, " vni %u\n", vpn->vni);
if (is_rd_configured(vpn))
vty_out(vty, " rd %pRD\n", &vpn->prd);
vty_out(vty, " rd %s\n", vpn->prd_pretty);
if (is_import_rt_configured(vpn)) {
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode,
@ -6111,7 +6135,7 @@ DEFUN (bgp_evpn_vrf_rd,
return CMD_SUCCESS;
/* Configure or update the RD. */
evpn_configure_vrf_rd(bgp_vrf, &prd);
evpn_configure_vrf_rd(bgp_vrf, &prd, argv[1]->arg);
return CMD_SUCCESS;
}
@ -6203,7 +6227,7 @@ DEFUN (bgp_evpn_vni_rd,
return CMD_SUCCESS;
/* Configure or update the RD. */
evpn_configure_rd(bgp, vpn, &prd);
evpn_configure_rd(bgp, vpn, &prd, argv[1]->arg);
return CMD_SUCCESS;
}
@ -6388,7 +6412,9 @@ DEFUN (show_bgp_vrf_l3vni_info,
for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, l3rt))
vty_out(vty, "%s ", ecommunity_str(l3rt->ecom));
vty_out(vty, "\n");
vty_out(vty, " RD: %pRD\n", &bgp->vrf_prd);
vty_out(vty, " RD: ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation), &bgp->vrf_prd);
vty_out(vty, "\n");
} else {
json_object_string_add(json, "vrf", name);
json_object_string_addf(json, "local-ip", "%pI4",
@ -6424,7 +6450,9 @@ DEFUN (show_bgp_vrf_l3vni_info,
json_object_new_string(
ecommunity_str(l3rt->ecom)));
json_object_object_add(json, "import-rts", json_import_rts);
json_object_string_addf(json, "rd", "%pRD", &bgp->vrf_prd);
json_object_string_addf(json, "rd",
BGP_RD_AS_FORMAT(bgp->asnotation),
&bgp->vrf_prd);
}
if (uj)
@ -7251,7 +7279,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
vty_out(vty, " rd %pRD\n", &bgp->vrf_prd);
vty_out(vty, " rd %s\n", bgp->vrf_prd_pretty);
/* import route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {

View File

@ -1853,7 +1853,7 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
int origin_local = 0;
struct bgp *src_vrf;
struct interface *ifp;
char rd_buf[RD_ADDRSTRLEN];
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
@ -1892,6 +1892,10 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return false;
}
rd_buf[0] = '\0';
if (debug && prd)
prefix_rd2str(prd, rd_buf, sizeof(rd_buf), to_bgp->asnotation);
/* A route MUST NOT ever be accepted back into its source VRF, even if
* it carries one or more RTs that match that VRF.
*/
@ -1900,15 +1904,14 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
ECOMMUNITY_SIZE) == 0) {
if (debug)
zlog_debug(
"%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)",
__func__, prd, to_bgp->name_pretty, p);
"%s: skipping import, match RD (%s) of src VRF (%s) and the prefix (%pFX)",
__func__, rd_buf, to_bgp->name_pretty, p);
return false;
}
if (debug)
zlog_debug("%s: updating RD %pRD, %pFX to %s", __func__, prd, p,
to_bgp->name_pretty);
zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@ -2403,7 +2406,7 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
&bgp->vrf_prd_auto);
bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto;
prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
sizeof(buf));
sizeof(buf), bgp->asnotation);
/* free up pre-existing memory if any and allocate
* the ecommunity attribute with new RD/RT
@ -2538,8 +2541,8 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto;
SET_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd,
buf, sizeof(buf));
prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, buf,
sizeof(buf), from_bgp->asnotation);
from_bgp->vpn_policy[afi].rtlist[edir] =
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
SET_FLAG(from_bgp->af_flags[afi][safi],

View File

@ -942,11 +942,13 @@ static uint8_t *mplsL3vpnVrfTable(struct variable *v, oid name[],
if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP].flags,
BGP_VPN_POLICY_TOVPN_RD_SET))
prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP].tovpn_rd,
rd_buf, sizeof(rd_buf));
rd_buf, sizeof(rd_buf),
bgp_get_asnotation(l3vpn_bgp));
else if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP6].flags,
BGP_VPN_POLICY_TOVPN_RD_SET))
prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP6].tovpn_rd,
rd_buf, sizeof(rd_buf));
rd_buf, sizeof(rd_buf),
bgp_get_asnotation(l3vpn_bgp));
*var_len = strnlen(rd_buf, RD_ADDRSTRLEN);
return (uint8_t *)rd_buf;

View File

@ -538,7 +538,7 @@ static void bgp_accept(struct thread *thread)
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
peer1->as, peer1->as_type, NULL, false);
peer1->as, peer1->as_type, NULL, false, NULL);
peer_xfer_config(peer, peer1);
bgp_peer_gr_flags_update(peer);

View File

@ -802,6 +802,7 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
safi = table->safi;
bgp_path = table->bgp;
if (json) {
json_path = json_object_new_object();
json_object_string_add(json_path, "afi", afi2str(afi));
@ -811,7 +812,8 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
dest);
if (dest->pdest)
json_object_string_addf(
json_path, "rd", "%pRD",
json_path, "rd",
BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest));
json_object_string_add(
@ -821,13 +823,14 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
json_object_array_add(paths, json_path);
continue;
}
if (dest->pdest)
vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n",
afi, safi, dest,
if (dest->pdest) {
vty_out(vty, " %d/%d %pBD RD ", afi, safi, dest);
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest),
bgp_path->name_pretty, path->flags);
else
dest->pdest));
vty_out(vty, " %s flags 0x%x\n", bgp_path->name_pretty,
path->flags);
} else
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
afi, safi, dest, bgp_path->name_pretty, path->flags);
}

View File

@ -1190,14 +1190,20 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
}
if (BGP_DEBUG(nht, NHT)) {
if (dest->pdest)
zlog_debug(
"... eval path %d/%d %pBD RD %pRD %s flags 0x%x",
afi, safi, dest,
if (dest->pdest) {
char rd_buf[RD_ADDRSTRLEN];
prefix_rd2str(
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest),
rd_buf, sizeof(rd_buf),
bgp_get_asnotation(bnc->bgp));
zlog_debug(
"... eval path %d/%d %pBD RD %s %s flags 0x%x",
afi, safi, dest, rd_buf,
bgp_path->name_pretty, path->flags);
else
} else
zlog_debug(
"... eval path %d/%d %pBD %s flags 0x%x",
afi, safi, dest, bgp_path->name_pretty,

View File

@ -83,12 +83,12 @@ void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth)
int str2prefix_rd(const char *str, struct prefix_rd *prd)
{
int ret = 0;
char *p;
char *p2;
int ret = 0, type = RD_TYPE_UNDEFINED;
char *p, *p2;
struct stream *s = NULL;
char *half = NULL;
struct in_addr addr;
as_t as_val;
prd->family = AF_UNSPEC;
prd->prefixlen = 64;
@ -97,41 +97,55 @@ int str2prefix_rd(const char *str, struct prefix_rd *prd)
if (!p)
goto out;
/* a second ':' is accepted */
p2 = strchr(p + 1, ':');
if (p2) {
/* type is in first part */
half = XMALLOC(MTYPE_TMP, (p - str) + 1);
memcpy(half, str, (p - str));
half[p - str] = '\0';
type = atoi(half);
if (type != RD_TYPE_AS && type != RD_TYPE_IP &&
type != RD_TYPE_AS4)
goto out;
XFREE(MTYPE_TMP, half);
half = XMALLOC(MTYPE_TMP, (p2 - p));
memcpy(half, p + 1, (p2 - p - 1));
half[p2 - p - 1] = '\0';
p = p2 + 1;
} else {
half = XMALLOC(MTYPE_TMP, (p - str) + 1);
memcpy(half, str, (p - str));
half[p - str] = '\0';
}
if (!all_digit(p + 1))
goto out;
s = stream_new(RD_BYTES);
half = XMALLOC(MTYPE_TMP, (p - str) + 1);
memcpy(half, str, (p - str));
half[p - str] = '\0';
p2 = strchr(str, '.');
if (!p2) {
unsigned long as_val;
if (!all_digit(half))
goto out;
as_val = atol(half);
if (as_val > 0xffff) {
/* if it is an AS format or an IP */
if (asn_str2asn(half, &as_val)) {
if (as_val > UINT16_MAX) {
stream_putw(s, RD_TYPE_AS4);
stream_putl(s, as_val);
stream_putw(s, atol(p + 1));
if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS4)
goto out;
} else {
stream_putw(s, RD_TYPE_AS);
stream_putw(s, as_val);
stream_putl(s, atol(p + 1));
if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS)
goto out;
}
} else {
if (!inet_aton(half, &addr))
goto out;
} else if (inet_aton(half, &addr)) {
stream_putw(s, RD_TYPE_IP);
stream_put_in_addr(s, &addr);
stream_putw(s, atol(p + 1));
}
if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_IP)
goto out;
} else
goto out;
memcpy(prd->val, s->data, 8);
ret = 1;
@ -142,12 +156,14 @@ out:
return ret;
}
char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size)
char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size,
enum asnotation_mode asnotation)
{
const uint8_t *pnt;
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
int len = 0;
assert(size >= RD_ADDRSTRLEN);
@ -157,11 +173,15 @@ char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size)
if (type == RD_TYPE_AS) {
decode_rd_as(pnt + 2, &rd_as);
snprintf(buf, size, "%u:%u", rd_as.as, rd_as.val);
len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
&rd_as.as);
snprintfrr(buf + len, size - len, ":%u", rd_as.val);
return buf;
} else if (type == RD_TYPE_AS4) {
decode_rd_as4(pnt + 2, &rd_as);
snprintf(buf, size, "%u:%u", rd_as.as, rd_as.val);
len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
&rd_as.as);
snprintfrr(buf + len, size - len, ":%u", rd_as.val);
return buf;
} else if (type == RD_TYPE_IP) {
decode_rd_ip(pnt + 2, &rd_ip);
@ -196,16 +216,38 @@ void form_auto_rd(struct in_addr router_id,
(void)str2prefix_rd(buf, prd);
}
printfrr_ext_autoreg_p("RD", printfrr_prd);
static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
static ssize_t printfrr_prd_asnotation(struct fbuf *buf,
struct printfrr_eargs *ea,
const void *ptr,
enum asnotation_mode asnotation)
{
char rd_buf[RD_ADDRSTRLEN];
if (!ptr)
return bputs(buf, "(null)");
prefix_rd2str(ptr, rd_buf, sizeof(rd_buf));
prefix_rd2str(ptr, rd_buf, sizeof(rd_buf), asnotation);
return bputs(buf, rd_buf);
}
printfrr_ext_autoreg_p("RDP", printfrr_prd);
static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
}
printfrr_ext_autoreg_p("RDD", printfrr_prd_dot);
static ssize_t printfrr_prd_dot(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOT);
}
printfrr_ext_autoreg_p("RDE", printfrr_prd_dotplus);
static ssize_t printfrr_prd_dotplus(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
}

View File

@ -7,7 +7,11 @@
#ifndef _QUAGGA_BGP_RD_H
#define _QUAGGA_BGP_RD_H
#include "asn.h"
#include "prefix.h"
/* RD types */
#define RD_TYPE_UNDEFINED (-1)
#define RD_TYPE_AS 0
#define RD_TYPE_IP 1
#define RD_TYPE_AS4 2
@ -19,6 +23,16 @@
#define RD_ADDRSTRLEN 28
#define RD_BYTES 8
#define BGP_RD_AS_FORMAT(mode) \
((mode == ASNOTATION_DOT) \
? "%pRDD" \
: ((mode == ASNOTATION_DOTPLUS) ? "%pRDE" : "%pRDP"))
#define BGP_RD_AS_FORMAT_SPACE(mode) \
((mode == ASNOTATION_DOT) \
? "%-21pRDD" \
: ((mode == ASNOTATION_DOTPLUS) ? "%-21pRDE" : "%-21pRDP"))
struct rd_as {
uint16_t type;
as_t as;
@ -51,7 +65,8 @@ extern void decode_rd_vnc_eth(const uint8_t *pnt,
#endif
extern int str2prefix_rd(const char *, struct prefix_rd *);
extern char *prefix_rd2str(const struct prefix_rd *, char *, size_t);
extern char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size,
enum asnotation_mode asnotation);
extern void form_auto_rd(struct in_addr router_id, uint16_t rd_id,
struct prefix_rd *prd);

View File

@ -6078,6 +6078,8 @@ 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);
if (bgp_static->prd_pretty)
XFREE(MTYPE_BGP, bgp_static->prd_pretty);
XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
XFREE(MTYPE_BGP_STATIC, bgp_static);
}
@ -6981,6 +6983,8 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
bgp_static->label = label;
bgp_static->prd = prd;
if (rd_str)
bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP, rd_str);
if (rmap_str) {
XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
route_map_counter_decrement(bgp_static->rmap.map);
@ -7243,7 +7247,7 @@ static bool aggr_suppress_map_test(struct bgp *bgp,
return false;
/* Call route map matching and return result. */
attr.aspath = aspath_empty();
attr.aspath = aspath_empty(bgp->asnotation);
rmap_path.peer = bgp->peer_self;
rmap_path.attr = &attr;
@ -7337,9 +7341,12 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin,
struct lcommunity *lcomm)
{
static struct aspath *ae = NULL;
enum asnotation_mode asnotation;
asnotation = bgp_get_asnotation(NULL);
if (!ae)
ae = aspath_empty();
ae = aspath_empty(asnotation);
if (!pi)
return false;
@ -10254,10 +10261,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (dest && dest->pdest) {
pdest = dest->pdest;
if (is_pi_family_evpn(parent_ri)) {
vty_out(vty,
" Imported from %pRD:%pFX, VNI %s",
vty_out(vty, " Imported from ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
pdest),
pdest));
vty_out(vty, ":%pFX, VNI %s",
(struct prefix_evpn *)
bgp_dest_get_prefix(dest),
tag_buf);
@ -10270,12 +10278,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
: "inactive");
vty_out(vty, "\n");
} else
vty_out(vty, " Imported from %pRD:%pFX\n",
} else {
vty_out(vty, " Imported from ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
pdest),
pdest));
vty_out(vty, ":%pFX\n",
(struct prefix_evpn *)
bgp_dest_get_prefix(dest));
}
}
}
@ -11184,17 +11195,26 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty, "{\n");
*json_header_depth = 2;
}
vty_out(vty,
" \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64
",\n \"routerId\": \"%pI4\",\n \"defaultLocPrf\": %u,\n"
" \"localAS\": %u,\n \"routes\": { ",
" \"localAS\": ",
bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
? VRF_DEFAULT_NAME
: bgp->name,
table->version, &bgp->router_id,
bgp->default_local_pref, bgp->as);
bgp->default_local_pref);
if ((bgp->asnotation == ASNOTATION_PLAIN) ||
((bgp->asnotation == ASNOTATION_DOT) &&
(bgp->as < UINT16_MAX)))
vty_out(vty, "%u", bgp->as);
else {
vty_out(vty, "\"");
vty_out(vty, ASN_FORMAT(bgp->asnotation), &bgp->as);
vty_out(vty, "\"");
}
vty_out(vty, ",\n \"routes\": { ");
if (rd) {
vty_out(vty, " \"routeDistinguishers\" : {");
++*json_header_depth;
@ -11468,7 +11488,10 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty, "\n");
vty_out(vty, "Default local pref %u, ",
bgp->default_local_pref);
vty_out(vty, "local AS %u\n", bgp->as);
vty_out(vty, "local AS ");
vty_out(vty, ASN_FORMAT(bgp->asnotation),
&bgp->as);
vty_out(vty, "\n");
if (!detail_routes) {
vty_out(vty, BGP_SHOW_SCODE_HEADER);
vty_out(vty, BGP_SHOW_NCODE_HEADER);
@ -11665,7 +11688,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
char rd[RD_ADDRSTRLEN];
memcpy(&prd, dest_p, sizeof(struct prefix_rd));
prefix_rd2str(&prd, rd, sizeof(rd));
prefix_rd2str(&prd, rd, sizeof(rd), bgp->asnotation);
bgp_show_table(vty, bgp, safi, itable, type, output_arg,
rd, next == NULL, &output_cum,
&total_cum, &json_header_depth,
@ -11816,13 +11839,16 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
if (safi == SAFI_EVPN) {
if (!json) {
vty_out(vty, "BGP routing table entry for %s%s%pFX\n",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
prd ? prefix_rd2str(prd, buf1, sizeof(buf1),
bgp->asnotation)
: "",
prd ? ":" : "", (struct prefix_evpn *)p);
} else {
json_object_string_add(json, "rd",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1)) :
"");
json_object_string_add(
json, "rd",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1),
bgp->asnotation)
: "");
bgp_evpn_route2json((struct prefix_evpn *)p, json);
}
} else {
@ -11832,7 +11858,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
"\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
? prefix_rd2str(prd, buf1,
sizeof(buf1))
sizeof(buf1),
bgp->asnotation)
: ""),
safi == SAFI_MPLS_VPN ? ":" : "", p,
dest->version);
@ -12055,8 +12082,9 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
json_object_object_add(json_header, "paths", json_paths);
if (pfx_rd)
json_object_object_addf(json, json_header, "%pRD",
pfx_rd);
json_object_object_addf(
json, json_header,
BGP_RD_AS_FORMAT(bgp->asnotation), pfx_rd);
}
}
@ -14465,7 +14493,8 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
prd = (const struct prefix_rd *)bgp_dest_get_prefix(
dest);
prefix_rd2str(prd, rd_str, sizeof(rd_str));
prefix_rd2str(prd, rd_str, sizeof(rd_str),
bgp->asnotation);
show_adj_route(
vty, peer, table, afi, safi, type, rmap_name,
@ -15594,7 +15623,6 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
struct bgp_dest *dest;
struct bgp_table *table;
const struct prefix *p;
const struct prefix_rd *prd;
struct bgp_static *bgp_static;
mpls_label_t label;
@ -15612,13 +15640,12 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
continue;
p = bgp_dest_get_prefix(dest);
prd = (const struct prefix_rd *)bgp_dest_get_prefix(
pdest);
/* "network" configuration display. */
label = decode_label(&bgp_static->label);
vty_out(vty, " network %pFX rd %pRD", p, prd);
vty_out(vty, " network %pFX rd %s", p,
bgp_static->prd_pretty);
if (safi == SAFI_MPLS_VPN)
vty_out(vty, " label %u", label);
@ -15641,7 +15668,6 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
struct bgp_dest *dest;
struct bgp_table *table;
const struct prefix *p;
const struct prefix_rd *prd;
struct bgp_static *bgp_static;
char buf[PREFIX_STRLEN * 2];
char buf2[SU_ADDRSTRLEN];
@ -15669,7 +15695,6 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
esi_to_str(bgp_static->eth_s_id,
esi_buf, sizeof(esi_buf));
p = bgp_dest_get_prefix(dest);
prd = (struct prefix_rd *)bgp_dest_get_prefix(pdest);
/* "network" configuration display. */
if (p->u.prefix_evpn.route_type == 5) {
@ -15696,8 +15721,9 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
&bgp_static->gatewayIp.u.prefix, buf2,
sizeof(buf2));
vty_out(vty,
" network %s rd %pRD ethtag %u label %u esi %s gwip %s routermac %s\n",
buf, prd, p->u.prefix_evpn.prefix_addr.eth_tag,
" network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
buf, bgp_static->prd_pretty,
p->u.prefix_evpn.prefix_addr.eth_tag,
decode_label(&bgp_static->label), esi_buf, buf2,
macrouter);

View File

@ -355,6 +355,7 @@ struct bgp_static {
/* Route Distinguisher */
struct prefix_rd prd;
char *prd_pretty;
/* MPLS label. */
mpls_label_t label;

View File

@ -213,7 +213,7 @@ static void *route_aspath_compile(const char *arg)
{
struct aspath *aspath;
aspath = aspath_str2aspath(arg);
aspath = aspath_str2aspath(arg, bgp_get_asnotation(NULL));
if (!aspath)
return NULL;
return aspath;
@ -5663,15 +5663,16 @@ DEFUN_YANG (no_set_label_index,
DEFUN_YANG (set_aspath_prepend_asn,
set_aspath_prepend_asn_cmd,
"set as-path prepend (1-4294967295)...",
"set as-path prepend ASNUM...",
SET_STR
"Transform BGP AS_PATH attribute\n"
"Prepend to the as-path\n"
"AS number\n")
AS_STR)
{
int idx_asn = 3;
int ret;
char *str;
struct aspath *aspath;
str = argv_concat(argv, argc, idx_asn);
@ -5679,6 +5680,12 @@ DEFUN_YANG (set_aspath_prepend_asn,
"./set-action[action='frr-bgp-route-map:as-path-prepend']";
char xpath_value[XPATH_MAXLEN];
aspath = route_aspath_compile(str);
if (!aspath) {
vty_out(vty, "%% Invalid AS path value %s\n", str);
return CMD_WARNING_CONFIG_FAILED;
}
route_aspath_free(aspath);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-set-action/frr-bgp-route-map:prepend-as-path", xpath);
@ -5713,16 +5720,22 @@ DEFUN_YANG (set_aspath_prepend_lastas,
DEFPY_YANG (set_aspath_replace_asn,
set_aspath_replace_asn_cmd,
"set as-path replace <any|(1-4294967295)>$replace",
"set as-path replace <any|ASNUM>$replace",
SET_STR
"Transform BGP AS_PATH attribute\n"
"Replace AS number to local AS number\n"
"Replace any AS number to local AS number\n"
"Replace a specific AS number to local AS number\n")
"Replace a specific AS number in plain or dotted format to local AS number\n")
{
const char *xpath =
"./set-action[action='frr-bgp-route-map:as-path-replace']";
char xpath_value[XPATH_MAXLEN];
as_t as_value;
if (!strmatch(replace, "any") && !asn_str2asn(replace, &as_value)) {
vty_out(vty, "%% Invalid AS value %s\n", replace);
return CMD_WARNING_CONFIG_FAILED;
}
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
@ -5733,13 +5746,13 @@ DEFPY_YANG (set_aspath_replace_asn,
DEFPY_YANG (no_set_aspath_replace_asn,
no_set_aspath_replace_asn_cmd,
"no set as-path replace [<any|(1-4294967295)>]",
"no set as-path replace [<any|ASNUM>]",
NO_STR
SET_STR
"Transform BGP AS_PATH attribute\n"
"Replace AS number to local AS number\n"
"Replace any AS number to local AS number\n"
"Replace a specific AS number to local AS number\n")
"Replace a specific AS number in plain or dotted format to local AS number\n")
{
const char *xpath =
"./set-action[action='frr-bgp-route-map:as-path-replace']";
@ -5750,12 +5763,12 @@ DEFPY_YANG (no_set_aspath_replace_asn,
DEFUN_YANG (no_set_aspath_prepend,
no_set_aspath_prepend_cmd,
"no set as-path prepend [(1-4294967295)]",
"no set as-path prepend [ASNUM]",
NO_STR
SET_STR
"Transform BGP AS_PATH attribute\n"
"Prepend to the as-path\n"
"AS number\n")
AS_STR)
{
const char *xpath =
"./set-action[action='frr-bgp-route-map:as-path-prepend']";
@ -5783,15 +5796,16 @@ DEFUN_YANG (no_set_aspath_prepend_lastas,
DEFUN_YANG (set_aspath_exclude,
set_aspath_exclude_cmd,
"set as-path exclude (1-4294967295)...",
"set as-path exclude ASNUM...",
SET_STR
"Transform BGP AS-path attribute\n"
"Exclude from the as-path\n"
"AS number\n")
AS_STR)
{
int idx_asn = 3;
int ret;
char *str;
struct aspath *aspath;
str = argv_concat(argv, argc, idx_asn);
@ -5799,6 +5813,12 @@ DEFUN_YANG (set_aspath_exclude,
"./set-action[action='frr-bgp-route-map:as-path-exclude']";
char xpath_value[XPATH_MAXLEN];
aspath = route_aspath_compile(str);
if (!aspath) {
vty_out(vty, "%% Invalid AS path value %s\n", str);
return CMD_WARNING_CONFIG_FAILED;
}
route_aspath_free(aspath);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-set-action/frr-bgp-route-map:exclude-as-path", xpath);
@ -5810,7 +5830,7 @@ DEFUN_YANG (set_aspath_exclude,
DEFUN_YANG (no_set_aspath_exclude,
no_set_aspath_exclude_cmd,
"no set as-path exclude (1-4294967295)...",
"no set as-path exclude ASNUM...",
NO_STR
SET_STR
"Transform BGP AS_PATH attribute\n"
@ -6496,11 +6516,11 @@ DEFPY_YANG (no_set_aigp_metric,
DEFUN_YANG (set_aggregator_as,
set_aggregator_as_cmd,
"set aggregator as (1-4294967295) A.B.C.D",
"set aggregator as ASNUM A.B.C.D",
SET_STR
"BGP aggregator attribute\n"
"AS number of aggregator\n"
"AS number\n"
AS_STR
"IP address of aggregator\n")
{
int idx_number = 3;
@ -6509,6 +6529,12 @@ DEFUN_YANG (set_aggregator_as,
char xpath_addr[XPATH_MAXLEN];
const char *xpath =
"./set-action[action='frr-bgp-route-map:aggregator']";
as_t as_value;
if (!asn_str2asn(argv[idx_number]->arg, &as_value)) {
vty_out(vty, "%% Invalid AS value %s\n", argv[idx_number]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
@ -6531,12 +6557,12 @@ DEFUN_YANG (set_aggregator_as,
DEFUN_YANG (no_set_aggregator_as,
no_set_aggregator_as_cmd,
"no set aggregator as [(1-4294967295) A.B.C.D]",
"no set aggregator as [ASNUM A.B.C.D]",
NO_STR
SET_STR
"BGP aggregator attribute\n"
"AS number of aggregator\n"
"AS number\n"
AS_STR
"IP address of aggregator\n")
{
const char *xpath =

View File

@ -81,6 +81,7 @@ struct rpki_for_each_record_arg {
unsigned int *prefix_amount;
as_t as;
json_object *json;
enum asnotation_mode asnotation;
};
static int start(void);
@ -105,7 +106,7 @@ static void rpki_delete_all_cache_nodes(void);
static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference, const char *bindaddr);
static void print_record(const struct pfx_record *record, struct vty *vty,
json_object *json);
json_object *json, enum asnotation_mode asnotation);
static bool is_synchronized(void);
static bool is_running(void);
static bool is_stopping(void);
@ -270,7 +271,7 @@ static void rpki_delete_all_cache_nodes(void)
}
static void print_record(const struct pfx_record *record, struct vty *vty,
json_object *json)
json_object *json, enum asnotation_mode asnotation)
{
char ip[INET6_ADDRSTRLEN];
json_object *json_record = NULL;
@ -278,8 +279,10 @@ static void print_record(const struct pfx_record *record, struct vty *vty,
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
if (!json) {
vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
record->max_len, record->asn);
vty_out(vty, "%-40s %3u - %3u ", ip, record->min_len,
record->max_len);
vty_out(vty, ASN_FORMAT(asnotation), &record->asn);
vty_out(vty, "\n");
} else {
json_record = json_object_new_object();
json_object_string_add(json_record, "prefix", ip);
@ -287,7 +290,7 @@ static void print_record(const struct pfx_record *record, struct vty *vty,
record->min_len);
json_object_int_add(json_record, "prefixLenMax",
record->max_len);
json_object_int_add(json_record, "asn", record->asn);
asn_asn2json(json_record, "asn", record->asn, asnotation);
json_object_array_add(json, json_record);
}
}
@ -299,7 +302,7 @@ static void print_record_by_asn(const struct pfx_record *record, void *data)
if (record->asn == arg->as) {
(*arg->prefix_amount)++;
print_record(record, vty, arg->json);
print_record(record, vty, arg->json, arg->asnotation);
}
}
@ -310,7 +313,7 @@ static void print_record_cb(const struct pfx_record *record, void *data)
(*arg->prefix_amount)++;
print_record(record, vty, arg->json);
print_record(record, vty, arg->json, arg->asnotation);
}
static struct rtr_mgr_group *get_groups(void)
@ -728,6 +731,7 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as,
arg.vty = vty;
arg.as = as;
arg.json = NULL;
arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
if (!group) {
if (!json)
@ -780,6 +784,7 @@ static void print_prefix_table(struct vty *vty, json_object *json)
arg.vty = vty;
arg.json = NULL;
arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
if (!group) {
if (!json)
@ -1337,7 +1342,7 @@ DEFPY (show_rpki_prefix_table,
DEFPY (show_rpki_as_number,
show_rpki_as_number_cmd,
"show rpki as-number (1-4294967295)$by_asn [json$uj]",
"show rpki as-number ASNUM$by_asn [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup by ASN in prefix table\n"
@ -1345,23 +1350,28 @@ DEFPY (show_rpki_as_number,
JSON_STR)
{
struct json_object *json = NULL;
as_t as;
if (!is_synchronized()) {
if (!uj)
vty_out(vty, "No Connection to RPKI cache server.\n");
return CMD_WARNING;
}
if (!asn_str2asn(by_asn, &as)) {
if (!uj)
vty_out(vty, "Invalid AS value: %s.\n", by_asn);
return CMD_WARNING;
}
if (uj)
json = json_object_new_object();
print_prefix_table_by_asn(vty, by_asn, json);
print_prefix_table_by_asn(vty, as, json);
return CMD_SUCCESS;
}
DEFPY (show_rpki_prefix,
show_rpki_prefix_cmd,
"show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn] [json$uj]",
"show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup IP prefix and optionally ASN in prefix table\n"
@ -1372,6 +1382,8 @@ DEFPY (show_rpki_prefix,
{
json_object *json = NULL;
json_object *json_records = NULL;
as_t as;
enum asnotation_mode asnotation;
if (!is_synchronized()) {
if (!uj)
@ -1392,13 +1404,19 @@ DEFPY (show_rpki_prefix,
return CMD_WARNING;
}
if (asn && !asn_str2asn(asn, &as)) {
if (!uj)
vty_out(vty, "Invalid AS value: %s.\n", asn);
return CMD_WARNING;
}
struct pfx_record *matches = NULL;
unsigned int match_count = 0;
enum pfxv_state result;
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
asn, &addr, prefix->prefixlen, &result)
!= PFX_SUCCESS) {
as, &addr, prefix->prefixlen,
&result) != PFX_SUCCESS) {
if (!json)
vty_out(vty, "Prefix lookup failed\n");
return CMD_WARNING;
@ -1415,13 +1433,14 @@ DEFPY (show_rpki_prefix,
json_object_object_add(json, "prefixes", json_records);
}
asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT));
for (size_t i = 0; i < match_count; ++i) {
const struct pfx_record *record = &matches[i];
if (record->max_len >= prefix->prefixlen
&& ((asn != 0 && (uint32_t)asn == record->asn)
|| asn == 0)) {
print_record(&matches[i], vty, json_records);
if (record->max_len >= prefix->prefixlen &&
((as != 0 && (uint32_t)as == record->asn) || as == 0)) {
print_record(&matches[i], vty, json_records,
asnotation);
}
}

View File

@ -149,7 +149,8 @@ void lua_decode_attr(lua_State *L, int idx, struct attr *attr)
attr->nh_ifindex = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, idx, "aspath");
attr->aspath = aspath_str2aspath(lua_tostring(L, -1));
attr->aspath = aspath_str2aspath(lua_tostring(L, -1),
bgp_get_asnotation(NULL));
lua_pop(L, 1);
lua_getfield(L, idx, "localpref");
attr->local_pref = lua_tointeger(L, -1);

View File

@ -24,6 +24,7 @@
#include "queue.h"
#include "filter.h"
#include "frrstr.h"
#include "asn.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr_evpn.h"
@ -579,9 +580,10 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi)
}
int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type inst_type)
enum bgp_instance_type inst_type, const char *as_pretty,
enum asnotation_mode asnotation)
{
int ret = bgp_get(bgp, as, name, inst_type);
int ret = bgp_get(bgp, as, name, inst_type, as_pretty, asnotation);
if (ret == BGP_CREATED) {
bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
@ -1222,7 +1224,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
/* Clear all neighbors belonging to a specific AS. */
if (sort == clear_as) {
as_t as = strtoul(arg, NULL, 10);
as_t as;
if (!asn_str2asn(arg, &as)) {
vty_out(vty, "%% BGP: No such AS %s\n", arg);
return CMD_WARNING;
}
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as != as)
@ -1460,16 +1467,23 @@ DEFUN (no_auto_summary,
/* "router bgp" commands. */
DEFUN_NOSH (router_bgp,
router_bgp_cmd,
"router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
"router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
ROUTER_STR
BGP_STR
AS_STR
BGP_INSTANCE_HELP_STR)
BGP_INSTANCE_HELP_STR
"Force the AS notation output\n"
"use 'AA.BB' format for AS 4 byte values\n"
"use 'AA.BB' format for all AS values\n"
"use plain format for all AS values\n")
{
int idx_asn = 2;
int idx_view_vrf = 3;
int idx_vrf = 4;
int is_new_bgp = 0;
int idx_asnotation = 3;
int idx_asnotation_kind = 4;
enum asnotation_mode asnotation = ASNOTATION_UNDEFINED;
int ret;
as_t as;
struct bgp *bgp;
@ -1494,39 +1508,62 @@ DEFUN_NOSH (router_bgp,
// "router bgp X"
else {
as = strtoul(argv[idx_asn]->arg, NULL, 10);
if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
vty_out(vty, "%% BGP: No such AS %s\n",
argv[idx_asn]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
if (as == BGP_PRIVATE_AS_MAX || as == BGP_AS4_MAX)
vty_out(vty, "Reserved AS used (%u|%u); AS is %u\n",
BGP_PRIVATE_AS_MAX, BGP_AS4_MAX, as);
inst_type = BGP_INSTANCE_TYPE_DEFAULT;
if (argc > 3) {
name = argv[idx_vrf]->arg;
if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
if (strmatch(name, VRF_DEFAULT_NAME))
name = NULL;
else
inst_type = BGP_INSTANCE_TYPE_VRF;
} else if (!strcmp(argv[idx_view_vrf]->text, "view"))
inst_type = BGP_INSTANCE_TYPE_VIEW;
if (argv_find(argv, argc, "VIEWVRFNAME", &idx_vrf)) {
idx_view_vrf = idx_vrf - 1;
if (argv[idx_view_vrf]->text) {
name = argv[idx_vrf]->arg;
if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
if (strmatch(name, VRF_DEFAULT_NAME))
name = NULL;
else
inst_type =
BGP_INSTANCE_TYPE_VRF;
} else if (!strcmp(argv[idx_view_vrf]->text,
"view"))
inst_type = BGP_INSTANCE_TYPE_VIEW;
}
}
if (argv_find(argv, argc, "as-notation", &idx_asnotation)) {
idx_asnotation_kind = idx_asnotation + 1;
if (strmatch(argv[idx_asnotation_kind]->text, "dot+"))
asnotation = ASNOTATION_DOTPLUS;
else if (strmatch(argv[idx_asnotation_kind]->text,
"dot"))
asnotation = ASNOTATION_DOT;
else if (strmatch(argv[idx_asnotation_kind]->text,
"plain"))
asnotation = ASNOTATION_PLAIN;
}
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
is_new_bgp = (bgp_lookup(as, name) == NULL);
ret = bgp_get_vty(&bgp, &as, name, inst_type);
ret = bgp_get_vty(&bgp, &as, name, inst_type,
argv[idx_asn]->arg, asnotation);
switch (ret) {
case BGP_ERR_AS_MISMATCH:
vty_out(vty, "BGP is already running; AS is %u\n", as);
vty_out(vty, "BGP is already running; AS is %s\n",
bgp->as_pretty);
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_INSTANCE_MISMATCH:
vty_out(vty,
"BGP instance name and AS number mismatch\n");
vty_out(vty,
"BGP instance is already running; AS is %u\n",
as);
"BGP instance is already running; AS is %s\n",
bgp->as_pretty);
return CMD_WARNING_CONFIG_FAILED;
}
@ -1542,6 +1579,19 @@ DEFUN_NOSH (router_bgp,
bgp_vpn_leak_export(bgp);
/* Pending: handle when user tries to change a view to vrf n vv.
*/
/* for pre-existing bgp instance,
* - update as_pretty
* - update asnotation if explicitly mentioned
*/
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
XFREE(MTYPE_BGP, bgp->as_pretty);
bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg);
if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) &&
asnotation != ASNOTATION_UNDEFINED) {
SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
bgp->asnotation = asnotation;
}
}
}
/* unset the auto created flag as the user config is now present */
@ -1554,12 +1604,16 @@ DEFUN_NOSH (router_bgp,
/* "no router bgp" commands. */
DEFUN (no_router_bgp,
no_router_bgp_cmd,
"no router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
"no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
NO_STR
ROUTER_STR
BGP_STR
AS_STR
BGP_INSTANCE_HELP_STR)
BGP_INSTANCE_HELP_STR
"Force the AS notation output\n"
"use 'AA.BB' format for AS 4 byte values\n"
"use 'AA.BB' format for all AS values\n"
"use plain format for all AS values\n")
{
int idx_asn = 3;
int idx_vrf = 5;
@ -1588,8 +1642,11 @@ DEFUN (no_router_bgp,
return CMD_WARNING_CONFIG_FAILED;
}
} else {
as = strtoul(argv[idx_asn]->arg, NULL, 10);
if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
vty_out(vty, "%% BGP: No such AS %s\n",
argv[idx_asn]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
if (argc > 4) {
name = argv[idx_vrf]->arg;
if (strmatch(argv[idx_vrf - 1]->text, "vrf")
@ -1821,7 +1878,6 @@ DEFPY (bgp_suppress_fib_pending,
return CMD_SUCCESS;
}
/* BGP Cluster ID. */
DEFUN (bgp_cluster_id,
bgp_cluster_id_cmd,
@ -1917,30 +1973,33 @@ DEFPY (no_bgp_send_extra_data,
DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd,
"bgp confederation identifier (1-4294967295)",
"bgp confederation identifier ASNUM",
BGP_STR
"AS confederation parameters\n"
"AS number\n"
AS_STR
"Set routing domain confederation AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
as_t as;
as = strtoul(argv[idx_number]->arg, NULL, 10);
if (!asn_str2asn(argv[idx_number]->arg, &as)) {
vty_out(vty, "%% BGP: No such AS %s\n", argv[idx_number]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
bgp_confederation_id_set(bgp, as);
bgp_confederation_id_set(bgp, as, argv[idx_number]->arg);
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_identifier,
no_bgp_confederation_identifier_cmd,
"no bgp confederation identifier [(1-4294967295)]",
"no bgp confederation identifier [ASNUM]",
NO_STR
BGP_STR
"AS confederation parameters\n"
"AS number\n"
AS_STR
"Set routing domain confederation AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
@ -1951,7 +2010,7 @@ DEFUN (no_bgp_confederation_identifier,
DEFUN (bgp_confederation_peers,
bgp_confederation_peers_cmd,
"bgp confederation peers (1-4294967295)...",
"bgp confederation peers ASNUM...",
BGP_STR
"AS confederation parameters\n"
"Peer ASs in BGP confederation\n"
@ -1963,15 +2022,20 @@ DEFUN (bgp_confederation_peers,
int i;
for (i = idx_asn; i < argc; i++) {
as = strtoul(argv[i]->arg, NULL, 10);
bgp_confederation_peers_add(bgp, as);
if (!asn_str2asn(argv[i]->arg, &as)) {
vty_out(vty, "%% Invalid confed peer AS value: %s\n",
argv[i]->arg);
continue;
}
bgp_confederation_peers_add(bgp, as, argv[i]->arg);
}
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_peers,
no_bgp_confederation_peers_cmd,
"no bgp confederation peers (1-4294967295)...",
"no bgp confederation peers ASNUM...",
NO_STR
BGP_STR
"AS confederation parameters\n"
@ -1984,8 +2048,11 @@ DEFUN (no_bgp_confederation_peers,
int i;
for (i = idx_asn; i < argc; i++) {
as = strtoul(argv[i]->arg, NULL, 10);
if (!asn_str2asn(argv[i]->arg, &as)) {
vty_out(vty, "%% Invalid confed peer AS value: %s\n",
argv[i]->arg);
continue;
}
bgp_confederation_peers_remove(bgp, as);
}
return CMD_SUCCESS;
@ -4489,11 +4556,13 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
} else if (as_str[0] == 'e') {
as = 0;
as_type = AS_EXTERNAL;
} else {
/* Get AS number. */
as = strtoul(as_str, NULL, 10);
}
} else if (!asn_str2asn(as_str, &as))
as_type = AS_UNSPECIFIED;
if (as_type == AS_UNSPECIFIED) {
vty_out(vty, "%% Invalid peer AS: %s\n", as_str);
return CMD_WARNING_CONFIG_FAILED;
}
/* If peer is peer group or interface peer, call proper function. */
ret = str2sockunion(peer_str, &su);
if (ret < 0) {
@ -4502,11 +4571,12 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
/* Check if existing interface peer */
peer = peer_lookup_by_conf_if(bgp, peer_str);
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type);
ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, as_str);
/* if not interface peer, check peer-group settings */
if (ret < 0 && !peer) {
ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
ret = peer_group_remote_as(bgp, peer_str, &as, as_type,
as_str);
if (ret < 0) {
vty_out(vty,
"%% Create the peer-group or interface first\n");
@ -4520,7 +4590,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
"%% Can not configure the local system as neighbor\n");
return CMD_WARNING_CONFIG_FAILED;
}
ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
ret = peer_remote_as(bgp, &su, NULL, &as, as_type, as_str);
}
return bgp_vty_return(vty, ret);
@ -4591,7 +4661,7 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
"neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
@ -4671,18 +4741,19 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
as_type = AS_EXTERNAL;
} else {
/* Get AS number. */
as = strtoul(as_str, NULL, 10);
as_type = AS_SPECIFIED;
if (asn_str2asn(as_str, &as))
as_type = AS_SPECIFIED;
}
}
peer = peer_lookup_by_conf_if(bgp, conf_if);
if (peer) {
if (as_str)
ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type,
as_str);
} else {
peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
NULL, true);
NULL, true, as_str);
if (!peer) {
vty_out(vty, "%% BGP failed to create peer\n");
@ -4784,7 +4855,7 @@ DEFUN (neighbor_interface_config_v6only,
DEFUN (neighbor_interface_config_remote_as,
neighbor_interface_config_remote_as_cmd,
"neighbor WORD interface remote-as <(1-4294967295)|internal|external>",
"neighbor WORD interface remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP on interface\n"
@ -4801,7 +4872,7 @@ DEFUN (neighbor_interface_config_remote_as,
DEFUN (neighbor_interface_v6only_config_remote_as,
neighbor_interface_v6only_config_remote_as_cmd,
"neighbor WORD interface v6only remote-as <(1-4294967295)|internal|external>",
"neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP with v6 link-local only\n"
@ -4970,7 +5041,7 @@ DEFUN (no_neighbor_peer_group,
DEFUN (no_neighbor_interface_peer_group_remote_as,
no_neighbor_interface_peer_group_remote_as_cmd,
"no neighbor WORD remote-as <(1-4294967295)|internal|external>",
"no neighbor WORD remote-as <ASNUM|internal|external>",
NO_STR
NEIGHBOR_STR
"Interface name or neighbor tag\n"
@ -4987,7 +5058,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
/* look up for neighbor by interface name config. */
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
if (peer) {
peer_as_change(peer, 0, AS_UNSPECIFIED);
peer_as_change(peer, 0, AS_UNSPECIFIED, NULL);
return CMD_SUCCESS;
}
@ -5003,11 +5074,11 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
DEFUN (neighbor_local_as,
neighbor_local_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295)",
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number used as local AS\n")
"AS number expressed in dotted or plain format used as local AS\n")
{
int idx_peer = 1;
int idx_number = 3;
@ -5019,18 +5090,23 @@ DEFUN (neighbor_local_as,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 0, 0);
if (!asn_str2asn(argv[idx_number]->arg, &as)) {
vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
argv[idx_number]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
ret = peer_local_as_set(peer, as, 0, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_local_as_no_prepend,
neighbor_local_as_no_prepend_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend",
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number used as local AS\n"
"AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n")
{
int idx_peer = 1;
@ -5043,18 +5119,23 @@ DEFUN (neighbor_local_as_no_prepend,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 1, 0);
if (!asn_str2asn(argv[idx_number]->arg, &as)) {
vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
argv[idx_number]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
ret = peer_local_as_set(peer, as, 1, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_local_as_no_prepend_replace_as,
neighbor_local_as_no_prepend_replace_as_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend replace-as",
"neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number used as local AS\n"
"AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
"Do not prepend local-as to updates from ibgp peers\n")
{
@ -5068,19 +5149,24 @@ DEFUN (neighbor_local_as_no_prepend_replace_as,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
as = strtoul(argv[idx_number]->arg, NULL, 10);
ret = peer_local_as_set(peer, as, 1, 1);
if (!asn_str2asn(argv[idx_number]->arg, &as)) {
vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
argv[idx_number]->arg);
return CMD_WARNING_CONFIG_FAILED;
}
ret = peer_local_as_set(peer, as, 1, 1, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (no_neighbor_local_as,
no_neighbor_local_as_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [(1-4294967295) [no-prepend [replace-as]]]",
"no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
"AS number used as local AS\n"
"AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
"Do not prepend local-as to updates from ibgp peers\n")
{
@ -9020,10 +9106,13 @@ DEFPY (af_rd_vpn_export,
bgp_get_default(), bgp);
if (yes) {
bgp->vpn_policy[afi].tovpn_rd_pretty =
XSTRDUP(MTYPE_BGP, rd_str);
bgp->vpn_policy[afi].tovpn_rd = prd;
SET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
} else {
XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
UNSET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
}
@ -9548,7 +9637,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&bgp_default, &as, NULL,
BGP_INSTANCE_TYPE_DEFAULT);
BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
@ -9660,7 +9750,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
if (!bgp_default) {
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&bgp_default, &as, NULL,
BGP_INSTANCE_TYPE_DEFAULT);
BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
@ -9675,8 +9766,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
vrf_bgp = bgp_default;
else
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type);
ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
NULL, ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
"VRF %s is not configured as a bgp instance\n",
@ -10144,7 +10235,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
/* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd,
"clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
"clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
CLEAR_STR
IP_STR
BGP_STR
@ -10157,7 +10248,7 @@ DEFUN (clear_ip_bgp_all,
"BGP IPv4 neighbor to clear\n"
"BGP IPv6 neighbor to clear\n"
"BGP neighbor on interface to clear\n"
"Clear peers with the AS number\n"
"Clear peers with the AS number in plain or dotted format\n"
"Clear all external peers\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
@ -10198,7 +10289,7 @@ DEFUN (clear_ip_bgp_all,
if (argv_find_and_parse_afi(argv, argc, &idx, &afi))
argv_find_and_parse_safi(argv, argc, &idx, &safi);
/* <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group PGNAME> */
/* <*|A.B.C.D|X:X::X:X|WORD|ASNUM|external|peer-group PGNAME> */
if (argv_find(argv, argc, "*", &idx)) {
clr_sort = clear_all;
} else if (argv_find(argv, argc, "A.B.C.D", &idx)) {
@ -10217,7 +10308,7 @@ DEFUN (clear_ip_bgp_all,
} else if (argv_find(argv, argc, "WORD", &idx)) {
clr_sort = clear_peer;
clr_arg = argv[idx]->arg;
} else if (argv_find(argv, argc, "(1-4294967295)", &idx)) {
} else if (argv_find(argv, argc, "ASNUM", &idx)) {
clr_sort = clear_as;
clr_arg = argv[idx]->arg;
} else if (argv_find(argv, argc, "external", &idx)) {
@ -10355,8 +10446,8 @@ DEFUN (show_bgp_views,
/* Skip VRFs. */
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
continue;
vty_out(vty, "\t%s (AS%u)\n", bgp->name ? bgp->name : "(null)",
bgp->as);
vty_out(vty, "\t%s (AS%s)\n", bgp->name ? bgp->name : "(null)",
bgp->as_pretty);
}
return CMD_SUCCESS;
@ -11142,7 +11233,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_string_addf(json, "routerId",
"%pI4",
&bgp->router_id);
json_object_int_add(json, "as", bgp->as);
asn_asn2json(json, "as", bgp->as,
bgp->asnotation);
json_object_int_add(json, "vrfId", vrf_id_ui);
json_object_string_add(
json, "vrfName",
@ -11152,8 +11244,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
: bgp->name);
} else {
vty_out(vty,
"BGP router identifier %pI4, local AS number %u vrf-id %d",
&bgp->router_id, bgp->as,
"BGP router identifier %pI4, local AS number %s vrf-id %d",
&bgp->router_id, bgp->as_pretty,
bgp->vrf_id == VRF_UNKNOWN
? -1
: (int)bgp->vrf_id);
@ -11387,12 +11479,13 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_string_add(json_peer, "domainname",
peer->domainname);
json_object_int_add(json_peer, "remoteAs", peer->as);
json_object_int_add(
json_peer, "localAs",
peer->change_local_as
? peer->change_local_as
: peer->local_as);
asn_asn2json(json_peer, "remoteAs", peer->as,
bgp->asnotation);
asn_asn2json(json_peer, "localAs",
peer->change_local_as
? peer->change_local_as
: peer->local_as,
bgp->asnotation);
json_object_int_add(json_peer, "version", 4);
json_object_int_add(json_peer, "msgRcvd",
PEER_TOTAL_RX(peer));
@ -11572,14 +11665,19 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
&peer->ibuf->count,
memory_order_relaxed);
if (show_wide)
vty_out(vty, "4 ");
vty_out(vty, ASN_FORMAT_SPACE(bgp->asnotation),
&peer->as);
if (show_wide) {
vty_out(vty,
"4 %10u %10u %9u %9u %8" PRIu64
" %4zu %4zu %8s",
peer->as,
ASN_FORMAT_SPACE(
bgp->asnotation),
peer->change_local_as
? peer->change_local_as
: peer->local_as,
? &peer->change_local_as
: &peer->local_as);
vty_out(vty,
" %9u %9u %8" PRIu64
" %4zu %4zu %8s",
PEER_TOTAL_RX(peer),
PEER_TOTAL_TX(peer),
peer->version[afi][safi],
@ -11588,10 +11686,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
timebuf,
BGP_UPTIME_LEN, 0,
NULL));
else
vty_out(vty, "4 %10u %9u %9u %8" PRIu64
" %4zu %4zu %8s",
peer->as, PEER_TOTAL_RX(peer),
} else {
vty_out(vty,
" %9u %9u %8" PRIu64
" %4zu %4zu %8s",
PEER_TOTAL_RX(peer),
PEER_TOTAL_TX(peer),
peer->version[afi][safi],
inq_count, outq_count,
@ -11599,7 +11698,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
timebuf,
BGP_UPTIME_LEN, 0,
NULL));
}
if (peer_established(peer)) {
if (peer->afc_recv[afi][safi]) {
if (CHECK_FLAG(
@ -11892,7 +11991,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
" [" BGP_SAFI_WITH_LABEL_CMD_STR
"]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [json$uj]",
"]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <ASNUM|internal|external>>] [terse] [wide] [json$uj]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display the entries for all address families\n"
@ -11903,8 +12002,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
"Neighbor to display information about\n"
"Neighbor to display information about\n"
"Neighbor on BGP configured interface\n"
"Show only the specified remote AS sessions\n"
"AS number\n"
"Show only the specified remote AS sessions\n" AS_STR
"Internal (iBGP) AS sessions\n"
"External (eBGP) AS sessions\n"
"Shorten the information on BGP instances\n"
@ -11946,8 +12044,12 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
as_type = AS_INTERNAL;
else if (argv[idx + 1]->arg[0] == 'e')
as_type = AS_EXTERNAL;
else
as = (as_t)atoi(argv[idx + 1]->arg);
else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
vty_out(vty,
"%% Invalid neighbor remote-as value: %s\n",
argv[idx + 1]->arg);
return CMD_SUCCESS;
}
}
if (argv_find(argv, argc, "terse", &idx))
@ -13082,13 +13184,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_string_addf(json_neigh, "bgpNeighborAddr",
"%pSU", &p->su);
json_object_int_add(json_neigh, "remoteAs", p->as);
asn_asn2json(json_neigh, "remoteAs", p->as, bgp->asnotation);
if (p->change_local_as)
json_object_int_add(json_neigh, "localAs",
p->change_local_as);
asn_asn2json(json_neigh, "localAs", p->change_local_as,
bgp->asnotation);
else
json_object_int_add(json_neigh, "localAs", p->local_as);
asn_asn2json(json_neigh, "localAs", p->local_as,
bgp->asnotation);
if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
json_object_boolean_true_add(json_neigh,
@ -13098,13 +13201,19 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_boolean_true_add(json_neigh,
"localAsReplaceAs");
} else {
if ((p->as_type == AS_SPECIFIED) || (p->as_type == AS_EXTERNAL)
|| (p->as_type == AS_INTERNAL))
vty_out(vty, "remote AS %u, ", p->as);
else
if ((p->as_type == AS_SPECIFIED) ||
(p->as_type == AS_EXTERNAL) ||
(p->as_type == AS_INTERNAL)) {
vty_out(vty, "remote AS ");
vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
vty_out(vty, ", ");
} else
vty_out(vty, "remote AS Unspecified, ");
vty_out(vty, "local AS %u%s%s, ",
p->change_local_as ? p->change_local_as : p->local_as,
vty_out(vty, "local AS ");
vty_out(vty, ASN_FORMAT(bgp->asnotation),
p->change_local_as ? &p->change_local_as
: &p->local_as);
vty_out(vty, "%s%s, ",
CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
? " no-prepend"
: "",
@ -15577,10 +15686,9 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
json_object_new_string(vname));
json_object_object_add(json, "exportToVrfs",
json_export_vrfs);
json_object_string_addf(json, "routeDistinguisher",
"%pRD",
&bgp->vpn_policy[afi].tovpn_rd);
json_object_string_addf(
json, "routeDistinguisher", "%s",
bgp->vpn_policy[afi].tovpn_rd_pretty);
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
ecom_str = ecommunity_ecom2str(
@ -15648,8 +15756,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
node, vname))
vty_out(vty, " %s\n", vname);
vty_out(vty, "RD: %pRD\n",
vty_out(vty, "RD: ");
vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
&bgp->vpn_policy[afi].tovpn_rd);
vty_out(vty, "\n");
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
@ -16014,18 +16124,22 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
if (json)
json_object_int_add(json_peer_group, "remoteAs",
conf->as);
else
vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
group->name, conf->as);
asn_asn2json(json_peer_group, "remoteAs", conf->as,
bgp_get_asnotation(conf->bgp));
else {
vty_out(vty, "\nBGP peer-group %s, remote AS ",
group->name);
vty_out(vty, ASN_FORMAT(bgp_get_asnotation(conf->bgp)),
&conf->as);
vty_out(vty, "\n");
}
} else if (conf->as_type == AS_INTERNAL) {
if (json)
json_object_int_add(json_peer_group, "remoteAs",
group->bgp->as);
asn_asn2json(json, "remoteAs", group->bgp->as,
group->bgp->asnotation);
else
vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
group->name, group->bgp->as);
vty_out(vty, "\nBGP peer-group %s, remote AS %s\n",
group->name, group->bgp->as_pretty);
} else {
if (!json)
vty_out(vty, "\nBGP peer-group %s\n", group->name);
@ -17148,8 +17262,8 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
}
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET))
vty_out(vty, "%*srd vpn export %pRD\n", indent, "",
&bgp->vpn_policy[afi].tovpn_rd);
vty_out(vty, "%*srd vpn export %s\n", indent, "",
bgp->vpn_policy[afi].tovpn_rd_pretty);
if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
@ -17319,7 +17433,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " peer-group %s", peer->group->name);
if_pg_printed = true;
} else if (peer->as_type == AS_SPECIFIED) {
vty_out(vty, " remote-as %u", peer->as);
vty_out(vty, " remote-as %s", peer->as_pretty);
if_ras_printed = true;
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty, " remote-as internal");
@ -17339,8 +17453,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) {
if (peer->as_type == AS_SPECIFIED) {
vty_out(vty, " neighbor %s remote-as %u\n",
addr, peer->as);
vty_out(vty, " neighbor %s remote-as %s\n",
addr, peer->as_pretty);
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty,
" neighbor %s remote-as internal\n",
@ -17368,8 +17482,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (!if_ras_printed) {
if (peer->as_type == AS_SPECIFIED) {
vty_out(vty, " neighbor %s remote-as %u\n",
addr, peer->as);
vty_out(vty, " neighbor %s remote-as %s\n",
addr, peer->as_pretty);
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty,
" neighbor %s remote-as internal\n",
@ -17384,8 +17498,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
/* local-as */
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) {
vty_out(vty, " neighbor %s local-as %u", addr,
peer->change_local_as);
vty_out(vty, " neighbor %s local-as %s", addr,
peer->change_local_as_pretty);
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND))
vty_out(vty, " no-prepend");
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
@ -18066,12 +18180,16 @@ int bgp_config_write(struct vty *vty)
continue;
/* Router bgp ASN */
vty_out(vty, "router bgp %u", bgp->as);
vty_out(vty, "router bgp %s", bgp->as_pretty);
if (bgp->name)
vty_out(vty, " %s %s",
(bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
? "view" : "vrf", bgp->name);
if (CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION))
vty_out(vty, " as-notation %s",
asn_mode2str(bgp->asnotation));
vty_out(vty, "\n");
/* BGP fast-external-failover. */
@ -18189,8 +18307,8 @@ int bgp_config_write(struct vty *vty)
/* Confederation identifier*/
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
vty_out(vty, " bgp confederation identifier %u\n",
bgp->confed_id);
vty_out(vty, " bgp confederation identifier %s\n",
bgp->confed_id_pretty);
/* Confederation peer */
if (bgp->confed_peers_cnt > 0) {
@ -18199,7 +18317,8 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, " bgp confederation peers");
for (i = 0; i < bgp->confed_peers_cnt; i++)
vty_out(vty, " %u", bgp->confed_peers[i]);
vty_out(vty, " %s",
bgp->confed_peers[i].as_pretty);
vty_out(vty, "\n");
}

View File

@ -135,7 +135,8 @@ extern void bgp_vty_init(void);
extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type inst_type);
enum bgp_instance_type inst_type, const char *as_pretty,
enum asnotation_mode asnotation);
extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp);
extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp);

View File

@ -553,7 +553,7 @@ void bgp_tcp_keepalive_unset(struct bgp *bgp)
}
/* BGP confederation configuration. */
void bgp_confederation_id_set(struct bgp *bgp, as_t as)
void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str)
{
struct peer *peer;
struct listnode *node, *nnode;
@ -565,6 +565,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as)
/* Remember - were we doing confederation before? */
already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION);
bgp->confed_id = as;
if (bgp->confed_id_pretty)
XFREE(MTYPE_BGP, bgp->confed_id_pretty);
bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str);
bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION);
/* If we were doing confederation already, this is just an external
@ -617,6 +620,7 @@ void bgp_confederation_id_unset(struct bgp *bgp)
struct listnode *node, *nnode;
bgp->confed_id = 0;
XFREE(MTYPE_BGP, bgp->confed_id_pretty);
bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
@ -644,14 +648,14 @@ bool bgp_confederation_peers_check(struct bgp *bgp, as_t as)
return false;
for (i = 0; i < bgp->confed_peers_cnt; i++)
if (bgp->confed_peers[i] == as)
if (bgp->confed_peers[i].as == as)
return true;
return false;
}
/* Add an AS to the confederation set. */
void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str)
{
struct peer *peer;
struct listnode *node, *nnode;
@ -662,11 +666,13 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
if (bgp_confederation_peers_check(bgp, as))
return;
bgp->confed_peers =
XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
(bgp->confed_peers_cnt + 1) * sizeof(as_t));
bgp->confed_peers = XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
(bgp->confed_peers_cnt + 1) *
sizeof(struct as_confed));
bgp->confed_peers[bgp->confed_peers_cnt] = as;
bgp->confed_peers[bgp->confed_peers_cnt].as = as;
bgp->confed_peers[bgp->confed_peers_cnt].as_pretty =
XSTRDUP(MTYPE_BGP, as_str);
bgp->confed_peers_cnt++;
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
@ -703,9 +709,15 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
return;
for (i = 0; i < bgp->confed_peers_cnt; i++)
if (bgp->confed_peers[i] == as)
for (j = i + 1; j < bgp->confed_peers_cnt; j++)
bgp->confed_peers[j - 1] = bgp->confed_peers[j];
if (bgp->confed_peers[i].as == as) {
XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty);
for (j = i + 1; j < bgp->confed_peers_cnt; j++) {
bgp->confed_peers[j - 1].as =
bgp->confed_peers[j].as;
bgp->confed_peers[j - 1].as_pretty =
bgp->confed_peers[j].as_pretty;
}
}
bgp->confed_peers_cnt--;
@ -714,9 +726,9 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
bgp->confed_peers = NULL;
} else
bgp->confed_peers =
XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
bgp->confed_peers_cnt * sizeof(as_t));
bgp->confed_peers = XREALLOC(
MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
bgp->confed_peers_cnt * sizeof(struct as_confed));
/* Now reset any peer who's remote AS has just been removed from the
CONFED */
@ -1172,6 +1184,11 @@ static void peer_free(struct peer *peer)
FOREACH_AFI_SAFI (afi, safi)
bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
if (peer->change_local_as_pretty)
XFREE(MTYPE_BGP, peer->change_local_as_pretty);
if (peer->as_pretty)
XFREE(MTYPE_BGP, peer->as_pretty);
bgp_unlock(peer->bgp);
memset(peer, 0, sizeof(struct peer));
@ -1753,7 +1770,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
int as_type, struct peer_group *group,
bool config_node)
bool config_node, const char *as_str)
{
int active;
struct peer *peer;
@ -1778,6 +1795,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
}
peer->local_as = local_as;
peer->as = remote_as;
/* internal and external values do not use as_pretty */
if (as_str && asn_str2asn(as_str, NULL))
peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
peer->as_type = as_type;
peer->local_id = bgp->router_id;
peer->v_holdtime = bgp->default_holdtime;
@ -1881,7 +1901,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
}
/* Change peer's AS number. */
void peer_as_change(struct peer *peer, as_t as, int as_specified)
void peer_as_change(struct peer *peer, as_t as, int as_specified,
const char *as_str)
{
enum bgp_peer_sort origtype, newtype;
@ -1896,6 +1917,12 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
}
origtype = peer_sort_lookup(peer);
peer->as = as;
if (as_specified == AS_SPECIFIED && as_str) {
if (peer->as_pretty)
XFREE(MTYPE_BGP, peer->as_pretty);
peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
} else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty)
XFREE(MTYPE_BGP, peer->as_pretty);
peer->as_type = as_specified;
if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
@ -1953,7 +1980,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
as_t *as, int as_type)
as_t *as, int as_type, const char *as_str)
{
struct peer *peer;
as_t local_as;
@ -2007,7 +2034,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
/* Existing peer's AS number change. */
if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
|| (peer->as_type != as_type))
peer_as_change(peer, *as, as_type);
peer_as_change(peer, *as, as_type, as_str);
} else {
if (conf_if)
return BGP_ERR_NO_INTERFACE_CONFIG;
@ -2022,7 +2049,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
local_as = bgp->as;
peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL,
true);
true, as_str);
}
return 0;
@ -2047,6 +2074,13 @@ const char *bgp_get_name_by_role(uint8_t role)
return "unknown";
}
enum asnotation_mode bgp_get_asnotation(struct bgp *bgp)
{
if (!bgp)
return ASNOTATION_PLAIN;
return bgp->asnotation;
}
static void peer_group2peer_config_copy_af(struct peer_group *group,
struct peer *peer, afi_t afi,
safi_t safi)
@ -2804,7 +2838,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
/* Peer group's remote AS configuration. */
int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
int as_type)
int as_type, const char *as_str)
{
struct peer_group *group;
struct peer *peer;
@ -2820,12 +2854,12 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
/* When we setup peer-group AS number all peer group member's AS
number must be updated to same number. */
peer_as_change(group->conf, *as, as_type);
peer_as_change(group->conf, *as, as_type, as_str);
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
|| (peer->as_type != as_type))
peer_as_change(peer, *as, as_type);
peer_as_change(peer, *as, as_type, as_str);
}
return 0;
@ -3132,7 +3166,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
}
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
group->conf->as_type, group, true);
group->conf->as_type, group, true, NULL);
peer = peer_lock(peer); /* group->peer list reference */
listnode_add(group->peer, peer);
@ -3184,23 +3218,37 @@ static void bgp_vrf_string_name_delete(void *data)
/* BGP instance creation by `router bgp' commands. */
static struct bgp *bgp_create(as_t *as, const char *name,
enum bgp_instance_type inst_type)
enum bgp_instance_type inst_type,
const char *as_pretty,
enum asnotation_mode asnotation)
{
struct bgp *bgp;
afi_t afi;
safi_t safi;
bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp));
bgp->as = *as;
if (as_pretty)
bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty);
else
bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as));
if (asnotation != ASNOTATION_UNDEFINED) {
bgp->asnotation = asnotation;
SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
} else
asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
if (BGP_DEBUG(zebra, ZEBRA)) {
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Creating Default VRF, AS %u", *as);
zlog_debug("Creating Default VRF, AS %s",
bgp->as_pretty);
else
zlog_debug("Creating %s %s, AS %u",
zlog_debug("Creating %s %s, AS %s",
(inst_type == BGP_INSTANCE_TYPE_VRF)
? "VRF"
: "VIEW",
name, *as);
name, bgp->as_pretty);
}
/* Default the EVPN VRF to the default one */
@ -3277,7 +3325,6 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->condition_check_period = DEFAULT_CONDITIONAL_ROUTES_POLL_TIME;
bgp_addpath_init_bgp_data(&bgp->tx_addpath);
bgp->fast_convergence = false;
bgp->as = *as;
bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
#ifdef ENABLE_BGP_VNC
@ -3514,7 +3561,8 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
/* Called from VTY commands. */
int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
enum bgp_instance_type inst_type)
enum bgp_instance_type inst_type, const char *as_pretty,
enum asnotation_mode asnotation)
{
struct bgp *bgp;
struct vrf *vrf = NULL;
@ -3524,7 +3572,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
if (ret || *bgp_val)
return ret;
bgp = bgp_create(as, name, inst_type);
bgp = bgp_create(as, name, inst_type, as_pretty, asnotation);
/*
* view instances will never work inside of a vrf
@ -3918,8 +3966,13 @@ void bgp_free(struct bgp *bgp)
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir])
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
if (bgp->vpn_policy[afi].tovpn_rd_pretty)
XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
}
bgp_confederation_id_unset(bgp);
XFREE(MTYPE_BGP, bgp->as_pretty);
XFREE(MTYPE_BGP, bgp->name);
XFREE(MTYPE_BGP, bgp->name_pretty);
XFREE(MTYPE_BGP, bgp->snmp_stats);
@ -4024,7 +4077,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
/* Create peer first; we've already checked group config is valid. */
peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
group->conf->as_type, group, true);
group->conf->as_type, group, true, NULL);
if (!peer)
return NULL;
@ -6228,7 +6281,7 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
}
int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
bool replace_as)
bool replace_as, const char *as_str)
{
bool old_no_prepend, old_replace_as;
struct bgp *bgp = peer->bgp;
@ -6253,6 +6306,9 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
&& old_replace_as == replace_as)
return 0;
peer->change_local_as = as;
if (as_str)
peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str);
(void)peer_sort(peer);
/* Check if handling a regular peer. */
@ -6286,6 +6342,9 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
replace_as);
member->change_local_as = as;
if (as_str)
member->change_local_as_pretty =
XSTRDUP(MTYPE_BGP, as_str);
}
return 0;
@ -6311,6 +6370,7 @@ int peer_local_as_unset(struct peer *peer)
peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
peer->change_local_as = 0;
XFREE(MTYPE_BGP, peer->change_local_as_pretty);
}
/* Check if handling a regular peer. */
@ -6341,6 +6401,7 @@ int peer_local_as_unset(struct peer *peer)
UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
member->change_local_as = 0;
XFREE(MTYPE_BGP, member->change_local_as_pretty);
/* Send notification or stop peer depending on state. */
if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
@ -8024,7 +8085,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
{
struct listnode *next, *next2;
struct bgp *bgp, *bgp2;
char buf[11];
char buf[ASN_STRING_MAX_SIZE];
for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
/* deduplicate */
@ -8037,7 +8098,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
if (bgp2 != bgp)
continue;
snprintf(buf, sizeof(buf), "%u", bgp->as);
snprintf(buf, sizeof(buf), "%s", bgp->as_pretty);
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, buf));
}
}

View File

@ -16,6 +16,7 @@
#include "vty.h"
#include "srv6.h"
#include "iana_afi.h"
#include "asn.h"
/* For union sockunion. */
#include "queue.h"
@ -62,7 +63,6 @@ enum zebra_gr_mode {
};
/* Typedef BGP specific types. */
typedef uint32_t as_t;
typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
typedef uint16_t bgp_size_t;
@ -203,6 +203,7 @@ struct vpn_policy {
/* should be mpls_label_t? */
uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
uint32_t tovpn_zebra_vrf_label_last_sent;
char *tovpn_rd_pretty;
struct prefix_rd tovpn_rd;
struct prefix tovpn_nexthop; /* unset => set to 0 */
uint32_t flags;
@ -324,10 +325,16 @@ struct bgp_srv6_function {
char locator_name[SRV6_LOCNAME_SIZE];
};
struct as_confed {
as_t as;
char *as_pretty;
};
/* BGP instance structure. */
struct bgp {
/* AS number of this BGP instance. */
as_t as;
char *as_pretty;
/* Name of this BGP instance. */
char *name;
@ -383,6 +390,7 @@ struct bgp {
uint16_t config;
#define BGP_CONFIG_CLUSTER_ID (1 << 0)
#define BGP_CONFIG_CONFEDERATION (1 << 1)
#define BGP_CONFIG_ASNOTATION (1 << 2)
/* BGP router identifier. */
struct in_addr router_id;
@ -394,7 +402,8 @@ struct bgp {
/* BGP confederation information. */
as_t confed_id;
as_t *confed_peers;
char *confed_id_pretty;
struct as_confed *confed_peers;
int confed_peers_cnt;
struct thread
@ -728,6 +737,7 @@ struct bgp {
/* RD for this VRF */
struct prefix_rd vrf_prd;
char *vrf_prd_pretty;
/* import rt list for the vrf instance */
struct list *vrf_import_rtl;
@ -782,6 +792,8 @@ struct bgp {
bool allow_martian;
enum asnotation_mode asnotation;
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@ -1105,6 +1117,8 @@ struct peer {
/* Peer's remote AS number. */
int as_type;
as_t as;
/* for vty as format */
char *as_pretty;
/* Peer's local AS number. */
as_t local_as;
@ -1113,6 +1127,8 @@ struct peer {
/* Peer's Change local AS number. */
as_t change_local_as;
/* for vty as format */
char *change_local_as_pretty;
/* Remote router ID. */
struct in_addr remote_id;
@ -2131,7 +2147,7 @@ extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
extern struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
int as_type, struct peer_group *group,
bool config_node);
bool config_node, const char *as_str);
extern struct peer *peer_create_accept(struct bgp *);
extern void peer_xfer_config(struct peer *dst, struct peer *src);
extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
@ -2158,7 +2174,9 @@ extern void bgp_option_norib_set_runtime(void);
/* unset the bgp no-rib option during runtime and reset all peers */
extern void bgp_option_norib_unset_runtime(void);
extern int bgp_get(struct bgp **, as_t *, const char *, enum bgp_instance_type);
extern int bgp_get(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type kind, const char *as_pretty,
enum asnotation_mode asnotation);
extern void bgp_instance_up(struct bgp *);
extern void bgp_instance_down(struct bgp *);
extern int bgp_delete(struct bgp *);
@ -2174,11 +2192,13 @@ extern void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set);
extern void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id);
extern void bgp_cluster_id_unset(struct bgp *bgp);
extern void bgp_confederation_id_set(struct bgp *bgp, as_t as);
extern void bgp_confederation_id_set(struct bgp *bgp, as_t as,
const char *as_str);
extern void bgp_confederation_id_unset(struct bgp *bgp);
extern bool bgp_confederation_peers_check(struct bgp *, as_t);
extern void bgp_confederation_peers_add(struct bgp *bgp, as_t as);
extern void bgp_confederation_peers_add(struct bgp *bgp, as_t as,
const char *as_str);
extern void bgp_confederation_peers_remove(struct bgp *bgp, as_t as);
extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime,
@ -2199,10 +2219,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp);
extern bool bgp_update_delay_active(struct bgp *);
extern bool bgp_update_delay_configured(struct bgp *);
extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
extern void peer_as_change(struct peer *, as_t, int);
extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *,
int);
extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int);
extern void peer_as_change(struct peer *peer, as_t as, int as_type,
const char *as_str);
extern int peer_remote_as(struct bgp *bgp, union sockunion *su,
const char *conf_if, as_t *as, int as_type,
const char *as_str);
extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as,
int as_type, const char *as_str);
extern int peer_delete(struct peer *peer);
extern void peer_notify_unconfig(struct peer *peer);
extern int peer_group_delete(struct peer_group *);
@ -2281,8 +2304,8 @@ extern int peer_distribute_unset(struct peer *, afi_t, safi_t, int);
extern int peer_allowas_in_set(struct peer *, afi_t, safi_t, int, int);
extern int peer_allowas_in_unset(struct peer *, afi_t, safi_t);
extern int peer_local_as_set(struct peer *, as_t, bool no_prepend,
bool replace_as);
extern int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
bool replace_as, const char *as_str);
extern int peer_local_as_unset(struct peer *);
extern int peer_prefix_list_set(struct peer *, afi_t, safi_t, int,
@ -2341,6 +2364,7 @@ extern void peer_tx_shutdown_message_unset(struct peer *);
extern void bgp_route_map_update_timer(struct thread *thread);
extern const char *bgp_get_name_by_role(uint8_t role);
extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp);
extern void bgp_route_map_terminate(void);

View File

@ -410,6 +410,7 @@ DEFUN (vnc_defaults_rd,
} else {
/* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@ -2874,6 +2875,7 @@ DEFUN (vnc_nve_group_rd,
} else {
/* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@ -3346,6 +3348,7 @@ DEFUN (vnc_vrf_policy_rd,
} else {
/* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@ -3924,7 +3927,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
vty_out(vty, " rd %pRD\n", &rfg->rd);
vty_out(vty, " rd %pRDP\n", &rfg->rd);
}
if (rfg->rt_import_list && rfg->rt_export_list
@ -4144,7 +4147,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
vty_out(vty, " rd %pRD\n",
vty_out(vty, " rd %pRDP\n",
&hc->default_rd);
}
if (hc->default_response_lifetime
@ -4224,7 +4227,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
vty_out(vty, " rd %pRD\n",
vty_out(vty, " rd %pRDP\n",
&rfg->rd);
}
if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) {

View File

@ -363,7 +363,7 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
vnc_zlog_debug_verbose(
"%s: peer=%p, prefix=%pFX, prd=%pRD afi=%d, safi=%d bn=%p, bn->info=%p",
"%s: peer=%p, prefix=%pFX, prd=%pRDP afi=%d, safi=%d bn=%p, bn->info=%p",
__func__, peer, p, prd, afi, safi, bn,
(bn ? bgp_dest_get_bgp_path_info(bn) : NULL));
@ -1053,7 +1053,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
bgp_process(bgp, bn, afi, safi);
vnc_zlog_debug_any(
"%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRD)",
"%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)",
__func__, safi2str(safi), buf, bn, prd);
done:
@ -3712,7 +3712,7 @@ int rfapi_set_autord_from_vn(struct prefix_rd *rd, struct rfapi_ip_addr *vn)
memcpy(rd->val + 2, &vn->addr.v6.s6_addr32[3],
4); /* low order 4 bytes */
}
vnc_zlog_debug_verbose("%s: auto-RD is set to %pRD", __func__, rd);
vnc_zlog_debug_verbose("%s: auto-RD is set to %pRDP", __func__, rd);
return 0;
}

View File

@ -2082,7 +2082,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
assert(bpi);
assert(bpi->extra);
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX_W_ALLOC(rn);
@ -2120,7 +2120,9 @@ static void rfapiItBiIndexDump(struct agg_node *rn)
char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
prefix_rd2str(&k->extra->vnc.import.rd, buf, sizeof(buf));
prefix_rd2str(
&k->extra->vnc.import.rd, buf, sizeof(buf),
bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
if (k->extra->vnc.import.aux_prefix.family) {
prefix2str(&k->extra->vnc.import.aux_prefix,
buf_aux_pfx, sizeof(buf_aux_pfx));
@ -2158,7 +2160,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
vnc_zlog_debug_verbose(
"%s want prd=%pRD, peer=%p, aux_prefix=%s", __func__,
"%s want prd=%pRDP, peer=%p, aux_prefix=%s", __func__,
prd, peer, buf_aux_pfx);
rfapiItBiIndexDump(rn);
}
@ -2174,7 +2176,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
bpi_result = bpi_result->next) {
#ifdef DEBUG_BI_SEARCH
vnc_zlog_debug_verbose(
"%s: bpi has prd=%pRD, peer=%p", __func__,
"%s: bpi has prd=%pRDP, peer=%p", __func__,
&bpi_result->extra->vnc.import.rd,
bpi_result->peer);
#endif
@ -2238,7 +2240,7 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
struct skiplist *sl;
int rc;
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX(rn);

View File

@ -1114,7 +1114,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
skiplist_insert(slRibPt, &ori->rk, ori);
vnc_zlog_debug_verbose(
"%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRD)",
"%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRDP)",
__func__, ri, &ori->rk.rd);
}
@ -1356,7 +1356,7 @@ callback:
ri->last_sent_time = monotime(NULL);
#if DEBUG_RIB_SL_RD
vnc_zlog_debug_verbose(
"%s: move route to recently deleted list, rd=%pRD",
"%s: move route to recently deleted list, rd=%pRDP",
__func__, &ri->rk.rd);
#endif
@ -2252,7 +2252,7 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
}
#endif
fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRD\n",
fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRDP\n",
deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn,
str_un, ri->cost, str_lifetime, str_age, &ri->rk.rd);

View File

@ -1589,7 +1589,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
vty_out(vty, " ");
rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr);
vty_out(vty, " %p %p ", rfd->response_cb, rfd->cookie);
vty_out(vty, "%pRD", &rfd->rd);
vty_out(vty, "%pRDP", &rfd->rd);
vty_out(vty, " %d", rfd->response_lifetime);
vty_out(vty, " %s", (rfd->rfg ? rfd->rfg->name : "<orphaned>"));
vty_out(vty, "%s", HVTYNL);
@ -4709,6 +4709,7 @@ static int vnc_add_vrf_prefix(struct vty *vty, const char *arg_vrf,
if (arg_rd) {
opt = &optary[cur_opt++];
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
/* TODO: save RD format */
if (!str2prefix_rd(arg_rd, &opt->v.internal_rd)) {
vty_out(vty, "Malformed RD \"%s\"\n", arg_rd);
return CMD_WARNING_CONFIG_FAILED;

View File

@ -151,6 +151,7 @@ by the parser.
: RANGE
: MAC
: MAC_PREFIX
: ASNUM
selector: "<" `selector_seq_seq` ">" `varname_token`
: "{" `selector_seq_seq` "}" `varname_token`
: "[" `selector_seq_seq` "]" `varname_token`
@ -176,27 +177,29 @@ parser, but this is merely a dumb copy job.
Here is a brief summary of the various token types along with examples.
+-----------------+-------------------+-------------------------------------------------------------+
| Token type | Syntax | Description |
+=================+===================+=============================================================+
| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
+-----------------+-------------------+-------------------------------------------------------------+
| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
+-----------------+-------------------+-------------------------------------------------------------+
+-----------------+-------------------------+-------------------------------------------------------+
| Token type | Syntax | Description |
+=================+=========================+=======================================================+
| ``WORD`` | ``show ip bgp`` | Matches itself. In the example every token is a WORD. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
+-----------------+-------------------------+-------------------------------------------------------+
| ``ASNUM`` | ``<A.B|(1-4294967295>`` | Matches an AS in plain or dot format. |
+-----------------+-------------------------+-------------------------------------------------------+
When presented with user input, the parser will search over all defined
commands in the current context to find a match. It is aware of the various

View File

@ -254,8 +254,9 @@ ASN and Router ID
-----------------
First of all you must configure BGP router with the :clicmd:`router bgp ASN`
command. The AS number is an identifier for the autonomous system. The BGP
protocol uses the AS number for detecting whether the BGP connection is
command. The AS number is an identifier for the autonomous system. The AS
identifier can either be a number or two numbers separated by a period. The
BGP protocol uses the AS identifier for detecting whether the BGP connection is
internal or external.
.. clicmd:: router bgp ASN
@ -4301,6 +4302,26 @@ Segment-Routing IPv6
vpn_policy[AFI_IP].tovpn_sid: none
vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::200
AS-notation support
-------------------
By default, the ASN value output follows how the BGP ASN instance is
expressed in the configuration. Three as-notation outputs are available:
- plain output: both AS4B and AS2B use a single number.
` router bgp 65536`.
- dot output: AS4B values are using two numbers separated by a period.
`router bgp 1.1` means that the AS number is 65536.
- dot+ output: AS2B and AS4B values are using two numbers separated by a
period. `router bgp 0.5` means that the AS number is 5.
The below option permits forcing the as-notation output:
.. clicmd:: router bgp ASN as-notation dot|dot+|plain
The chosen as-notation format will override the BGP ASN output.
.. _bgp-route-reflector:

260
lib/asn.c Normal file
View File

@ -0,0 +1,260 @@
/*
* ASN functions
*
* Copyright 2022 6WIND
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "log.h"
#include "asn.h"
static bool relax_as_zero;
static const struct message asnotation_mode_msg[] = {
{ASNOTATION_PLAIN, "plain"},
{ASNOTATION_DOT, "dot"},
{ASNOTATION_DOTPLUS, "dot+"},
{ASNOTATION_UNDEFINED, "undefined"},
{0}
};
/* converts a string into an Autonomous system number
* "1.1" => 65536
* "65500" => 65500
*/
static bool asn_str2asn_internal(const char *asstring, as_t *asn,
const char **next, bool *partial,
enum asnotation_mode *mode)
{
uint32_t high = 0, low = 0;
uint64_t temp_val;
const char *p = asstring;
bool ret = false;
uint32_t digit;
enum asnotation_mode val = ASNOTATION_PLAIN;
if (!asstring)
goto end;
if (!isdigit((unsigned char)*p))
goto end;
temp_val = 0;
while (isdigit((unsigned char)*p)) {
digit = (*p) - '0';
temp_val *= 10;
temp_val += digit;
if (temp_val > UINT32_MAX)
/* overflow */
goto end;
p++;
}
high = (uint32_t)temp_val;
if (*p == '.') { /* dot format */
p++;
temp_val = 0;
if (*p == '\0' && partial) {
*partial = true;
goto end;
}
while (isdigit((unsigned char)*p)) {
digit = (*p) - '0';
temp_val *= 10;
temp_val += digit;
if (temp_val > UINT16_MAX)
/* overflow */
goto end;
p++;
}
low = (uint32_t)temp_val;
if (!next && *p != '\0' && !isdigit((unsigned char)*p))
goto end;
/* AS <AS4B>.<AS4B> is forbidden */
if (high > UINT16_MAX)
goto end;
/* AS 0.0 is authorised for some case only */
if (!relax_as_zero && high == 0 && low == 0) {
if (partial)
*partial = true;
goto end;
}
if (asn)
*asn = (high << 16) + low;
ret = true;
if (high == 0)
val = ASNOTATION_DOTPLUS;
else
val = ASNOTATION_DOT;
goto end;
}
/* AS 0 is forbidden */
if (!relax_as_zero && high == 0)
goto end;
if (!asn) {
ret = true;
goto end;
}
*asn = high;
ret = true;
end:
if (next)
*next = p;
if (mode)
*mode = val;
return ret;
}
static void asn_asn2asdot(as_t asn, char *asstring, size_t len)
{
uint16_t low, high;
high = (asn >> 16) & 0xffff;
low = asn & 0xffff;
snprintf(asstring, len, "%hu.%hu", high, low);
}
bool asn_str2asn(const char *asstring, as_t *asn)
{
return asn_str2asn_internal(asstring, asn, NULL, NULL, NULL);
}
const char *asn_asn2asplain(as_t asn)
{
static char buf[ASN_STRING_MAX_SIZE];
snprintf(buf, sizeof(buf), "%u", asn);
return buf;
}
const char *asn_str2asn_parse(const char *asstring, as_t *asn, bool *found_ptr)
{
const char *p = NULL;
const char **next = &p;
bool found;
found = asn_str2asn_internal(asstring, asn, next, NULL, NULL);
if (found_ptr)
*found_ptr = found;
return *next;
}
void asn_relax_as_zero(bool relax)
{
relax_as_zero = relax;
}
enum match_type asn_str2asn_match(const char *str)
{
bool found, partial = false;
found = asn_str2asn_internal(str, NULL, NULL, &partial, NULL);
if (found && !partial)
return exact_match;
if (partial)
return partly_match;
return no_match;
}
bool asn_str2asn_notation(const char *asstring, as_t *asn,
enum asnotation_mode *asnotation)
{
return asn_str2asn_internal(asstring, asn, NULL, NULL, asnotation);
}
const char *asn_mode2str(enum asnotation_mode asnotation)
{
return lookup_msg(asnotation_mode_msg, asnotation,
"Unrecognized AS notation mode");
}
void asn_asn2json(json_object *json, const char *attr,
as_t asn, enum asnotation_mode asnotation)
{
static char as_str[ASN_STRING_MAX_SIZE];
if ((asnotation == ASNOTATION_PLAIN) ||
((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
json_object_int_add(json, attr, asn);
else {
asn_asn2asdot(asn, as_str, sizeof(as_str));
json_object_string_add(json, attr, as_str);
}
}
void asn_asn2json_array(json_object *jseg_list, as_t asn,
enum asnotation_mode asnotation)
{
static char as_str[ASN_STRING_MAX_SIZE];
if ((asnotation == ASNOTATION_PLAIN) ||
((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
json_object_array_add(jseg_list,
json_object_new_int64(asn));
else {
asn_asn2asdot(asn, as_str, sizeof(as_str));
json_array_string_add(jseg_list, as_str);
}
}
char *asn_asn2string(const as_t *asn, char *buf, size_t len,
enum asnotation_mode asnotation)
{
if ((asnotation == ASNOTATION_PLAIN) ||
((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX))
snprintf(buf, len, "%u", *asn);
else
asn_asn2asdot(*asn, buf, len);
return buf;
}
static ssize_t printfrr_asnotation(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr,
enum asnotation_mode asnotation)
{
/* for alignemnt up to 33 chars - %33pASD for instance - */
char as_str[ASN_STRING_MAX_SIZE*3];
const as_t *asn;
if (!ptr)
return bputs(buf, "(null)");
asn = ptr;
asn_asn2string(asn, as_str, sizeof(as_str), asnotation);
return bputs(buf, as_str);
}
printfrr_ext_autoreg_p("ASP", printfrr_asplain);
static ssize_t printfrr_asplain(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
}
printfrr_ext_autoreg_p("ASD", printfrr_asdot);
static ssize_t printfrr_asdot(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOT);
}
printfrr_ext_autoreg_p("ASE", printfrr_asdotplus);
static ssize_t printfrr_asdotplus(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
}

81
lib/asn.h Normal file
View File

@ -0,0 +1,81 @@
/*
* AS number structure
* Copyright 2022 6WIND
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2, or (at your
* option) any later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FRR_ASN_H
#define _FRR_ASN_H
#include "zebra.h"
#include "command_match.h"
#include "json.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ASN_STRING_MAX_SIZE 12
enum asnotation_mode {
ASNOTATION_PLAIN = 0,
ASNOTATION_DOT,
ASNOTATION_DOTPLUS,
ASNOTATION_UNDEFINED,
};
typedef uint32_t as_t;
extern bool asn_str2asn(const char *asstring, as_t *asn);
extern const char *asn_asn2asplain(as_t asn);
extern const char *asn_str2asn_parse(const char *asstring, as_t *asn,
bool *found_ptr);
extern enum match_type asn_str2asn_match(const char *str);
extern bool asn_str2asn_notation(const char *asstring, as_t *asn,
enum asnotation_mode *asnotation);
extern const char *asn_mode2str(enum asnotation_mode asnotation);
void asn_asn2json_array(json_object *jseg_list, as_t asn,
enum asnotation_mode asnotation);
void asn_asn2json(json_object *jseg_list, const char *attr,
as_t asn, enum asnotation_mode asnotation);
extern char *asn_asn2string(const as_t *as, char *buf, size_t len,
enum asnotation_mode asnotation);
/* display AS in appropriate format */
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pASP" (as_t *)
#pragma FRR printfrr_ext "%pASD" (as_t *)
#pragma FRR printfrr_ext "%pASE" (as_t *)
#endif
#define ASN_FORMAT(mode) \
((mode == ASNOTATION_DOT) ? "%pASD" : \
((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \
"%pASP"))
#define ASN_FORMAT_SPACE(mode) \
((mode == ASNOTATION_DOT) ? "%10pASD" : \
((mode == ASNOTATION_DOTPLUS) ? "%10pASE" : \
"%10pASP"))
/* for test */
extern void asn_relax_as_zero(bool relax);
#ifdef __cplusplus
}
#endif
#endif /* _FRR_ASN_H */

View File

@ -56,6 +56,7 @@ const struct message tokennames[] = {
item(IPV6_PREFIX_TKN),
item(MAC_TKN),
item(MAC_PREFIX_TKN),
item(ASNUM_TKN),
item(FORK_TKN),
item(JOIN_TKN),
item(START_TKN),

View File

@ -391,7 +391,8 @@ struct cmd_node {
#define DEBUG_STR "Debugging functions\n"
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
#define ROUTER_STR "Enable a routing process\n"
#define AS_STR "AS number\n"
#define AS_STR \
"AS number in plain <1-4294967295> or dotted <0-65535>.<0-65535> format\n"
#define MAC_STR "MAC address\n"
#define MBGP_STR "MBGP information\n"
#define MATCH_STR "Match values from routing table\n"

View File

@ -266,6 +266,7 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb)
case END_TKN:
case NEG_ONLY_TKN:
case WORD_TKN:
case ASNUM_TKN:
return true;
}
@ -535,6 +536,7 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
case MAC_PREFIX_TKN:
case END_TKN:
case VARIABLE_TKN:
case ASNUM_TKN:
color = "#ffffff";
break;
}

View File

@ -45,6 +45,7 @@ enum cmd_token_type {
IPV6_PREFIX_TKN, // IPV6 network prefixes
MAC_TKN, // Ethernet address
MAC_PREFIX_TKN, // Ethernet address w/ CIDR mask
ASNUM_TKN, // AS dot format
/* plumbing types */
FORK_TKN, // marks subgraph beginning

View File

@ -38,6 +38,7 @@ VARIABLE [A-Z][-_A-Z:0-9]+
WORD (\-|\+)?[a-zA-Z0-9\*][-+_a-zA-Z0-9\*]*
NUMBER (\-|\+)?[0-9]{1,20}
RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
ASNUM ASNUM
/* yytext shall be a pointer */
%pointer
@ -57,6 +58,7 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
%}
[ \t]+ LOC_STEP /* ignore whitespace */;
{ASNUM} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return ASNUM;}
{IPV4} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4;}
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4_PREFIX;}
{IPV6} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV6;}

View File

@ -10,6 +10,7 @@
#include "command_match.h"
#include "memory.h"
#include "asn.h"
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
@ -541,6 +542,7 @@ static enum match_type min_match_level(enum cmd_token_type type)
case END_TKN:
case NEG_ONLY_TKN:
case VARIABLE_TKN:
case ASNUM_TKN:
return exact_match;
}
@ -564,6 +566,7 @@ static int score_precedence(enum cmd_token_type type)
case IPV6_PREFIX_TKN:
case MAC_TKN:
case MAC_PREFIX_TKN:
case ASNUM_TKN:
case RANGE_TKN:
return 2;
case WORD_TKN:
@ -698,6 +701,8 @@ static enum match_type match_token(struct cmd_token *token, char *input_token)
return match_mac(input_token, false);
case MAC_PREFIX_TKN:
return match_mac(input_token, true);
case ASNUM_TKN:
return asn_str2asn_match(input_token);
case END_TKN:
case FORK_TKN:
case JOIN_TKN:
@ -840,7 +845,6 @@ static enum match_type match_ipv4_prefix(const char *str)
return exact_match;
}
#define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
#define STATE_START 1

View File

@ -88,6 +88,7 @@
%token <string> RANGE
%token <string> MAC
%token <string> MAC_PREFIX
%token <string> ASNUM
/* special syntax, value is irrelevant */
%token <string> EXCL_BRACKET
@ -277,6 +278,11 @@ placeholder_token_real:
$$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
XFREE (MTYPE_LEX, $1);
}
| ASNUM
{
$$ = new_token_node (ctx, ASNUM_TKN, $1, doc_next(ctx));
XFREE (MTYPE_LEX, $1);
}
placeholder_token:
placeholder_token_real varname_token

View File

@ -201,6 +201,7 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
item(IPV6_PREFIX_TKN); // IPV6 network prefixes
item(MAC_TKN); // MAC address
item(MAC_PREFIX_TKN); // MAC address with mask
item(ASNUM_TKN); // ASNUM
/* plumbing types */
item(FORK_TKN);

View File

@ -644,7 +644,10 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr)
#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *)
#pragma FRR printfrr_ext "%pRD" (struct prefix_rd *)
#pragma FRR printfrr_ext "%pRDP" (struct prefix_rd *)
/* RD with AS4B with dot and dot+ format */
#pragma FRR printfrr_ext "%pRDD" (struct prefix_rd *)
#pragma FRR printfrr_ext "%pRDE" (struct prefix_rd *)
#pragma FRR printfrr_ext "%pPSG4" (struct prefix_sg *)
#endif

View File

@ -13,6 +13,7 @@ lib_libfrr_la_SOURCES = \
lib/affinitymap_northbound.c \
lib/agg_table.c \
lib/atomlist.c \
lib/asn.c \
lib/base64.c \
lib/bfd.c \
lib/buffer.c \
@ -169,6 +170,7 @@ pkginclude_HEADERS += \
lib/admin_group.h \
lib/affinitymap.h \
lib/agg_table.h \
lib/asn.h \
lib/atomlist.h \
lib/base64.h \
lib/bfd.h \

View File

@ -51,6 +51,12 @@ _fail = (_end == argv[_i]->arg) || (*_end != '\\0');"""
)
class AsDotHandler(RenderHandler):
argtype = "as_t"
decl = Template("as_t $varname = 0;")
code = Template("_fail = !asn_str2asn(argv[_i]->arg, &$varname);")
# A.B.C.D/M (prefix_ipv4) and
# X:X::X:X/M (prefix_ipv6) are "compatible" and can merge into a
# struct prefix:
@ -152,6 +158,7 @@ handlers = {
"IPV6_PREFIX_TKN": Prefix6Handler,
"MAC_TKN": PrefixEthHandler,
"MAC_PREFIX_TKN": PrefixEthHandler,
"ASNUM_TKN": AsDotHandler,
}
# core template invoked for each occurence of DEFPY.

View File

@ -55,6 +55,7 @@ static struct test_segment {
const uint8_t asdata[1024];
int len;
struct test_spec sp;
enum asnotation_mode asnotation;
} test_segments[] = {
{
/* 0 */
@ -64,6 +65,7 @@ static struct test_segment {
10,
{"8466 3 52737 4096", "8466 3 52737 4096", 4, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
0,
},
{
/* 1 */
@ -72,8 +74,16 @@ static struct test_segment {
{0x2, 0x1, 0x22, 0x12, 0x2, 0x1, 0x00, 0x04},
8,
{
"8722 4", "8722 4", 2, 0, NOT_ALL_PRIVATE, 4, 5, 8722,
"8722 4",
"8722 4",
2,
0,
NOT_ALL_PRIVATE,
4,
5,
8722,
},
0,
},
{
/* 2 */
@ -84,6 +94,7 @@ static struct test_segment {
14,
{"8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0,
NOT_ALL_PRIVATE, 3, 5, 8466},
0,
},
{
/* 3 */
@ -93,6 +104,7 @@ static struct test_segment {
10,
{"8482 51457 {5204}", "8482 51457 {5204}", 3, 0,
NOT_ALL_PRIVATE, 5204, 51456, 8482},
0,
},
{
/* 4 */
@ -104,6 +116,7 @@ static struct test_segment {
{"8467 59649 {4196,48658} {17322,30745}",
"8467 59649 {4196,48658} {17322,30745}", 4, 0, NOT_ALL_PRIVATE,
48658, 1, 8467},
0,
},
{
/* 5 */
@ -116,6 +129,7 @@ static struct test_segment {
{"6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
"6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0,
NOT_ALL_PRIVATE, 51793, 1, 6435},
0,
},
{
/* 6 */
@ -124,6 +138,7 @@ static struct test_segment {
{0x3, 0x3, 0x00, 0x7b, 0x01, 0xc8, 0x03, 0x15},
8,
{"(123 456 789)", "", 0, 3, NOT_ALL_PRIVATE, 789, 1, NULL_ASN},
0,
},
{
/* 7 */
@ -134,6 +149,7 @@ static struct test_segment {
14,
{"(123 456 789) (111 222)", "", 0, 5, NOT_ALL_PRIVATE, 111, 1,
NULL_ASN},
0,
},
{
/* 8 */
@ -142,6 +158,7 @@ static struct test_segment {
{0x4, 0x3, 0x01, 0xc8, 0x00, 0x7b, 0x03, 0x15},
8,
{"[123,456,789]", "", 0, 1, NOT_ALL_PRIVATE, 123, 1, NULL_ASN},
0,
},
{
/* 9 */
@ -153,6 +170,7 @@ static struct test_segment {
24,
{"(123 456 789) [111,222] 8722 {4196,48658}",
"8722 {4196,48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1, NULL_ASN},
0,
},
{
/* 10 */
@ -163,6 +181,7 @@ static struct test_segment {
14,
{"8466 2 52737 4096 8722 4", "8466 2 52737 4096 8722 4", 6, 0,
NOT_ALL_PRIVATE, 4096, 1, 8466},
0,
},
{
/* 11 */
@ -174,6 +193,7 @@ static struct test_segment {
{"8466 2 52737 4096 8722 4 8722",
"8466 2 52737 4096 8722 4 8722", 7, 0, NOT_ALL_PRIVATE, 4096,
1, 8466},
0,
},
{
/* 12 */
@ -183,6 +203,7 @@ static struct test_segment {
10,
{"8466 64512 52737 65535", "8466 64512 52737 65535", 4, 0,
NOT_ALL_PRIVATE, 65535, 4, 8466},
0,
},
{
/* 13 */
@ -192,6 +213,7 @@ static struct test_segment {
10,
{"65534 64512 64513 65535", "65534 64512 64513 65535", 4, 0,
ALL_PRIVATE, 65534, 4, 65534},
0,
},
{
/* 14 */
@ -260,6 +282,7 @@ static struct test_segment {
"8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285",
250, 0, NOT_ALL_PRIVATE, 4096, 4, 8466},
0,
},
{
/* 15 */
@ -270,6 +293,7 @@ static struct test_segment {
12,
{"8466 3 52737 4096 3456", "8466 3 52737 4096 3456", 5, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
0,
},
{
/* 16 */
@ -278,6 +302,7 @@ static struct test_segment {
{},
0,
{"", "", 0, 0, 0, 0, 0, 0},
0,
},
{
/* 17 */
@ -293,6 +318,7 @@ static struct test_segment {
"8466 3 52737 4096 3456 {7099,8153}",
"8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE,
4096, 4, 8466},
0,
},
{
/* 18 */
@ -305,6 +331,7 @@ static struct test_segment {
{"6435 59408 21665 {23456} 23456 23456 23456",
"6435 59408 21665 {23456} 23456 23456 23456", 7, 0,
NOT_ALL_PRIVATE, 23456, 1, 6435},
0,
},
{
/* 19 */
@ -316,6 +343,7 @@ static struct test_segment {
{"{2457,4369,61697} 1842 41591 51793",
"{2457,4369,61697} 1842 41591 51793", 4, 0, NOT_ALL_PRIVATE,
51793, 1, 2457},
0,
},
{
/* 20 */
@ -329,44 +357,88 @@ static struct test_segment {
{"(123 456 789) [124,456,788] 6435 59408 21665 {23456} 23456 23456 23456",
"6435 59408 21665 {23456} 23456 23456 23456", 7, 4,
NOT_ALL_PRIVATE, 23456, 1, 6435},
0,
},
{
/* 21 */
"reconcile_start_trans",
"seq(23456,23456,23456) seq(6435,59408,21665)",
{
0x2, 0x3, 0x5b, 0xa0, 0x5b, 0xa0, 0x5b, 0xa0, 0x2, 0x3,
0x19, 0x23, 0xe8, 0x10, 0x54, 0xa1,
0x2,
0x3,
0x5b,
0xa0,
0x5b,
0xa0,
0x5b,
0xa0,
0x2,
0x3,
0x19,
0x23,
0xe8,
0x10,
0x54,
0xa1,
},
16,
{"23456 23456 23456 6435 59408 21665",
"23456 23456 23456 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE,
21665, 1, 23456},
0,
},
{
/* 22 */
"reconcile_start_trans4",
"seq(1842,41591,51793) seq(6435,59408,21665)",
{
0x2, 0x3, 0x07, 0x32, 0xa2, 0x77, 0xca, 0x51, 0x2, 0x3,
0x19, 0x23, 0xe8, 0x10, 0x54, 0xa1,
0x2,
0x3,
0x07,
0x32,
0xa2,
0x77,
0xca,
0x51,
0x2,
0x3,
0x19,
0x23,
0xe8,
0x10,
0x54,
0xa1,
},
16,
{"1842 41591 51793 6435 59408 21665",
"1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE,
41591, 1, 1842},
0,
},
{
/* 23 */
"reconcile_start_trans_error",
"seq(23456,23456,23456) seq(6435,59408)",
{
0x2, 0x3, 0x5b, 0xa0, 0x5b, 0xa0, 0x5b, 0xa0, 0x2, 0x2,
0x19, 0x23, 0xe8, 0x10,
0x2,
0x3,
0x5b,
0xa0,
0x5b,
0xa0,
0x5b,
0xa0,
0x2,
0x2,
0x19,
0x23,
0xe8,
0x10,
},
14,
{"23456 23456 23456 6435 59408", "23456 23456 23456 6435 59408",
5, 0, NOT_ALL_PRIVATE, 59408, 1, 23456},
0,
},
{
/* 24 */
@ -382,6 +454,7 @@ static struct test_segment {
"8466 3 52737 4096 3456 {7099,8153}",
"8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE,
4096, 4, 8466},
0,
},
{
/* 25 */
@ -391,6 +464,7 @@ static struct test_segment {
0x80},
12,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
0,
},
{
/* 26 */
@ -400,6 +474,7 @@ static struct test_segment {
0x00, 0x0d, 0x80},
14,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
0,
},
{
/* 27 */
@ -408,20 +483,66 @@ static struct test_segment {
{0x8, 0x2, 0x10, 0x00, 0x0d, 0x80},
14,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
0,
},
{
/* 28 */
"BGP_AS_ZERO",
"seq(8466,3,52737,0,4096)",
{0x2, 0x5,
0x21, 0x12,
0x00, 0x03,
0xce, 0x01,
0x00, 0x00,
0x10, 0x00},
{0x2, 0x5, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x00, 0x00, 0x10,
0x00},
12,
{"8466 3 52737 0 4096", "8466 3 52737 0 4096", 5, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
0,
},
{
/* 29 */
"seq3_asdot+",
"seq(0.8466,0.3,0.52737,0.4096,0.8722,0.4)",
{0x2, 0x6, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x10, 0x00, 0x22,
0x12, 0x00, 0x04},
14,
{"0.8466 0.3 0.52737 0.4096 0.8722 0.4",
"0.8466 0.3 0.52737 0.4096 0.8722 0.4", 6, 0, NOT_ALL_PRIVATE,
3, 5, 8466},
ASNOTATION_DOTPLUS,
},
{
/* 30 */
"confmulti_asdot+",
"confseq(0.123,0.456,0.789) confset(0.222,0.111) seq(0.8722) set(0.4196,0.48658)",
{0x3, 0x3, 0x00, 0x7b, 0x01, 0xc8, 0x03, 0x15,
0x4, 0x2, 0x00, 0xde, 0x00, 0x6f, 0x2, 0x1,
0x22, 0x12, 0x1, 0x2, 0x10, 0x64, 0xbe, 0x12},
24,
{"(0.123 0.456 0.789) [0.111,0.222] 0.8722 {0.4196,0.48658}",
"0.8722 {0.4196,0.48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1,
NULL_ASN},
ASNOTATION_DOTPLUS,
},
{
/* 31 */
"someprivate asdot+",
"seq(0.8466,0.64512,0.52737,0.65535)",
{0x2, 0x4, 0x21, 0x12, 0xfc, 0x00, 0xce, 0x01, 0xff, 0xff},
10,
{"0.8466 0.64512 0.52737 0.65535",
"0.8466 0.64512 0.52737 0.65535", 4, 0, NOT_ALL_PRIVATE, 65535,
4, 8466},
ASNOTATION_DOTPLUS,
},
{
/* 32 */
"BGP_AS_ZERO asdot+",
"seq(0.8466,0.3,0.52737,0.0,0.4096)",
{0x2, 0x5, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x00, 0x00, 0x10,
0x00},
12,
{"0.8466 0.3 0.52737 0.0 0.4096",
"0.8466 0.3 0.52737 0.0 0.4096", 5, 0, NOT_ALL_PRIVATE, 4096,
4, 8466},
ASNOTATION_DOTPLUS,
},
{NULL, NULL, {0}, 0, {NULL, 0, 0}}};
@ -856,16 +977,16 @@ struct compare_tests {
};
/* make an aspath from a data stream */
static struct aspath *make_aspath(const uint8_t *data, size_t len, int use32bit)
static struct aspath *make_aspath(const uint8_t *data, size_t len, int use32bit,
enum asnotation_mode asnotation)
{
struct stream *s = NULL;
struct aspath *as;
if (len) {
s = stream_new(len);
stream_put(s, data, len);
}
as = aspath_parse(s, len, use32bit);
as = aspath_parse(s, len, use32bit, asnotation);
if (s)
stream_free(s);
@ -901,15 +1022,16 @@ static int validate(struct aspath *as, const struct test_spec *sp)
}
out = aspath_snmp_pathseg(as, &bytes);
asinout = make_aspath(out, bytes, 0);
asinout = make_aspath(out, bytes, 0, as->asnotation);
/* Excercise AS4 parsing a bit, with a dogfood test */
if (!s)
s = stream_new(BGP_MAX_PACKET_SIZE);
bytes4 = aspath_put(s, as, 1);
as4 = make_aspath(STREAM_DATA(s), bytes4, 1);
as4 = make_aspath(STREAM_DATA(s), bytes4, 1, as->asnotation);
asstr = aspath_str2aspath(sp->shouldbe);
asn_relax_as_zero(true);
asstr = aspath_str2aspath(sp->shouldbe, as->asnotation);
asn_relax_as_zero(false);
asconfeddel = aspath_delete_confed_seq(aspath_dup(asinout));
@ -1036,7 +1158,7 @@ static void parse_test(struct test_segment *t)
printf("%s: %s\n", t->name, t->desc);
asp = make_aspath(t->asdata, t->len, 0);
asp = make_aspath(t->asdata, t->len, 0, t->asnotation);
printf("aspath: %s\nvalidating...:\n", aspath_print(asp));
@ -1058,8 +1180,10 @@ static void prepend_test(struct tests *t)
printf("prepend %s: %s\n", t->test1->name, t->test1->desc);
printf("to %s: %s\n", t->test2->name, t->test2->desc);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
ASNOTATION_PLAIN);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
ASNOTATION_PLAIN);
ascratch = aspath_dup(asp2);
aspath_unintern(&asp2);
@ -1085,8 +1209,8 @@ static void empty_prepend_test(struct test_segment *t)
printf("empty prepend %s: %s\n", t->name, t->desc);
asp1 = make_aspath(t->asdata, t->len, 0);
asp2 = aspath_empty();
asp1 = make_aspath(t->asdata, t->len, 0, t->asnotation);
asp2 = aspath_empty(t->asnotation);
ascratch = aspath_dup(asp2);
aspath_unintern(&asp2);
@ -1113,8 +1237,10 @@ static void as4_reconcile_test(struct tests *t)
printf("reconciling %s:\n %s\n", t->test1->name, t->test1->desc);
printf("with %s:\n %s\n", t->test2->name, t->test2->desc);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
ASNOTATION_PLAIN);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
ASNOTATION_PLAIN);
ascratch = aspath_reconcile_as4(asp1, asp2);
@ -1138,8 +1264,10 @@ static void aggregate_test(struct tests *t)
printf("aggregate %s: %s\n", t->test1->name, t->test1->desc);
printf("with %s: %s\n", t->test2->name, t->test2->desc);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
ASNOTATION_PLAIN);
asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
ASNOTATION_PLAIN);
ascratch = aspath_aggregate(asp1, asp2);
@ -1171,8 +1299,8 @@ static void cmp_test(void)
printf("left cmp %s: %s\n", t1->name, t1->desc);
printf("and %s: %s\n", t2->name, t2->desc);
asp1 = make_aspath(t1->asdata, t1->len, 0);
asp2 = make_aspath(t2->asdata, t2->len, 0);
asp1 = make_aspath(t1->asdata, t1->len, 0, ASNOTATION_PLAIN);
asp2 = make_aspath(t2->asdata, t2->len, 0, ASNOTATION_PLAIN);
if (aspath_cmp_left(asp1, asp2) != left_compare[i].shouldbe_cmp
|| aspath_cmp_left(asp2, asp1)
@ -1210,7 +1338,9 @@ static int handle_attr_test(struct aspath_tests *t)
struct aspath *asp;
size_t datalen;
asp = make_aspath(t->segment->asdata, t->segment->len, 0);
asp = make_aspath(t->segment->asdata, t->segment->len, 0,
t->segment->asnotation);
bgp.asnotation = t->segment->asnotation;
peer.curr = stream_new(BGP_MAX_PACKET_SIZE);
peer.obuf = stream_fifo_new();
@ -1286,8 +1416,8 @@ int main(void)
parse_test(&test_segments[i]);
empty_prepend_test(&test_segments[i++]);
}
i = 0;
while (prepend_tests[i].test1) {
printf("prepend test %u\n", i);
prepend_test(&prepend_tests[i++]);

View File

@ -937,7 +937,8 @@ int main(void)
if (fileno(stdout) >= 0)
tty = isatty(fileno(stdout));
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);

View File

@ -1079,7 +1079,8 @@ int main(void)
if (fileno(stdout) >= 0)
tty = isatty(fileno(stdout));
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);

View File

@ -50,7 +50,8 @@ int main(int argc, char *argv[])
vrf_init(NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);

View File

@ -12,6 +12,7 @@
#include "lib/memory.h"
#include "lib/prefix.h"
#include "lib/nexthop.h"
#include "lib/asn.h"
static int errors;
@ -145,6 +146,7 @@ int main(int argc, char **argv)
struct in_addr ip;
char *p;
char buf[256];
as_t asn;
printcmp("%d %u %d %u", 123, 123, -456, -456);
printcmp("%lld %llu %lld %llu", 123LL, 123LL, -456LL, -456LL);
@ -392,6 +394,13 @@ int main(int argc, char **argv)
printchk("-00:09", "%pTSIm", &ts);
printchk("--:--", "%pTVImx", &tv);
printchk("--:--", "%pTTImx", &tt);
/* ASN checks */
asn = 65536;
printchk("1.0", "%pASD", &asn);
asn = 65400;
printchk("65400", "%pASP", &asn);
printchk("0.65400", "%pASE", &asn);
printchk("65400", "%pASD", &asn);
return !!errors;
}

View File

@ -0,0 +1,27 @@
router bgp 1.1
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.255.2 remote-as 1.2
address-family ipv4 unicast
network 172.31.1.0/24 route-map rmapout
network 172.31.2.0/24 route-map rmapout
neighbor 192.168.255.2 route-map rmapin in
neighbor 192.168.255.2 activate
exit-address-family
exit
bgp as-path access-list only1_4 permit _1.4_
bgp as-path access-list only65540 permit _65540_
access-list 172313 permit 172.31.3.0/24
access-list 172314 permit 172.31.4.0/24
route-map rmapout permit 1
set as-path prepend 1.4
exit
route-map rmapin permit 1
match ip address 172313
match as-path only1_4
exit
route-map rmapin permit 2
match ip address 172314
match as-path only65540
exit

View File

@ -0,0 +1,80 @@
{
"vrfId": 0,
"vrfName": "default",
"tableVersion": 3,
"routerId": "192.168.255.1",
"defaultLocPrf": 100,
"localAS": "1.1",
"routes": { "172.31.1.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.1.0",
"prefixLen":24,
"network":"172.31.1.0/24",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"1.4",
"origin":"IGP",
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
,"172.31.2.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.2.0",
"prefixLen":24,
"network":"172.31.2.0/24",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"1.4",
"origin":"IGP",
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
,"172.31.3.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.3.0",
"prefixLen":24,
"network":"172.31.3.0/24",
"metric":0,
"weight":0,
"peerId":"192.168.255.2",
"path":"1.2 1.4",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.255.2",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
} }

View File

@ -0,0 +1,6 @@
!
interface r1-eth0
ip address 192.168.255.1/24
!
ip forwarding
!

View File

@ -0,0 +1,26 @@
router bgp 65538
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.255.1 remote-as 65537
address-family ipv4 unicast
network 172.31.3.0/24 route-map rmapout
network 172.31.4.0/24 route-map rmapout
neighbor 192.168.255.1 route-map rmapin in
neighbor 192.168.255.1 activate
exit-address-family
exit
bgp as-path access-list only65540 permit _65540_
bgp as-path access-list only1_4 permit _1.4_
access-list 172311 permit 172.31.1.0/24
access-list 172312 permit 172.31.2.0/24
route-map rmapout permit 1
set as-path prepend 65540
exit
route-map rmapin permit 1
match ip address 172311
match as-path only65540
exit
route-map rmapin permit 2
match ip address 172312
match as-path only1_4
exit

View File

@ -0,0 +1,80 @@
{
"vrfId": 0,
"vrfName": "default",
"tableVersion": 3,
"routerId": "192.168.255.2",
"defaultLocPrf": 100,
"localAS": 65538,
"routes": { "172.31.1.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.1.0",
"prefixLen":24,
"network":"172.31.1.0/24",
"metric":0,
"weight":0,
"peerId":"192.168.255.1",
"path":"65537 65540",
"origin":"IGP",
"nexthops":[
{
"ip":"192.168.255.1",
"hostname":"r1",
"afi":"ipv4",
"used":true
}
]
}
]
,"172.31.3.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.3.0",
"prefixLen":24,
"network":"172.31.3.0/24",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"65540",
"origin":"IGP",
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
,"172.31.4.0/24": [
{
"valid":true,
"bestpath":true,
"selectionReason":"First path received",
"pathFrom":"external",
"prefix":"172.31.4.0",
"prefixLen":24,
"network":"172.31.4.0/24",
"metric":0,
"weight":32768,
"peerId":"(unspec)",
"path":"65540",
"origin":"IGP",
"nexthops":[
{
"ip":"0.0.0.0",
"hostname":"r2",
"afi":"ipv4",
"used":true
}
]
}
]
} }

View File

@ -0,0 +1,6 @@
!
interface r2-eth0
ip address 192.168.255.2/24
!
ip forwarding
!

View File

@ -0,0 +1,122 @@
#!/usr/bin/env python
#
# test_bgp_asdot_regex.py
# Part of Topotests
#
# Copyright 2022 6WIND S.A.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_bgp_asdot_regex.py:
Test how regex applies when asnotation to forge bgp config is based on dot or not.
"""
import os
import sys
import json
import pytest
from functools import partial
# add after imports, before defining classes or functions:
pytestmark = [pytest.mark.bgpd]
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
for routern in range(1, 3):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.start_router()
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
def test_bgp_asdot_regex():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
router1 = tgen.gears["r1"]
router2 = tgen.gears["r2"]
def _bgp_converge(router):
output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
expected = {
"192.168.255.2": {
"bgpState": "Established",
"addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}},
}
}
return topotest.json_cmp(output, expected)
logger.info("Check if neighbor sessions are up in {}".format(router1.name))
test_func = partial(_bgp_converge, router1)
success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5)
assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name)
logger.info("BGP neighbor session is up in {}".format(router1.name))
logger.info("waiting for bgp peers exchanging UPDATES")
for router in tgen.routers().values():
ref_file = "{}/{}/show_bgp_ipv4.json".format(CWD, router.name)
expected = json.loads(open(ref_file).read())
test_func = partial(
topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected
)
_, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5)
assertmsg = "{}: BGP UPDATE exchange failure".format(router.name)
assert res is None, assertmsg
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,8 @@
router bgp 0.65000 as-notation dot+
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 0.1000
neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 0.500
address-family ipv4 unicast
neighbor 192.168.255.2 remove-private-AS
redistribute connected

View File

@ -0,0 +1,9 @@
!
interface lo
ip address 172.16.255.254/32
!
interface r1-eth0
ip address 192.168.255.1/24
!
ip forwarding
!

View File

@ -0,0 +1,5 @@
router bgp 0.1000 as-notation dot+
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 0.500
neighbor 192.168.255.1 timers 3 10
!

View File

@ -0,0 +1,6 @@
!
interface r2-eth0
ip address 192.168.255.2/24
!
ip forwarding
!

View File

@ -0,0 +1,8 @@
router bgp 3000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 1000
neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 500
address-family ipv4 unicast
neighbor 192.168.255.2 remove-private-AS
redistribute connected

View File

@ -0,0 +1,9 @@
!
interface lo
ip address 172.16.255.254/32
!
interface r3-eth0
ip address 192.168.255.1/24
!
ip forwarding
!

View File

@ -0,0 +1,5 @@
router bgp 0.1000 as-notation dot+
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 0.500
neighbor 192.168.255.1 timers 3 10
!

View File

@ -0,0 +1,6 @@
!
interface r4-eth0
ip address 192.168.255.2/24
!
ip forwarding
!

View File

@ -0,0 +1,114 @@
#!/usr/bin/env python
#
# bgp_local_as_private_remove.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2019 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
bgp_local_as_private_remove.py:
Test if primary AS number is not removed in cases when `local-as`
used together with `remove-private-AS`.
"""
import os
import sys
import json
import time
import pytest
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib.topogen import Topogen, TopoRouter, get_topogen
pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
for routern in range(1, 5):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r3"])
switch.add_link(tgen.gears["r4"])
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.start_router()
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
def test_bgp_remove_private_as():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
def _bgp_converge(router):
while True:
output = json.loads(
tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
)
if output["192.168.255.1"]["bgpState"] == "Established":
time.sleep(1)
return True
def _bgp_as_path(router):
output = json.loads(
tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
)
if output["prefix"] == "172.16.255.254/32":
return output["paths"][0]["aspath"]["segments"][0]["list"]
if _bgp_converge("r2"):
assert len(_bgp_as_path("r2")) == 1
assert '0.65000' not in _bgp_as_path("r2")
if _bgp_converge("r4"):
assert len(_bgp_as_path("r4")) == 2
assert '0.3000' in _bgp_as_path("r4")
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,147 @@
{
"address_types": ["ipv4", "ipv6"],
"ipv4base": "10.0.0.0",
"ipv4mask": 30,
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
"lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
"routers": {
"r1": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.100",
"address_family": {
"ipv4": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r3": {"dest_link": {"r1": {}}}
}
}
},
"ipv6": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r3": {"dest_link": {"r1": {}}}
}
}
}
}
},
"static_routes":[
{
"network":"10.1.1.0/32",
"next_hop":"Null0"
},
{
"network":"10:1::1:0/128",
"next_hop":"Null0"
}]
},
"r2": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.200",
"address_family": {
"ipv4": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r3": {"dest_link": {"r2": {}}}
}
}
},
"ipv6": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r3": {"dest_link": {"r2": {}}}
}
}
}
}
},
"static_routes":[
{
"network":"10.1.2.0/32",
"next_hop":"Null0"
},
{
"network":"10:1::2:0/128",
"next_hop":"Null0"
}]
},
"r3": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r1": {"ipv4": "auto", "ipv6": "auto"},
"r2": {"ipv4": "auto", "ipv6": "auto"},
"r4": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.300",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r1": {"dest_link": {"r3": {}}},
"r2": {"dest_link": {"r3": {}}},
"r4": {"dest_link": {"r3": {}}}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r1": {"dest_link": {"r3": {}}},
"r2": {"dest_link": {"r3": {}}},
"r4": {"dest_link": {"r3": {}}}
}
}
}
}
}
},
"r4": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.400",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r3": {"dest_link": {"r4": {}}}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r3": {"dest_link": {"r4": {}}}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,317 @@
{
"address_types": [
"ipv4",
"ipv6"
],
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24,
"ipv6": "fd00::",
"v6mask": 64
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32,
"ipv6": "2001:DB8:F::",
"v6mask": 128
},
"routers": {
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"ipv6": "auto",
"type": "loopback"
},
"r2-link1": {
"ipv4": "auto",
"ipv6": "auto"
}
},
"bgp": [{
"local_as": "1.100",
"address_family": {
"ipv4": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r2": {
"dest_link": {
"r1-link1": {}
}
}
}
}
},
"ipv6": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r2": {
"dest_link": {
"r1-link1": {}
}
}
}
}
}
}
}
],
"static_routes":[
{
"network":"10.0.0.1/32",
"next_hop":"Null0"
},
{
"network":"10::1/128",
"next_hop":"Null0"
}
]
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"ipv6": "auto",
"type": "loopback"
},
"r1-link1": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link1": {
"ipv4": "auto",
"ipv6": "auto"
}
},
"bgp": [{
"local_as": "1.200",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r1": {
"dest_link": {
"r2-link1": {}
}
},
"r3": {
"dest_link": {
"r2-link1": {}
}
}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r1": {
"dest_link": {
"r2-link1": {}
}
},
"r3": {
"dest_link": {
"r2-link1": {}
}
}
}
}
}
}
}
]
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"ipv6": "auto",
"type": "loopback"
},
"r2-link1": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link1": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link2": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link3": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link4": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link5": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link6": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link7": {
"ipv4": "auto",
"ipv6": "auto"
},
"r4-link8": {
"ipv4": "auto",
"ipv6": "auto"
}
},
"bgp": [{
"local_as": "1.300",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r2": {
"dest_link": {
"r3-link1": {}
}
},
"r4": {
"dest_link": {
"r3-link1": {},
"r3-link2": {},
"r3-link3": {},
"r3-link4": {},
"r3-link5": {},
"r3-link6": {},
"r3-link7": {},
"r3-link8": {}
}
}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r2": {
"dest_link": {
"r3-link1": {}
}
},
"r4": {
"dest_link": {
"r3-link1": {},
"r3-link2": {},
"r3-link3": {},
"r3-link4": {},
"r3-link5": {},
"r3-link6": {},
"r3-link7": {},
"r3-link8": {}
}
}
}
}
}
}
}
]
},
"r4": {
"links": {
"lo": {
"ipv4": "auto",
"ipv6": "auto",
"type": "loopback"
},
"r3-link1": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link2": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link3": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link4": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link5": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link6": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link7": {
"ipv4": "auto",
"ipv6": "auto"
},
"r3-link8": {
"ipv4": "auto",
"ipv6": "auto"
}
},
"bgp": [{
"local_as": "1.400",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r3": {
"dest_link": {
"r4-link1": {},
"r4-link2": {},
"r4-link3": {},
"r4-link4": {},
"r4-link5": {},
"r4-link6": {},
"r4-link7": {},
"r4-link8": {}
}
}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r3": {
"dest_link": {
"r4-link1": {},
"r4-link2": {},
"r4-link3": {},
"r4-link4": {},
"r4-link5": {},
"r4-link6": {},
"r4-link7": {},
"r4-link8": {}
}
}
}
}
}
}
}
]
}
}
}

View File

@ -0,0 +1,132 @@
{
"address_types": ["ipv4", "ipv6"],
"ipv4base": "10.0.0.0",
"ipv4mask": 30,
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
"lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
"routers": {
"r1": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r2": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.100",
"address_family": {
"ipv4": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r2": {"dest_link": {"r1": {}}}
}
}
},
"ipv6": {
"unicast": {
"redistribute": [
{"redist_type": "static"}
],
"neighbor": {
"r2": {"dest_link": {"r1": {}}}
}
}
}
}
},
"static_routes":[
{
"network":"10.1.1.0/32",
"next_hop":"Null0"
},
{
"network":"10:1::1:0/128",
"next_hop":"Null0"
}]
},
"r2": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r1": {"ipv4": "auto", "ipv6": "auto"},
"r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.200",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r1": {"dest_link": {"r2": {}}},
"r3": {"dest_link": {"r2": {}}}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r1": {"dest_link": {"r2": {}}},
"r3": {"dest_link": {"r2": {}}}
}
}
}
}
}
},
"r3": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r2": {"ipv4": "auto", "ipv6": "auto"},
"r4": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.300",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r2": {"dest_link": {"r3": {}}},
"r4": {"dest_link": {"r3": {}}}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r2": {"dest_link": {"r3": {}}},
"r4": {"dest_link": {"r3": {}}}
}
}
}
}
}
},
"r4": {
"links": {
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
"r3": {"ipv4": "auto", "ipv6": "auto"}
},
"bgp": {
"local_as": "1.400",
"address_family": {
"ipv4": {
"unicast": {
"neighbor": {
"r3": {"dest_link": {"r4": {}}}
}
}
},
"ipv6": {
"unicast": {
"neighbor": {
"r3": {"dest_link": {"r4": {}}}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,420 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation,
# Inc. ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
1. Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
"""
import os
import sys
import time
import pytest
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from lib.topotest import version_cmp
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
verify_rib,
step,
check_address_types,
check_router_status
)
from lib.topolog import logger
from lib.bgp import (
verify_bgp_convergence,
verify_bgp_rib,
create_router_bgp,
)
from lib.topojson import build_config_from_json
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
# Global variables
BGP_CONVERGENCE = False
ADDR_TYPES = check_address_types()
NETWORK_1_1 = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
NETWORK_1_2 = {"ipv4": "10.1.2.0/32", "ipv6": "10:1::2:0/128"}
AGGREGATE_NW = {"ipv4": "10.1.0.0/16", "ipv6": "10:1::/96"}
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
json_file = "{}/bgp_local_asn_dot_agg.json".format(CWD)
tgen = Topogen(json_file, mod.__name__)
global topo
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
global BGP_CONVERGENCE
global ADDR_TYPES
ADDR_TYPES = check_address_types()
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
BGP_CONVERGENCE
)
logger.info("Running setup_module() done")
def teardown_module():
"""Teardown the pytest environment"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
####################################################################################################################
#
# Testcases
#
####################################################################################################################
def test_verify_bgp_local_as_agg_in_EBGP_p0(request):
"""
Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
"""
tgen = get_topogen()
global BGP_CONVERGENCE
if BGP_CONVERGENCE != True:
pytest.skip("skipped because of BGP Convergence failure")
# test case name
tc_name = request.node.name
write_test_header(tc_name)
if tgen.routers_have_failure():
check_router_status(tgen)
reset_config_on_routers(tgen)
step("Base config is done as part of JSON")
step("Configure local-as at R3 towards R4.")
for addr_type in ADDR_TYPES:
for neighbor in ["r2", "r4"]:
input_dict_r3 = {
"r3": {
"bgp": {
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
neighbor: {
"dest_link": {
"r3": {"local_asn": {"local_as": "1.110"}}
}
}
}
}
}
},
}
}
}
result = create_router_bgp(tgen, topo, input_dict_r3)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
for addr_type in ADDR_TYPES:
for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
input_dict_r2_r4 = {
dut: {
"bgp": {
"local_as": asn,
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
neighbor: {
"dest_link": {
dut: {"local_asn": {"remote_as": "1.110"}}
}
}
}
}
}
},
}
}
}
result = create_router_bgp(tgen, topo, input_dict_r2_r4)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
step("Done in base config: Advertise prefix 10.1.1.0/24 from Router-1(AS-1.100).")
step(
"Done in base config: Advertise an ipv6 prefix 10:1::1:0/120 from Router-1(AS-1.100)."
)
step("Verify that Static routes are redistributed in BGP process")
for addr_type in ADDR_TYPES:
input_static_verify_r1 = {
"r1": {"static_routes": [{"network": NETWORK_1_1[addr_type]}]}
}
input_static_verify_r2 = {
"r2": {"static_routes": [{"network": NETWORK_1_2[addr_type]}]}
}
result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
assert result is True, "Testcase {}: Failed \n Error: {}".format(
tc_name, result
)
result = verify_rib(tgen, addr_type, "r2", input_static_verify_r2)
assert result is True, "Testcase {}: Failed \n Error: {}".format(
tc_name, result
)
step("Configure aggregate-address to summarise all the advertised routes.")
for addr_type in ADDR_TYPES:
route_aggregate = {
"r3": {
"bgp": {
"address_family": {
addr_type: {
"unicast": {
"aggregate_address": [
{
"network": AGGREGATE_NW[addr_type],
"summary": True,
"as_set": True,
}
]
}
}
}
}
}
}
result = create_router_bgp(tgen, topo, route_aggregate)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step(
"Verify that we see a summarised route on advertising router R3 "
"and receiving router R4 for both AFIs"
)
for addr_type in ADDR_TYPES:
input_static_agg_r1 = {
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
}
input_static_r1 = {
"r1": {"static_routes": [{"network": [NETWORK_1_1[addr_type]]}]}
}
input_static_r2 = {
"r2": {"static_routes": [{"network": [NETWORK_1_2[addr_type]]}]}
}
for dut in ["r3", "r4"]:
result = verify_rib(tgen, addr_type, dut, input_static_agg_r1)
assert result is True, "Testcase {}: Failed \n Error: {}".format(
tc_name, result
)
for dut, input_routes in zip(["r1", "r2"], [input_static_r1, input_static_r2]):
result = verify_rib(tgen, addr_type, dut, input_routes)
assert result is True, "Testcase {}: Failed \n Error: {}".format(
tc_name, result
)
step(
"Verify that AS-110 is got added in the AS list 1.110 {1.100,1.110,1.200} by following "
"commands at R3 router."
)
dut = "r3"
aspath = "{1.100,1.110,1.200}"
for addr_type in ADDR_TYPES:
input_static_agg_r1 = {
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
}
result = verify_bgp_rib(
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend at R3 towards R4 & R2.")
for addr_type in ADDR_TYPES:
for neighbor in ["r2", "r4"]:
input_dict_r3 = {
"r3": {
"bgp": {
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
neighbor: {
"dest_link": {
"r3": {
"local_asn": {
"local_as": "1.110",
"no_prepend": True,
}
}
}
}
}
}
}
},
}
}
}
result = create_router_bgp(tgen, topo, input_dict_r3)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
dut = "r3"
aspath = "{1.100,1.200}"
for addr_type in ADDR_TYPES:
input_static_agg_r1 = {
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
}
result = verify_bgp_rib(
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
for addr_type in ADDR_TYPES:
for neighbor in ["r2", "r4"]:
input_dict_r3 = {
"r3": {
"bgp": {
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
neighbor: {
"dest_link": {
"r3": {
"local_asn": {
"local_as": "1.110",
"no_prepend": True,
"replace_as": True,
}
}
}
}
}
}
}
},
}
}
}
result = create_router_bgp(tgen, topo, input_dict_r3)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
dut = "r4"
aspath = "1.110 {1.100,1.200}"
for addr_type in ADDR_TYPES:
input_static_agg_r1 = {
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
}
result = verify_bgp_rib(
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,524 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation,
# Inc. ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
#
##########################################################################################################################################
#
# Testcases
#
###########################################################################################################################################
###########################################################################################################################################
#
# 1.10.1.7. Verify the BGP Local AS functionality with ECMP on 8 links by adding no-prepend and replace-as command in between eBGP Peers.
#
#################################################################################################################################################
import os
import sys
import time
import pytest
import platform
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from lib.topotest import version_cmp
from lib.common_config import (
start_topology,
write_test_header,
create_static_routes,
write_test_footer,
reset_config_on_routers,
verify_rib,
step,
check_address_types,
check_router_status,
create_static_routes,
verify_fib_routes,
)
from lib.topolog import logger
from lib.bgp import (
verify_bgp_convergence,
verify_bgp_rib,
create_router_bgp,
)
from lib.topojson import build_config_from_json
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
# Global variables
BGP_CONVERGENCE = False
NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
json_file = "{}/bgp_local_asn_dot_ecmp.json".format(CWD)
tgen = Topogen(json_file, mod.__name__)
global topo
topo = tgen.json_topo
# ... and here it calls Mininet initialization functions.
# Starting topology, create tmp files which are loaded to routers
# to start daemons and then start routers
start_topology(tgen)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
global BGP_CONVERGENCE
global ADDR_TYPES
ADDR_TYPES = check_address_types()
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
BGP_CONVERGENCE
)
logger.info("Running setup_module() done")
def teardown_module():
"""Teardown the pytest environment"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
##########################################################################################################################################
#
# Testcases
#
###########################################################################################################################################
def test_verify_bgp_local_as_in_ecmp_EBGP_p0(request):
"""
Verify the BGP Local AS functionality with ECMP on 8 links by
adding no-prepend and replace-as command in between eBGP Peers.
"""
tgen = get_topogen()
global BGP_CONVERGENCE
if BGP_CONVERGENCE != True:
pytest.skip("skipped because of BGP Convergence failure")
# test case name
tc_name = request.node.name
write_test_header(tc_name)
if tgen.routers_have_failure():
check_router_status(tgen)
reset_config_on_routers(tgen)
step("Base config is done as part of JSON")
dut = "r1"
for addr_type in ADDR_TYPES:
# Enable static routes
input_dict_static_route = {
"r1": {
"static_routes": [
{"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
]
}
}
logger.info("Configure static routes")
result = create_static_routes(tgen, input_dict_static_route)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("configure redistribute static in Router BGP in R1")
input_dict_static_route_redist = {
"r1": {
"bgp": [
{
"address_family": {
addr_type: {
"unicast": {"redistribute": [{"redist_type": "static"}]}
}
}
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Verify IPv4 and IPv6 static routes received on R1")
result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
assert result is True, "Testcase {}: Failed \n Error: {}".format(
tc_name, result
)
result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as at R3 towards R2.")
for addr_type in ADDR_TYPES:
input_dict_r3_to_r2 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
"r2": {
"dest_link": {
"r3-link1": {
"local_asn": {"local_as": "1.110"}
}
}
}
}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as at R3 towards R4.")
dest_link = {}
for link_no in range(1, 9):
link = "r3-link" + str(link_no)
dest_link[link] = {"local_asn": {"local_as": "1.110"}}
for addr_type in ADDR_TYPES:
input_dict_r3_to_r4 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {"r4": {"dest_link": dest_link}}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("Configure remote-as at R2 towards R3.")
for addr_type in ADDR_TYPES:
input_dict_r2_to_r3 = {
"r2": {
"bgp": [
{
"local_as": "1.200",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
"r3": {
"dest_link": {
"r2-link1": {
"local_asn": {"remote_as": "1.110"}
}
}
}
}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("Configure remote-as at R4 towards R3.")
dest_link = {}
for link_no in range(1, 9):
link = "r4-link" + str(link_no)
dest_link[link] = {"local_asn": {"remote_as": "1.110"}}
for addr_type in ADDR_TYPES:
input_dict_r4_to_r3 = {
"r4": {
"bgp": [
{
"local_as": "1.400",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {"r3": {"dest_link": dest_link}}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
step("Verify IPv4 and IPv6 static routes received on R3 & R4")
for addr_type in ADDR_TYPES:
static_routes_input = {
"r1": {
"static_routes": [
{"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
]
}
}
for dut in ["r3", "r4"]:
result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step(
"Verify that AS-110 is got added in the AS list 1.110 1.200 1.100 by following "
" commands at R3 router."
)
dut = "r3"
aspath = "1.110 1.200 1.100"
for addr_type in ADDR_TYPES:
input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend at R3 towards R2.")
for addr_type in ADDR_TYPES:
input_dict_no_prep_r3_to_r2 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
"r2": {
"dest_link": {
"r3-link1": {
"local_asn": {
"local_as": "1.110",
"no_prepend": True,
}
}
}
}
}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend at R3 towards R4.")
dest_link = {}
for link_no in range(1, 9):
link = "r3-link" + str(link_no)
dest_link[link] = {"local_asn": {"local_as": "1.110"}}
for addr_type in ADDR_TYPES:
input_dict_no_prep_r3_to_r4 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {"r4": {"dest_link": dest_link}}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
dut = "r3"
aspath = "1.200 1.100"
for addr_type in ADDR_TYPES:
input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend and replace-as at R3 towards R2")
for addr_type in ADDR_TYPES:
input_dict_no_prep_rep_as_r3_to_r2 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {
"r2": {
"dest_link": {
"r3-link1": {
"local_asn": {
"local_as": "1.110",
"no_prepend": True,
"replace_as": True,
}
}
}
}
}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("Configure local-as with no-prepend and replace-as at R3 towards R4")
dest_link = {}
for link_no in range(1, 9):
link = "r3-link" + str(link_no)
dest_link[link] = {
"local_asn": {"local_as": "1.110", "no_prepend": True, "replace_as": True}
}
for addr_type in ADDR_TYPES:
input_dict_no_prep_rep_as_r3_to_r4 = {
"r3": {
"bgp": [
{
"local_as": "1.300",
"address_family": {
addr_type: {
"unicast": {
"neighbor": {"r4": {"dest_link": dest_link}}
}
}
},
}
]
}
}
result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
assert result is True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("BGP neighborship is verified by following commands in R3 routers")
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
BGP_CONVERGENCE
)
dut = "r4"
aspath = "1.110 1.200 1.100"
for addr_type in ADDR_TYPES:
input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

File diff suppressed because it is too large Load Diff

View File

@ -1673,10 +1673,14 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd,
#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
"router bgp [(1-4294967295) [<view|vrf> VIEWVRFNAME]]",
"router bgp [ASNUM [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
ROUTER_STR BGP_STR AS_STR
"BGP view\nBGP VRF\n"
"View/VRF name\n")
"View/VRF name\n"
"Force the AS notation output\n"
"use 'AA.BB' format for AS 4 byte values\n"
"use 'AA.BB' format for all AS values\n"
"use plain format for all AS values\n")
{
vty->node = BGP_NODE;
return CMD_SUCCESS;

View File

@ -356,6 +356,102 @@ module frr-bgp-route-map {
}
}
typedef route-distinguisher {
type string {
pattern
'(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ '42949672[0-8][0-9]|'
+ '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ '42949[0-5][0-9]{4}|'
+ '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
+ '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ '655[0-2][0-9]|'
+ '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ '(2:(429496729[0-5]|42949672[0-8][0-9]|'
+ '4294967[01][0-9]{2}|'
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ '4294[0-8][0-9]{5}|'
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ '(6(:[a-fA-F0-9]{2}){6})|'
+ '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
+ '[0-9a-fA-F]{1,12})|'
+ '((6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ '42949672[0-8][0-9]|'
+ '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ '42949[0-5][0-9]{4}|'
+ '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0)|'
+ '((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ '655[0-2][0-9]|'
+ '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ '((429496729[0-5]|42949672[0-8][0-9]|'
+ '4294967[01][0-9]{2}|'
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ '4294[0-8][0-9]{5}|'
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ '((6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0).'
+ '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ '6[0-4][0-9]{3}|'
+ '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):'
+ '(429496729[0-5]|42949672[0-8][0-9]|'
+ '4294967[01][0-9]{2}|'
+ '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ '4294[0-8][0-9]{5}|'
+ '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))';
}
description
"A Route Distinguisher is an 8-octet value used to
distinguish routes from different BGP VPNs (RFC 4364).
A Route Distinguisher will have the same format as a
Route Target as per RFC 4360 and will consist of
two or three fields: a 2-octet Type field, an administrator
field, and, optionally, an assigned number field.
According to the data formats for types 0, 1, 2, and 6 as
defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
pattern is defined as:
0:2-octet-asn:4-octet-number
1:4-octet-ipv4addr:2-octet-number
2:4-octet-asn:2-octet-number
6:6-octet-mac-address
Additionally, a generic pattern is defined for future
route discriminator types:
2-octet-other-hex-number:6-octet-hex-number
Some valid examples are 0:100:100, 1:1.1.1.1:100,
2:1234567890:203, and 6:26:00:08:92:78:00.
The following route distinguisher with two fields are also
accepted : 10000:44 1.2.3.4:44.";
reference
"RFC 4360: BGP Extended Communities Attribute.
RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
RFC 5668: 4-Octet AS Specific BGP Extended Community.
RFC 7432: BGP MPLS-Based Ethernet VPN.";
}
typedef extcommunity-lb-type {
type enumeration {
enum "explicit-bandwidth" {
@ -598,7 +694,7 @@ module frr-bgp-route-map {
description
"Match eVPN route-distinguisher";
leaf route-distinguisher {
type rt-types:route-distinguisher;
type route-distinguisher;
}
}