mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 11:50:21 +00:00
Merge pull request #12248 from pguibert6WIND/bgpasdot
lib, bgp: add initial support for asdot format
This commit is contained in:
commit
ba755d35e5
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -1054,7 +1054,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
|
||||
|
||||
attr->origin = origin;
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
|
||||
attr->aspath = aspath_empty();
|
||||
attr->aspath = aspath_empty(bgp->asnotation);
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
|
||||
attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
|
||||
attr->tag = 0;
|
||||
@ -1092,7 +1092,7 @@ struct attr *bgp_attr_aggregate_intern(
|
||||
if (aspath)
|
||||
attr.aspath = aspath_intern(aspath);
|
||||
else
|
||||
attr.aspath = aspath_empty();
|
||||
attr.aspath = aspath_empty(bgp->asnotation);
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
|
||||
|
||||
/* Next hop attribute. */
|
||||
@ -1590,15 +1590,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
|
||||
struct attr *const attr = args->attr;
|
||||
struct peer *const peer = args->peer;
|
||||
const bgp_size_t length = args->length;
|
||||
enum asnotation_mode asnotation;
|
||||
|
||||
asnotation = bgp_get_asnotation(
|
||||
args->peer && args->peer->bgp ? args->peer->bgp : NULL);
|
||||
/*
|
||||
* peer with AS4 => will get 4Byte ASnums
|
||||
* otherwise, will get 16 Bit
|
||||
*/
|
||||
attr->aspath = aspath_parse(
|
||||
peer->curr, length,
|
||||
CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
|
||||
&& CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV));
|
||||
attr->aspath =
|
||||
aspath_parse(peer->curr, length,
|
||||
CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) &&
|
||||
CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV),
|
||||
asnotation);
|
||||
|
||||
/* In case of IBGP, length will be zero. */
|
||||
if (!attr->aspath) {
|
||||
@ -1614,7 +1618,8 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
|
||||
* such messages, conformant BGP speakers SHOULD use the "Treat-as-
|
||||
* withdraw" error handling behavior as per [RFC7606].
|
||||
*/
|
||||
if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
|
||||
if (peer->bgp && peer->bgp->reject_as_sets &&
|
||||
aspath_check_as_sets(attr->aspath)) {
|
||||
flog_err(EC_BGP_ATTR_MAL_AS_PATH,
|
||||
"AS_SET and AS_CONFED_SET are deprecated from %pBP",
|
||||
peer);
|
||||
@ -1690,8 +1695,11 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
|
||||
struct peer *const peer = args->peer;
|
||||
struct attr *const attr = args->attr;
|
||||
const bgp_size_t length = args->length;
|
||||
enum asnotation_mode asnotation;
|
||||
|
||||
*as4_path = aspath_parse(peer->curr, length, 1);
|
||||
asnotation = bgp_get_asnotation(peer->bgp);
|
||||
|
||||
*as4_path = aspath_parse(peer->curr, length, 1, asnotation);
|
||||
|
||||
/* In case of IBGP, length will be zero. */
|
||||
if (!*as4_path) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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":"-");
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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],
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
100
bgpd/bgp_rd.c
100
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -355,6 +355,7 @@ struct bgp_static {
|
||||
|
||||
/* Route Distinguisher */
|
||||
struct prefix_rd prd;
|
||||
char *prd_pretty;
|
||||
|
||||
/* MPLS label. */
|
||||
mpls_label_t label;
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
395
bgpd/bgp_vty.c
395
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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
127
bgpd/bgpd.c
127
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));
|
||||
}
|
||||
}
|
||||
|
48
bgpd/bgpd.h
48
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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -254,8 +254,9 @@ ASN and Router ID
|
||||
-----------------
|
||||
|
||||
First of all you must configure BGP router with the :clicmd:`router bgp ASN`
|
||||
command. The AS number is an identifier for the autonomous system. The BGP
|
||||
protocol uses the AS number for detecting whether the BGP connection is
|
||||
command. The AS number is an identifier for the autonomous system. The AS
|
||||
identifier can either be a number or two numbers separated by a period. The
|
||||
BGP protocol uses the AS identifier for detecting whether the BGP connection is
|
||||
internal or external.
|
||||
|
||||
.. clicmd:: router bgp ASN
|
||||
@ -4301,6 +4302,26 @@ Segment-Routing IPv6
|
||||
vpn_policy[AFI_IP].tovpn_sid: none
|
||||
vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::200
|
||||
|
||||
AS-notation support
|
||||
-------------------
|
||||
|
||||
By default, the ASN value output follows how the BGP ASN instance is
|
||||
expressed in the configuration. Three as-notation outputs are available:
|
||||
|
||||
- plain output: both AS4B and AS2B use a single number.
|
||||
` router bgp 65536`.
|
||||
|
||||
- dot output: AS4B values are using two numbers separated by a period.
|
||||
`router bgp 1.1` means that the AS number is 65536.
|
||||
|
||||
- dot+ output: AS2B and AS4B values are using two numbers separated by a
|
||||
period. `router bgp 0.5` means that the AS number is 5.
|
||||
|
||||
The below option permits forcing the as-notation output:
|
||||
|
||||
.. clicmd:: router bgp ASN as-notation dot|dot+|plain
|
||||
|
||||
The chosen as-notation format will override the BGP ASN output.
|
||||
|
||||
.. _bgp-route-reflector:
|
||||
|
||||
|
260
lib/asn.c
Normal file
260
lib/asn.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* ASN functions
|
||||
*
|
||||
* Copyright 2022 6WIND
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <zebra.h>
|
||||
#include "log.h"
|
||||
#include "asn.h"
|
||||
|
||||
static bool relax_as_zero;
|
||||
|
||||
static const struct message asnotation_mode_msg[] = {
|
||||
{ASNOTATION_PLAIN, "plain"},
|
||||
{ASNOTATION_DOT, "dot"},
|
||||
{ASNOTATION_DOTPLUS, "dot+"},
|
||||
{ASNOTATION_UNDEFINED, "undefined"},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* converts a string into an Autonomous system number
|
||||
* "1.1" => 65536
|
||||
* "65500" => 65500
|
||||
*/
|
||||
static bool asn_str2asn_internal(const char *asstring, as_t *asn,
|
||||
const char **next, bool *partial,
|
||||
enum asnotation_mode *mode)
|
||||
{
|
||||
uint32_t high = 0, low = 0;
|
||||
uint64_t temp_val;
|
||||
const char *p = asstring;
|
||||
bool ret = false;
|
||||
uint32_t digit;
|
||||
enum asnotation_mode val = ASNOTATION_PLAIN;
|
||||
|
||||
if (!asstring)
|
||||
goto end;
|
||||
|
||||
if (!isdigit((unsigned char)*p))
|
||||
goto end;
|
||||
|
||||
temp_val = 0;
|
||||
while (isdigit((unsigned char)*p)) {
|
||||
digit = (*p) - '0';
|
||||
temp_val *= 10;
|
||||
temp_val += digit;
|
||||
if (temp_val > UINT32_MAX)
|
||||
/* overflow */
|
||||
goto end;
|
||||
p++;
|
||||
}
|
||||
high = (uint32_t)temp_val;
|
||||
if (*p == '.') { /* dot format */
|
||||
p++;
|
||||
temp_val = 0;
|
||||
if (*p == '\0' && partial) {
|
||||
*partial = true;
|
||||
goto end;
|
||||
}
|
||||
while (isdigit((unsigned char)*p)) {
|
||||
digit = (*p) - '0';
|
||||
temp_val *= 10;
|
||||
temp_val += digit;
|
||||
if (temp_val > UINT16_MAX)
|
||||
/* overflow */
|
||||
goto end;
|
||||
p++;
|
||||
}
|
||||
low = (uint32_t)temp_val;
|
||||
|
||||
if (!next && *p != '\0' && !isdigit((unsigned char)*p))
|
||||
goto end;
|
||||
/* AS <AS4B>.<AS4B> is forbidden */
|
||||
if (high > UINT16_MAX)
|
||||
goto end;
|
||||
/* AS 0.0 is authorised for some case only */
|
||||
if (!relax_as_zero && high == 0 && low == 0) {
|
||||
if (partial)
|
||||
*partial = true;
|
||||
goto end;
|
||||
}
|
||||
if (asn)
|
||||
*asn = (high << 16) + low;
|
||||
ret = true;
|
||||
if (high == 0)
|
||||
val = ASNOTATION_DOTPLUS;
|
||||
else
|
||||
val = ASNOTATION_DOT;
|
||||
goto end;
|
||||
}
|
||||
/* AS 0 is forbidden */
|
||||
if (!relax_as_zero && high == 0)
|
||||
goto end;
|
||||
if (!asn) {
|
||||
ret = true;
|
||||
goto end;
|
||||
}
|
||||
*asn = high;
|
||||
ret = true;
|
||||
end:
|
||||
if (next)
|
||||
*next = p;
|
||||
if (mode)
|
||||
*mode = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asn_asn2asdot(as_t asn, char *asstring, size_t len)
|
||||
{
|
||||
uint16_t low, high;
|
||||
|
||||
high = (asn >> 16) & 0xffff;
|
||||
low = asn & 0xffff;
|
||||
snprintf(asstring, len, "%hu.%hu", high, low);
|
||||
}
|
||||
|
||||
bool asn_str2asn(const char *asstring, as_t *asn)
|
||||
{
|
||||
return asn_str2asn_internal(asstring, asn, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
const char *asn_asn2asplain(as_t asn)
|
||||
{
|
||||
static char buf[ASN_STRING_MAX_SIZE];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", asn);
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *asn_str2asn_parse(const char *asstring, as_t *asn, bool *found_ptr)
|
||||
{
|
||||
const char *p = NULL;
|
||||
const char **next = &p;
|
||||
bool found;
|
||||
|
||||
found = asn_str2asn_internal(asstring, asn, next, NULL, NULL);
|
||||
if (found_ptr)
|
||||
*found_ptr = found;
|
||||
return *next;
|
||||
}
|
||||
|
||||
void asn_relax_as_zero(bool relax)
|
||||
{
|
||||
relax_as_zero = relax;
|
||||
}
|
||||
|
||||
enum match_type asn_str2asn_match(const char *str)
|
||||
{
|
||||
bool found, partial = false;
|
||||
|
||||
found = asn_str2asn_internal(str, NULL, NULL, &partial, NULL);
|
||||
if (found && !partial)
|
||||
return exact_match;
|
||||
|
||||
if (partial)
|
||||
return partly_match;
|
||||
|
||||
return no_match;
|
||||
}
|
||||
|
||||
bool asn_str2asn_notation(const char *asstring, as_t *asn,
|
||||
enum asnotation_mode *asnotation)
|
||||
{
|
||||
return asn_str2asn_internal(asstring, asn, NULL, NULL, asnotation);
|
||||
}
|
||||
|
||||
const char *asn_mode2str(enum asnotation_mode asnotation)
|
||||
{
|
||||
return lookup_msg(asnotation_mode_msg, asnotation,
|
||||
"Unrecognized AS notation mode");
|
||||
}
|
||||
|
||||
void asn_asn2json(json_object *json, const char *attr,
|
||||
as_t asn, enum asnotation_mode asnotation)
|
||||
{
|
||||
static char as_str[ASN_STRING_MAX_SIZE];
|
||||
|
||||
if ((asnotation == ASNOTATION_PLAIN) ||
|
||||
((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
|
||||
json_object_int_add(json, attr, asn);
|
||||
else {
|
||||
asn_asn2asdot(asn, as_str, sizeof(as_str));
|
||||
json_object_string_add(json, attr, as_str);
|
||||
}
|
||||
}
|
||||
|
||||
void asn_asn2json_array(json_object *jseg_list, as_t asn,
|
||||
enum asnotation_mode asnotation)
|
||||
{
|
||||
static char as_str[ASN_STRING_MAX_SIZE];
|
||||
|
||||
if ((asnotation == ASNOTATION_PLAIN) ||
|
||||
((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
|
||||
json_object_array_add(jseg_list,
|
||||
json_object_new_int64(asn));
|
||||
else {
|
||||
asn_asn2asdot(asn, as_str, sizeof(as_str));
|
||||
json_array_string_add(jseg_list, as_str);
|
||||
}
|
||||
}
|
||||
|
||||
char *asn_asn2string(const as_t *asn, char *buf, size_t len,
|
||||
enum asnotation_mode asnotation)
|
||||
{
|
||||
if ((asnotation == ASNOTATION_PLAIN) ||
|
||||
((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX))
|
||||
snprintf(buf, len, "%u", *asn);
|
||||
else
|
||||
asn_asn2asdot(*asn, buf, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static ssize_t printfrr_asnotation(struct fbuf *buf, struct printfrr_eargs *ea,
|
||||
const void *ptr,
|
||||
enum asnotation_mode asnotation)
|
||||
{
|
||||
/* for alignemnt up to 33 chars - %33pASD for instance - */
|
||||
char as_str[ASN_STRING_MAX_SIZE*3];
|
||||
const as_t *asn;
|
||||
|
||||
if (!ptr)
|
||||
return bputs(buf, "(null)");
|
||||
asn = ptr;
|
||||
asn_asn2string(asn, as_str, sizeof(as_str), asnotation);
|
||||
return bputs(buf, as_str);
|
||||
}
|
||||
|
||||
printfrr_ext_autoreg_p("ASP", printfrr_asplain);
|
||||
static ssize_t printfrr_asplain(struct fbuf *buf, struct printfrr_eargs *ea,
|
||||
const void *ptr)
|
||||
{
|
||||
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
|
||||
}
|
||||
|
||||
printfrr_ext_autoreg_p("ASD", printfrr_asdot);
|
||||
static ssize_t printfrr_asdot(struct fbuf *buf, struct printfrr_eargs *ea,
|
||||
const void *ptr)
|
||||
{
|
||||
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOT);
|
||||
}
|
||||
|
||||
printfrr_ext_autoreg_p("ASE", printfrr_asdotplus);
|
||||
static ssize_t printfrr_asdotplus(struct fbuf *buf, struct printfrr_eargs *ea,
|
||||
const void *ptr)
|
||||
{
|
||||
return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
|
||||
}
|
81
lib/asn.h
Normal file
81
lib/asn.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* AS number structure
|
||||
* Copyright 2022 6WIND
|
||||
*
|
||||
* This file is part of GNU Zebra.
|
||||
*
|
||||
* GNU Zebra is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* GNU Zebra is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_ASN_H
|
||||
#define _FRR_ASN_H
|
||||
|
||||
#include "zebra.h"
|
||||
#include "command_match.h"
|
||||
#include "json.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ASN_STRING_MAX_SIZE 12
|
||||
|
||||
enum asnotation_mode {
|
||||
ASNOTATION_PLAIN = 0,
|
||||
ASNOTATION_DOT,
|
||||
ASNOTATION_DOTPLUS,
|
||||
ASNOTATION_UNDEFINED,
|
||||
};
|
||||
|
||||
typedef uint32_t as_t;
|
||||
|
||||
extern bool asn_str2asn(const char *asstring, as_t *asn);
|
||||
extern const char *asn_asn2asplain(as_t asn);
|
||||
extern const char *asn_str2asn_parse(const char *asstring, as_t *asn,
|
||||
bool *found_ptr);
|
||||
extern enum match_type asn_str2asn_match(const char *str);
|
||||
extern bool asn_str2asn_notation(const char *asstring, as_t *asn,
|
||||
enum asnotation_mode *asnotation);
|
||||
extern const char *asn_mode2str(enum asnotation_mode asnotation);
|
||||
void asn_asn2json_array(json_object *jseg_list, as_t asn,
|
||||
enum asnotation_mode asnotation);
|
||||
void asn_asn2json(json_object *jseg_list, const char *attr,
|
||||
as_t asn, enum asnotation_mode asnotation);
|
||||
extern char *asn_asn2string(const as_t *as, char *buf, size_t len,
|
||||
enum asnotation_mode asnotation);
|
||||
/* display AS in appropriate format */
|
||||
#ifdef _FRR_ATTRIBUTE_PRINTFRR
|
||||
#pragma FRR printfrr_ext "%pASP" (as_t *)
|
||||
#pragma FRR printfrr_ext "%pASD" (as_t *)
|
||||
#pragma FRR printfrr_ext "%pASE" (as_t *)
|
||||
#endif
|
||||
|
||||
#define ASN_FORMAT(mode) \
|
||||
((mode == ASNOTATION_DOT) ? "%pASD" : \
|
||||
((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \
|
||||
"%pASP"))
|
||||
#define ASN_FORMAT_SPACE(mode) \
|
||||
((mode == ASNOTATION_DOT) ? "%10pASD" : \
|
||||
((mode == ASNOTATION_DOTPLUS) ? "%10pASE" : \
|
||||
"%10pASP"))
|
||||
|
||||
/* for test */
|
||||
extern void asn_relax_as_zero(bool relax);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FRR_ASN_H */
|
@ -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),
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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.
|
||||
|
@ -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++]);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
0
tests/topotests/bgp_asdot_regex/__init__.py
Normal file
0
tests/topotests/bgp_asdot_regex/__init__.py
Normal file
27
tests/topotests/bgp_asdot_regex/r1/bgpd.conf
Normal file
27
tests/topotests/bgp_asdot_regex/r1/bgpd.conf
Normal file
@ -0,0 +1,27 @@
|
||||
router bgp 1.1
|
||||
no bgp ebgp-requires-policy
|
||||
no bgp network import-check
|
||||
neighbor 192.168.255.2 remote-as 1.2
|
||||
address-family ipv4 unicast
|
||||
network 172.31.1.0/24 route-map rmapout
|
||||
network 172.31.2.0/24 route-map rmapout
|
||||
neighbor 192.168.255.2 route-map rmapin in
|
||||
neighbor 192.168.255.2 activate
|
||||
exit-address-family
|
||||
exit
|
||||
bgp as-path access-list only1_4 permit _1.4_
|
||||
bgp as-path access-list only65540 permit _65540_
|
||||
access-list 172313 permit 172.31.3.0/24
|
||||
access-list 172314 permit 172.31.4.0/24
|
||||
route-map rmapout permit 1
|
||||
set as-path prepend 1.4
|
||||
exit
|
||||
route-map rmapin permit 1
|
||||
match ip address 172313
|
||||
match as-path only1_4
|
||||
exit
|
||||
route-map rmapin permit 2
|
||||
match ip address 172314
|
||||
match as-path only65540
|
||||
exit
|
||||
|
80
tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
Normal file
80
tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"vrfId": 0,
|
||||
"vrfName": "default",
|
||||
"tableVersion": 3,
|
||||
"routerId": "192.168.255.1",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": "1.1",
|
||||
"routes": { "172.31.1.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.1.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.1.0/24",
|
||||
"metric":0,
|
||||
"weight":32768,
|
||||
"peerId":"(unspec)",
|
||||
"path":"1.4",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"0.0.0.0",
|
||||
"hostname":"r1",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
,"172.31.2.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.2.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.2.0/24",
|
||||
"metric":0,
|
||||
"weight":32768,
|
||||
"peerId":"(unspec)",
|
||||
"path":"1.4",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"0.0.0.0",
|
||||
"hostname":"r1",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
,"172.31.3.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.3.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.3.0/24",
|
||||
"metric":0,
|
||||
"weight":0,
|
||||
"peerId":"192.168.255.2",
|
||||
"path":"1.2 1.4",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"192.168.255.2",
|
||||
"hostname":"r2",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
} }
|
6
tests/topotests/bgp_asdot_regex/r1/zebra.conf
Normal file
6
tests/topotests/bgp_asdot_regex/r1/zebra.conf
Normal file
@ -0,0 +1,6 @@
|
||||
!
|
||||
interface r1-eth0
|
||||
ip address 192.168.255.1/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
26
tests/topotests/bgp_asdot_regex/r2/bgpd.conf
Normal file
26
tests/topotests/bgp_asdot_regex/r2/bgpd.conf
Normal file
@ -0,0 +1,26 @@
|
||||
router bgp 65538
|
||||
no bgp ebgp-requires-policy
|
||||
no bgp network import-check
|
||||
neighbor 192.168.255.1 remote-as 65537
|
||||
address-family ipv4 unicast
|
||||
network 172.31.3.0/24 route-map rmapout
|
||||
network 172.31.4.0/24 route-map rmapout
|
||||
neighbor 192.168.255.1 route-map rmapin in
|
||||
neighbor 192.168.255.1 activate
|
||||
exit-address-family
|
||||
exit
|
||||
bgp as-path access-list only65540 permit _65540_
|
||||
bgp as-path access-list only1_4 permit _1.4_
|
||||
access-list 172311 permit 172.31.1.0/24
|
||||
access-list 172312 permit 172.31.2.0/24
|
||||
route-map rmapout permit 1
|
||||
set as-path prepend 65540
|
||||
exit
|
||||
route-map rmapin permit 1
|
||||
match ip address 172311
|
||||
match as-path only65540
|
||||
exit
|
||||
route-map rmapin permit 2
|
||||
match ip address 172312
|
||||
match as-path only1_4
|
||||
exit
|
80
tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
Normal file
80
tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"vrfId": 0,
|
||||
"vrfName": "default",
|
||||
"tableVersion": 3,
|
||||
"routerId": "192.168.255.2",
|
||||
"defaultLocPrf": 100,
|
||||
"localAS": 65538,
|
||||
"routes": { "172.31.1.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.1.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.1.0/24",
|
||||
"metric":0,
|
||||
"weight":0,
|
||||
"peerId":"192.168.255.1",
|
||||
"path":"65537 65540",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"192.168.255.1",
|
||||
"hostname":"r1",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
,"172.31.3.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.3.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.3.0/24",
|
||||
"metric":0,
|
||||
"weight":32768,
|
||||
"peerId":"(unspec)",
|
||||
"path":"65540",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"0.0.0.0",
|
||||
"hostname":"r2",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
,"172.31.4.0/24": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"First path received",
|
||||
"pathFrom":"external",
|
||||
"prefix":"172.31.4.0",
|
||||
"prefixLen":24,
|
||||
"network":"172.31.4.0/24",
|
||||
"metric":0,
|
||||
"weight":32768,
|
||||
"peerId":"(unspec)",
|
||||
"path":"65540",
|
||||
"origin":"IGP",
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"0.0.0.0",
|
||||
"hostname":"r2",
|
||||
"afi":"ipv4",
|
||||
"used":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
} }
|
6
tests/topotests/bgp_asdot_regex/r2/zebra.conf
Normal file
6
tests/topotests/bgp_asdot_regex/r2/zebra.conf
Normal file
@ -0,0 +1,6 @@
|
||||
!
|
||||
interface r2-eth0
|
||||
ip address 192.168.255.2/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
122
tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
Normal file
122
tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
Normal file
@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_bgp_asdot_regex.py
|
||||
# Part of Topotests
|
||||
#
|
||||
# Copyright 2022 6WIND S.A.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
"""
|
||||
test_bgp_asdot_regex.py:
|
||||
|
||||
Test how regex applies when asnotation to forge bgp config is based on dot or not.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import pytest
|
||||
from functools import partial
|
||||
|
||||
# add after imports, before defining classes or functions:
|
||||
pytestmark = [pytest.mark.bgpd]
|
||||
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
pytestmark = [pytest.mark.bgpd]
|
||||
|
||||
|
||||
def build_topo(tgen):
|
||||
for routern in range(1, 3):
|
||||
tgen.add_router("r{}".format(routern))
|
||||
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["r1"])
|
||||
switch.add_link(tgen.gears["r2"])
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
tgen = Topogen(build_topo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
|
||||
for i, (rname, router) in enumerate(router_list.items(), 1):
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
|
||||
)
|
||||
|
||||
tgen.start_router()
|
||||
|
||||
|
||||
def teardown_module(mod):
|
||||
tgen = get_topogen()
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_bgp_asdot_regex():
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
router1 = tgen.gears["r1"]
|
||||
router2 = tgen.gears["r2"]
|
||||
|
||||
def _bgp_converge(router):
|
||||
output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
|
||||
expected = {
|
||||
"192.168.255.2": {
|
||||
"bgpState": "Established",
|
||||
"addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}},
|
||||
}
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
logger.info("Check if neighbor sessions are up in {}".format(router1.name))
|
||||
test_func = partial(_bgp_converge, router1)
|
||||
success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5)
|
||||
assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name)
|
||||
|
||||
logger.info("BGP neighbor session is up in {}".format(router1.name))
|
||||
|
||||
logger.info("waiting for bgp peers exchanging UPDATES")
|
||||
|
||||
for router in tgen.routers().values():
|
||||
ref_file = "{}/{}/show_bgp_ipv4.json".format(CWD, router.name)
|
||||
expected = json.loads(open(ref_file).read())
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5)
|
||||
assertmsg = "{}: BGP UPDATE exchange failure".format(router.name)
|
||||
assert res is None, assertmsg
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -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
|
@ -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
|
||||
!
|
@ -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
|
||||
!
|
@ -0,0 +1,6 @@
|
||||
!
|
||||
interface r2-eth0
|
||||
ip address 192.168.255.2/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
@ -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
|
@ -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
|
||||
!
|
@ -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
|
||||
!
|
@ -0,0 +1,6 @@
|
||||
!
|
||||
interface r4-eth0
|
||||
ip address 192.168.255.2/24
|
||||
!
|
||||
ip forwarding
|
||||
!
|
@ -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))
|
147
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
Normal file
147
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
Normal file
@ -0,0 +1,147 @@
|
||||
{
|
||||
"address_types": ["ipv4", "ipv6"],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 30,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
|
||||
"lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r3": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r1": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r1": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"static_routes":[
|
||||
{
|
||||
"network":"10.1.1.0/32",
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network":"10:1::1:0/128",
|
||||
"next_hop":"Null0"
|
||||
}]
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r3": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.200",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r2": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r2": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"static_routes":[
|
||||
{
|
||||
"network":"10.1.2.0/32",
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network":"10:1::2:0/128",
|
||||
"next_hop":"Null0"
|
||||
}]
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r2": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r4": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {"dest_link": {"r3": {}}},
|
||||
"r2": {"dest_link": {"r3": {}}},
|
||||
"r4": {"dest_link": {"r3": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {"dest_link": {"r3": {}}},
|
||||
"r2": {"dest_link": {"r3": {}}},
|
||||
"r4": {"dest_link": {"r3": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r3": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.400",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r4": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r4": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
317
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
Normal file
317
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
Normal file
@ -0,0 +1,317 @@
|
||||
{
|
||||
"address_types": [
|
||||
"ipv4",
|
||||
"ipv6"
|
||||
],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 24,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {
|
||||
"ipv4": "10.0.0.0",
|
||||
"v4mask": 24,
|
||||
"ipv6": "fd00::",
|
||||
"v6mask": 64
|
||||
},
|
||||
"lo_prefix": {
|
||||
"ipv4": "1.0.",
|
||||
"v4mask": 32,
|
||||
"ipv6": "2001:DB8:F::",
|
||||
"v6mask": 128
|
||||
},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": [{
|
||||
"local_as": "1.100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"static_routes":[
|
||||
{
|
||||
"network":"10.0.0.1/32",
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network":"10::1/128",
|
||||
"next_hop":"Null0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r1-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": [{
|
||||
"local_as": "1.200",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r2-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r4-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": [{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {}
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {}
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r3-link1": {},
|
||||
"r3-link2": {},
|
||||
"r3-link3": {},
|
||||
"r3-link4": {},
|
||||
"r3-link5": {},
|
||||
"r3-link6": {},
|
||||
"r3-link7": {},
|
||||
"r3-link8": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"r4": {
|
||||
"links": {
|
||||
"lo": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto",
|
||||
"type": "loopback"
|
||||
},
|
||||
"r3-link1": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link2": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link3": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link4": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link5": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link6": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link7": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
},
|
||||
"r3-link8": {
|
||||
"ipv4": "auto",
|
||||
"ipv6": "auto"
|
||||
}
|
||||
},
|
||||
"bgp": [{
|
||||
"local_as": "1.400",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r4-link1": {},
|
||||
"r4-link2": {},
|
||||
"r4-link3": {},
|
||||
"r4-link4": {},
|
||||
"r4-link5": {},
|
||||
"r4-link6": {},
|
||||
"r4-link7": {},
|
||||
"r4-link8": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r4-link1": {},
|
||||
"r4-link2": {},
|
||||
"r4-link3": {},
|
||||
"r4-link4": {},
|
||||
"r4-link5": {},
|
||||
"r4-link6": {},
|
||||
"r4-link7": {},
|
||||
"r4-link8": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
132
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
Normal file
132
tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
Normal file
@ -0,0 +1,132 @@
|
||||
{
|
||||
"address_types": ["ipv4", "ipv6"],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 30,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
|
||||
"lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r2": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r2": {"dest_link": {"r1": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"redistribute": [
|
||||
{"redist_type": "static"}
|
||||
],
|
||||
"neighbor": {
|
||||
"r2": {"dest_link": {"r1": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"static_routes":[
|
||||
{
|
||||
"network":"10.1.1.0/32",
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network":"10:1::1:0/128",
|
||||
"next_hop":"Null0"
|
||||
}]
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r3": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.200",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {"dest_link": {"r2": {}}},
|
||||
"r3": {"dest_link": {"r2": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {"dest_link": {"r2": {}}},
|
||||
"r3": {"dest_link": {"r2": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r2": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r4": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {"dest_link": {"r3": {}}},
|
||||
"r4": {"dest_link": {"r3": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {"dest_link": {"r3": {}}},
|
||||
"r4": {"dest_link": {"r3": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"links": {
|
||||
"lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
|
||||
"r3": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp": {
|
||||
"local_as": "1.400",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r4": {}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {"dest_link": {"r4": {}}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
420
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
Normal file
420
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
Normal file
@ -0,0 +1,420 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022 by VMware, Inc. ("VMware")
|
||||
# Used Copyright (c) 2018 by Network Device Education Foundation,
|
||||
# Inc. ("NetDEF") in this file.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
|
||||
1. Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
sys.path.append(os.path.join(CWD, "../lib/"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topotest import version_cmp
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology,
|
||||
write_test_header,
|
||||
write_test_footer,
|
||||
reset_config_on_routers,
|
||||
verify_rib,
|
||||
step,
|
||||
check_address_types,
|
||||
check_router_status
|
||||
)
|
||||
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence,
|
||||
verify_bgp_rib,
|
||||
create_router_bgp,
|
||||
)
|
||||
from lib.topojson import build_config_from_json
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
|
||||
|
||||
# Global variables
|
||||
BGP_CONVERGENCE = False
|
||||
ADDR_TYPES = check_address_types()
|
||||
NETWORK_1_1 = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
|
||||
NETWORK_1_2 = {"ipv4": "10.1.2.0/32", "ipv6": "10:1::2:0/128"}
|
||||
AGGREGATE_NW = {"ipv4": "10.1.0.0/16", "ipv6": "10:1::/96"}
|
||||
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"""
|
||||
Sets up the pytest environment
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
|
||||
testsuite_run_time = time.asctime(time.localtime(time.time()))
|
||||
logger.info("Testsuite start time: {}".format(testsuite_run_time))
|
||||
logger.info("=" * 40)
|
||||
|
||||
logger.info("Running setup_module to create topology")
|
||||
|
||||
# This function initiates the topology build with Topogen...
|
||||
json_file = "{}/bgp_local_asn_dot_agg.json".format(CWD)
|
||||
tgen = Topogen(json_file, mod.__name__)
|
||||
global topo
|
||||
topo = tgen.json_topo
|
||||
# ... and here it calls Mininet initialization functions.
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start daemons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
global BGP_CONVERGENCE
|
||||
global ADDR_TYPES
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""Teardown the pytest environment"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
logger.info(
|
||||
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
|
||||
)
|
||||
logger.info("=" * 40)
|
||||
|
||||
|
||||
####################################################################################################################
|
||||
#
|
||||
# Testcases
|
||||
#
|
||||
####################################################################################################################
|
||||
|
||||
|
||||
def test_verify_bgp_local_as_agg_in_EBGP_p0(request):
|
||||
"""
|
||||
Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
global BGP_CONVERGENCE
|
||||
|
||||
if BGP_CONVERGENCE != True:
|
||||
pytest.skip("skipped because of BGP Convergence failure")
|
||||
|
||||
# test case name
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
if tgen.routers_have_failure():
|
||||
check_router_status(tgen)
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
step("Base config is done as part of JSON")
|
||||
step("Configure local-as at R3 towards R4.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
for neighbor in ["r2", "r4"]:
|
||||
input_dict_r3 = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
neighbor: {
|
||||
"dest_link": {
|
||||
"r3": {"local_asn": {"local_as": "1.110"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r3)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
|
||||
input_dict_r2_r4 = {
|
||||
dut: {
|
||||
"bgp": {
|
||||
"local_as": asn,
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
neighbor: {
|
||||
"dest_link": {
|
||||
dut: {"local_asn": {"remote_as": "1.110"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r2_r4)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
step("Done in base config: Advertise prefix 10.1.1.0/24 from Router-1(AS-1.100).")
|
||||
step(
|
||||
"Done in base config: Advertise an ipv6 prefix 10:1::1:0/120 from Router-1(AS-1.100)."
|
||||
)
|
||||
step("Verify that Static routes are redistributed in BGP process")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_verify_r1 = {
|
||||
"r1": {"static_routes": [{"network": NETWORK_1_1[addr_type]}]}
|
||||
}
|
||||
|
||||
input_static_verify_r2 = {
|
||||
"r2": {"static_routes": [{"network": NETWORK_1_2[addr_type]}]}
|
||||
}
|
||||
result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
|
||||
assert result is True, "Testcase {}: Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
result = verify_rib(tgen, addr_type, "r2", input_static_verify_r2)
|
||||
assert result is True, "Testcase {}: Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure aggregate-address to summarise all the advertised routes.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
route_aggregate = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"aggregate_address": [
|
||||
{
|
||||
"network": AGGREGATE_NW[addr_type],
|
||||
"summary": True,
|
||||
"as_set": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = create_router_bgp(tgen, topo, route_aggregate)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step(
|
||||
"Verify that we see a summarised route on advertising router R3 "
|
||||
"and receiving router R4 for both AFIs"
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_agg_r1 = {
|
||||
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
|
||||
}
|
||||
input_static_r1 = {
|
||||
"r1": {"static_routes": [{"network": [NETWORK_1_1[addr_type]]}]}
|
||||
}
|
||||
|
||||
input_static_r2 = {
|
||||
"r2": {"static_routes": [{"network": [NETWORK_1_2[addr_type]]}]}
|
||||
}
|
||||
|
||||
for dut in ["r3", "r4"]:
|
||||
result = verify_rib(tgen, addr_type, dut, input_static_agg_r1)
|
||||
assert result is True, "Testcase {}: Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for dut, input_routes in zip(["r1", "r2"], [input_static_r1, input_static_r2]):
|
||||
result = verify_rib(tgen, addr_type, dut, input_routes)
|
||||
assert result is True, "Testcase {}: Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step(
|
||||
"Verify that AS-110 is got added in the AS list 1.110 {1.100,1.110,1.200} by following "
|
||||
"commands at R3 router."
|
||||
)
|
||||
dut = "r3"
|
||||
aspath = "{1.100,1.110,1.200}"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_agg_r1 = {
|
||||
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
|
||||
}
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend at R3 towards R4 & R2.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
for neighbor in ["r2", "r4"]:
|
||||
input_dict_r3 = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
neighbor: {
|
||||
"dest_link": {
|
||||
"r3": {
|
||||
"local_asn": {
|
||||
"local_as": "1.110",
|
||||
"no_prepend": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r3)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
dut = "r3"
|
||||
aspath = "{1.100,1.200}"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_agg_r1 = {
|
||||
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
|
||||
}
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
for neighbor in ["r2", "r4"]:
|
||||
input_dict_r3 = {
|
||||
"r3": {
|
||||
"bgp": {
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
neighbor: {
|
||||
"dest_link": {
|
||||
"r3": {
|
||||
"local_asn": {
|
||||
"local_as": "1.110",
|
||||
"no_prepend": True,
|
||||
"replace_as": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r3)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
dut = "r4"
|
||||
aspath = "1.110 {1.100,1.200}"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_agg_r1 = {
|
||||
"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
|
||||
}
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
524
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
Normal file
524
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
Normal file
@ -0,0 +1,524 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2022 by VMware, Inc. ("VMware")
|
||||
# Used Copyright (c) 2018 by Network Device Education Foundation,
|
||||
# Inc. ("NetDEF") in this file.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
#
|
||||
##########################################################################################################################################
|
||||
#
|
||||
# Testcases
|
||||
#
|
||||
###########################################################################################################################################
|
||||
###########################################################################################################################################
|
||||
#
|
||||
# 1.10.1.7. Verify the BGP Local AS functionality with ECMP on 8 links by adding no-prepend and replace-as command in between eBGP Peers.
|
||||
#
|
||||
#################################################################################################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
import platform
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
sys.path.append(os.path.join(CWD, "../lib/"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topotest import version_cmp
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology,
|
||||
write_test_header,
|
||||
create_static_routes,
|
||||
write_test_footer,
|
||||
reset_config_on_routers,
|
||||
verify_rib,
|
||||
step,
|
||||
check_address_types,
|
||||
check_router_status,
|
||||
create_static_routes,
|
||||
verify_fib_routes,
|
||||
)
|
||||
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence,
|
||||
verify_bgp_rib,
|
||||
create_router_bgp,
|
||||
)
|
||||
from lib.topojson import build_config_from_json
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
|
||||
|
||||
# Global variables
|
||||
BGP_CONVERGENCE = False
|
||||
NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
|
||||
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"""
|
||||
Sets up the pytest environment
|
||||
|
||||
* `mod`: module name
|
||||
"""
|
||||
|
||||
testsuite_run_time = time.asctime(time.localtime(time.time()))
|
||||
logger.info("Testsuite start time: {}".format(testsuite_run_time))
|
||||
logger.info("=" * 40)
|
||||
|
||||
logger.info("Running setup_module to create topology")
|
||||
|
||||
# This function initiates the topology build with Topogen...
|
||||
json_file = "{}/bgp_local_asn_dot_ecmp.json".format(CWD)
|
||||
tgen = Topogen(json_file, mod.__name__)
|
||||
global topo
|
||||
topo = tgen.json_topo
|
||||
# ... and here it calls Mininet initialization functions.
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start daemons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
global BGP_CONVERGENCE
|
||||
global ADDR_TYPES
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""Teardown the pytest environment"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
logger.info(
|
||||
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
|
||||
)
|
||||
logger.info("=" * 40)
|
||||
|
||||
|
||||
##########################################################################################################################################
|
||||
#
|
||||
# Testcases
|
||||
#
|
||||
###########################################################################################################################################
|
||||
|
||||
|
||||
def test_verify_bgp_local_as_in_ecmp_EBGP_p0(request):
|
||||
"""
|
||||
Verify the BGP Local AS functionality with ECMP on 8 links by
|
||||
adding no-prepend and replace-as command in between eBGP Peers.
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
global BGP_CONVERGENCE
|
||||
if BGP_CONVERGENCE != True:
|
||||
pytest.skip("skipped because of BGP Convergence failure")
|
||||
# test case name
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
if tgen.routers_have_failure():
|
||||
check_router_status(tgen)
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
step("Base config is done as part of JSON")
|
||||
dut = "r1"
|
||||
for addr_type in ADDR_TYPES:
|
||||
# Enable static routes
|
||||
input_dict_static_route = {
|
||||
"r1": {
|
||||
"static_routes": [
|
||||
{"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Configure static routes")
|
||||
result = create_static_routes(tgen, input_dict_static_route)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("configure redistribute static in Router BGP in R1")
|
||||
input_dict_static_route_redist = {
|
||||
"r1": {
|
||||
"bgp": [
|
||||
{
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {"redistribute": [{"redist_type": "static"}]}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Verify IPv4 and IPv6 static routes received on R1")
|
||||
result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
|
||||
assert result is True, "Testcase {}: Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as at R3 towards R2.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_r3_to_r2 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"local_asn": {"local_as": "1.110"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as at R3 towards R4.")
|
||||
dest_link = {}
|
||||
for link_no in range(1, 9):
|
||||
link = "r3-link" + str(link_no)
|
||||
dest_link[link] = {"local_asn": {"local_as": "1.110"}}
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_r3_to_r4 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {"r4": {"dest_link": dest_link}}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure remote-as at R2 towards R3.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_r2_to_r3 = {
|
||||
"r2": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.200",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"local_asn": {"remote_as": "1.110"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure remote-as at R4 towards R3.")
|
||||
dest_link = {}
|
||||
for link_no in range(1, 9):
|
||||
link = "r4-link" + str(link_no)
|
||||
dest_link[link] = {"local_asn": {"remote_as": "1.110"}}
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_r4_to_r3 = {
|
||||
"r4": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.400",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {"r3": {"dest_link": dest_link}}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
step("Verify IPv4 and IPv6 static routes received on R3 & R4")
|
||||
for addr_type in ADDR_TYPES:
|
||||
static_routes_input = {
|
||||
"r1": {
|
||||
"static_routes": [
|
||||
{"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
|
||||
]
|
||||
}
|
||||
}
|
||||
for dut in ["r3", "r4"]:
|
||||
result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step(
|
||||
"Verify that AS-110 is got added in the AS list 1.110 1.200 1.100 by following "
|
||||
" commands at R3 router."
|
||||
)
|
||||
dut = "r3"
|
||||
aspath = "1.110 1.200 1.100"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend at R3 towards R2.")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_no_prep_r3_to_r2 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"local_asn": {
|
||||
"local_as": "1.110",
|
||||
"no_prepend": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend at R3 towards R4.")
|
||||
dest_link = {}
|
||||
for link_no in range(1, 9):
|
||||
link = "r3-link" + str(link_no)
|
||||
dest_link[link] = {"local_asn": {"local_as": "1.110"}}
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_no_prep_r3_to_r4 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {"r4": {"dest_link": dest_link}}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
dut = "r3"
|
||||
aspath = "1.200 1.100"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend and replace-as at R3 towards R2")
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_no_prep_rep_as_r3_to_r2 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"local_asn": {
|
||||
"local_as": "1.110",
|
||||
"no_prepend": True,
|
||||
"replace_as": True,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Configure local-as with no-prepend and replace-as at R3 towards R4")
|
||||
dest_link = {}
|
||||
for link_no in range(1, 9):
|
||||
link = "r3-link" + str(link_no)
|
||||
dest_link[link] = {
|
||||
"local_asn": {"local_as": "1.110", "no_prepend": True, "replace_as": True}
|
||||
}
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_dict_no_prep_rep_as_r3_to_r4 = {
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "1.300",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {"r4": {"dest_link": dest_link}}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("BGP neighborship is verified by following commands in R3 routers")
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
dut = "r4"
|
||||
aspath = "1.110 1.200 1.100"
|
||||
for addr_type in ADDR_TYPES:
|
||||
input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
3655
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
Normal file
3655
tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user