summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2023-02-21 08:01:03 -0500
committerGitHub <noreply@github.com>2023-02-21 08:01:03 -0500
commitba755d35e508c2452e5459bdd7c0dd67a70a88a4 (patch)
treeadc08f46788b8012240faec23ae7e7271bb0d40d
parent39c664c4ea530a9460efa1a78fe669ae56c85f83 (diff)
parent616e9f0d9f0458788adf4b30707016c8db383b02 (diff)
Merge pull request #12248 from pguibert6WIND/bgpasdot
lib, bgp: add initial support for asdot format
-rw-r--r--bgpd/bgp_aspath.c81
-rw-r--r--bgpd/bgp_aspath.h12
-rw-r--r--bgpd/bgp_attr.c24
-rw-r--r--bgpd/bgp_btoa.c3
-rw-r--r--bgpd/bgp_debug.c11
-rw-r--r--bgpd/bgp_evpn.c16
-rw-r--r--bgpd/bgp_evpn_mh.c28
-rw-r--r--bgpd/bgp_evpn_private.h1
-rw-r--r--bgpd/bgp_evpn_vty.c78
-rw-r--r--bgpd/bgp_mplsvpn.c21
-rw-r--r--bgpd/bgp_mplsvpn_snmp.c6
-rw-r--r--bgpd/bgp_network.c2
-rw-r--r--bgpd/bgp_nexthop.c17
-rw-r--r--bgpd/bgp_nht.c16
-rw-r--r--bgpd/bgp_rd.c100
-rw-r--r--bgpd/bgp_rd.h17
-rw-r--r--bgpd/bgp_route.c84
-rw-r--r--bgpd/bgp_route.h1
-rw-r--r--bgpd/bgp_routemap.c58
-rw-r--r--bgpd/bgp_rpki.c53
-rw-r--r--bgpd/bgp_script.c3
-rw-r--r--bgpd/bgp_vty.c395
-rw-r--r--bgpd/bgp_vty.h3
-rw-r--r--bgpd/bgpd.c127
-rw-r--r--bgpd/bgpd.h48
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c9
-rw-r--r--bgpd/rfapi/rfapi.c6
-rw-r--r--bgpd/rfapi/rfapi_import.c12
-rw-r--r--bgpd/rfapi/rfapi_rib.c6
-rw-r--r--bgpd/rfapi/rfapi_vty.c3
-rw-r--r--doc/developer/cli.rst45
-rw-r--r--doc/user/bgp.rst25
-rw-r--r--lib/asn.c260
-rw-r--r--lib/asn.h81
-rw-r--r--lib/command.c1
-rw-r--r--lib/command.h3
-rw-r--r--lib/command_graph.c2
-rw-r--r--lib/command_graph.h1
-rw-r--r--lib/command_lex.l2
-rw-r--r--lib/command_match.c6
-rw-r--r--lib/command_parse.y6
-rw-r--r--lib/command_py.c1
-rw-r--r--lib/prefix.h5
-rw-r--r--lib/subdir.am2
-rw-r--r--python/clidef.py7
-rw-r--r--tests/bgpd/test_aspath.c196
-rw-r--r--tests/bgpd/test_capability.c3
-rw-r--r--tests/bgpd/test_mp_attr.c3
-rw-r--r--tests/bgpd/test_packet.c3
-rw-r--r--tests/lib/test_printfrr.c9
-rw-r--r--tests/topotests/bgp_asdot_regex/__init__.py0
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/bgpd.conf27
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json80
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/bgpd.conf26
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json80
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py122
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py0
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf5
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf8
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf5
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py114
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json147
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json317
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json132
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py420
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py524
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py3655
-rw-r--r--vtysh/vtysh.c8
-rw-r--r--yang/frr-bgp-route-map.yang98
76 files changed, 7247 insertions, 473 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 584f524f05..2cc7e46573 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -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))
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index dd65b423a7..18af375c13 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -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);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index fe918a3e03..19c65ce4d2 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -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;
+
+ asnotation = bgp_get_asnotation(peer->bgp);
- *as4_path = aspath_parse(peer->curr, length, 1);
+ *as4_path = aspath_parse(peer->curr, length, 1, asnotation);
/* In case of IBGP, length will be zero. */
if (!*as4_path) {
diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c
index b410a4b896..fc3363b098 100644
--- a/bgpd/bgp_btoa.c
+++ b/bgpd/bgp_btoa.c
@@ -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;
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 2dec1ca46d..782245e512 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -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;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 4758cd98ec..51b44a9e78 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -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);
}
/*
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index fa913016fb..391ca4cd19 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -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":"-");
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index d63e7a1a16..fbf3b19c37 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -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;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 33c202c3d7..59986102a5 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -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)) {
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index bd8ce54775..ab02170183 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -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],
diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c
index 95a7bb8117..9b2ab66806 100644
--- a/bgpd/bgp_mplsvpn_snmp.c
+++ b/bgpd/bgp_mplsvpn_snmp.c
@@ -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;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index da89c594c8..df67e2a72c 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -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);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index a3014c0c6d..00a0bc8402 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -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);
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 4f42766b9f..25b458a8e5 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -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,
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c
index 6e73ab8d1e..bb9f76b8a3 100644
--- a/bgpd/bgp_rd.c
+++ b/bgpd/bgp_rd.c
@@ -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);
+}
diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h
index 44173b7a24..e38c2fad3b 100644
--- a/bgpd/bgp_rd.h
+++ b/bgpd/bgp_rd.h
@@ -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);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 0d93abc12f..977dca13dc 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -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);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index d449152c21..bd4191bfd9 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -355,6 +355,7 @@ struct bgp_static {
/* Route Distinguisher */
struct prefix_rd prd;
+ char *prd_pretty;
/* MPLS label. */
mpls_label_t label;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index dbffecee30..4b6f290c71 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -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 =
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 61b8b4edce..d7e1a6341b 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -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);
}
}
diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c
index 6cc75494ed..f4ab233524 100644
--- a/bgpd/bgp_script.c
+++ b/bgpd/bgp_script.c
@@ -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);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b858d9c4b4..8ef18a34d0 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -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");
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 56485035e8..1c5adff68d 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9ea5a92adc..09d7944aec 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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));
}
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 91f0de0cea..2a7c7a3143 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -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);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 40cb8f8d5a..5b6961d18a 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -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) {
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 0c8fdc72e0..8d6db9d775 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -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;
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 6d4fc53f83..a504405361 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -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);
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index b15620741b..f727f24f1d 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -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);
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 0144c28d58..2b768b8f8d 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -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;
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index 5d1dda06df..2a08531bd7 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -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
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index c5319a8e88..e0f1c6266a 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -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:
diff --git a/lib/asn.c b/lib/asn.c
new file mode 100644
index 0000000000..c64666375d
--- /dev/null
+++ b/lib/asn.c
@@ -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);
+}
diff --git a/lib/asn.h b/lib/asn.h
new file mode 100644
index 0000000000..81a42c658d
--- /dev/null
+++ b/lib/asn.h
@@ -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 */
diff --git a/lib/command.c b/lib/command.c
index cf96df6f95..ee5a3889e8 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -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),
diff --git a/lib/command.h b/lib/command.h
index 2121bfd623..6538e56588 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -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"
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 850fdeafcd..ff3c11db69 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -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;
}
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 8e84fa928d..25aa47db7b 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -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
diff --git a/lib/command_lex.l b/lib/command_lex.l
index 64f74498b8..dc89191c13 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -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;}
diff --git a/lib/command_match.c b/lib/command_match.c
index 5ed643bc91..ff3c48fc31 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -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
diff --git a/lib/command_parse.y b/lib/command_parse.y
index a29e090ef0..8867e98ccc 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -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
diff --git a/lib/command_py.c b/lib/command_py.c
index ceea5883d5..f8abcf8ef4 100644
--- a/lib/command_py.c
+++ b/lib/command_py.c
@@ -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);
diff --git a/lib/prefix.h b/lib/prefix.h
index 1fd652507f..a6435be1b4 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -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
diff --git a/lib/subdir.am b/lib/subdir.am
index 8d00668c8c..beef8675aa 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -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 \
diff --git a/python/clidef.py b/python/clidef.py
index d71b482a99..244a8205bf 100644
--- a/python/clidef.py
+++ b/python/clidef.py
@@ -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.
diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c
index 8806bcd8fc..926097f571 100644
--- a/tests/bgpd/test_aspath.c
+++ b/tests/bgpd/test_aspath.c
@@ -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++]);
diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c
index 01b0740b87..8ef5748671 100644
--- a/tests/bgpd/test_capability.c
+++ b/tests/bgpd/test_capability.c
@@ -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);
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index 3abf7bd141..b1f3314f1f 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -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);
diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c
index 1a2d21ad22..aeebbd9a35 100644
--- a/tests/bgpd/test_packet.c
+++ b/tests/bgpd/test_packet.c
@@ -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);
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 9cabae8f20..0ab40b2ecd 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -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;
}
diff --git a/tests/topotests/bgp_asdot_regex/__init__.py b/tests/topotests/bgp_asdot_regex/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/__init__.py
diff --git a/tests/topotests/bgp_asdot_regex/r1/bgpd.conf b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf
new file mode 100644
index 0000000000..4dd95dd8b7
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf
@@ -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
+
diff --git a/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
new file mode 100644
index 0000000000..e3703bf953
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
@@ -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
+ }
+ ]
+ }
+]
+ } }
diff --git a/tests/topotests/bgp_asdot_regex/r1/zebra.conf b/tests/topotests/bgp_asdot_regex/r1/zebra.conf
new file mode 100644
index 0000000000..6e9b0b4a7e
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_asdot_regex/r2/bgpd.conf b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf
new file mode 100644
index 0000000000..216dbd19ef
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf
@@ -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
diff --git a/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
new file mode 100644
index 0000000000..1af4ff7e3d
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
@@ -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
+ }
+ ]
+ }
+]
+ } }
diff --git a/tests/topotests/bgp_asdot_regex/r2/zebra.conf b/tests/topotests/bgp_asdot_regex/r2/zebra.conf
new file mode 100644
index 0000000000..6c14de583b
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
new file mode 100644
index 0000000000..5d5f1659e9
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
@@ -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))
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py b/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf
new file mode 100644
index 0000000000..1846df24f3
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf
@@ -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
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf
new file mode 100644
index 0000000000..0a283c06d5
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf
new file mode 100644
index 0000000000..c9adfa4671
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf
@@ -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
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf
new file mode 100644
index 0000000000..9a831270b4
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf
@@ -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
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf
new file mode 100644
index 0000000000..39499a198d
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf
new file mode 100644
index 0000000000..c9adfa4671
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf
@@ -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
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf
new file mode 100644
index 0000000000..b85911504e
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r4-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py
new file mode 100644
index 0000000000..efecad3eb2
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py
@@ -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))
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
new file mode 100644
index 0000000000..b481932449
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
@@ -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": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
new file mode 100644
index 0000000000..afacab4946
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
@@ -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": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
new file mode 100644
index 0000000000..02aacf791a
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
@@ -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": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
new file mode 100644
index 0000000000..cb8fa1e9f9
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
@@ -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))
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
new file mode 100644
index 0000000000..6937a61c33
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
@@ -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))
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
new file mode 100644
index 0000000000..e9234f5172
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
@@ -0,0 +1,3655 @@
+#!/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.
+#
+
+##########################################################################################################
+#
+# Functionality Testcases
+#
+##########################################################################################################
+"""
+1. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between eBGP Peers.
+2. Verify the BGP Local AS functionality by configuring 4 Byte AS at R3 and 2 Byte AS at R2 & R4 in between eBGP Peers.
+3. Verify that BGP Local AS functionality by performing graceful restart in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend command in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP Peers.
+5. Verify the BGP Local AS functionality with allowas-in in between iBGP Peers.
+6. Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+7. Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+8. Verify the BGP Local AS functionality with different AS configurations.
+9. Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+"""
+
+import os
+import sys
+import time
+import pytest
+from copy import deepcopy
+
+# 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,
+ get_frr_ipv6_linklocal,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+ create_route_maps,
+ kill_router_daemons,
+ start_router_daemons,
+ shutdown_bringup_interface,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ clear_bgp_and_verify,
+ verify_bgp_rib,
+ modify_as_number,
+ create_router_bgp,
+ verify_bgp_advertised_routes_from_neighbor,
+ verify_graceful_restart,
+ verify_r_bit,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+NEXT_HOP_IP_GR = {"ipv4": "10.0.0.5", "ipv6": "fd00:0:0:1::2/64"}
+NEXT_HOP_IP_1 = {"ipv4": "10.0.0.101", "ipv6": "fd00::1"}
+NEXT_HOP_IP_2 = {"ipv4": "10.0.0.102", "ipv6": "fd00::2"}
+
+BGP_CONVERGENCE = False
+PREFERRED_NEXT_HOP = "link_local"
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+
+
+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_topo1.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)
+
+
+##########################################################################################################
+#
+# Local APIs
+#
+##########################################################################################################
+
+
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
+ """
+ This function groups the repetitive function calls into one function.
+ """
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = clear_bgp_and_verify(tgen, topo, dut)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ return True
+
+
+def next_hop_per_address_family(
+ tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP
+):
+ """
+ This function returns link_local or global next_hop per address-family
+ """
+ intferface = topo["routers"][peer]["links"]["{}".format(dut)]["interface"]
+ if addr_type == "ipv6" and "link_local" in preferred_next_hop:
+ next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface)
+ else:
+ next_hop = next_hop_dict[addr_type]
+
+ return next_hop
+
+
+##########################################################################################################
+#
+# Testcases
+#
+##########################################################################################################
+
+
+def test_verify_bgp_local_as_in_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality 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")
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-1.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 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
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "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 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.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)
+
+
+def test_verify_bgp_local_as_in_EBGP_4B_AS_mid_4B_AS_p0(request):
+ """
+ Verify the BGP Local AS functionality by configuring 4 Byte AS
+ at R3 and 4 Byte AS at R2 & R4 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": "183.2926"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ 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": "183.2926"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-183.2926 is got added in the AS list 183.2926 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "183.2926 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 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": "183.2926",
+ "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
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "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 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": "183.2926",
+ "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 = "183.2926 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)
+
+
+def test_verify_bgp_local_as_GR_EBGP_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing graceful restart 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("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ 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_GR[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": {"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.")
+ 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": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ 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": {
+ "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.")
+ 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": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ 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_GR[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-1.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
+ )
+
+ """
+ GR Steps : Helper BGP router R2, mark and unmark IPV4 routes
+ as stale as the restarting router R3 come up within the restart time
+ """
+ # Create route-map to prefer global next-hop
+ input_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ "r3": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_neigh_rm = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_neigh_rm)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure graceful-restart
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "1.110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "1.110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r3", peer="r2")
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying BGP RIB routes
+ dut = "r2"
+ peer = "r3"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, "bgp")
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Phase 2] : R3 goes for reload ")
+
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R3 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB"
+ " and ZEBRA"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Phase 5] : R3 is about to come up now ")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info("[Phase 5] : R3 is UP Now ! ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_bgp_convergence(tgen, topo)
+ assert (
+ result is True
+ ), "BGP Convergence after BGPd restart" " :Failed \n Error:{}".format(result)
+
+ # Verifying GR stats
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r3")
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ 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": {
+ "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.")
+ 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": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ 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": {
+ "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")
+ 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": {
+ "r3": {
+ "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_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)
+
+
+def test_verify_bgp_local_as_in_EBGP_aspath_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend 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("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-1.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 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
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "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 a route-map on R3 to prepend AS 2 times.")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "1.1000 1.1000", "as_action": "prepend"}
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure route map in out direction on R4")
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "ASP_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ 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
+ )
+
+ step(
+ "Verify that AS-1.300 is got replaced with 1.200 in the AS list 1.110 1.1000 1.1000 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r4"
+ aspath = "1.110 1.1000 1.1000 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)
+
+
+def test_verify_bgp_local_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP 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("Modify AS Number for R3")
+ input_dict_modify_as_number = {"r3": {"bgp": {"local_as": "1.200"}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ step("Base config is done as part of JSON")
+ 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 R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ 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 R4 towards R3.")
+ 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": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ 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": {
+ "next_hop_self": True,
+ "local_asn": {
+ "remote_as": "1.200",
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_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-1.110 is got added in the AS list 1.110 1.200 1.100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "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
+ )
+
+ 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
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ 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.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 and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "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_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.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)
+
+
+def test_verify_bgp_local_as_allow_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality with allowas-in in between iBGP 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("Modidy AS Number for R4")
+ input_dict_modify_as_number = {"r4": {"bgp": {"local_as": "1.100"}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ 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 allow-as at R4")
+ for addr_type in ADDR_TYPES:
+ allow_as_config_r4 = {
+ "r4": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "allowas-in": {
+ "number_occurences": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+
+ step(
+ "Configuring allow-as for {} address-family on router R4 ".format(addr_type)
+ )
+ result = create_router_bgp(tgen, topo, allow_as_config_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # now modify the as in r4 and reconfig bgp in r3 with new remote as.
+ topo1 = deepcopy(topo)
+ topo1["routers"]["r4"]["bgp"]["local_as"] = "1.100"
+
+ delete_bgp = {"r3": {"bgp": {"delete": True}}}
+ result = create_router_bgp(tgen, topo1, delete_bgp)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ build_config_from_json(tgen, topo1, save_bkup=False)
+
+ 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": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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.")
+ 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": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "1.100",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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, topo1)
+ 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-1.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": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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.")
+ 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": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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, topo1)
+ 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": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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")
+ 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": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, 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, topo1)
+ 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)
+
+
+def test_verify_bgp_local_as_in_EBGP_port_reset_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+ """
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Api call to modfiy BGP timers at R3")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_timers = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_timers)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.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("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for count in range(1, 1):
+ step("Iteration {}".format(count))
+ step("Shut down connecting interface between R3<<>>R4 on R3.")
+
+ intf1 = topo["routers"]["r3"]["links"]["r4"]["interface"]
+
+ interfaces = [intf1]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r3", intf, False)
+
+ step(
+ "On R3, all BGP peering in respective vrf instances go down"
+ " when the interface is shut"
+ )
+
+ result = verify_bgp_convergence(tgen, topo, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: BGP will not be converged \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("BGP neighborship is verified after restart of r3")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-1.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 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.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 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.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)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative2_p0(request):
+ """
+ Verify the BGP Local AS functionality with different AS configurations.
+ """
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-1.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 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
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "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 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
+ )
+ step("Verify that AS-1.300 is replaced with AS-1.110 at R3 router.")
+ 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
+ )
+
+ # configure negative scenarios
+ step("Configure local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.110",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \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
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative3_p0(request):
+ """
+ Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+ """
+ 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("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-1.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
+ )
+
+ # Perform Negative scenarios
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_restart_daemons_p0(request):
+ """
+ Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+ """
+ 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
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "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_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ 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[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
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ 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-1.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("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-1.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("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ 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
+ )
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.200 1.100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "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("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.200 1.100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "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 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
+ )
+
+ step(
+ "Verified that AS-1.300 is got replaced with original AS-1.110 at R4 by following commands"
+ )
+ 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
+ )
+
+ step(
+ "Verified that AS-1.300 is got replaced with original AS-1.110 at R4 by following commands"
+ )
+ 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))
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index a17ee812e4..200427fb6e 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -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;
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index ad2a142fef..8e288194ec 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -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;
}
}