summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c81
-rw-r--r--bgpd/bgp_aspath.h12
-rw-r--r--bgpd/bgp_attr.c70
-rw-r--r--bgpd/bgp_bmp.c9
-rw-r--r--bgpd/bgp_btoa.c3
-rw-r--r--bgpd/bgp_clist.c4
-rw-r--r--bgpd/bgp_community.c13
-rw-r--r--bgpd/bgp_community.h3
-rw-r--r--bgpd/bgp_debug.c11
-rw-r--r--bgpd/bgp_evpn.c34
-rw-r--r--bgpd/bgp_evpn_mh.c40
-rw-r--r--bgpd/bgp_evpn_private.h1
-rw-r--r--bgpd/bgp_evpn_vty.c97
-rw-r--r--bgpd/bgp_flowspec.c12
-rw-r--r--bgpd/bgp_label.c2
-rw-r--r--bgpd/bgp_mplsvpn.c23
-rw-r--r--bgpd/bgp_mplsvpn_snmp.c6
-rw-r--r--bgpd/bgp_network.c16
-rw-r--r--bgpd/bgp_nexthop.c17
-rw-r--r--bgpd/bgp_nht.c16
-rw-r--r--bgpd/bgp_rd.c100
-rw-r--r--bgpd/bgp_rd.h17
-rw-r--r--bgpd/bgp_route.c103
-rw-r--r--bgpd/bgp_route.h12
-rw-r--r--bgpd/bgp_routemap.c85
-rw-r--r--bgpd/bgp_rpki.c37
-rw-r--r--bgpd/bgp_script.c3
-rw-r--r--bgpd/bgp_vty.c395
-rw-r--r--bgpd/bgp_vty.h6
-rw-r--r--bgpd/bgpd.c139
-rw-r--r--bgpd/bgpd.h54
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c9
-rw-r--r--bgpd/rfapi/rfapi.c6
-rw-r--r--bgpd/rfapi/rfapi_import.c27
-rw-r--r--bgpd/rfapi/rfapi_rib.c6
-rw-r--r--bgpd/rfapi/rfapi_vty.c3
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c9
-rw-r--r--doc/developer/cli.rst45
-rw-r--r--doc/user/bgp.rst55
-rw-r--r--doc/user/ospfd.rst6
-rw-r--r--doc/user/ripd.rst15
-rw-r--r--doc/user/ripngd.rst8
-rw-r--r--doc/user/zebra.rst5
-rw-r--r--ldpd/address.c25
-rw-r--r--ldpd/lde.c230
-rw-r--r--ldpd/ldpd.c150
-rw-r--r--lib/asn.c260
-rw-r--r--lib/asn.h81
-rw-r--r--lib/command.c1
-rw-r--r--lib/command.h3
-rw-r--r--lib/command_graph.c2
-rw-r--r--lib/command_graph.h1
-rw-r--r--lib/command_lex.l2
-rw-r--r--lib/command_match.c6
-rw-r--r--lib/command_parse.y6
-rw-r--r--lib/command_py.c1
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/log.h15
-rw-r--r--lib/northbound.c19
-rw-r--r--lib/northbound.h22
-rw-r--r--lib/northbound_cli.c11
-rw-r--r--lib/northbound_confd.c2
-rw-r--r--lib/northbound_db.c2
-rw-r--r--lib/northbound_grpc.cpp4
-rw-r--r--lib/northbound_sysrepo.c2
-rw-r--r--lib/prefix.c23
-rw-r--r--lib/prefix.h6
-rw-r--r--lib/routemap.c97
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/vty.c9
-rw-r--r--lib/vty.h2
-rwxr-xr-xospfclient/ospfclient.py193
-rw-r--r--ospfd/ospf_abr.c272
-rw-r--r--ospfd/ospf_abr.h21
-rw-r--r--ospfd/ospf_apiserver.c7
-rw-r--r--ospfd/ospf_dump.c7
-rw-r--r--ospfd/ospf_dump.h2
-rw-r--r--ospfd/ospf_flood.c137
-rw-r--r--ospfd/ospf_flood.h2
-rw-r--r--ospfd/ospf_lsa.c88
-rw-r--r--ospfd/ospf_lsa.h24
-rw-r--r--ospfd/ospf_lsdb.c21
-rw-r--r--ospfd/ospf_opaque.c19
-rw-r--r--ospfd/ospf_packet.c11
-rw-r--r--ospfd/ospf_route.c71
-rw-r--r--ospfd/ospf_vty.c808
-rw-r--r--ospfd/ospfd.c12
-rw-r--r--ospfd/ospfd.h26
-rw-r--r--pimd/pim_mroute.c76
-rw-r--r--python/clidef.py7
-rw-r--r--tests/bgpd/test_aspath.c196
-rw-r--r--tests/bgpd/test_capability.c3
-rw-r--r--tests/bgpd/test_mp_attr.c3
-rw-r--r--tests/bgpd/test_packet.c3
-rw-r--r--tests/bgpd/test_peer_attr.c27
-rw-r--r--tests/lib/test_printfrr.c9
-rw-r--r--tests/topotests/bgp_asdot_regex/__init__.py0
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/bgpd.conf27
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json80
-rw-r--r--tests/topotests/bgp_asdot_regex/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/bgpd.conf26
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json80
-rw-r--r--tests/topotests/bgp_asdot_regex/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py122
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py64
-rw-r--r--tests/topotests/bgp_confederation_astype/__init__.py0
-rw-r--r--tests/topotests/bgp_confederation_astype/r1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_confederation_astype/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_confederation_astype/r2/bgpd.conf13
-rw-r--r--tests/topotests/bgp_confederation_astype/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_confederation_astype/r3/bgpd.conf10
-rw-r--r--tests/topotests/bgp_confederation_astype/r3/zebra.conf4
-rw-r--r--tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py140
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py0
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf5
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf8
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf5
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py114
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json147
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json317
-rw-r--r--tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json132
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py420
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py524
-rw-r--r--tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py3655
-rw-r--r--tests/topotests/lib/ospf.py583
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_flood_reduction.json214
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py1066
-rw-r--r--tests/topotests/ospfapi/r1/ospfd.conf7
-rw-r--r--tests/topotests/ospfapi/r1/zebra.conf2
-rw-r--r--tests/topotests/ospfapi/r2/ospfd.conf2
-rw-r--r--tests/topotests/ospfapi/r3/ospfd.conf2
-rw-r--r--tests/topotests/ospfapi/r4/ospfd.conf7
-rw-r--r--tests/topotests/ospfapi/r4/zebra.conf2
-rw-r--r--tests/topotests/ospfapi/test_ospf_clientapi.py212
-rw-r--r--vtysh/vtysh.c8
-rw-r--r--yang/frr-bgp-route-map.yang98
-rw-r--r--zebra/rib.h9
-rw-r--r--zebra/zapi_msg.c9
-rw-r--r--zebra/zebra_rib.c101
-rw-r--r--zebra/zebra_vty.c48
145 files changed, 11412 insertions, 1570 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 584f524f05..2cc7e46573 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -287,9 +287,13 @@ static struct assegment *assegment_normalise(struct assegment *head)
return head;
}
-static struct aspath *aspath_new(void)
+static struct aspath *aspath_new(enum asnotation_mode asnotation)
{
- return XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
+ struct aspath *as;
+
+ as = XCALLOC(MTYPE_AS_PATH, sizeof(struct aspath));
+ as->asnotation = asnotation;
+ return as;
}
/* Free AS path structure. */
@@ -537,8 +541,10 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
*
* This was changed to 10 after the well-known BGP assertion, which
* had hit some parts of the Internet in May of 2009.
+ * plain format : '4294967295 ' : 10 + 1
+ * astod format : '65535.65535 ': 11 + 1
*/
-#define ASN_STR_LEN (10 + 1)
+#define ASN_STR_LEN (11 + 1)
str_size = MAX(assegment_count_asns(seg, 0) * ASN_STR_LEN + 2 + 1,
ASPATH_STR_DEFAULT_LEN);
str_buf = XMALLOC(MTYPE_AS_STR, str_size);
@@ -569,7 +575,7 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
/* We might need to increase str_buf, particularly if path has
* differing segments types, our initial guesstimate above will
- * have been wrong. Need 10 chars for ASN, a separator each and
+ * have been wrong. Need 11 chars for ASN, a separator each and
* potentially two segment delimiters, plus a space between each
* segment and trailing zero.
*
@@ -595,12 +601,11 @@ static void aspath_make_str_count(struct aspath *as, bool make_json)
/* write out the ASNs, with their separators, bar the last one*/
for (i = 0; i < seg->length; i++) {
if (make_json)
- json_object_array_add(
- jseg_list,
- json_object_new_int64(seg->as[i]));
-
- len += snprintf(str_buf + len, str_size - len, "%u",
- seg->as[i]);
+ asn_asn2json_array(jseg_list, seg->as[i],
+ as->asnotation);
+ len += snprintfrr(str_buf + len, str_size - len,
+ ASN_FORMAT(as->asnotation),
+ &seg->as[i]);
if (i < (seg->length - 1))
len += snprintf(str_buf + len, str_size - len,
@@ -691,6 +696,7 @@ struct aspath *aspath_dup(struct aspath *aspath)
new->str = XMALLOC(MTYPE_AS_STR, buflen);
new->str_len = aspath->str_len;
+ new->asnotation = aspath->asnotation;
/* copy the string data */
if (aspath->str_len > 0)
@@ -718,6 +724,7 @@ static void *aspath_hash_alloc(void *arg)
new->str = aspath->str;
new->str_len = aspath->str_len;
new->json = aspath->json;
+ new->asnotation = aspath->asnotation;
return new;
}
@@ -825,7 +832,8 @@ static int assegments_parse(struct stream *s, size_t length,
On error NULL is returned.
*/
-struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit)
+struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit,
+ enum asnotation_mode asnotation)
{
struct aspath as;
struct aspath *find;
@@ -840,6 +848,7 @@ struct aspath *aspath_parse(struct stream *s, size_t length, int use32bit)
return NULL;
memset(&as, 0, sizeof(as));
+ as.asnotation = asnotation;
if (assegments_parse(s, length, &as.segments, use32bit) < 0)
return NULL;
@@ -1057,7 +1066,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
seg = assegment_append_asns(seg, seg1->as, match);
if (!aspath) {
- aspath = aspath_new();
+ aspath = aspath_new(as1->asnotation);
aspath->segments = seg;
} else
prevseg->next = seg;
@@ -1077,7 +1086,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2)
}
if (!aspath)
- aspath = aspath_new();
+ aspath = aspath_new(as1->asnotation);
/* Make as-set using rest of all information. */
from = match;
@@ -1521,7 +1530,7 @@ struct aspath *aspath_filter_exclude(struct aspath *source,
struct assegment *srcseg, *exclseg, *lastseg;
struct aspath *newpath;
- newpath = aspath_new();
+ newpath = aspath_new(source->asnotation);
lastseg = NULL;
for (srcseg = source->segments; srcseg; srcseg = srcseg->next) {
@@ -1751,7 +1760,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
newseg = assegment_append_asns(newseg, seg->as, cpasns);
if (!newpath) {
- newpath = aspath_new();
+ newpath = aspath_new(aspath->asnotation);
newpath->segments = newseg;
} else
prevseg->next = newseg;
@@ -1880,16 +1889,16 @@ static void aspath_segment_add(struct aspath *as, int type)
as->segments = new;
}
-struct aspath *aspath_empty(void)
+struct aspath *aspath_empty(enum asnotation_mode asnotation)
{
- return aspath_parse(NULL, 0, 1); /* 32Bit ;-) */
+ return aspath_parse(NULL, 0, 1, asnotation); /* 32Bit ;-) */
}
struct aspath *aspath_empty_get(void)
{
struct aspath *aspath;
- aspath = aspath_new();
+ aspath = aspath_new(bgp_get_asnotation(NULL));
aspath_make_str_count(aspath, false);
return aspath;
}
@@ -1925,6 +1934,8 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
unsigned long *asno)
{
const char *p = buf;
+ as_t asval;
+ bool found = false;
/* Skip separators (space for sequences, ',' for sets). */
while (isspace((unsigned char)*p) || *p == ',')
@@ -1961,30 +1972,18 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
return p;
}
- /* Check actual AS value. */
- if (isdigit((unsigned char)*p)) {
- as_t asval;
-
- *token = as_token_asval;
- asval = (*p - '0');
- p++;
-
- while (isdigit((unsigned char)*p)) {
- asval *= 10;
- asval += (*p - '0');
- p++;
- }
+ asval = 0;
+ p = asn_str2asn_parse(p, &asval, &found);
+ if (found) {
*asno = asval;
- return p;
- }
-
- /* There is no match then return unknown token. */
- *token = as_token_unknown;
- p++;
+ *token = as_token_asval;
+ } else
+ *token = as_token_unknown;
return p;
}
-struct aspath *aspath_str2aspath(const char *str)
+struct aspath *aspath_str2aspath(const char *str,
+ enum asnotation_mode asnotation)
{
enum as_token token = as_token_unknown;
unsigned short as_type;
@@ -1992,7 +1991,7 @@ struct aspath *aspath_str2aspath(const char *str)
struct aspath *aspath;
int needtype;
- aspath = aspath_new();
+ aspath = aspath_new(asnotation);
/* We start default type as AS_SEQUENCE. */
as_type = AS_SEQUENCE;
@@ -2066,6 +2065,10 @@ bool aspath_cmp(const void *arg1, const void *arg2)
const struct assegment *seg1 = ((const struct aspath *)arg1)->segments;
const struct assegment *seg2 = ((const struct aspath *)arg2)->segments;
+ if (((const struct aspath *)arg1)->asnotation !=
+ ((const struct aspath *)arg2)->asnotation)
+ return false;
+
while (seg1 || seg2) {
int i;
if ((!seg1 && seg2) || (seg1 && !seg2))
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index dd65b423a7..18af375c13 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -57,6 +57,9 @@ struct aspath {
and AS path regular expression match. */
char *str;
unsigned short str_len;
+
+ /* AS notation used by string expression of AS path */
+ enum asnotation_mode asnotation;
};
#define ASPATH_STR_DEFAULT_LEN 32
@@ -65,7 +68,9 @@ struct aspath {
extern void aspath_init(void);
extern void aspath_finish(void);
extern struct aspath *aspath_parse(struct stream *s, size_t length,
- int use32bit);
+ int use32bit,
+ enum asnotation_mode asnotation);
+
extern struct aspath *aspath_dup(struct aspath *aspath);
extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2);
extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2);
@@ -81,9 +86,10 @@ extern bool aspath_cmp_left(const struct aspath *aspath1,
extern bool aspath_cmp_left_confed(const struct aspath *as1,
const struct aspath *as2);
extern struct aspath *aspath_delete_confed_seq(struct aspath *aspath);
-extern struct aspath *aspath_empty(void);
+extern struct aspath *aspath_empty(enum asnotation_mode asnotation);
extern struct aspath *aspath_empty_get(void);
-extern struct aspath *aspath_str2aspath(const char *str);
+extern struct aspath *aspath_str2aspath(const char *str,
+ enum asnotation_mode asnotation);
extern void aspath_str_update(struct aspath *as, bool make_json);
extern void aspath_free(struct aspath *aspath);
extern struct aspath *aspath_intern(struct aspath *aspath);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index fe918a3e03..1e2698cd92 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1054,7 +1054,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
attr->origin = origin;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
- attr->aspath = aspath_empty();
+ attr->aspath = aspath_empty(bgp->asnotation);
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->tag = 0;
@@ -1092,7 +1092,7 @@ struct attr *bgp_attr_aggregate_intern(
if (aspath)
attr.aspath = aspath_intern(aspath);
else
- attr.aspath = aspath_empty();
+ attr.aspath = aspath_empty(bgp->asnotation);
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
/* Next hop attribute. */
@@ -1590,15 +1590,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
struct attr *const attr = args->attr;
struct peer *const peer = args->peer;
const bgp_size_t length = args->length;
+ enum asnotation_mode asnotation;
+ asnotation = bgp_get_asnotation(
+ args->peer && args->peer->bgp ? args->peer->bgp : NULL);
/*
* peer with AS4 => will get 4Byte ASnums
* otherwise, will get 16 Bit
*/
- attr->aspath = aspath_parse(
- peer->curr, length,
- CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
- && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV));
+ attr->aspath =
+ aspath_parse(peer->curr, length,
+ CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) &&
+ CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV),
+ asnotation);
/* In case of IBGP, length will be zero. */
if (!attr->aspath) {
@@ -1614,7 +1618,8 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
* such messages, conformant BGP speakers SHOULD use the "Treat-as-
* withdraw" error handling behavior as per [RFC7606].
*/
- if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
+ if (peer->bgp && peer->bgp->reject_as_sets &&
+ aspath_check_as_sets(attr->aspath)) {
flog_err(EC_BGP_ATTR_MAL_AS_PATH,
"AS_SET and AS_CONFED_SET are deprecated from %pBP",
peer);
@@ -1640,6 +1645,14 @@ static enum bgp_attr_parse_ret bgp_attr_aspath_check(struct peer *const peer,
*/
struct aspath *aspath;
+ /* Refresh peer's type. If we set e.g.: AS_EXTERNAL/AS_INTERNAL,
+ * then peer->sort remains BGP_PEER_EBGP/IBGP, hence we need to
+ * have an actual type before checking.
+ * This is especially a case for BGP confederation peers, to avoid
+ * receiving and treating AS_PATH as malformed.
+ */
+ (void)peer_sort(peer);
+
/* Confederation sanity check. */
if ((peer->sort == BGP_PEER_CONFED
&& !aspath_left_confed_check(attr->aspath))
@@ -1690,8 +1703,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) {
@@ -3969,22 +3985,20 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
} break;
case SAFI_MPLS_VPN: {
if (attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
+ stream_putc(s, attr->mp_nexthop_len);
+ else
+ stream_putc(s, BGP_ATTR_NHLEN_VPNV6_GLOBAL);
+ stream_putl(s, 0); /* RD = 0, per RFC */
+ stream_putl(s, 0);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ if (attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
- stream_putc(s, 48);
- stream_putl(s, 0); /* RD = 0, per RFC */
- stream_putl(s, 0);
- stream_put(s, &attr->mp_nexthop_global,
- IPV6_MAX_BYTELEN);
stream_putl(s, 0); /* RD = 0, per RFC */
stream_putl(s, 0);
stream_put(s, &attr->mp_nexthop_local,
IPV6_MAX_BYTELEN);
- } else {
- stream_putc(s, 24);
- stream_putl(s, 0); /* RD = 0, per RFC */
- stream_putl(s, 0);
- stream_put(s, &attr->mp_nexthop_global,
- IPV6_MAX_BYTELEN);
}
} break;
case SAFI_ENCAP:
@@ -4289,8 +4303,22 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
aspath = aspath_delete_confed_seq(aspath);
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
- /* Stuff our path CONFED_ID on the front */
- aspath = aspath_add_seq(aspath, bgp->confed_id);
+ /* A confed member, so we need to do the
+ * AS_CONFED_SEQUENCE thing if it's outside a common
+ * administration.
+ * Configured confederation peers MUST be validated
+ * under BGP_PEER_CONFED, but if we have configured
+ * remote-as as AS_EXTERNAL, we need to check again
+ * if the peer belongs to us.
+ */
+ if (bgp_confederation_peers_check(bgp, peer->as)) {
+ aspath = aspath_dup(attr->aspath);
+ aspath = aspath_add_confed_seq(aspath,
+ peer->local_as);
+ } else {
+ /* Stuff our path CONFED_ID on the front */
+ aspath = aspath_add_seq(aspath, bgp->confed_id);
+ }
} else {
if (peer->change_local_as) {
/* If replace-as is specified, we only use the
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index d89f6de649..92d92ada2b 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -2498,14 +2498,13 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
vty_out(vty, " bmp mirror\n");
FOREACH_AFI_SAFI (afi, safi) {
- const char *afi_str = (afi == AFI_IP) ? "ipv4" : "ipv6";
-
if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY)
vty_out(vty, " bmp monitor %s %s pre-policy\n",
- afi_str, safi2str(safi));
+ afi2str_lower(afi), safi2str(safi));
if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY)
- vty_out(vty, " bmp monitor %s %s post-policy\n",
- afi_str, safi2str(safi));
+ vty_out(vty,
+ " bmp monitor %s %s post-policy\n",
+ afi2str_lower(afi), safi2str(safi));
}
frr_each (bmp_listeners, &bt->listeners, bl)
vty_out(vty, " \n bmp listener %pSU port %d\n",
diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c
index b410a4b896..fc3363b098 100644
--- a/bgpd/bgp_btoa.c
+++ b/bgpd/bgp_btoa.c
@@ -86,7 +86,8 @@ static void attr_parse(struct stream *s, uint16_t len)
case BGP_ATTR_AS_PATH: {
struct aspath *aspath;
- aspath = aspath_parse(s, length, 1);
+ aspath = aspath_parse(s, length, 1,
+ bgp_get_asnotation(NULL));
printf("ASPATH: %s\n", aspath->str);
aspath_free(aspath);
} break;
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 2cbbe0a5a9..1d2ba3bf58 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -449,8 +449,12 @@ static char *community_str_get(struct community *com, int i)
comval = ntohl(comval);
switch (comval) {
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
case COMMUNITY_INTERNET:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet");
+ zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown");
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index e2bce9cbce..ff6e477355 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -168,7 +168,6 @@ struct community *community_uniq_sort(struct community *com)
For Well-known communities value, below keyword is used.
- 0x0 "internet"
0xFFFF0000 "graceful-shutdown"
0xFFFF0001 "accept-own"
0xFFFF0002 "route-filter-translated-v4"
@@ -229,8 +228,12 @@ static void set_community_string(struct community *com, bool make_json,
comval = ntohl(comval);
switch (comval) {
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
case COMMUNITY_INTERNET:
len += strlen(" internet");
+ zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
len += strlen(" graceful-shutdown");
@@ -295,6 +298,9 @@ static void set_community_string(struct community *com, bool make_json,
strlcat(str, " ", len);
switch (comval) {
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
case COMMUNITY_INTERNET:
strlcat(str, "internet", len);
if (make_json) {
@@ -303,6 +309,7 @@ static void set_community_string(struct community *com, bool make_json,
json_object_array_add(json_community_list,
json_string);
}
+ zlog_warn("`internet` community is deprecated");
break;
case COMMUNITY_GSHUT:
strlcat(str, "graceful-shutdown", len);
@@ -673,10 +680,14 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
/* Well known community string check. */
if (isalpha((unsigned char)*p)) {
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
if (strncmp(p, "internet", strlen("internet")) == 0) {
*val = COMMUNITY_INTERNET;
*token = community_token_no_export;
p += strlen("internet");
+ zlog_warn("`internet` community is deprecated");
return p;
}
if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown"))
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index 35909a638d..e7af362ea8 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -30,6 +30,9 @@ struct community {
};
/* Well-known communities value. */
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
#define COMMUNITY_INTERNET 0x0
#define COMMUNITY_GSHUT 0xFFFF0000
#define COMMUNITY_ACCEPT_OWN 0xFFFF0001
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 2dec1ca46d..782245e512 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -2635,6 +2635,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
char tag_buf[30];
char overlay_index_buf[INET6_ADDRSTRLEN + 14];
const struct prefix_evpn *evp;
+ int len = 0;
/* ' with addpath ID ' 17
* max strlen of uint32 + 10
@@ -2688,11 +2689,15 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
}
}
- if (prd)
- snprintfrr(str, size, "RD %pRD %pFX%s%s%s %s %s", prd, pu.p,
+ if (prd) {
+ len += snprintfrr(str + len, size - len, "RD ");
+ len += snprintfrr(str + len, size - len,
+ BGP_RD_AS_FORMAT(bgp_get_asnotation(NULL)),
+ prd);
+ snprintfrr(str + len, size - len, " %pFX%s%s%s %s %s", pu.p,
overlay_index_buf, tag_buf, pathid_buf, afi2str(afi),
safi2str(safi));
- else if (safi == SAFI_FLOWSPEC) {
+ } else if (safi == SAFI_FLOWSPEC) {
char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
const struct prefix_fs *fs = pu.fs;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 4758cd98ec..a8560ab539 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -4517,9 +4517,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
&label[0], num_labels, 0, &evpn);
else
- bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi,
- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- &label[0], num_labels, &evpn);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0],
+ num_labels, &evpn);
goto done;
fail:
@@ -4608,9 +4608,9 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
0, 0, NULL);
else
- bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi,
- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- NULL, 0, NULL);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
+ NULL);
return 0;
}
@@ -4751,9 +4751,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
peer->hostname, peer->bgp->vrf_id, &p,
attr_str);
}
- bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi,
- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- &label, 1, &evpn);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1,
+ &evpn);
}
return 0;
@@ -5923,6 +5923,8 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn)
vpn->prd.prefixlen = 64;
snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id);
(void)str2prefix_rd(buf, &vpn->prd);
+ if (vpn->prd_pretty)
+ XFREE(MTYPE_BGP, vpn->prd_pretty);
UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
}
@@ -6027,6 +6029,8 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
bf_release_index(bm->rd_idspace, vpn->rd_id);
hash_release(bgp->vni_svi_hash, vpn);
hash_release(bgp->vnihash, vpn);
+ if (vpn->prd_pretty)
+ XFREE(MTYPE_BGP, vpn->prd_pretty);
QOBJ_UNREG(vpn);
XFREE(MTYPE_BGP_EVPN, vpn);
}
@@ -6238,13 +6242,14 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
ret = bgp_get_vty(&bgp_vrf, &as, vrf_id_to_name(vrf_id),
vrf_id == VRF_DEFAULT
- ? BGP_INSTANCE_TYPE_DEFAULT
- : BGP_INSTANCE_TYPE_VRF);
+ ? BGP_INSTANCE_TYPE_DEFAULT
+ : BGP_INSTANCE_TYPE_VRF,
+ NULL, ASNOTATION_UNDEFINED);
switch (ret) {
case BGP_ERR_AS_MISMATCH:
flog_err(EC_BGP_EVPN_AS_MISMATCH,
- "BGP instance is already running; AS is %u",
- as);
+ "BGP instance is already running; AS is %s",
+ bgp_vrf->as_pretty);
return -1;
case BGP_ERR_INSTANCE_MISMATCH:
flog_err(EC_BGP_EVPN_INSTANCE_MISMATCH,
@@ -6660,6 +6665,9 @@ void bgp_evpn_cleanup(struct bgp *bgp)
list_delete(&bgp->vrf_import_rtl);
list_delete(&bgp->vrf_export_rtl);
list_delete(&bgp->l2vnis);
+
+ if (bgp->vrf_prd_pretty)
+ XFREE(MTYPE_BGP, bgp->vrf_prd_pretty);
}
/*
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index fa913016fb..2f95023aa9 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -742,9 +742,9 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
0, 0, NULL);
} else {
- bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi,
- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- NULL, 0, NULL);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
+ NULL);
}
return 0;
}
@@ -1210,9 +1210,9 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL,
0, 0, NULL);
} else {
- bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr, afi,
- safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd,
- NULL, 0, NULL);
+ bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi,
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0,
+ NULL);
}
return 0;
}
@@ -2395,7 +2395,8 @@ static void bgp_evpn_es_json_frag_fill(json_object *json_frags,
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
json_frag = json_object_new_object();
- json_object_string_addf(json_frag, "rd", "%pRD", &es_frag->prd);
+ json_object_string_addf(json_frag, "rd", "%pRDP",
+ &es_frag->prd);
json_object_int_add(json_frag, "eviCount",
listcount(es_frag->es_evi_frag_list));
@@ -2410,7 +2411,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty,
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
- vty_out(vty, " %pRD EVIs: %d\n", &es_frag->prd,
+ vty_out(vty, " %pRDP EVIs: %d\n", &es_frag->prd,
listcount(es_frag->es_evi_frag_list));
}
}
@@ -2524,7 +2525,7 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
json_object_string_add(json, "esi", es->esi_str);
if (es->es_base_frag)
- json_object_string_addf(json, "rd", "%pRD",
+ json_object_string_addf(json, "rd", "%pRDP",
&es->es_base_frag->prd);
if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
@@ -2562,7 +2563,7 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
- vty_out(vty, "%-30s %-5s %-21pRD %-8d %s\n", es->esi_str,
+ vty_out(vty, "%-30s %-5s %-21pRDP %-8d %s\n", es->esi_str,
type_str, &es->es_base_frag->prd,
listcount(es->es_evi_list), vtep_str);
}
@@ -2639,7 +2640,7 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
vty_out(vty, "ESI: %s\n", es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
- vty_out(vty, " RD: %pRD\n", &es->es_base_frag->prd);
+ vty_out(vty, " RD: %pRDP\n", &es->es_base_frag->prd);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
if (es->flags & BGP_EVPNES_LOCAL)
vty_out(vty, " Local ES DF preference: %u\n",
@@ -3958,7 +3959,8 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
json_object *json_types;
json_object_string_add(json, "esi", es_evi->es->esi_str);
- json_object_int_add(json, "vni", es_evi->vpn->vni);
+ if (es_evi->vpn)
+ json_object_int_add(json, "vni", es_evi->vpn->vni);
if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
BGP_EVPNES_EVI_REMOTE)) {
@@ -4002,13 +4004,18 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
struct bgp_evpn_es_evi *es_evi, json_object *json)
{
+ enum asnotation_mode mode;
+
+ mode = bgp_get_asnotation(es_evi->vpn->bgp_vrf);
+
if (json) {
json_object *json_flags;
/* Add the "brief" info first */
bgp_evpn_es_evi_show_entry(vty, es_evi, json);
if (es_evi->es_frag)
- json_object_string_addf(json, "esFragmentRd", "%pRD",
+ json_object_string_addf(json, "esFragmentRd",
+ BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd);
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
json_flags = json_object_new_array();
@@ -4032,9 +4039,12 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
vty_out(vty, "VNI: %d ESI: %s\n",
es_evi->vpn->vni, es_evi->es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
- if (es_evi->es_frag)
- vty_out(vty, " ES fragment RD: %pRD\n",
+ if (es_evi->es_frag) {
+ vty_out(vty, " ES fragment RD: ");
+ vty_out(vty, BGP_RD_AS_FORMAT(mode),
&es_evi->es_frag->prd);
+ vty_out(vty, "\n");
+ }
vty_out(vty, " Inconsistencies: %s\n",
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
"es-vtep-mismatch":"-");
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index d63e7a1a16..fbf3b19c37 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -76,6 +76,7 @@ struct bgpevpn {
/* RD for this VNI. */
struct prefix_rd prd;
+ char *prd_pretty;
/* Route type 3 field */
struct in_addr originator_ip;
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 33c202c3d7..e28a8c8057 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -374,7 +374,9 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_int_add(json, "vni", bgp_vrf->l3vni);
json_object_string_add(json, "type", "L3");
json_object_string_add(json, "inKernel", "True");
- json_object_string_addf(json, "rd", "%pRD", &bgp_vrf->vrf_prd);
+ json_object_string_addf(json, "rd",
+ BGP_RD_AS_FORMAT(bgp_vrf->asnotation),
+ &bgp_vrf->vrf_prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&bgp_vrf->originator_ip);
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
@@ -398,7 +400,10 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Type: %s\n", "L3");
vty_out(vty, " Tenant VRF: %s\n",
vrf_id_to_name(bgp_vrf->vrf_id));
- vty_out(vty, " RD: %pRD\n", &bgp_vrf->vrf_prd);
+ vty_out(vty, " RD: ");
+ vty_out(vty, BGP_RD_AS_FORMAT(bgp_vrf->asnotation),
+ &bgp_vrf->vrf_prd);
+ vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n",
&bgp_vrf->originator_ip);
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
@@ -461,8 +466,10 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
struct bgp *bgp_evpn;
+ enum asnotation_mode asnotation;
bgp_evpn = bgp_get_evpn();
+ asnotation = bgp_get_asnotation(bgp_evpn);
if (json) {
json_import_rtl = json_object_new_array();
@@ -471,7 +478,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_string_add(json, "type", "L2");
json_object_string_add(json, "inKernel",
is_vni_live(vpn) ? "True" : "False");
- json_object_string_addf(json, "rd", "%pRD", &vpn->prd);
+ json_object_string_addf(
+ json, "rd", BGP_RD_AS_FORMAT(asnotation), &vpn->prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json, "mcastGroup", "%pI4",
@@ -512,7 +520,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
vty_out(vty, " Type: %s\n", "L2");
vty_out(vty, " Tenant-Vrf: %s\n",
vrf_id_to_name(vpn->tenant_vrf_id));
- vty_out(vty, " RD: %pRD\n", &vpn->prd);
+ vty_out(vty, " RD: ");
+ vty_out(vty, BGP_RD_AS_FORMAT(asnotation), &vpn->prd);
+ vty_out(vty, "\n");
vty_out(vty, " Originator IP: %pI4\n", &vpn->originator_ip);
vty_out(vty, " Mcast group: %pI4\n", &vpn->mcast_grp);
if (!vpn->advertise_gw_macip &&
@@ -991,7 +1001,9 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_object_string_add(json_vni, "inKernel", "True");
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&bgp->originator_ip);
- json_object_string_addf(json_vni, "rd", "%pRD", &bgp->vrf_prd);
+ json_object_string_addf(json_vni, "rd",
+ BGP_RD_AS_FORMAT(bgp->asnotation),
+ &bgp->vrf_prd);
json_object_string_add(json_vni, "advertiseGatewayMacip",
"n/a");
json_object_string_add(json_vni, "advertiseSviMacIp", "n/a");
@@ -1007,7 +1019,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_vni, "rmac",
prefix_mac2str(&bgp->rmac, buf2, sizeof(buf2)));
} else {
- vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, bgp->l3vni, "L3",
+ vty_out(vty, "%-1s %-10u %-4s ", buf1, bgp->l3vni, "L3");
+ vty_out(vty, BGP_RD_AS_FORMAT_SPACE(bgp->asnotation),
&bgp->vrf_prd);
}
@@ -1091,11 +1104,13 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
struct listnode *node, *nnode;
struct ecommunity *ecom;
struct bgp *bgp_evpn;
+ enum asnotation_mode asnotation;
vty = args[0];
json = args[1];
bgp_evpn = bgp_get_evpn();
+ asnotation = bgp_get_asnotation(bgp_evpn);
if (json) {
json_vni = json_object_new_object();
@@ -1112,7 +1127,9 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "type", "L2");
json_object_string_add(json_vni, "inKernel",
is_vni_live(vpn) ? "True" : "False");
- json_object_string_addf(json_vni, "rd", "%pRD", &vpn->prd);
+ json_object_string_addf(json_vni, "rd",
+ BGP_RD_AS_FORMAT(asnotation),
+ &vpn->prd);
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json_vni, "mcastGroup", "%pI4",
@@ -1142,8 +1159,8 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "advertiseSviMacIp",
"Disabled");
} else {
- vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, vpn->vni, "L2",
- &vpn->prd);
+ vty_out(vty, "%-1s %-10u %-4s ", buf1, vpn->vni, "L2");
+ vty_out(vty, BGP_RD_AS_FORMAT_SPACE(asnotation), &vpn->prd);
}
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@@ -1332,9 +1349,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
json,
"defaultLocPrf",
bgp->default_local_pref);
- json_object_int_add(
- json, "localAS",
- bgp->as);
+ asn_asn2json(json, "localAS",
+ bgp->as,
+ bgp->asnotation);
} else {
if (option == SHOW_DISPLAY_TAGS)
vty_out(vty,
@@ -2203,7 +2220,8 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
/*
* Configure RD for VRF
*/
-static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
+static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd,
+ const char *rd_pretty)
{
/* If we have already advertise type-5 routes with a diffrent RD, we
* have to delete and withdraw them firs
@@ -2212,6 +2230,7 @@ static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd)
/* update RD */
memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
+ bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
/* We have a new RD for VRF.
@@ -2233,7 +2252,8 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
/* fall back to default RD */
bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
-
+ if (bgp_vrf->vrf_prd_pretty)
+ XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty);
/* We have a new RD for VRF.
* Advertise all type-5 routes again with the new RD
*/
@@ -2244,7 +2264,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
* Configure RD for a VNI (vty handler)
*/
static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
- struct prefix_rd *rd)
+ struct prefix_rd *rd, const char *rd_pretty)
{
/* If the VNI is "live", we need to delete and withdraw this VNI's
* local routes with the prior RD first. Then, after updating RD,
@@ -2255,6 +2275,7 @@ static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn,
/* update RD */
memcpy(&vpn->prd, rd, sizeof(struct prefix_rd));
+ vpn->prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty);
SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD);
if (is_vni_live(vpn))
@@ -2778,7 +2799,8 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
json_rd = json_object_new_object();
- json_object_string_addf(json_rd, "rd", "%pRD", prd);
+ json_object_string_addf(json_rd, "rd",
+ BGP_RD_AS_FORMAT(bgp->asnotation), prd);
}
bgp_dest_unlock_node(rd_dest);
@@ -2861,7 +2883,9 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
if (add_rd_to_json)
- json_object_object_addf(json, json_rd, "%pRD", prd);
+ json_object_object_addf(
+ json, json_rd,
+ BGP_RD_AS_FORMAT(bgp->asnotation), prd);
else {
json_object_free(json_rd);
json_rd = NULL;
@@ -2916,7 +2940,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
continue;
prefix_rd2str((struct prefix_rd *)rd_destp, rd_str,
- sizeof(rd_str));
+ sizeof(rd_str), bgp->asnotation);
/* Construct an RT-2 from the user-supplied mac(ip),
* then search the l2vpn evpn table for it.
@@ -3010,7 +3034,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
* If 'type' is non-zero, only routes matching that type are shown.
*/
static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
- json_object *json, int detail)
+ json_object *json, int detail, bool self_orig)
{
struct bgp_dest *rd_dest;
struct bgp_table *table;
@@ -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();
@@ -3068,6 +3092,9 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
pi = bgp_dest_get_bgp_path_info(dest);
if (pi) {
+ if (self_orig && (pi->peer != bgp->peer_self))
+ continue;
+
/* Overall header/legend displayed once. */
if (header) {
bgp_evpn_show_route_header(vty, bgp,
@@ -3187,7 +3214,7 @@ int bgp_evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
if (use_json)
json = json_object_new_object();
- evpn_show_all_routes(vty, bgp, type, json, detail);
+ evpn_show_all_routes(vty, bgp, type, json, detail, false);
if (use_json)
vty_json(vty, json);
@@ -3460,7 +3487,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,
@@ -4760,7 +4787,7 @@ int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc)
*/
DEFUN(show_bgp_l2vpn_evpn_route,
show_bgp_l2vpn_evpn_route_cmd,
- "show bgp l2vpn evpn route [detail] [type "EVPN_TYPE_ALL_LIST"] [json]",
+ "show bgp l2vpn evpn route [detail] [type "EVPN_TYPE_ALL_LIST"] ["BGP_SELF_ORIG_CMD_STR"] [json]",
SHOW_STR
BGP_STR
L2VPN_HELP_STR
@@ -4769,12 +4796,15 @@ DEFUN(show_bgp_l2vpn_evpn_route,
"Display Detailed Information\n"
EVPN_TYPE_HELP_STR
EVPN_TYPE_ALL_LIST_HELP_STR
+ BGP_SELF_ORIG_HELP_STR
JSON_STR)
{
struct bgp *bgp;
int detail = 0;
int type = 0;
bool uj = false;
+ int arg_idx = 0;
+ bool self_orig = false;
json_object *json = NULL;
uj = use_json(argc, argv);
@@ -4792,7 +4822,10 @@ DEFUN(show_bgp_l2vpn_evpn_route,
if (argv_find(argv, argc, "detail", &detail))
detail = 1;
- evpn_show_all_routes(vty, bgp, type, json, detail);
+ if (argv_find(argv, argc, BGP_SELF_ORIG_CMD_STR, &arg_idx))
+ self_orig = true;
+
+ evpn_show_all_routes(vty, bgp, type, json, detail, self_orig);
/*
* This is an extremely expensive operation at scale
@@ -4858,7 +4891,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
return CMD_WARNING;
if (rd_all)
- evpn_show_all_routes(vty, bgp, type, json, 1);
+ evpn_show_all_routes(vty, bgp, type, json, 1, false);
else
evpn_show_route_rd(vty, bgp, &prd, type, json);
@@ -6111,7 +6144,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 +6236,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 +6421,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 +6459,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 +7288,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
- vty_out(vty, " rd %pRD\n", &bgp->vrf_prd);
+ vty_out(vty, " rd %s\n", bgp->vrf_prd_pretty);
/* import route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 6b35f7155f..f9debe43cd 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -127,6 +127,13 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
psize);
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
}
+
+ if (psize == 0) {
+ flog_err(EC_BGP_FLOWSPEC_PACKET,
+ "Flowspec NLRI length 0 which makes no sense");
+ return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
+ }
+
if (bgp_fs_nlri_validate(pnt, psize, afi) < 0) {
flog_err(
EC_BGP_FLOWSPEC_PACKET,
@@ -180,9 +187,8 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
NULL, 0, 0, NULL);
else
- bgp_withdraw(peer, &p, 0, attr, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
- NULL, 0, NULL);
+ bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
}
return BGP_NLRI_PARSE_OK;
}
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 28fac0bedd..0cad119af1 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -442,7 +442,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
NULL, &label, 1, 0, NULL);
} else {
- bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
+ bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
}
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index bd8ce54775..551da69249 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -240,7 +240,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
} else {
- bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
+ bgp_withdraw(peer, &p, addpath_id, packet->afi,
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
}
@@ -1853,7 +1853,7 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
int origin_local = 0;
struct bgp *src_vrf;
struct interface *ifp;
-
+ char rd_buf[RD_ADDRSTRLEN];
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
@@ -1892,6 +1892,10 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return false;
}
+ rd_buf[0] = '\0';
+ if (debug && prd)
+ prefix_rd2str(prd, rd_buf, sizeof(rd_buf), to_bgp->asnotation);
+
/* A route MUST NOT ever be accepted back into its source VRF, even if
* it carries one or more RTs that match that VRF.
*/
@@ -1900,15 +1904,14 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
ECOMMUNITY_SIZE) == 0) {
if (debug)
zlog_debug(
- "%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)",
- __func__, prd, to_bgp->name_pretty, p);
-
+ "%s: skipping import, match RD (%s) of src VRF (%s) and the prefix (%pFX)",
+ __func__, rd_buf, to_bgp->name_pretty, p);
return false;
}
if (debug)
- zlog_debug("%s: updating RD %pRD, %pFX to %s", __func__, prd, p,
- to_bgp->name_pretty);
+ zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf,
+ p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@@ -2403,7 +2406,7 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
&bgp->vrf_prd_auto);
bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto;
prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
- sizeof(buf));
+ sizeof(buf), bgp->asnotation);
/* free up pre-existing memory if any and allocate
* the ecommunity attribute with new RD/RT
@@ -2538,8 +2541,8 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto;
SET_FLAG(from_bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
- prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd,
- buf, sizeof(buf));
+ prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, buf,
+ sizeof(buf), from_bgp->asnotation);
from_bgp->vpn_policy[afi].rtlist[edir] =
ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0);
SET_FLAG(from_bgp->af_flags[afi][safi],
diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c
index 95a7bb8117..9b2ab66806 100644
--- a/bgpd/bgp_mplsvpn_snmp.c
+++ b/bgpd/bgp_mplsvpn_snmp.c
@@ -942,11 +942,13 @@ static uint8_t *mplsL3vpnVrfTable(struct variable *v, oid name[],
if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP].flags,
BGP_VPN_POLICY_TOVPN_RD_SET))
prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP].tovpn_rd,
- rd_buf, sizeof(rd_buf));
+ rd_buf, sizeof(rd_buf),
+ bgp_get_asnotation(l3vpn_bgp));
else if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP6].flags,
BGP_VPN_POLICY_TOVPN_RD_SET))
prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP6].tovpn_rd,
- rd_buf, sizeof(rd_buf));
+ rd_buf, sizeof(rd_buf),
+ bgp_get_asnotation(l3vpn_bgp));
*var_len = strnlen(rd_buf, RD_ADDRSTRLEN);
return (uint8_t *)rd_buf;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index da89c594c8..1c2e686e1c 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -506,10 +506,16 @@ static void bgp_accept(struct thread *thread)
* is shutdown.
*/
if (BGP_PEER_START_SUPPRESSED(peer1)) {
- if (bgp_debug_neighbor_events(peer1))
- zlog_debug(
- "[Event] Incoming BGP connection rejected from %s due to maximum-prefix or shutdown",
- peer1->host);
+ if (bgp_debug_neighbor_events(peer1)) {
+ if (peer1->shut_during_cfg)
+ zlog_debug(
+ "[Event] Incoming BGP connection rejected from %s due to configuration being currently read in",
+ peer1->host);
+ else
+ zlog_debug(
+ "[Event] Incoming BGP connection rejected from %s due to maximum-prefix or shutdown",
+ peer1->host);
+ }
close(bgp_sock);
return;
}
@@ -538,7 +544,7 @@ static void bgp_accept(struct thread *thread)
peer1->host);
peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
- peer1->as, peer1->as_type, NULL, false);
+ peer1->as, peer1->as_type, NULL, false, NULL);
peer_xfer_config(peer, peer1);
bgp_peer_gr_flags_update(peer);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index a3014c0c6d..00a0bc8402 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -802,6 +802,7 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
safi = table->safi;
bgp_path = table->bgp;
+
if (json) {
json_path = json_object_new_object();
json_object_string_add(json_path, "afi", afi2str(afi));
@@ -811,7 +812,8 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
dest);
if (dest->pdest)
json_object_string_addf(
- json_path, "rd", "%pRD",
+ json_path, "rd",
+ BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest));
json_object_string_add(
@@ -821,13 +823,14 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
json_object_array_add(paths, json_path);
continue;
}
- if (dest->pdest)
- vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n",
- afi, safi, dest,
+ if (dest->pdest) {
+ vty_out(vty, " %d/%d %pBD RD ", afi, safi, dest);
+ vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
(struct prefix_rd *)bgp_dest_get_prefix(
- dest->pdest),
- bgp_path->name_pretty, path->flags);
- else
+ dest->pdest));
+ vty_out(vty, " %s flags 0x%x\n", bgp_path->name_pretty,
+ path->flags);
+ } else
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
afi, safi, dest, bgp_path->name_pretty, path->flags);
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 4f42766b9f..25b458a8e5 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -1190,14 +1190,20 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
}
if (BGP_DEBUG(nht, NHT)) {
- if (dest->pdest)
- zlog_debug(
- "... eval path %d/%d %pBD RD %pRD %s flags 0x%x",
- afi, safi, dest,
+
+ if (dest->pdest) {
+ char rd_buf[RD_ADDRSTRLEN];
+
+ prefix_rd2str(
(struct prefix_rd *)bgp_dest_get_prefix(
dest->pdest),
+ rd_buf, sizeof(rd_buf),
+ bgp_get_asnotation(bnc->bgp));
+ zlog_debug(
+ "... eval path %d/%d %pBD RD %s %s flags 0x%x",
+ afi, safi, dest, rd_buf,
bgp_path->name_pretty, path->flags);
- else
+ } else
zlog_debug(
"... eval path %d/%d %pBD %s flags 0x%x",
afi, safi, dest, bgp_path->name_pretty,
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c
index 6e73ab8d1e..bb9f76b8a3 100644
--- a/bgpd/bgp_rd.c
+++ b/bgpd/bgp_rd.c
@@ -83,12 +83,12 @@ void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth)
int str2prefix_rd(const char *str, struct prefix_rd *prd)
{
- int ret = 0;
- char *p;
- char *p2;
+ int ret = 0, type = RD_TYPE_UNDEFINED;
+ char *p, *p2;
struct stream *s = NULL;
char *half = NULL;
struct in_addr addr;
+ as_t as_val;
prd->family = AF_UNSPEC;
prd->prefixlen = 64;
@@ -97,41 +97,55 @@ int str2prefix_rd(const char *str, struct prefix_rd *prd)
if (!p)
goto out;
+ /* a second ':' is accepted */
+ p2 = strchr(p + 1, ':');
+ if (p2) {
+ /* type is in first part */
+ half = XMALLOC(MTYPE_TMP, (p - str) + 1);
+ memcpy(half, str, (p - str));
+ half[p - str] = '\0';
+ type = atoi(half);
+ if (type != RD_TYPE_AS && type != RD_TYPE_IP &&
+ type != RD_TYPE_AS4)
+ goto out;
+ XFREE(MTYPE_TMP, half);
+ half = XMALLOC(MTYPE_TMP, (p2 - p));
+ memcpy(half, p + 1, (p2 - p - 1));
+ half[p2 - p - 1] = '\0';
+ p = p2 + 1;
+ } else {
+ half = XMALLOC(MTYPE_TMP, (p - str) + 1);
+ memcpy(half, str, (p - str));
+ half[p - str] = '\0';
+ }
if (!all_digit(p + 1))
goto out;
s = stream_new(RD_BYTES);
- half = XMALLOC(MTYPE_TMP, (p - str) + 1);
- memcpy(half, str, (p - str));
- half[p - str] = '\0';
-
- p2 = strchr(str, '.');
-
- if (!p2) {
- unsigned long as_val;
-
- if (!all_digit(half))
- goto out;
-
- as_val = atol(half);
- if (as_val > 0xffff) {
+ /* if it is an AS format or an IP */
+ if (asn_str2asn(half, &as_val)) {
+ if (as_val > UINT16_MAX) {
stream_putw(s, RD_TYPE_AS4);
stream_putl(s, as_val);
stream_putw(s, atol(p + 1));
+ if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS4)
+ goto out;
} else {
stream_putw(s, RD_TYPE_AS);
stream_putw(s, as_val);
stream_putl(s, atol(p + 1));
+ if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS)
+ goto out;
}
- } else {
- if (!inet_aton(half, &addr))
- goto out;
-
+ } else if (inet_aton(half, &addr)) {
stream_putw(s, RD_TYPE_IP);
stream_put_in_addr(s, &addr);
stream_putw(s, atol(p + 1));
- }
+ if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_IP)
+ goto out;
+ } else
+ goto out;
memcpy(prd->val, s->data, 8);
ret = 1;
@@ -142,12 +156,14 @@ out:
return ret;
}
-char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size)
+char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size,
+ enum asnotation_mode asnotation)
{
const uint8_t *pnt;
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
+ int len = 0;
assert(size >= RD_ADDRSTRLEN);
@@ -157,11 +173,15 @@ char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size)
if (type == RD_TYPE_AS) {
decode_rd_as(pnt + 2, &rd_as);
- snprintf(buf, size, "%u:%u", rd_as.as, rd_as.val);
+ len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
+ &rd_as.as);
+ snprintfrr(buf + len, size - len, ":%u", rd_as.val);
return buf;
} else if (type == RD_TYPE_AS4) {
decode_rd_as4(pnt + 2, &rd_as);
- snprintf(buf, size, "%u:%u", rd_as.as, rd_as.val);
+ len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation),
+ &rd_as.as);
+ snprintfrr(buf + len, size - len, ":%u", rd_as.val);
return buf;
} else if (type == RD_TYPE_IP) {
decode_rd_ip(pnt + 2, &rd_ip);
@@ -196,16 +216,38 @@ void form_auto_rd(struct in_addr router_id,
(void)str2prefix_rd(buf, prd);
}
-printfrr_ext_autoreg_p("RD", printfrr_prd);
-static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
- const void *ptr)
+static ssize_t printfrr_prd_asnotation(struct fbuf *buf,
+ struct printfrr_eargs *ea,
+ const void *ptr,
+ enum asnotation_mode asnotation)
{
char rd_buf[RD_ADDRSTRLEN];
if (!ptr)
return bputs(buf, "(null)");
- prefix_rd2str(ptr, rd_buf, sizeof(rd_buf));
+ prefix_rd2str(ptr, rd_buf, sizeof(rd_buf), asnotation);
return bputs(buf, rd_buf);
}
+
+printfrr_ext_autoreg_p("RDP", printfrr_prd);
+static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
+}
+
+printfrr_ext_autoreg_p("RDD", printfrr_prd_dot);
+static ssize_t printfrr_prd_dot(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOT);
+}
+
+printfrr_ext_autoreg_p("RDE", printfrr_prd_dotplus);
+static ssize_t printfrr_prd_dotplus(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
+}
diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h
index 44173b7a24..e38c2fad3b 100644
--- a/bgpd/bgp_rd.h
+++ b/bgpd/bgp_rd.h
@@ -7,7 +7,11 @@
#ifndef _QUAGGA_BGP_RD_H
#define _QUAGGA_BGP_RD_H
+#include "asn.h"
+#include "prefix.h"
+
/* RD types */
+#define RD_TYPE_UNDEFINED (-1)
#define RD_TYPE_AS 0
#define RD_TYPE_IP 1
#define RD_TYPE_AS4 2
@@ -19,6 +23,16 @@
#define RD_ADDRSTRLEN 28
#define RD_BYTES 8
+#define BGP_RD_AS_FORMAT(mode) \
+ ((mode == ASNOTATION_DOT) \
+ ? "%pRDD" \
+ : ((mode == ASNOTATION_DOTPLUS) ? "%pRDE" : "%pRDP"))
+
+#define BGP_RD_AS_FORMAT_SPACE(mode) \
+ ((mode == ASNOTATION_DOT) \
+ ? "%-21pRDD" \
+ : ((mode == ASNOTATION_DOTPLUS) ? "%-21pRDE" : "%-21pRDP"))
+
struct rd_as {
uint16_t type;
as_t as;
@@ -51,7 +65,8 @@ extern void decode_rd_vnc_eth(const uint8_t *pnt,
#endif
extern int str2prefix_rd(const char *, struct prefix_rd *);
-extern char *prefix_rd2str(const struct prefix_rd *, char *, size_t);
+extern char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size,
+ enum asnotation_mode asnotation);
extern void form_auto_rd(struct in_addr router_id, uint16_t rd_id,
struct prefix_rd *prd);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 0d93abc12f..0beef97a04 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4897,10 +4897,9 @@ filtered:
}
void bgp_withdraw(struct peer *peer, const struct prefix *p,
- uint32_t addpath_id, struct attr *attr, afi_t afi,
- safi_t safi, int type, int sub_type, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
- struct bgp_route_evpn *evpn)
+ uint32_t addpath_id, afi_t afi, safi_t safi, int type,
+ int sub_type, struct prefix_rd *prd, mpls_label_t *label,
+ uint32_t num_labels, struct bgp_route_evpn *evpn)
{
struct bgp *bgp;
char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -6046,7 +6045,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
NULL, 0, 0, NULL);
else
- bgp_withdraw(peer, &p, addpath_id, attr, afi, safi,
+ bgp_withdraw(peer, &p, addpath_id, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
NULL, 0, NULL);
@@ -6078,6 +6077,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 +6982,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 +7246,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 +7340,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 +10260,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 +10277,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 +11194,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;
@@ -11455,6 +11474,10 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
|| CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
continue;
}
+ if (type == bgp_show_type_self_originated) {
+ if (pi->peer != bgp->peer_self)
+ continue;
+ }
if (!use_json && header) {
vty_out(vty,
@@ -11468,7 +11491,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 +11691,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 +11842,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 +11861,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 +12085,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);
}
}
@@ -12623,6 +12654,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|alias ALIAS_NAME\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
+ |"BGP_SELF_ORIG_CMD_STR"\
|detail-routes$detail_routes\
] [json$uj [detail$detail_json] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
@@ -12672,6 +12704,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"Display route and more specific routes\n"
"IPv6 prefix\n"
"Display route and more specific routes\n"
+ BGP_SELF_ORIG_HELP_STR
"Display detailed version of all routes\n"
JSON_STR
"Display detailed version of JSON output\n"
@@ -12866,6 +12899,10 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
output_arg = &p;
}
+ /* self originated only */
+ if (argv_find(argv, argc, BGP_SELF_ORIG_CMD_STR, &idx))
+ sh_type = bgp_show_type_self_originated;
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
@@ -14465,7 +14502,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 +15632,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 +15649,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 +15677,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 +15704,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 +15730,9 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
&bgp_static->gatewayIp.u.prefix, buf2,
sizeof(buf2));
vty_out(vty,
- " network %s rd %pRD ethtag %u label %u esi %s gwip %s routermac %s\n",
- buf, prd, p->u.prefix_evpn.prefix_addr.eth_tag,
+ " network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
+ buf, bgp_static->prd_pretty,
+ p->u.prefix_evpn.prefix_addr.eth_tag,
decode_label(&bgp_static->label), esi_buf, buf2,
macrouter);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index d449152c21..66cc62ab09 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -46,6 +46,7 @@ enum bgp_show_type {
bgp_show_type_detail,
bgp_show_type_rpki,
bgp_show_type_prefix_version,
+ bgp_show_type_self_originated,
};
enum bgp_show_adj_route_type {
@@ -66,7 +67,7 @@ enum bgp_show_adj_route_type {
#define BGP_SHOW_RPKI_HEADER \
"RPKI validation codes: V valid, I invalid, N Not found\n\n"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
-#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
+#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
/* Maximum number of labels we can process or send with a prefix. We
* really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
@@ -355,6 +356,7 @@ struct bgp_static {
/* Route Distinguisher */
struct prefix_rd prd;
+ char *prd_pretty;
/* MPLS label. */
mpls_label_t label;
@@ -742,10 +744,10 @@ extern void bgp_update(struct peer *peer, const struct prefix *p,
uint32_t num_labels, int soft_reconfig,
struct bgp_route_evpn *evpn);
extern void bgp_withdraw(struct peer *peer, const struct prefix *p,
- uint32_t addpath_id, struct attr *attr, afi_t afi,
- safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, mpls_label_t *label,
- uint32_t num_labels, struct bgp_route_evpn *evpn);
+ uint32_t addpath_id, afi_t afi, safi_t safi, int type,
+ int sub_type, struct prefix_rd *prd,
+ mpls_label_t *label, uint32_t num_labels,
+ struct bgp_route_evpn *evpn);
/* for bgp_nexthop and bgp_damp */
extern void bgp_process(struct bgp *, struct bgp_dest *, afi_t, safi_t);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index f9def03693..8fd46d00af 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -213,7 +213,7 @@ static void *route_aspath_compile(const char *arg)
{
struct aspath *aspath;
- aspath = aspath_str2aspath(arg);
+ aspath = aspath_str2aspath(arg, bgp_get_asnotation(NULL));
if (!aspath)
return NULL;
return aspath;
@@ -3024,11 +3024,11 @@ static void *route_set_origin_compile(const char *arg)
origin = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
if (strcmp(arg, "igp") == 0)
- *origin = 0;
+ *origin = BGP_ORIGIN_IGP;
else if (strcmp(arg, "egp") == 0)
- *origin = 1;
+ *origin = BGP_ORIGIN_EGP;
else
- *origin = 2;
+ *origin = BGP_ORIGIN_INCOMPLETE;
return origin;
}
@@ -3631,17 +3631,29 @@ route_set_ipv6_nexthop_local(void *rule, const struct prefix *p, void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
+ struct bgp_dest *dest;
+ struct bgp_table *table = NULL;
/* Fetch routemap's rule information. */
address = rule;
path = object;
+ dest = path->net;
+
+ if (!dest)
+ return RMAP_OKAY;
+
+ table = bgp_dest_table(dest);
+ if (!table)
+ return RMAP_OKAY;
/* Set next hop value. */
path->attr->mp_nexthop_local = *address;
/* Set nexthop length. */
- if (path->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
- path->attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
+ if (table->safi == SAFI_MPLS_VPN || table->safi == SAFI_ENCAP ||
+ table->safi == SAFI_EVPN)
+ path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
+ else
path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
SET_FLAG(path->attr->rmap_change_flags,
@@ -5663,15 +5675,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 +5692,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 +5732,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 +5758,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 +5775,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 +5808,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 +5825,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 +5842,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"
@@ -5870,9 +5902,14 @@ DEFUN_YANG (set_community,
else
first = 1;
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
if (strncmp(argv[i]->arg, "internet", strlen(argv[i]->arg))
== 0) {
buffer_putstr(b, "internet");
+ vty_out(vty, "%% `internet` community is deprecated\n");
+ zlog_warn("`internet` community is deprecated");
continue;
}
if (strncmp(argv[i]->arg, "local-AS", strlen(argv[i]->arg))
@@ -6496,11 +6533,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 +6546,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 +6574,12 @@ DEFUN_YANG (set_aggregator_as,
DEFUN_YANG (no_set_aggregator_as,
no_set_aggregator_as_cmd,
- "no set aggregator as [(1-4294967295) A.B.C.D]",
+ "no set aggregator as [ASNUM A.B.C.D]",
NO_STR
SET_STR
"BGP aggregator attribute\n"
"AS number of aggregator\n"
- "AS number\n"
+ AS_STR
"IP address of aggregator\n")
{
const char *xpath =
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 61b8b4edce..32ca909fe6 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -81,6 +81,7 @@ struct rpki_for_each_record_arg {
unsigned int *prefix_amount;
as_t as;
json_object *json;
+ enum asnotation_mode asnotation;
};
static int start(void);
@@ -105,7 +106,7 @@ static void rpki_delete_all_cache_nodes(void);
static int add_tcp_cache(const char *host, const char *port,
const uint8_t preference, const char *bindaddr);
static void print_record(const struct pfx_record *record, struct vty *vty,
- json_object *json);
+ json_object *json, enum asnotation_mode asnotation);
static bool is_synchronized(void);
static bool is_running(void);
static bool is_stopping(void);
@@ -270,7 +271,7 @@ static void rpki_delete_all_cache_nodes(void)
}
static void print_record(const struct pfx_record *record, struct vty *vty,
- json_object *json)
+ json_object *json, enum asnotation_mode asnotation)
{
char ip[INET6_ADDRSTRLEN];
json_object *json_record = NULL;
@@ -278,8 +279,10 @@ static void print_record(const struct pfx_record *record, struct vty *vty,
lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
if (!json) {
- vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len,
- record->max_len, record->asn);
+ vty_out(vty, "%-40s %3u - %3u ", ip, record->min_len,
+ record->max_len);
+ vty_out(vty, ASN_FORMAT(asnotation), (as_t *)&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"
@@ -1361,7 +1366,7 @@ DEFPY (show_rpki_as_number,
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 +1377,7 @@ DEFPY (show_rpki_prefix,
{
json_object *json = NULL;
json_object *json_records = NULL;
+ enum asnotation_mode asnotation;
if (!is_synchronized()) {
if (!uj)
@@ -1397,8 +1403,8 @@ DEFPY (show_rpki_prefix,
enum pfxv_state result;
if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
- asn, &addr, prefix->prefixlen, &result)
- != PFX_SUCCESS) {
+ asn, &addr, prefix->prefixlen,
+ &result) != PFX_SUCCESS) {
if (!json)
vty_out(vty, "Prefix lookup failed\n");
return CMD_WARNING;
@@ -1415,13 +1421,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 &&
+ ((asn != 0 && (uint32_t)asn == record->asn) || asn == 0)) {
+ print_record(&matches[i], vty, json_records,
+ asnotation);
}
}
diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c
index 6cc75494ed..f4ab233524 100644
--- a/bgpd/bgp_script.c
+++ b/bgpd/bgp_script.c
@@ -149,7 +149,8 @@ void lua_decode_attr(lua_State *L, int idx, struct attr *attr)
attr->nh_ifindex = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, idx, "aspath");
- attr->aspath = aspath_str2aspath(lua_tostring(L, -1));
+ attr->aspath = aspath_str2aspath(lua_tostring(L, -1),
+ bgp_get_asnotation(NULL));
lua_pop(L, 1);
lua_getfield(L, idx, "localpref");
attr->local_pref = lua_tointeger(L, -1);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b858d9c4b4..8ef18a34d0 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -24,6 +24,7 @@
#include "queue.h"
#include "filter.h"
#include "frrstr.h"
+#include "asn.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr_evpn.h"
@@ -579,9 +580,10 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi)
}
int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
- enum bgp_instance_type inst_type)
+ enum bgp_instance_type inst_type, const char *as_pretty,
+ enum asnotation_mode asnotation)
{
- int ret = bgp_get(bgp, as, name, inst_type);
+ int ret = bgp_get(bgp, as, name, inst_type, as_pretty, asnotation);
if (ret == BGP_CREATED) {
bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
@@ -1222,7 +1224,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
/* Clear all neighbors belonging to a specific AS. */
if (sort == clear_as) {
- as_t as = strtoul(arg, NULL, 10);
+ as_t as;
+
+ if (!asn_str2asn(arg, &as)) {
+ vty_out(vty, "%% BGP: No such AS %s\n", arg);
+ return CMD_WARNING;
+ }
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (peer->as != as)
@@ -1460,16 +1467,23 @@ DEFUN (no_auto_summary,
/* "router bgp" commands. */
DEFUN_NOSH (router_bgp,
router_bgp_cmd,
- "router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
+ "router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
ROUTER_STR
BGP_STR
AS_STR
- BGP_INSTANCE_HELP_STR)
+ BGP_INSTANCE_HELP_STR
+ "Force the AS notation output\n"
+ "use 'AA.BB' format for AS 4 byte values\n"
+ "use 'AA.BB' format for all AS values\n"
+ "use plain format for all AS values\n")
{
int idx_asn = 2;
int idx_view_vrf = 3;
int idx_vrf = 4;
int is_new_bgp = 0;
+ int idx_asnotation = 3;
+ int idx_asnotation_kind = 4;
+ enum asnotation_mode asnotation = ASNOTATION_UNDEFINED;
int ret;
as_t as;
struct bgp *bgp;
@@ -1494,39 +1508,62 @@ DEFUN_NOSH (router_bgp,
// "router bgp X"
else {
- as = strtoul(argv[idx_asn]->arg, NULL, 10);
+ if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
+ vty_out(vty, "%% BGP: No such AS %s\n",
+ argv[idx_asn]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
if (as == BGP_PRIVATE_AS_MAX || as == BGP_AS4_MAX)
vty_out(vty, "Reserved AS used (%u|%u); AS is %u\n",
BGP_PRIVATE_AS_MAX, BGP_AS4_MAX, as);
inst_type = BGP_INSTANCE_TYPE_DEFAULT;
- if (argc > 3) {
- name = argv[idx_vrf]->arg;
- if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
- if (strmatch(name, VRF_DEFAULT_NAME))
- name = NULL;
- else
- inst_type = BGP_INSTANCE_TYPE_VRF;
- } else if (!strcmp(argv[idx_view_vrf]->text, "view"))
- inst_type = BGP_INSTANCE_TYPE_VIEW;
+ if (argv_find(argv, argc, "VIEWVRFNAME", &idx_vrf)) {
+ idx_view_vrf = idx_vrf - 1;
+ if (argv[idx_view_vrf]->text) {
+ name = argv[idx_vrf]->arg;
+
+ if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
+ if (strmatch(name, VRF_DEFAULT_NAME))
+ name = NULL;
+ else
+ inst_type =
+ BGP_INSTANCE_TYPE_VRF;
+ } else if (!strcmp(argv[idx_view_vrf]->text,
+ "view"))
+ inst_type = BGP_INSTANCE_TYPE_VIEW;
+ }
+ }
+ if (argv_find(argv, argc, "as-notation", &idx_asnotation)) {
+ idx_asnotation_kind = idx_asnotation + 1;
+ if (strmatch(argv[idx_asnotation_kind]->text, "dot+"))
+ asnotation = ASNOTATION_DOTPLUS;
+ else if (strmatch(argv[idx_asnotation_kind]->text,
+ "dot"))
+ asnotation = ASNOTATION_DOT;
+ else if (strmatch(argv[idx_asnotation_kind]->text,
+ "plain"))
+ asnotation = ASNOTATION_PLAIN;
}
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
is_new_bgp = (bgp_lookup(as, name) == NULL);
- ret = bgp_get_vty(&bgp, &as, name, inst_type);
+ ret = bgp_get_vty(&bgp, &as, name, inst_type,
+ argv[idx_asn]->arg, asnotation);
switch (ret) {
case BGP_ERR_AS_MISMATCH:
- vty_out(vty, "BGP is already running; AS is %u\n", as);
+ vty_out(vty, "BGP is already running; AS is %s\n",
+ bgp->as_pretty);
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_INSTANCE_MISMATCH:
vty_out(vty,
"BGP instance name and AS number mismatch\n");
vty_out(vty,
- "BGP instance is already running; AS is %u\n",
- as);
+ "BGP instance is already running; AS is %s\n",
+ bgp->as_pretty);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -1542,6 +1579,19 @@ DEFUN_NOSH (router_bgp,
bgp_vpn_leak_export(bgp);
/* Pending: handle when user tries to change a view to vrf n vv.
*/
+ /* for pre-existing bgp instance,
+ * - update as_pretty
+ * - update asnotation if explicitly mentioned
+ */
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
+ XFREE(MTYPE_BGP, bgp->as_pretty);
+ bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg);
+ if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) &&
+ asnotation != ASNOTATION_UNDEFINED) {
+ SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+ bgp->asnotation = asnotation;
+ }
+ }
}
/* unset the auto created flag as the user config is now present */
@@ -1554,12 +1604,16 @@ DEFUN_NOSH (router_bgp,
/* "no router bgp" commands. */
DEFUN (no_router_bgp,
no_router_bgp_cmd,
- "no router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
+ "no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
NO_STR
ROUTER_STR
BGP_STR
AS_STR
- BGP_INSTANCE_HELP_STR)
+ BGP_INSTANCE_HELP_STR
+ "Force the AS notation output\n"
+ "use 'AA.BB' format for AS 4 byte values\n"
+ "use 'AA.BB' format for all AS values\n"
+ "use plain format for all AS values\n")
{
int idx_asn = 3;
int idx_vrf = 5;
@@ -1588,8 +1642,11 @@ DEFUN (no_router_bgp,
return CMD_WARNING_CONFIG_FAILED;
}
} else {
- as = strtoul(argv[idx_asn]->arg, NULL, 10);
-
+ if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
+ vty_out(vty, "%% BGP: No such AS %s\n",
+ argv[idx_asn]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
if (argc > 4) {
name = argv[idx_vrf]->arg;
if (strmatch(argv[idx_vrf - 1]->text, "vrf")
@@ -1821,7 +1878,6 @@ DEFPY (bgp_suppress_fib_pending,
return CMD_SUCCESS;
}
-
/* BGP Cluster ID. */
DEFUN (bgp_cluster_id,
bgp_cluster_id_cmd,
@@ -1917,30 +1973,33 @@ DEFPY (no_bgp_send_extra_data,
DEFUN (bgp_confederation_identifier,
bgp_confederation_identifier_cmd,
- "bgp confederation identifier (1-4294967295)",
+ "bgp confederation identifier ASNUM",
BGP_STR
"AS confederation parameters\n"
- "AS number\n"
+ AS_STR
"Set routing domain confederation AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
as_t as;
- as = strtoul(argv[idx_number]->arg, NULL, 10);
+ if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+ vty_out(vty, "%% BGP: No such AS %s\n", argv[idx_number]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- bgp_confederation_id_set(bgp, as);
+ bgp_confederation_id_set(bgp, as, argv[idx_number]->arg);
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_identifier,
no_bgp_confederation_identifier_cmd,
- "no bgp confederation identifier [(1-4294967295)]",
+ "no bgp confederation identifier [ASNUM]",
NO_STR
BGP_STR
"AS confederation parameters\n"
- "AS number\n"
+ AS_STR
"Set routing domain confederation AS\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
@@ -1951,7 +2010,7 @@ DEFUN (no_bgp_confederation_identifier,
DEFUN (bgp_confederation_peers,
bgp_confederation_peers_cmd,
- "bgp confederation peers (1-4294967295)...",
+ "bgp confederation peers ASNUM...",
BGP_STR
"AS confederation parameters\n"
"Peer ASs in BGP confederation\n"
@@ -1963,15 +2022,20 @@ DEFUN (bgp_confederation_peers,
int i;
for (i = idx_asn; i < argc; i++) {
- as = strtoul(argv[i]->arg, NULL, 10);
- bgp_confederation_peers_add(bgp, as);
+ if (!asn_str2asn(argv[i]->arg, &as)) {
+ vty_out(vty, "%% Invalid confed peer AS value: %s\n",
+ argv[i]->arg);
+ continue;
+ }
+
+ bgp_confederation_peers_add(bgp, as, argv[i]->arg);
}
return CMD_SUCCESS;
}
DEFUN (no_bgp_confederation_peers,
no_bgp_confederation_peers_cmd,
- "no bgp confederation peers (1-4294967295)...",
+ "no bgp confederation peers ASNUM...",
NO_STR
BGP_STR
"AS confederation parameters\n"
@@ -1984,8 +2048,11 @@ DEFUN (no_bgp_confederation_peers,
int i;
for (i = idx_asn; i < argc; i++) {
- as = strtoul(argv[i]->arg, NULL, 10);
-
+ if (!asn_str2asn(argv[i]->arg, &as)) {
+ vty_out(vty, "%% Invalid confed peer AS value: %s\n",
+ argv[i]->arg);
+ continue;
+ }
bgp_confederation_peers_remove(bgp, as);
}
return CMD_SUCCESS;
@@ -4489,11 +4556,13 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
} else if (as_str[0] == 'e') {
as = 0;
as_type = AS_EXTERNAL;
- } else {
- /* Get AS number. */
- as = strtoul(as_str, NULL, 10);
- }
+ } else if (!asn_str2asn(as_str, &as))
+ as_type = AS_UNSPECIFIED;
+ if (as_type == AS_UNSPECIFIED) {
+ vty_out(vty, "%% Invalid peer AS: %s\n", as_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
/* If peer is peer group or interface peer, call proper function. */
ret = str2sockunion(peer_str, &su);
if (ret < 0) {
@@ -4502,11 +4571,12 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
/* Check if existing interface peer */
peer = peer_lookup_by_conf_if(bgp, peer_str);
- ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type);
+ ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, as_str);
/* if not interface peer, check peer-group settings */
if (ret < 0 && !peer) {
- ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
+ ret = peer_group_remote_as(bgp, peer_str, &as, as_type,
+ as_str);
if (ret < 0) {
vty_out(vty,
"%% Create the peer-group or interface first\n");
@@ -4520,7 +4590,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
"%% Can not configure the local system as neighbor\n");
return CMD_WARNING_CONFIG_FAILED;
}
- ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
+ ret = peer_remote_as(bgp, &su, NULL, &as, as_type, as_str);
}
return bgp_vty_return(vty, ret);
@@ -4591,7 +4661,7 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
DEFUN (neighbor_remote_as,
neighbor_remote_as_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a BGP neighbor\n"
@@ -4671,18 +4741,19 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
as_type = AS_EXTERNAL;
} else {
/* Get AS number. */
- as = strtoul(as_str, NULL, 10);
- as_type = AS_SPECIFIED;
+ if (asn_str2asn(as_str, &as))
+ as_type = AS_SPECIFIED;
}
}
peer = peer_lookup_by_conf_if(bgp, conf_if);
if (peer) {
if (as_str)
- ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
+ ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type,
+ as_str);
} else {
peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
- NULL, true);
+ NULL, true, as_str);
if (!peer) {
vty_out(vty, "%% BGP failed to create peer\n");
@@ -4784,7 +4855,7 @@ DEFUN (neighbor_interface_config_v6only,
DEFUN (neighbor_interface_config_remote_as,
neighbor_interface_config_remote_as_cmd,
- "neighbor WORD interface remote-as <(1-4294967295)|internal|external>",
+ "neighbor WORD interface remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP on interface\n"
@@ -4801,7 +4872,7 @@ DEFUN (neighbor_interface_config_remote_as,
DEFUN (neighbor_interface_v6only_config_remote_as,
neighbor_interface_v6only_config_remote_as_cmd,
- "neighbor WORD interface v6only remote-as <(1-4294967295)|internal|external>",
+ "neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
NEIGHBOR_STR
"Interface name or neighbor tag\n"
"Enable BGP with v6 link-local only\n"
@@ -4970,7 +5041,7 @@ DEFUN (no_neighbor_peer_group,
DEFUN (no_neighbor_interface_peer_group_remote_as,
no_neighbor_interface_peer_group_remote_as_cmd,
- "no neighbor WORD remote-as <(1-4294967295)|internal|external>",
+ "no neighbor WORD remote-as <ASNUM|internal|external>",
NO_STR
NEIGHBOR_STR
"Interface name or neighbor tag\n"
@@ -4987,7 +5058,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
/* look up for neighbor by interface name config. */
peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
if (peer) {
- peer_as_change(peer, 0, AS_UNSPECIFIED);
+ peer_as_change(peer, 0, AS_UNSPECIFIED, NULL);
return CMD_SUCCESS;
}
@@ -5003,11 +5074,11 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
DEFUN (neighbor_local_as,
neighbor_local_as_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295)",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
- "AS number used as local AS\n")
+ "AS number expressed in dotted or plain format used as local AS\n")
{
int idx_peer = 1;
int idx_number = 3;
@@ -5019,18 +5090,23 @@ DEFUN (neighbor_local_as,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- as = strtoul(argv[idx_number]->arg, NULL, 10);
- ret = peer_local_as_set(peer, as, 0, 0);
+ if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+ vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+ argv[idx_number]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = peer_local_as_set(peer, as, 0, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_local_as_no_prepend,
neighbor_local_as_no_prepend_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
- "AS number used as local AS\n"
+ "AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n")
{
int idx_peer = 1;
@@ -5043,18 +5119,23 @@ DEFUN (neighbor_local_as_no_prepend,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- as = strtoul(argv[idx_number]->arg, NULL, 10);
- ret = peer_local_as_set(peer, as, 1, 0);
+ if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+ vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+ argv[idx_number]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = peer_local_as_set(peer, as, 1, 0, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (neighbor_local_as_no_prepend_replace_as,
neighbor_local_as_no_prepend_replace_as_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend replace-as",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
- "AS number used as local AS\n"
+ "AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
"Do not prepend local-as to updates from ibgp peers\n")
{
@@ -5068,19 +5149,24 @@ DEFUN (neighbor_local_as_no_prepend_replace_as,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- as = strtoul(argv[idx_number]->arg, NULL, 10);
- ret = peer_local_as_set(peer, as, 1, 1);
+ if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+ vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+ argv[idx_number]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ ret = peer_local_as_set(peer, as, 1, 1, argv[idx_number]->arg);
return bgp_vty_return(vty, ret);
}
DEFUN (no_neighbor_local_as,
no_neighbor_local_as_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [(1-4294967295) [no-prepend [replace-as]]]",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Specify a local-as number\n"
- "AS number used as local AS\n"
+ "AS number expressed in dotted or plain format used as local AS\n"
"Do not prepend local-as to updates from ebgp peers\n"
"Do not prepend local-as to updates from ibgp peers\n")
{
@@ -9020,10 +9106,13 @@ DEFPY (af_rd_vpn_export,
bgp_get_default(), bgp);
if (yes) {
+ bgp->vpn_policy[afi].tovpn_rd_pretty =
+ XSTRDUP(MTYPE_BGP, rd_str);
bgp->vpn_policy[afi].tovpn_rd = prd;
SET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
} else {
+ XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
UNSET_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_RD_SET);
}
@@ -9548,7 +9637,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&bgp_default, &as, NULL,
- BGP_INSTANCE_TYPE_DEFAULT);
+ BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
@@ -9660,7 +9750,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
if (!bgp_default) {
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&bgp_default, &as, NULL,
- BGP_INSTANCE_TYPE_DEFAULT);
+ BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
@@ -9675,8 +9766,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
vrf_bgp = bgp_default;
else
/* Auto-create assuming the same AS */
- ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type);
-
+ ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
+ NULL, ASNOTATION_UNDEFINED);
if (ret) {
vty_out(vty,
"VRF %s is not configured as a bgp instance\n",
@@ -10144,7 +10235,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
/* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd,
- "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
+ "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
CLEAR_STR
IP_STR
BGP_STR
@@ -10157,7 +10248,7 @@ DEFUN (clear_ip_bgp_all,
"BGP IPv4 neighbor to clear\n"
"BGP IPv6 neighbor to clear\n"
"BGP neighbor on interface to clear\n"
- "Clear peers with the AS number\n"
+ "Clear peers with the AS number in plain or dotted format\n"
"Clear all external peers\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
@@ -10198,7 +10289,7 @@ DEFUN (clear_ip_bgp_all,
if (argv_find_and_parse_afi(argv, argc, &idx, &afi))
argv_find_and_parse_safi(argv, argc, &idx, &safi);
- /* <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group PGNAME> */
+ /* <*|A.B.C.D|X:X::X:X|WORD|ASNUM|external|peer-group PGNAME> */
if (argv_find(argv, argc, "*", &idx)) {
clr_sort = clear_all;
} else if (argv_find(argv, argc, "A.B.C.D", &idx)) {
@@ -10217,7 +10308,7 @@ DEFUN (clear_ip_bgp_all,
} else if (argv_find(argv, argc, "WORD", &idx)) {
clr_sort = clear_peer;
clr_arg = argv[idx]->arg;
- } else if (argv_find(argv, argc, "(1-4294967295)", &idx)) {
+ } else if (argv_find(argv, argc, "ASNUM", &idx)) {
clr_sort = clear_as;
clr_arg = argv[idx]->arg;
} else if (argv_find(argv, argc, "external", &idx)) {
@@ -10355,8 +10446,8 @@ DEFUN (show_bgp_views,
/* Skip VRFs. */
if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
continue;
- vty_out(vty, "\t%s (AS%u)\n", bgp->name ? bgp->name : "(null)",
- bgp->as);
+ vty_out(vty, "\t%s (AS%s)\n", bgp->name ? bgp->name : "(null)",
+ bgp->as_pretty);
}
return CMD_SUCCESS;
@@ -11142,7 +11233,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_string_addf(json, "routerId",
"%pI4",
&bgp->router_id);
- json_object_int_add(json, "as", bgp->as);
+ asn_asn2json(json, "as", bgp->as,
+ bgp->asnotation);
json_object_int_add(json, "vrfId", vrf_id_ui);
json_object_string_add(
json, "vrfName",
@@ -11152,8 +11244,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
: bgp->name);
} else {
vty_out(vty,
- "BGP router identifier %pI4, local AS number %u vrf-id %d",
- &bgp->router_id, bgp->as,
+ "BGP router identifier %pI4, local AS number %s vrf-id %d",
+ &bgp->router_id, bgp->as_pretty,
bgp->vrf_id == VRF_UNKNOWN
? -1
: (int)bgp->vrf_id);
@@ -11387,12 +11479,13 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_string_add(json_peer, "domainname",
peer->domainname);
- json_object_int_add(json_peer, "remoteAs", peer->as);
- json_object_int_add(
- json_peer, "localAs",
- peer->change_local_as
- ? peer->change_local_as
- : peer->local_as);
+ asn_asn2json(json_peer, "remoteAs", peer->as,
+ bgp->asnotation);
+ asn_asn2json(json_peer, "localAs",
+ peer->change_local_as
+ ? peer->change_local_as
+ : peer->local_as,
+ bgp->asnotation);
json_object_int_add(json_peer, "version", 4);
json_object_int_add(json_peer, "msgRcvd",
PEER_TOTAL_RX(peer));
@@ -11572,14 +11665,19 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
&peer->ibuf->count,
memory_order_relaxed);
- if (show_wide)
+ vty_out(vty, "4 ");
+ vty_out(vty, ASN_FORMAT_SPACE(bgp->asnotation),
+ &peer->as);
+ if (show_wide) {
vty_out(vty,
- "4 %10u %10u %9u %9u %8" PRIu64
- " %4zu %4zu %8s",
- peer->as,
+ ASN_FORMAT_SPACE(
+ bgp->asnotation),
peer->change_local_as
- ? peer->change_local_as
- : peer->local_as,
+ ? &peer->change_local_as
+ : &peer->local_as);
+ vty_out(vty,
+ " %9u %9u %8" PRIu64
+ " %4zu %4zu %8s",
PEER_TOTAL_RX(peer),
PEER_TOTAL_TX(peer),
peer->version[afi][safi],
@@ -11588,10 +11686,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
timebuf,
BGP_UPTIME_LEN, 0,
NULL));
- else
- vty_out(vty, "4 %10u %9u %9u %8" PRIu64
- " %4zu %4zu %8s",
- peer->as, PEER_TOTAL_RX(peer),
+ } else {
+ vty_out(vty,
+ " %9u %9u %8" PRIu64
+ " %4zu %4zu %8s",
+ PEER_TOTAL_RX(peer),
PEER_TOTAL_TX(peer),
peer->version[afi][safi],
inq_count, outq_count,
@@ -11599,7 +11698,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
timebuf,
BGP_UPTIME_LEN, 0,
NULL));
-
+ }
if (peer_established(peer)) {
if (peer->afc_recv[afi][safi]) {
if (CHECK_FLAG(
@@ -11892,7 +11991,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
" [" BGP_SAFI_WITH_LABEL_CMD_STR
- "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [json$uj]",
+ "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <ASNUM|internal|external>>] [terse] [wide] [json$uj]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display the entries for all address families\n"
@@ -11903,8 +12002,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
"Neighbor to display information about\n"
"Neighbor to display information about\n"
"Neighbor on BGP configured interface\n"
- "Show only the specified remote AS sessions\n"
- "AS number\n"
+ "Show only the specified remote AS sessions\n" AS_STR
"Internal (iBGP) AS sessions\n"
"External (eBGP) AS sessions\n"
"Shorten the information on BGP instances\n"
@@ -11946,8 +12044,12 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
as_type = AS_INTERNAL;
else if (argv[idx + 1]->arg[0] == 'e')
as_type = AS_EXTERNAL;
- else
- as = (as_t)atoi(argv[idx + 1]->arg);
+ else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
+ vty_out(vty,
+ "%% Invalid neighbor remote-as value: %s\n",
+ argv[idx + 1]->arg);
+ return CMD_SUCCESS;
+ }
}
if (argv_find(argv, argc, "terse", &idx))
@@ -13082,13 +13184,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_string_addf(json_neigh, "bgpNeighborAddr",
"%pSU", &p->su);
- json_object_int_add(json_neigh, "remoteAs", p->as);
+ asn_asn2json(json_neigh, "remoteAs", p->as, bgp->asnotation);
if (p->change_local_as)
- json_object_int_add(json_neigh, "localAs",
- p->change_local_as);
+ asn_asn2json(json_neigh, "localAs", p->change_local_as,
+ bgp->asnotation);
else
- json_object_int_add(json_neigh, "localAs", p->local_as);
+ asn_asn2json(json_neigh, "localAs", p->local_as,
+ bgp->asnotation);
if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
json_object_boolean_true_add(json_neigh,
@@ -13098,13 +13201,19 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object_boolean_true_add(json_neigh,
"localAsReplaceAs");
} else {
- if ((p->as_type == AS_SPECIFIED) || (p->as_type == AS_EXTERNAL)
- || (p->as_type == AS_INTERNAL))
- vty_out(vty, "remote AS %u, ", p->as);
- else
+ if ((p->as_type == AS_SPECIFIED) ||
+ (p->as_type == AS_EXTERNAL) ||
+ (p->as_type == AS_INTERNAL)) {
+ vty_out(vty, "remote AS ");
+ vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as);
+ vty_out(vty, ", ");
+ } else
vty_out(vty, "remote AS Unspecified, ");
- vty_out(vty, "local AS %u%s%s, ",
- p->change_local_as ? p->change_local_as : p->local_as,
+ vty_out(vty, "local AS ");
+ vty_out(vty, ASN_FORMAT(bgp->asnotation),
+ p->change_local_as ? &p->change_local_as
+ : &p->local_as);
+ vty_out(vty, "%s%s, ",
CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
? " no-prepend"
: "",
@@ -15577,10 +15686,9 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
json_object_new_string(vname));
json_object_object_add(json, "exportToVrfs",
json_export_vrfs);
- json_object_string_addf(json, "routeDistinguisher",
- "%pRD",
- &bgp->vpn_policy[afi].tovpn_rd);
-
+ json_object_string_addf(
+ json, "routeDistinguisher", "%s",
+ bgp->vpn_policy[afi].tovpn_rd_pretty);
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
ecom_str = ecommunity_ecom2str(
@@ -15648,8 +15756,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
node, vname))
vty_out(vty, " %s\n", vname);
- vty_out(vty, "RD: %pRD\n",
+ vty_out(vty, "RD: ");
+ vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
&bgp->vpn_policy[afi].tovpn_rd);
+ vty_out(vty, "\n");
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
@@ -16014,18 +16124,22 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
if (json)
- json_object_int_add(json_peer_group, "remoteAs",
- conf->as);
- else
- vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
- group->name, conf->as);
+ asn_asn2json(json_peer_group, "remoteAs", conf->as,
+ bgp_get_asnotation(conf->bgp));
+ else {
+ vty_out(vty, "\nBGP peer-group %s, remote AS ",
+ group->name);
+ vty_out(vty, ASN_FORMAT(bgp_get_asnotation(conf->bgp)),
+ &conf->as);
+ vty_out(vty, "\n");
+ }
} else if (conf->as_type == AS_INTERNAL) {
if (json)
- json_object_int_add(json_peer_group, "remoteAs",
- group->bgp->as);
+ asn_asn2json(json, "remoteAs", group->bgp->as,
+ group->bgp->asnotation);
else
- vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
- group->name, group->bgp->as);
+ vty_out(vty, "\nBGP peer-group %s, remote AS %s\n",
+ group->name, group->bgp->as_pretty);
} else {
if (!json)
vty_out(vty, "\nBGP peer-group %s\n", group->name);
@@ -17148,8 +17262,8 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
}
if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET))
- vty_out(vty, "%*srd vpn export %pRD\n", indent, "",
- &bgp->vpn_policy[afi].tovpn_rd);
+ vty_out(vty, "%*srd vpn export %s\n", indent, "",
+ bgp->vpn_policy[afi].tovpn_rd_pretty);
if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
@@ -17319,7 +17433,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " peer-group %s", peer->group->name);
if_pg_printed = true;
} else if (peer->as_type == AS_SPECIFIED) {
- vty_out(vty, " remote-as %u", peer->as);
+ vty_out(vty, " remote-as %s", peer->as_pretty);
if_ras_printed = true;
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty, " remote-as internal");
@@ -17339,8 +17453,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) {
if (peer->as_type == AS_SPECIFIED) {
- vty_out(vty, " neighbor %s remote-as %u\n",
- addr, peer->as);
+ vty_out(vty, " neighbor %s remote-as %s\n",
+ addr, peer->as_pretty);
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty,
" neighbor %s remote-as internal\n",
@@ -17368,8 +17482,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (!if_ras_printed) {
if (peer->as_type == AS_SPECIFIED) {
- vty_out(vty, " neighbor %s remote-as %u\n",
- addr, peer->as);
+ vty_out(vty, " neighbor %s remote-as %s\n",
+ addr, peer->as_pretty);
} else if (peer->as_type == AS_INTERNAL) {
vty_out(vty,
" neighbor %s remote-as internal\n",
@@ -17384,8 +17498,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
/* local-as */
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) {
- vty_out(vty, " neighbor %s local-as %u", addr,
- peer->change_local_as);
+ vty_out(vty, " neighbor %s local-as %s", addr,
+ peer->change_local_as_pretty);
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND))
vty_out(vty, " no-prepend");
if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS))
@@ -18066,12 +18180,16 @@ int bgp_config_write(struct vty *vty)
continue;
/* Router bgp ASN */
- vty_out(vty, "router bgp %u", bgp->as);
+ vty_out(vty, "router bgp %s", bgp->as_pretty);
if (bgp->name)
vty_out(vty, " %s %s",
(bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
? "view" : "vrf", bgp->name);
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION))
+ vty_out(vty, " as-notation %s",
+ asn_mode2str(bgp->asnotation));
+
vty_out(vty, "\n");
/* BGP fast-external-failover. */
@@ -18189,8 +18307,8 @@ int bgp_config_write(struct vty *vty)
/* Confederation identifier*/
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
- vty_out(vty, " bgp confederation identifier %u\n",
- bgp->confed_id);
+ vty_out(vty, " bgp confederation identifier %s\n",
+ bgp->confed_id_pretty);
/* Confederation peer */
if (bgp->confed_peers_cnt > 0) {
@@ -18199,7 +18317,8 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, " bgp confederation peers");
for (i = 0; i < bgp->confed_peers_cnt; i++)
- vty_out(vty, " %u", bgp->confed_peers[i]);
+ vty_out(vty, " %s",
+ bgp->confed_peers[i].as_pretty);
vty_out(vty, "\n");
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 56485035e8..826723b92d 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -28,6 +28,9 @@ struct bgp;
BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR \
BGP_AF_MODIFIER_STR BGP_AF_MODIFIER_STR
+#define BGP_SELF_ORIG_CMD_STR "self-originate"
+#define BGP_SELF_ORIG_HELP_STR "Display only self-originated routes\n"
+
#define SHOW_GR_HEADER \
"Codes: GR - Graceful Restart," \
" * - Inheriting Global GR Config,\n" \
@@ -135,7 +138,8 @@ extern void bgp_vty_init(void);
extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
- enum bgp_instance_type inst_type);
+ enum bgp_instance_type inst_type, const char *as_pretty,
+ enum asnotation_mode asnotation);
extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp);
extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9ea5a92adc..0fd0dafa22 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -553,7 +553,7 @@ void bgp_tcp_keepalive_unset(struct bgp *bgp)
}
/* BGP confederation configuration. */
-void bgp_confederation_id_set(struct bgp *bgp, as_t as)
+void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str)
{
struct peer *peer;
struct listnode *node, *nnode;
@@ -565,6 +565,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as)
/* Remember - were we doing confederation before? */
already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION);
bgp->confed_id = as;
+ if (bgp->confed_id_pretty)
+ XFREE(MTYPE_BGP, bgp->confed_id_pretty);
+ bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str);
bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION);
/* If we were doing confederation already, this is just an external
@@ -617,6 +620,7 @@ void bgp_confederation_id_unset(struct bgp *bgp)
struct listnode *node, *nnode;
bgp->confed_id = 0;
+ XFREE(MTYPE_BGP, bgp->confed_id_pretty);
bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
@@ -644,14 +648,14 @@ bool bgp_confederation_peers_check(struct bgp *bgp, as_t as)
return false;
for (i = 0; i < bgp->confed_peers_cnt; i++)
- if (bgp->confed_peers[i] == as)
+ if (bgp->confed_peers[i].as == as)
return true;
return false;
}
/* Add an AS to the confederation set. */
-void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
+void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str)
{
struct peer *peer;
struct listnode *node, *nnode;
@@ -662,11 +666,13 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
if (bgp_confederation_peers_check(bgp, as))
return;
- bgp->confed_peers =
- XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
- (bgp->confed_peers_cnt + 1) * sizeof(as_t));
+ bgp->confed_peers = XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+ (bgp->confed_peers_cnt + 1) *
+ sizeof(struct as_confed));
- bgp->confed_peers[bgp->confed_peers_cnt] = as;
+ bgp->confed_peers[bgp->confed_peers_cnt].as = as;
+ bgp->confed_peers[bgp->confed_peers_cnt].as_pretty =
+ XSTRDUP(MTYPE_BGP, as_str);
bgp->confed_peers_cnt++;
if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
@@ -703,9 +709,15 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
return;
for (i = 0; i < bgp->confed_peers_cnt; i++)
- if (bgp->confed_peers[i] == as)
- for (j = i + 1; j < bgp->confed_peers_cnt; j++)
- bgp->confed_peers[j - 1] = bgp->confed_peers[j];
+ if (bgp->confed_peers[i].as == as) {
+ XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty);
+ for (j = i + 1; j < bgp->confed_peers_cnt; j++) {
+ bgp->confed_peers[j - 1].as =
+ bgp->confed_peers[j].as;
+ bgp->confed_peers[j - 1].as_pretty =
+ bgp->confed_peers[j].as_pretty;
+ }
+ }
bgp->confed_peers_cnt--;
@@ -714,9 +726,9 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
bgp->confed_peers = NULL;
} else
- bgp->confed_peers =
- XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
- bgp->confed_peers_cnt * sizeof(as_t));
+ bgp->confed_peers = XREALLOC(
+ MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+ bgp->confed_peers_cnt * sizeof(struct as_confed));
/* Now reset any peer who's remote AS has just been removed from the
CONFED */
@@ -1172,6 +1184,11 @@ static void peer_free(struct peer *peer)
FOREACH_AFI_SAFI (afi, safi)
bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
+ if (peer->change_local_as_pretty)
+ XFREE(MTYPE_BGP, peer->change_local_as_pretty);
+ if (peer->as_pretty)
+ XFREE(MTYPE_BGP, peer->as_pretty);
+
bgp_unlock(peer->bgp);
memset(peer, 0, sizeof(struct peer));
@@ -1753,7 +1770,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
struct peer *peer_create(union sockunion *su, const char *conf_if,
struct bgp *bgp, as_t local_as, as_t remote_as,
int as_type, struct peer_group *group,
- bool config_node)
+ bool config_node, const char *as_str)
{
int active;
struct peer *peer;
@@ -1778,6 +1795,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
}
peer->local_as = local_as;
peer->as = remote_as;
+ /* internal and external values do not use as_pretty */
+ if (as_str && asn_str2asn(as_str, NULL))
+ peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
peer->as_type = as_type;
peer->local_id = bgp->router_id;
peer->v_holdtime = bgp->default_holdtime;
@@ -1881,7 +1901,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
}
/* Change peer's AS number. */
-void peer_as_change(struct peer *peer, as_t as, int as_specified)
+void peer_as_change(struct peer *peer, as_t as, int as_specified,
+ const char *as_str)
{
enum bgp_peer_sort origtype, newtype;
@@ -1896,6 +1917,12 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
}
origtype = peer_sort_lookup(peer);
peer->as = as;
+ if (as_specified == AS_SPECIFIED && as_str) {
+ if (peer->as_pretty)
+ XFREE(MTYPE_BGP, peer->as_pretty);
+ peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
+ } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty)
+ XFREE(MTYPE_BGP, peer->as_pretty);
peer->as_type = as_specified;
if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
@@ -1953,7 +1980,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
- as_t *as, int as_type)
+ as_t *as, int as_type, const char *as_str)
{
struct peer *peer;
as_t local_as;
@@ -2007,22 +2034,22 @@ 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;
/* If the peer is not part of our confederation, and its not an
iBGP peer then spoof the source AS */
- if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)
- && !bgp_confederation_peers_check(bgp, *as)
- && bgp->as != *as)
+ if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) &&
+ !bgp_confederation_peers_check(bgp, *as) && *as &&
+ bgp->as != *as)
local_as = bgp->confed_id;
else
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;
@@ -4583,6 +4636,9 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg)
/* Disable global administrative shutdown of all peers of BGP instance */
void bgp_shutdown_disable(struct bgp *bgp)
{
+ const struct listnode *node;
+ struct peer *peer;
+
/* do nothing if not shut down. */
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
return;
@@ -4593,6 +4649,9 @@ void bgp_shutdown_disable(struct bgp *bgp)
/* clear the BGP instances shutdown flag */
UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN);
+
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+ bgp_timer_set(peer);
}
/* Change specified peer flag. */
@@ -6228,7 +6287,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 +6312,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 +6348,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 +6376,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 +6407,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 +8091,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 +8104,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
if (bgp2 != bgp)
continue;
- snprintf(buf, sizeof(buf), "%u", bgp->as);
+ snprintf(buf, sizeof(buf), "%s", bgp->as_pretty);
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, buf));
}
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index b5faa4d353..2a7c7a3143 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -16,6 +16,7 @@
#include "vty.h"
#include "srv6.h"
#include "iana_afi.h"
+#include "asn.h"
/* For union sockunion. */
#include "queue.h"
@@ -62,7 +63,6 @@ enum zebra_gr_mode {
};
/* Typedef BGP specific types. */
-typedef uint32_t as_t;
typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
typedef uint16_t bgp_size_t;
@@ -203,6 +203,7 @@ struct vpn_policy {
/* should be mpls_label_t? */
uint32_t tovpn_label; /* may be MPLS_LABEL_NONE */
uint32_t tovpn_zebra_vrf_label_last_sent;
+ char *tovpn_rd_pretty;
struct prefix_rd tovpn_rd;
struct prefix tovpn_nexthop; /* unset => set to 0 */
uint32_t flags;
@@ -324,10 +325,16 @@ struct bgp_srv6_function {
char locator_name[SRV6_LOCNAME_SIZE];
};
+struct as_confed {
+ as_t as;
+ char *as_pretty;
+};
+
/* BGP instance structure. */
struct bgp {
/* AS number of this BGP instance. */
as_t as;
+ char *as_pretty;
/* Name of this BGP instance. */
char *name;
@@ -383,6 +390,7 @@ struct bgp {
uint16_t config;
#define BGP_CONFIG_CLUSTER_ID (1 << 0)
#define BGP_CONFIG_CONFEDERATION (1 << 1)
+#define BGP_CONFIG_ASNOTATION (1 << 2)
/* BGP router identifier. */
struct in_addr router_id;
@@ -394,7 +402,8 @@ struct bgp {
/* BGP confederation information. */
as_t confed_id;
- as_t *confed_peers;
+ char *confed_id_pretty;
+ struct as_confed *confed_peers;
int confed_peers_cnt;
struct thread
@@ -728,6 +737,7 @@ struct bgp {
/* RD for this VRF */
struct prefix_rd vrf_prd;
+ char *vrf_prd_pretty;
/* import rt list for the vrf instance */
struct list *vrf_import_rtl;
@@ -782,6 +792,8 @@ struct bgp {
bool allow_martian;
+ enum asnotation_mode asnotation;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@@ -1105,6 +1117,8 @@ struct peer {
/* Peer's remote AS number. */
int as_type;
as_t as;
+ /* for vty as format */
+ char *as_pretty;
/* Peer's local AS number. */
as_t local_as;
@@ -1113,6 +1127,8 @@ struct peer {
/* Peer's Change local AS number. */
as_t change_local_as;
+ /* for vty as format */
+ char *change_local_as_pretty;
/* Remote router ID. */
struct in_addr remote_id;
@@ -1270,7 +1286,7 @@ struct peer {
* so if a flag is unset, the corresponding override flag is unset too.
* However if a flag is set, the corresponding override flag is set.
*/
- uint32_t flags_override;
+ uint64_t flags_override;
/*
* Parallel array to flags that indicates whether the default behavior
* of *flags_override* should be inverted. If a flag is unset and the
@@ -1308,11 +1324,13 @@ struct peer {
* inversion state of the flag differs between peer and peer-group, the
* newly set value must equal to the inverted state of the peer-group.
*/
- uint32_t flags_invert;
+ uint64_t flags_invert;
/*
* Effective array for storing the peer/peer-group flags. In case of a
* peer-group, the peer-specific overrides (see flags_override and
* flags_invert) must be respected.
+ * When changing the structure of flags/af_flags, do not forget to
+ * change flags_invert/flags_override too.
*/
uint64_t flags;
#define PEER_FLAG_PASSIVE (1ULL << 0) /* passive mode */
@@ -2129,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,
@@ -2156,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 *);
@@ -2172,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,
@@ -2197,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 *);
@@ -2279,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,
@@ -2339,6 +2364,7 @@ extern void peer_tx_shutdown_message_unset(struct peer *);
extern void bgp_route_map_update_timer(struct thread *thread);
extern const char *bgp_get_name_by_role(uint8_t role);
+extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp);
extern void bgp_route_map_terminate(void);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 40cb8f8d5a..5b6961d18a 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -410,6 +410,7 @@ DEFUN (vnc_defaults_rd,
} else {
+ /* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@@ -2874,6 +2875,7 @@ DEFUN (vnc_nve_group_rd,
} else {
+ /* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@@ -3346,6 +3348,7 @@ DEFUN (vnc_vrf_policy_rd,
} else {
+ /* TODO: save RD format */
ret = str2prefix_rd(argv[1]->arg, &prd);
if (!ret) {
vty_out(vty, "%% Malformed rd\n");
@@ -3924,7 +3927,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %pRD\n", &rfg->rd);
+ vty_out(vty, " rd %pRDP\n", &rfg->rd);
}
if (rfg->rt_import_list && rfg->rt_export_list
@@ -4144,7 +4147,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %pRD\n",
+ vty_out(vty, " rd %pRDP\n",
&hc->default_rd);
}
if (hc->default_response_lifetime
@@ -4224,7 +4227,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %pRD\n",
+ vty_out(vty, " rd %pRDP\n",
&rfg->rd);
}
if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) {
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 0c8fdc72e0..8d6db9d775 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -363,7 +363,7 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
vnc_zlog_debug_verbose(
- "%s: peer=%p, prefix=%pFX, prd=%pRD afi=%d, safi=%d bn=%p, bn->info=%p",
+ "%s: peer=%p, prefix=%pFX, prd=%pRDP afi=%d, safi=%d bn=%p, bn->info=%p",
__func__, peer, p, prd, afi, safi, bn,
(bn ? bgp_dest_get_bgp_path_info(bn) : NULL));
@@ -1053,7 +1053,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
bgp_process(bgp, bn, afi, safi);
vnc_zlog_debug_any(
- "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRD)",
+ "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)",
__func__, safi2str(safi), buf, bn, prd);
done:
@@ -3712,7 +3712,7 @@ int rfapi_set_autord_from_vn(struct prefix_rd *rd, struct rfapi_ip_addr *vn)
memcpy(rd->val + 2, &vn->addr.v6.s6_addr32[3],
4); /* low order 4 bytes */
}
- vnc_zlog_debug_verbose("%s: auto-RD is set to %pRD", __func__, rd);
+ vnc_zlog_debug_verbose("%s: auto-RD is set to %pRDP", __func__, rd);
return 0;
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 6d4fc53f83..5c68545398 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2082,7 +2082,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
assert(bpi);
assert(bpi->extra);
- vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
+ vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX_W_ALLOC(rn);
@@ -2120,7 +2120,9 @@ static void rfapiItBiIndexDump(struct agg_node *rn)
char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
- prefix_rd2str(&k->extra->vnc.import.rd, buf, sizeof(buf));
+ prefix_rd2str(
+ &k->extra->vnc.import.rd, buf, sizeof(buf),
+ bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
if (k->extra->vnc.import.aux_prefix.family) {
prefix2str(&k->extra->vnc.import.aux_prefix,
buf_aux_pfx, sizeof(buf_aux_pfx));
@@ -2158,7 +2160,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
vnc_zlog_debug_verbose(
- "%s want prd=%pRD, peer=%p, aux_prefix=%s", __func__,
+ "%s want prd=%pRDP, peer=%p, aux_prefix=%s", __func__,
prd, peer, buf_aux_pfx);
rfapiItBiIndexDump(rn);
}
@@ -2174,7 +2176,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
bpi_result = bpi_result->next) {
#ifdef DEBUG_BI_SEARCH
vnc_zlog_debug_verbose(
- "%s: bpi has prd=%pRD, peer=%p", __func__,
+ "%s: bpi has prd=%pRDP, peer=%p", __func__,
&bpi_result->extra->vnc.import.rd,
bpi_result->peer);
#endif
@@ -2238,7 +2240,7 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
struct skiplist *sl;
int rc;
- vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
+ vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX(rn);
@@ -2335,8 +2337,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
}
/*
- * quagga lib/thread.h says this must return int even though
- * it doesn't do anything with the return value
+ * Timer callback for withdraw
*/
static void rfapiWithdrawTimerVPN(struct thread *t)
{
@@ -2346,19 +2347,27 @@ static void rfapiWithdrawTimerVPN(struct thread *t)
const struct prefix *p;
struct rfapi_monitor_vpn *moved;
afi_t afi;
+ bool early_exit = false;
if (bgp == NULL) {
vnc_zlog_debug_verbose(
"%s: NULL BGP pointer, assume shutdown race condition!!!",
__func__);
- return;
+ early_exit = true;
}
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
+ if (bgp && CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
vnc_zlog_debug_verbose(
"%s: BGP delete in progress, assume shutdown race condition!!!",
__func__);
+ early_exit = true;
+ }
+
+ /* This callback is responsible for the withdraw object's memory */
+ if (early_exit) {
+ XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
return;
}
+
assert(wcb->node);
assert(bpi);
assert(wcb->import_table);
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index b15620741b..f727f24f1d 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -1114,7 +1114,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
skiplist_insert(slRibPt, &ori->rk, ori);
vnc_zlog_debug_verbose(
- "%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRD)",
+ "%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRDP)",
__func__, ri, &ori->rk.rd);
}
@@ -1356,7 +1356,7 @@ callback:
ri->last_sent_time = monotime(NULL);
#if DEBUG_RIB_SL_RD
vnc_zlog_debug_verbose(
- "%s: move route to recently deleted list, rd=%pRD",
+ "%s: move route to recently deleted list, rd=%pRDP",
__func__, &ri->rk.rd);
#endif
@@ -2252,7 +2252,7 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
}
#endif
- fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRD\n",
+ fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRDP\n",
deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn,
str_un, ri->cost, str_lifetime, str_age, &ri->rk.rd);
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 0144c28d58..2b768b8f8d 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -1589,7 +1589,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
vty_out(vty, " ");
rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr);
vty_out(vty, " %p %p ", rfd->response_cb, rfd->cookie);
- vty_out(vty, "%pRD", &rfd->rd);
+ vty_out(vty, "%pRDP", &rfd->rd);
vty_out(vty, " %d", rfd->response_lifetime);
vty_out(vty, " %s", (rfd->rfg ? rfd->rfg->name : "<orphaned>"));
vty_out(vty, "%s", HVTYNL);
@@ -4709,6 +4709,7 @@ static int vnc_add_vrf_prefix(struct vty *vty, const char *arg_vrf,
if (arg_rd) {
opt = &optary[cur_opt++];
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+ /* TODO: save RD format */
if (!str2prefix_rd(arg_rd, &opt->v.internal_rd)) {
vty_out(vty, "Malformed RD \"%s\"\n", arg_rd);
return CMD_WARNING_CONFIG_FAILED;
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index e7cc278df0..5449220448 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -386,7 +386,6 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn,
* withdraw the route
*/
bgp_withdraw(bpi->peer, p, 0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */
@@ -478,7 +477,6 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
bgp_withdraw(
ri->peer, bgp_dest_get_prefix(dest),
0, /* addpath_id */
- NULL, /* ignored */
AFI_IP, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -863,7 +861,6 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
bgp_withdraw(irfd->peer, p, /* prefix */
0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
@@ -893,7 +890,6 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
bgp_withdraw(irfd->peer, p, /* prefix */
0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
@@ -1130,7 +1126,6 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
bgp_withdraw(irfd->peer, p, /* prefix */
0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -1362,7 +1357,6 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), /* prefix */
0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, 0, NULL); /* tag not used for unicast */
@@ -1481,7 +1475,6 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt,
bgp_withdraw(irfd->peer,
agg_node_get_prefix(rn),
0, /* addpath_id */
- NULL, /* attr, ignored */
afi, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
@@ -1720,7 +1713,6 @@ static void vncExportWithdrawTimer(struct thread *t)
* withdraw the route
*/
bgp_withdraw(eti->peer, p, 0, /* addpath_id */
- NULL, /* attr, ignored */
family2afi(p->family), SAFI_UNICAST, eti->type,
eti->subtype, NULL, /* RD not used for unicast */
NULL, 0,
@@ -2005,7 +1997,6 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
bgp_withdraw(ri->peer, dest_p, /* prefix */
0, /* addpath_id */
- NULL, /* ignored */
AFI_IP, SAFI_UNICAST,
ZEBRA_ROUTE_VNC_DIRECT_RH,
BGP_ROUTE_REDISTRIBUTE,
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index 5d1dda06df..2a08531bd7 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -151,6 +151,7 @@ by the parser.
: RANGE
: MAC
: MAC_PREFIX
+ : ASNUM
selector: "<" `selector_seq_seq` ">" `varname_token`
: "{" `selector_seq_seq` "}" `varname_token`
: "[" `selector_seq_seq` "]" `varname_token`
@@ -176,27 +177,29 @@ parser, but this is merely a dumb copy job.
Here is a brief summary of the various token types along with examples.
-+-----------------+-------------------+-------------------------------------------------------------+
-| Token type | Syntax | Description |
-+=================+===================+=============================================================+
-| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
-+-----------------+-------------------+-------------------------------------------------------------+
++-----------------+-------------------------+-------------------------------------------------------+
+| Token type | Syntax | Description |
++=================+=========================+=======================================================+
+| ``WORD`` | ``show ip bgp`` | Matches itself. In the example every token is a WORD. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``ASNUM`` | ``<A.B|(1-4294967295>`` | Matches an AS in plain or dot format. |
++-----------------+-------------------------+-------------------------------------------------------+
When presented with user input, the parser will search over all defined
commands in the current context to find a match. It is aware of the various
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index c5319a8e88..1798f1ad2a 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -254,8 +254,9 @@ ASN and Router ID
-----------------
First of all you must configure BGP router with the :clicmd:`router bgp ASN`
-command. The AS number is an identifier for the autonomous system. The BGP
-protocol uses the AS number for detecting whether the BGP connection is
+command. The AS number is an identifier for the autonomous system. The AS
+identifier can either be a number or two numbers separated by a period. The
+BGP protocol uses the AS identifier for detecting whether the BGP connection is
internal or external.
.. clicmd:: router bgp ASN
@@ -2113,9 +2114,6 @@ is 4 octet long. The following format is used to define the community value.
``7675:80`` can be used when AS 7675 wants to pass local policy value 80 to
neighboring peer.
-``internet``
- ``internet`` represents well-known communities value 0.
-
``graceful-shutdown``
``graceful-shutdown`` represents well-known communities value
``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
@@ -2486,17 +2484,6 @@ community-list.
match community FILTER
-The communities value keyword ``internet`` has special meanings in standard
-community lists. In the below example ``internet`` matches all BGP routes even
-if the route does not have communities attribute at all. So community list
-``INTERNET`` is the same as ``FILTER`` in the previous example.
-
-.. code-block:: frr
-
- bgp community-list standard INTERNET deny 1:1
- bgp community-list standard INTERNET permit internet
-
-
The following configuration is an example of communities value deletion. With
this configuration the community values ``100:1`` and ``100:2`` are removed
from BGP updates. For communities value deletion, only ``permit``
@@ -2566,9 +2553,6 @@ Extended Community Lists
there is no matched entry, deny will be returned. When `extcommunity` is
empty it matches to any routes.
- A special handling for ``internet`` community is applied. It matches
- any community.
-
.. clicmd:: bgp extcommunity-list expanded NAME permit|deny LINE
This command defines a new expanded extcommunity-list. `line` is a string
@@ -3899,6 +3883,10 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
EVPN prefixes can also be filtered by EVPN route type.
+.. clicmd:: show bgp l2vpn evpn route [detail] [type <ead|1|macip|2|multicast|3|es|4|prefix|5>] self-originate [json]
+
+ Display self-originated EVPN prefixes which can also be filtered by EVPN route type.
+
.. clicmd:: show bgp vni <all|VNI> [vtep VTEP] [type <ead|1|macip|2|multicast|3>] [<detail|json>]
Display per-VNI EVPN routing table in bgp. Filter route-type, vtep, or VNI.
@@ -4055,6 +4043,15 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
If the ``json`` option is specified, output is displayed in JSON format.
+.. clicmd:: show [ip] bgp [afi] [safi] [all] self-originate [wide|json]
+
+ Display self-originated routes.
+
+ If ``wide`` option is specified, then the prefix table's width is increased
+ to fully display the prefix and the nexthop.
+
+ If the ``json`` option is specified, output is displayed in JSON format.
+
.. clicmd:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [<A.B.C.D/M|X:X::X:X/M> | detail] [json|wide]
Display the routes advertised to a BGP neighbor or received routes
@@ -4301,6 +4298,26 @@ Segment-Routing IPv6
vpn_policy[AFI_IP].tovpn_sid: none
vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::200
+AS-notation support
+-------------------
+
+By default, the ASN value output follows how the BGP ASN instance is
+expressed in the configuration. Three as-notation outputs are available:
+
+- plain output: both AS4B and AS2B use a single number.
+ ` router bgp 65536`.
+
+- dot output: AS4B values are using two numbers separated by a period.
+ `router bgp 1.1` means that the AS number is 65536.
+
+- dot+ output: AS2B and AS4B values are using two numbers separated by a
+ period. `router bgp 0.5` means that the AS number is 5.
+
+The below option permits forcing the as-notation output:
+
+.. clicmd:: router bgp ASN as-notation dot|dot+|plain
+
+ The chosen as-notation format will override the BGP ASN output.
.. _bgp-route-reflector:
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index b69230b99d..ce3648bf6d 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -794,13 +794,13 @@ Showing Information
.. clicmd:: show ip ospf neighbor [json]
-.. clicmd:: show ip ospf neighbor INTERFACE [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] neighbor INTERFACE [json]
.. clicmd:: show ip ospf neighbor detail [json]
-.. clicmd:: show ip ospf neighbor A.B.C.D [detail] [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] neighbor A.B.C.D [detail] [json]
-.. clicmd:: show ip ospf neighbor INTERFACE detail [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] neighbor INTERFACE detail [json]
Display lsa information of LSDB.
Json o/p of this command covers base route information
diff --git a/doc/user/ripd.rst b/doc/user/ripd.rst
index 5c60f4f4f1..67323e61f3 100644
--- a/doc/user/ripd.rst
+++ b/doc/user/ripd.rst
@@ -88,7 +88,7 @@ multipath routing.
RIP Configuration
=================
-.. clicmd:: router rip
+.. clicmd:: router rip [vrf NAME]
The `router rip` command is necessary to enable RIP. To disable RIP, use the
`no router rip` command. RIP must be enabled before carrying out any of the
@@ -149,13 +149,16 @@ RIP Configuration
The default is to be passive on all interfaces.
-.. clicmd:: ip split-horizon
+.. clicmd:: ip split-horizon [poisoned-reverse]
Control split-horizon on the interface. Default is `ip split-horizon`. If
you don't perform split-horizon on the interface, please specify `no ip
split-horizon`.
+ If `poisoned-reverse` is also set, the router sends the poisoned routes
+ with highest metric back to the sending router.
+
.. _rip-version-control:
RIP Version Control
@@ -174,8 +177,8 @@ discussion on the security implications of RIPv1 see :ref:`rip-authentication`.
.. clicmd:: version VERSION
- Set RIP version to accept for reads and send. ``VERSION`` can be either 1 or
- 1.
+ Set RIP version to accept for reads and send. VERSION can be either
+ ``1`` or ``2``.
Disabling RIPv1 by specifying version 2 is STRONGLY encouraged,
:ref:`rip-authentication`. This may become the default in a future release.
@@ -472,7 +475,7 @@ Show RIP Information
To display RIP routes.
-.. clicmd:: show ip rip
+.. clicmd:: show ip rip [vrf NAME]
Show RIP routes.
@@ -481,7 +484,7 @@ through RIP, this command will display the time the packet was sent and
the tag information. This command will also display this information
for routes redistributed into RIP.
-.. clicmd:: show ip rip status
+.. clicmd:: show ip rip [vrf NAME] status
The command displays current RIP status. It includes RIP timer,
filtering, version, RIP enabled interface and RIP peer information.
diff --git a/doc/user/ripngd.rst b/doc/user/ripngd.rst
index c7ca22bf95..df7a0e249e 100644
--- a/doc/user/ripngd.rst
+++ b/doc/user/ripngd.rst
@@ -22,14 +22,10 @@ ripngd Configuration
Currently ripngd supports the following commands:
-.. clicmd:: router ripng
+.. clicmd:: router ripng [vrf NAME]
Enable RIPng.
-.. clicmd:: flush_timer TIME
-
- Set flush timer.
-
.. clicmd:: network NETWORK
Set RIPng enabled interface by NETWORK.
@@ -48,7 +44,7 @@ Currently ripngd supports the following commands:
ripngd Terminal Mode Commands
=============================
-.. clicmd:: show ip ripng
+.. clicmd:: show ipv6 ripng [vrf NAME] status
.. clicmd:: show debugging ripng
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index e7e2e5d2ed..d7e768b710 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -974,7 +974,7 @@ unicast topology!
Unreachable routes do not receive special treatment and do not cause
fallback to a second lookup.
-.. clicmd:: show ip rpf ADDR
+.. clicmd:: show [ip|ipv6] rpf ADDR
Performs a Multicast RPF lookup, as configured with ``ip multicast
rpf-lookup-mode MODE``. ADDR specifies the multicast source address to look
@@ -984,7 +984,6 @@ unicast topology!
> show ip rpf 192.0.2.1
Routing entry for 192.0.2.0/24 using Unicast RIB
-
Known via "kernel", distance 0, metric 0, best
* 198.51.100.1, via eth0
@@ -992,7 +991,7 @@ unicast topology!
Indicates that a multicast source lookup for 192.0.2.1 would use an
Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1.
-.. clicmd:: show ip rpf
+.. clicmd:: show [ip|ipv6] rpf
Prints the entire Multicast RIB. Note that this is independent of the
configured RPF lookup mode, the Multicast RIB may be printed yet not
diff --git a/ldpd/address.c b/ldpd/address.c
index 45d1bb14b8..107eb5d780 100644
--- a/ldpd/address.c
+++ b/ldpd/address.c
@@ -72,12 +72,13 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
if ((buf = ibuf_open(size)) == NULL)
fatal(__func__);
- err |= gen_ldp_hdr(buf, size);
+ SET_FLAG(err, gen_ldp_hdr(buf, size));
size -= LDP_HDR_SIZE;
- err |= gen_msg_hdr(buf, msg_type, size);
+ SET_FLAG(err, gen_msg_hdr(buf, msg_type, size));
size -= LDP_MSG_SIZE;
- err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
+ SET_FLAG(err, gen_address_list_tlv(buf, af, addr_list, tlv_addr_count));
(void)size;
+
if (err) {
address_list_clr(addr_list);
ibuf_free(buf);
@@ -158,10 +159,12 @@ send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
err = gen_ldp_hdr(buf, size);
size -= LDP_HDR_SIZE;
- err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
- err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
- err |= gen_fec_tlv(buf, fec);
- err |= gen_mac_list_tlv(buf, mac);
+
+ SET_FLAG(err, gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size));
+ SET_FLAG(err, gen_address_list_tlv(buf, AF_INET, NULL, 0));
+ SET_FLAG(err, gen_fec_tlv(buf, fec));
+ SET_FLAG(err, gen_mac_list_tlv(buf, mac));
+
if (err) {
ibuf_free(buf);
return;
@@ -340,12 +343,14 @@ gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
}
alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
- err |= ibuf_add(buf, &alt, sizeof(alt));
+ SET_FLAG(err, ibuf_add(buf, &alt, sizeof(alt)));
+
if (addr_list == NULL)
return (err);
LIST_FOREACH(if_addr, addr_list, entry) {
- err |= ibuf_add(buf, &if_addr->addr, addr_size);
+ SET_FLAG(err, ibuf_add(buf, &if_addr->addr, addr_size));
+
if (--tlv_addr_count == 0)
break;
}
@@ -365,7 +370,7 @@ gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
tlv.length = htons(ETH_ALEN);
err = ibuf_add(buf, &tlv, sizeof(tlv));
if (mac)
- err |= ibuf_add(buf, mac, ETH_ALEN);
+ SET_FLAG(err, ibuf_add(buf, mac, ETH_ALEN));
return (err);
}
diff --git a/ldpd/lde.c b/ldpd/lde.c
index edd13fed35..325b33d057 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -261,8 +261,7 @@ static void lde_dispatch_imsg(struct thread *thread)
case IMSG_LABEL_MAPPING_FULL:
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
- log_debug("%s: cannot find lde neighbor",
- __func__);
+ log_debug("%s: cannot find lde neighbor", __func__);
break;
}
@@ -273,15 +272,13 @@ static void lde_dispatch_imsg(struct thread *thread)
case IMSG_LABEL_RELEASE:
case IMSG_LABEL_WITHDRAW:
case IMSG_LABEL_ABORT:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct map))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct map))
fatalx("lde_dispatch_imsg: wrong imsg len");
map = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
- log_debug("%s: cannot find lde neighbor",
- __func__);
+ log_debug("%s: cannot find lde neighbor", __func__);
break;
}
@@ -304,49 +301,45 @@ static void lde_dispatch_imsg(struct thread *thread)
}
break;
case IMSG_ADDRESS_ADD:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct lde_addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
lde_addr = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
- log_debug("%s: cannot find lde neighbor",
- __func__);
+ log_debug("%s: cannot find lde neighbor", __func__);
break;
}
+
if (lde_address_add(ln, lde_addr) < 0) {
log_debug("%s: cannot add address %s, it already exists", __func__,
log_addr(lde_addr->af, &lde_addr->addr));
}
break;
case IMSG_ADDRESS_DEL:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct lde_addr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_addr))
fatalx("lde_dispatch_imsg: wrong imsg len");
lde_addr = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
- log_debug("%s: cannot find lde neighbor",
- __func__);
+ log_debug("%s: cannot find lde neighbor", __func__);
break;
}
+
if (lde_address_del(ln, lde_addr) < 0) {
log_debug("%s: cannot delete address %s, it does not exist", __func__,
log_addr(lde_addr->af, &lde_addr->addr));
}
break;
case IMSG_NOTIFICATION:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct notify_msg))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct notify_msg))
fatalx("lde_dispatch_imsg: wrong imsg len");
nm = imsg.data;
ln = lde_nbr_find(imsg.hdr.peerid);
if (ln == NULL) {
- log_debug("%s: cannot find lde neighbor",
- __func__);
+ log_debug("%s: cannot find lde neighbor", __func__);
break;
}
@@ -366,8 +359,7 @@ static void lde_dispatch_imsg(struct thread *thread)
}
break;
case IMSG_NEIGHBOR_UP:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct lde_nbr))
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_nbr))
fatalx("lde_dispatch_imsg: wrong imsg len");
if (lde_nbr_find(imsg.hdr.peerid))
@@ -386,18 +378,15 @@ static void lde_dispatch_imsg(struct thread *thread)
case IMSG_CTL_SHOW_L2VPN_PW:
l2vpn_pw_ctl(imsg.hdr.pid);
- lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
- imsg.hdr.pid, NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_CTL_END, 0, imsg.hdr.pid, NULL, 0);
break;
case IMSG_CTL_SHOW_L2VPN_BINDING:
l2vpn_binding_ctl(imsg.hdr.pid);
- lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
- imsg.hdr.pid, NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_CTL_END, 0, imsg.hdr.pid, NULL, 0);
break;
default:
- log_debug("%s: unexpected imsg %d", __func__,
- imsg.hdr.type);
+ log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type);
break;
}
imsg_free(&imsg);
@@ -452,8 +441,7 @@ static void lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_IFSTATUS:
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct kif))
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kif))
fatalx("IFSTATUS imsg with wrong len");
kif = imsg.data;
@@ -481,18 +469,15 @@ static void lde_dispatch_parent(struct thread *thread)
}
break;
case IMSG_PW_UPDATE:
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct zapi_pw_status))
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct zapi_pw_status))
fatalx("PW_UPDATE imsg with wrong len");
if (l2vpn_pw_status_update(imsg.data) != 0)
- log_warnx("%s: error updating PW status",
- __func__);
+ log_warnx("%s: error updating PW status", __func__);
break;
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_UPDATE:
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct kroute)) {
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kroute)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
@@ -516,9 +501,8 @@ static void lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
lde_kernel_insert(&fec, kr->af, &kr->nexthop,
- kr->ifindex, kr->route_type,
- kr->route_instance,
- kr->flags & F_CONNECTED, NULL);
+ kr->ifindex, kr->route_type, kr->route_instance,
+ CHECK_FLAG(kr->flags, F_CONNECTED), NULL);
break;
case IMSG_NETWORK_UPDATE:
lde_kernel_update(&fec);
@@ -556,8 +540,7 @@ static void lde_dispatch_parent(struct thread *thread)
ldp_agentx_enabled();
break;
case IMSG_RECONF_CONF:
- if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
- NULL)
+ if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL)
fatal(NULL);
memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
@@ -681,8 +664,7 @@ static void lde_dispatch_parent(struct thread *thread)
}
break;
default:
- log_debug("%s: unexpected imsg %d", __func__,
- imsg.hdr.type);
+ log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type);
break;
}
imsg_free(&imsg);
@@ -708,7 +690,7 @@ static bool lde_fec_connected(const struct fec_node *fn)
struct fec_nh *fnh;
LIST_FOREACH(fnh, &fn->nexthops, entry)
- if (fnh->flags & F_FEC_NH_CONNECTED)
+ if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED))
return true;
return false;
@@ -719,7 +701,7 @@ static bool lde_fec_outside_mpls_network(const struct fec_node *fn)
struct fec_nh *fnh;
LIST_FOREACH(fnh, &fn->nexthops, entry)
- if (!(fnh->flags & F_FEC_NH_NO_LDP))
+ if (!CHECK_FLAG(fnh->flags, F_FEC_NH_NO_LDP))
return false;
return true;
@@ -732,18 +714,20 @@ lde_update_label(struct fec_node *fn)
/* should we allocate a label for this fec? */
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
- if ((ldeconf->ipv4.flags & F_LDPD_AF_ALLOCHOSTONLY)
+ if (CHECK_FLAG(ldeconf->ipv4.flags, F_LDPD_AF_ALLOCHOSTONLY)
&& fn->fec.u.ipv4.prefixlen != IPV4_MAX_BITLEN)
return (NO_LABEL);
+
if (lde_acl_check(ldeconf->ipv4.acl_label_allocate_for,
AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
return (NO_LABEL);
break;
case FEC_TYPE_IPV6:
- if ((ldeconf->ipv6.flags & F_LDPD_AF_ALLOCHOSTONLY)
+ if (CHECK_FLAG(ldeconf->ipv6.flags, F_LDPD_AF_ALLOCHOSTONLY)
&& fn->fec.u.ipv6.prefixlen != IPV6_MAX_BITLEN)
return (NO_LABEL);
+
if (lde_acl_check(ldeconf->ipv6.acl_label_allocate_for,
AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
@@ -764,16 +748,18 @@ lde_update_label(struct fec_node *fn)
/* choose implicit or explicit-null depending on configuration */
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
- if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL))
+ if (!CHECK_FLAG(ldeconf->ipv4.flags, F_LDPD_AF_EXPNULL))
return (MPLS_LABEL_IMPLICIT_NULL);
+
if (lde_acl_check(ldeconf->ipv4.acl_label_expnull_for,
AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
return (MPLS_LABEL_IMPLICIT_NULL);
return MPLS_LABEL_IPV4_EXPLICIT_NULL;
case FEC_TYPE_IPV6:
- if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL))
+ if (!CHECK_FLAG(ldeconf->ipv6.flags, F_LDPD_AF_EXPNULL))
return (MPLS_LABEL_IMPLICIT_NULL);
+
if (lde_acl_check(ldeconf->ipv6.acl_label_expnull_for,
AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
@@ -803,7 +789,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
* Ordered Control: don't program label into HW until a
* labelmap msg has been received from upstream router
*/
- if (fnh->flags & F_FEC_NH_DEFER)
+ if (CHECK_FLAG(fnh->flags, F_FEC_NH_DEFER))
return;
switch (fn->fec.type) {
@@ -818,8 +804,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.remote_label = fnh->remote_label;
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
- lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
- sizeof(kr));
+ lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr));
break;
case FEC_TYPE_IPV6:
memset(&kr, 0, sizeof(kr));
@@ -833,8 +818,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
- lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
- sizeof(kr));
+ lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr));
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
@@ -871,8 +855,7 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
- lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
- sizeof(kr));
+ lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr));
break;
case FEC_TYPE_IPV6:
memset(&kr, 0, sizeof(kr));
@@ -886,8 +869,7 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
- lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
- sizeof(kr));
+ lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr));
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
@@ -967,7 +949,7 @@ lde_fec2map(struct fec *fec, struct map *map)
map->type = MAP_TYPE_PWID;
map->fec.pwid.type = fec->u.pwid.type;
map->fec.pwid.group_id = 0;
- map->flags |= F_MAP_PW_ID;
+ SET_FLAG(map->flags, F_MAP_PW_ID);
map->fec.pwid.pwid = fec->u.pwid.pwid;
break;
}
@@ -1021,9 +1003,9 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
* a labelmap message is received from downstream router
* and don't send labelmap back to downstream router
*/
- if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
+ if (CHECK_FLAG(ldeconf->flags, F_LDPD_ORDERED_CONTROL)) {
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (fnh->flags & F_FEC_NH_DEFER)
+ if (CHECK_FLAG(fnh->flags, F_FEC_NH_DEFER))
continue;
if (lde_address_find(ln, fnh->af, &fnh->nexthop))
@@ -1061,9 +1043,11 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
case FEC_TYPE_IPV4:
if (!ln->v4_enabled)
return;
+
if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_to,
AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT)
return;
+
if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_for,
AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
@@ -1072,9 +1056,11 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
case FEC_TYPE_IPV6:
if (!ln->v6_enabled)
return;
+
if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_to,
AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT)
return;
+
if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_for,
AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
@@ -1086,12 +1072,14 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
/* not the remote end of the pseudowire */
return;
- map.flags |= F_MAP_PW_IFMTU;
+ SET_FLAG(map.flags, F_MAP_PW_IFMTU);
map.fec.pwid.ifmtu = pw->l2vpn->mtu;
- if (pw->flags & F_PW_CWORD)
- map.flags |= F_MAP_PW_CWORD;
- if (pw->flags & F_PW_STATUSTLV) {
- map.flags |= F_MAP_PW_STATUS;
+
+ if (CHECK_FLAG(pw->flags, F_PW_CWORD))
+ SET_FLAG(map.flags, F_MAP_PW_CWORD);
+
+ if (CHECK_FLAG(pw->flags, F_PW_STATUSTLV)) {
+ SET_FLAG(map.flags, F_MAP_PW_STATUS);
map.pw_status = pw->local_status;
}
break;
@@ -1149,8 +1137,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
/* not the remote end of the pseudowire */
return;
- if (pw->flags & F_PW_CWORD)
- map.flags |= F_MAP_PW_CWORD;
+ if (CHECK_FLAG(pw->flags, F_PW_CWORD))
+ SET_FLAG(map.flags, F_MAP_PW_CWORD);
break;
}
map.label = fn->local_label;
@@ -1161,7 +1149,7 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
map.st.status_code = st->status_code;
map.st.msg_id = st->msg_id;
map.st.msg_type = st->msg_type;
- map.flags |= F_MAP_STATUS;
+ SET_FLAG(map.flags, F_MAP_STATUS);
}
/* SWd.1: send label withdraw. */
@@ -1184,10 +1172,10 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn,
if (lde_wildcard_apply(wcard, &fn->fec, me) == 0)
continue;
- lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw,
- &fn->fec);
+ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
if (lw == NULL)
lw = lde_wdraw_add(ln, fn);
+
lw->label = map.label;
}
}
@@ -1271,8 +1259,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn,
/* not the remote end of the pseudowire */
return;
- if (pw->flags & F_PW_CWORD)
- map.flags |= F_MAP_PW_CWORD;
+ if (CHECK_FLAG(pw->flags, F_PW_CWORD))
+ SET_FLAG(map.flags, F_MAP_PW_CWORD);
break;
}
} else
@@ -1333,8 +1321,7 @@ lde_send_labelrequest(struct lde_nbr *ln, struct fec_node *fn,
lde_imsg_compose_ldpe(IMSG_REQUEST_ADD,
ln->peerid, 0, &map, sizeof(map));
if (single)
- lde_imsg_compose_ldpe(IMSG_REQUEST_ADD_END,
- ln->peerid, 0, NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_REQUEST_ADD_END, ln->peerid, 0, NULL, 0);
/* SLRq.4: record sent request */
RB_FOREACH(f, fec_tree, &ft) {
@@ -1386,7 +1373,7 @@ lde_send_notification_eol_prefix(struct lde_nbr *ln, int af)
nm.fec.type = MAP_TYPE_TYPED_WCARD;
nm.fec.fec.twcard.type = MAP_TYPE_PREFIX;
nm.fec.fec.twcard.u.prefix_af = af;
- nm.flags |= F_NOTIF_FEC;
+ SET_FLAG(nm.flags, F_NOTIF_FEC);
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
&nm, sizeof(nm));
@@ -1402,7 +1389,7 @@ lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type)
nm.fec.type = MAP_TYPE_TYPED_WCARD;
nm.fec.fec.twcard.type = MAP_TYPE_PWID;
nm.fec.fec.twcard.u.pw_type = pw_type;
- nm.flags |= F_NOTIF_FEC;
+ SET_FLAG(nm.flags, F_NOTIF_FEC);
lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0,
&nm, sizeof(nm));
@@ -1465,8 +1452,7 @@ lde_nbr_del(struct lde_nbr *ln)
switch (f->type) {
case FEC_TYPE_IPV4:
case FEC_TYPE_IPV6:
- if (!lde_address_find(ln, fnh->af,
- &fnh->nexthop))
+ if (!lde_address_find(ln, fnh->af, &fnh->nexthop))
continue;
/*
@@ -1478,8 +1464,8 @@ lde_nbr_del(struct lde_nbr *ln)
* to other neighbors for all fecs from neighbor
* going down
*/
- if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) {
- fnh->flags |= F_FEC_NH_DEFER;
+ if (CHECK_FLAG(ldeconf->flags, F_LDPD_ORDERED_CONTROL)) {
+ SET_FLAG(fnh->flags, F_FEC_NH_DEFER);
RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) {
if (ln->peerid == lnbr->peerid)
@@ -1594,8 +1580,7 @@ lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed)
continue;
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (ldp_addrcmp(fnh->af, &fnh->nexthop,
- &lde_addr->addr))
+ if (ldp_addrcmp(fnh->af, &fnh->nexthop, &lde_addr->addr))
continue;
if (removed) {
@@ -1658,15 +1643,13 @@ lde_map_add(struct lde_nbr *ln, struct fec_node *fn, int sent)
RB_INSERT(lde_map_head, &fn->upstream, me);
me->head = &fn->upstream;
if (fec_insert(&ln->sent_map, &me->fec))
- log_warnx("failed to add %s to sent map",
- log_fec(&me->fec));
+ log_warnx("failed to add %s to sent map", log_fec(&me->fec));
/* XXX on failure more cleanup is needed */
} else {
RB_INSERT(lde_map_head, &fn->downstream, me);
me->head = &fn->downstream;
if (fec_insert(&ln->recv_map, &me->fec))
- log_warnx("failed to add %s to recv map",
- log_fec(&me->fec));
+ log_warnx("failed to add %s to recv map", log_fec(&me->fec));
}
return (me);
@@ -1703,8 +1686,7 @@ lde_map_pending_add(struct lde_nbr *ln, struct fec_node *fn)
*map = fn->fec;
if (fec_insert(&ln->sent_map_pending, map))
- log_warnx("failed to add %s to sent map (pending)",
- log_fec(map));
+ log_warnx("failed to add %s to sent map (pending)", log_fec(map));
return (map);
}
@@ -1762,8 +1744,7 @@ lde_wdraw_add(struct lde_nbr *ln, struct fec_node *fn)
lw->fec = fn->fec;
if (fec_insert(&ln->sent_wdraw, &lw->fec))
- log_warnx("failed to add %s to sent wdraw",
- log_fec(&lw->fec));
+ log_warnx("failed to add %s to sent wdraw", log_fec(&lw->fec));
return (lw);
}
@@ -1786,13 +1767,9 @@ lde_change_egress_label(int af)
RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLICIT_NULL);
if (ln->v4_enabled)
- lde_send_labelwithdraw_wcard(
- ln,
- MPLS_LABEL_IPV4_EXPLICIT_NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4_EXPLICIT_NULL);
if (ln->v6_enabled)
- lde_send_labelwithdraw_wcard(
- ln,
- MPLS_LABEL_IPV6_EXPLICIT_NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6_EXPLICIT_NULL);
}
/* update label of connected routes */
@@ -1820,8 +1797,7 @@ lde_change_egress_label(int af)
lde_send_labelmapping(ln, fn, 0);
}
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
- NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
}
void
@@ -1861,8 +1837,7 @@ lde_change_allocate_filter(int af)
if (fn->local_label != new_label) {
if (new_label == NO_LABEL)
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- lde_send_labelwithdraw(ln, fn,
- NULL, NULL);
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
fn->local_label = new_label;
if (fn->local_label != NO_LABEL)
@@ -1870,6 +1845,7 @@ lde_change_allocate_filter(int af)
lde_send_labelmapping(ln, fn, 0);
}
}
+
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0,
NULL, 0);
@@ -1915,34 +1891,30 @@ lde_change_advertise_filter(int af)
case AF_INET:
if (fn->fec.type != FEC_TYPE_IPV4)
continue;
- prefix = (union ldpd_addr *)
- &fn->fec.u.ipv4.prefix;
+ prefix = (union ldpd_addr *)&fn->fec.u.ipv4.prefix;
plen = fn->fec.u.ipv4.prefixlen;
break;
case FEC_TYPE_IPV6:
if (fn->fec.type != FEC_TYPE_IPV6)
continue;
- prefix = (union ldpd_addr *)
- &fn->fec.u.ipv6.prefix;
+ prefix = (union ldpd_addr *)&fn->fec.u.ipv6.prefix;
plen = fn->fec.u.ipv6.prefixlen;
break;
default:
continue;
}
+
if (lde_acl_check(acl_for_filter, af,
prefix, plen) != FILTER_PERMIT) {
- me = (struct lde_map *)fec_find(
- &ln->sent_map, &fn->fec);
+ me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec);
if (me)
/* fec filtered withdraw */
- lde_send_labelwithdraw(ln, fn,
- NULL, NULL);
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
} else
/* fec allowed send map */
lde_send_labelmapping(ln, fn, 0);
}
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END,
- ln->peerid, 0, NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
}
}
}
@@ -1988,13 +1960,12 @@ lde_change_accept_filter(int af)
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
if (fn->fec.type == type) {
- me = (struct lde_map *)fec_find(
- &ln->recv_map, &fn->fec);
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
if (me)
lde_map_del(ln, me, 0);
}
}
- } else if (ln->flags & F_NBR_CAP_TWCARD) {
+ } else if (CHECK_FLAG(ln->flags, F_NBR_CAP_TWCARD)) {
/* This neighbor is allowed and supports type
* wildcard so send a labelrequest
* to get any new labels from neighbor
@@ -2007,15 +1978,13 @@ lde_change_accept_filter(int af)
case AF_INET:
if (fn->fec.type != FEC_TYPE_IPV4)
continue;
- prefix = (union ldpd_addr *)
- &fn->fec.u.ipv4.prefix;
+ prefix = (union ldpd_addr *)&fn->fec.u.ipv4.prefix;
plen = fn->fec.u.ipv4.prefixlen;
break;
case AF_INET6:
if (fn->fec.type != FEC_TYPE_IPV6)
continue;
- prefix = (union ldpd_addr *)
- &fn->fec.u.ipv6.prefix;
+ prefix = (union ldpd_addr *)&fn->fec.u.ipv6.prefix;
plen = fn->fec.u.ipv6.prefixlen;
break;
default:
@@ -2023,8 +1992,7 @@ lde_change_accept_filter(int af)
}
if (lde_acl_check(acl_for_filter, af,
prefix, plen) != FILTER_PERMIT) {
- me = (struct lde_map *)fec_find(
- &ln->recv_map, &fn->fec);
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
if (me)
lde_map_del(ln, me, 0);
}
@@ -2032,8 +2000,7 @@ lde_change_accept_filter(int af)
lde_send_labelrequest_wcard(ln, af);
} else
/* Type Wildcard is not supported so restart session */
- lde_imsg_compose_ldpe(IMSG_NBR_SHUTDOWN, ln->peerid, 0,
- NULL, 0);
+ lde_imsg_compose_ldpe(IMSG_NBR_SHUTDOWN, ln->peerid, 0, NULL, 0);
}
}
@@ -2299,7 +2266,7 @@ lde_free_label(uint32_t label)
for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) {
if (label <= label_chunk->end && label >= label_chunk->start) {
pos = 1ULL << (label - label_chunk->start);
- label_chunk->used_mask &= ~pos;
+ UNSET_FLAG(label_chunk->used_mask, pos);
/* if nobody is using this chunk and it's not current_label_chunk, then free it */
if (!label_chunk->used_mask && (current_label_chunk != node)) {
if (lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0)
@@ -2312,6 +2279,7 @@ lde_free_label(uint32_t label)
break;
}
}
+
return;
}
@@ -2332,7 +2300,7 @@ lde_get_next_label(void)
size = label_chunk->end - label_chunk->start + 1;
for (i = 0, pos = 1; i < size; i++, pos <<= 1) {
if (!(pos & label_chunk->used_mask)) {
- label_chunk->used_mask |= pos;
+ SET_FLAG(label_chunk->used_mask, pos);
label = label_chunk->start + i;
goto end;
}
@@ -2360,12 +2328,15 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf,
{
if (strcmp(af_conf->acl_label_allocate_for, filter_name) == 0)
lde_change_allocate_filter(af);
+
if ((strcmp(af_conf->acl_label_advertise_to, filter_name) == 0)
|| (strcmp(af_conf->acl_label_advertise_for, filter_name) == 0))
lde_change_advertise_filter(af);
+
if ((strcmp(af_conf->acl_label_accept_for, filter_name) == 0)
|| (strcmp(af_conf->acl_label_accept_from, filter_name) == 0))
lde_change_accept_filter(af);
+
if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)
lde_change_expnull_for_filter(af);
}
@@ -2379,6 +2350,7 @@ void lde_route_update(struct iface *iface, int af)
/* update label of non-connected routes */
log_debug("update labels for interface %s", iface->name);
+
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
if (IS_MPLS_UNRESERVED_LABEL(fn->local_label))
@@ -2405,13 +2377,13 @@ void lde_route_update(struct iface *iface, int af)
* may need new label. If no LDP configured
* treat fec as a connected route
*/
- if (fnh->flags & F_FEC_NH_CONNECTED)
+ if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED))
break;
if (fnh->ifindex != iface->ifindex)
continue;
- fnh->flags &= ~F_FEC_NH_NO_LDP;
+ UNSET_FLAG(fnh->flags, F_FEC_NH_NO_LDP);
if (IS_MPLS_RESERVED_LABEL(fn->local_label)) {
fn->local_label = NO_LABEL;
fn->local_label = lde_update_label(fn);
@@ -2423,6 +2395,7 @@ void lde_route_update(struct iface *iface, int af)
break;
}
}
+
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
0, NULL, 0);
@@ -2438,6 +2411,7 @@ void lde_route_update_release(struct iface *iface, int af)
/* update label of interfaces no longer running LDP */
log_debug("release all labels for interface %s af %s", iface->name,
af == AF_INET ? "ipv4" : "ipv6");
+
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
@@ -2463,13 +2437,13 @@ void lde_route_update_release(struct iface *iface, int af)
* removed from interface may need new label
* and would be treated as a connected route
*/
- if (fnh->flags & F_FEC_NH_CONNECTED)
+ if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED))
break;
if (fnh->ifindex != iface->ifindex)
continue;
- fnh->flags |= F_FEC_NH_NO_LDP;
+ SET_FLAG(fnh->flags, F_FEC_NH_NO_LDP);
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_send_labelwithdraw(ln, fn, NULL, NULL);
lde_free_label(fn->local_label);
@@ -2481,6 +2455,7 @@ void lde_route_update_release(struct iface *iface, int af)
break;
}
}
+
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
0, NULL, 0);
@@ -2498,6 +2473,7 @@ void lde_route_update_release_all(int af)
*/
log_debug("release all labels for address family %s",
af == AF_INET ? "ipv4" : "ipv6");
+
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
switch (af) {
@@ -2517,7 +2493,7 @@ void lde_route_update_release_all(int af)
lde_send_labelwithdraw(ln, fn, NULL, NULL);
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- fnh->flags |= F_FEC_NH_NO_LDP;
+ SET_FLAG(fnh->flags, F_FEC_NH_NO_LDP);
lde_send_delete_klabel(fn, fnh);
}
}
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index fe97c54831..2026a7857c 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -329,14 +329,18 @@ main(int argc, char *argv[])
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)
fatal("socketpair");
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
pipe_parent2ldpe_sync) == -1)
fatal("socketpair");
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1)
fatal("socketpair");
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
pipe_parent2lde_sync) == -1)
fatal("socketpair");
+
sock_set_nonblock(pipe_parent2ldpe[0]);
sock_set_cloexec(pipe_parent2ldpe[0]);
sock_set_nonblock(pipe_parent2ldpe[1]);
@@ -387,6 +391,7 @@ main(int argc, char *argv[])
(iev_lde = calloc(1, sizeof(struct imsgev))) == NULL ||
(iev_lde_sync = calloc(1, sizeof(struct imsgev))) == NULL)
fatal(NULL);
+
imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]);
iev_ldpe->handler_read = main_dispatch_ldpe;
thread_add_read(master, iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd,
@@ -413,14 +418,15 @@ main(int argc, char *argv[])
if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf))
fatal("could not establish imsg links");
- main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
- sizeof(ldp_debug));
+
+ main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, sizeof(ldp_debug));
main_imsg_compose_both(IMSG_INIT, &init, sizeof(init));
main_imsg_send_config(ldpd_conf);
- if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
+ if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED))
main_imsg_send_net_sockets(AF_INET);
- if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
+
+ if (CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_ENABLED))
main_imsg_send_net_sockets(AF_INET6);
frr_run(master);
@@ -523,6 +529,7 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
if (dup2(fd_async, LDPD_FD_ASYNC) == -1)
fatal("cannot setup imsg async fd");
+
if (dup2(fd_sync, LDPD_FD_SYNC) == -1)
fatal("cannot setup imsg sync fd");
@@ -563,6 +570,7 @@ static void main_dispatch_ldpe(struct thread *thread)
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
+
if (n == 0) /* connection closed */
shut = 1;
@@ -608,6 +616,7 @@ static void main_dispatch_ldpe(struct thread *thread)
THREAD_OFF(iev->ev_read);
THREAD_OFF(iev->ev_write);
ldpe_pid = 0;
+
if (lde_pid == 0)
ldpd_shutdown();
else
@@ -629,6 +638,7 @@ static void main_dispatch_lde(struct thread *thread)
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
+
if (n == 0) /* connection closed */
shut = 1;
@@ -704,8 +714,10 @@ static void main_dispatch_lde(struct thread *thread)
imsg.hdr.type);
break;
}
+
imsg_free(&imsg);
}
+
if (!shut)
imsg_event_add(iev);
else {
@@ -746,6 +758,7 @@ main_imsg_compose_ldpe(int type, pid_t pid, void *data, uint16_t datalen)
{
if (iev_ldpe == NULL)
return;
+
imsg_compose_event(iev_ldpe, type, 0, pid, -1, data, datalen);
}
@@ -760,10 +773,13 @@ main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len)
{
if (iev_ldpe == NULL || iev_lde == NULL)
return (0);
+
if (imsg_compose_event(iev_ldpe, type, 0, 0, -1, buf, len) == -1)
return (-1);
+
if (imsg_compose_event(iev_lde, type, 0, 0, -1, buf, len) == -1)
return (-1);
+
return (0);
}
@@ -788,6 +804,7 @@ imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
if ((ret = imsg_compose(&iev->ibuf, type, peerid,
pid, fd, data, datalen)) != -1)
imsg_event_add(iev);
+
return (ret);
}
@@ -836,6 +853,7 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf)
if (imsg_compose(ldpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_ldpe2lde[0],
NULL, 0) == -1)
return (-1);
+
if (imsg_compose(lde_buf, IMSG_SOCKET_IPC, 0, 0, pipe_ldpe2lde[1],
NULL, 0) == -1)
return (-1);
@@ -894,8 +912,10 @@ ldp_acl_request(struct imsgev *iev, char *acl_name, int af,
/* receive (blocking) and parse result */
if (imsg_read(&iev->ibuf) == -1)
fatal("imsg_read error");
+
if (imsg_get(&iev->ibuf, &imsg) == -1)
fatal("imsg_get");
+
if (imsg.hdr.type != IMSG_ACL_CHECK ||
imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(int))
fatalx("ldp_acl_request: invalid response");
@@ -962,8 +982,8 @@ ldp_af_global_get(struct ldpd_global *xglobal, int af)
int
ldp_is_dual_stack(struct ldpd_conf *xconf)
{
- return ((xconf->ipv4.flags & F_LDPD_AF_ENABLED) &&
- (xconf->ipv6.flags & F_LDPD_AF_ENABLED));
+ return (CHECK_FLAG(xconf->ipv4.flags, F_LDPD_AF_ENABLED)
+ && CHECK_FLAG(xconf->ipv6.flags, F_LDPD_AF_ENABLED));
}
in_addr_t
@@ -1017,11 +1037,13 @@ main_imsg_send_config(struct ldpd_conf *xconf)
sizeof(*lif)) == -1)
return (-1);
}
+
RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) {
if (main_imsg_compose_both(IMSG_RECONF_L2VPN_PW, pw,
sizeof(*pw)) == -1)
return (-1);
}
+
RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) {
if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IPW, pw,
sizeof(*pw)) == -1)
@@ -1065,12 +1087,12 @@ ldp_config_normalize(struct ldpd_conf *xconf)
struct l2vpn *l2vpn;
struct l2vpn_pw *pw, *ptmp;
- if (!(xconf->flags & F_LDPD_ENABLED))
+ if (!CHECK_FLAG(xconf->flags, F_LDPD_ENABLED))
ldp_config_reset_main(xconf);
else {
- if (!(xconf->ipv4.flags & F_LDPD_AF_ENABLED))
+ if (!CHECK_FLAG(xconf->ipv4.flags, F_LDPD_AF_ENABLED))
ldp_config_reset_af(xconf, AF_INET);
- if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED))
+ if (!CHECK_FLAG(xconf->ipv6.flags, F_LDPD_AF_ENABLED))
ldp_config_reset_af(xconf, AF_INET6);
RB_FOREACH_SAFE(iface, iface_head, &xconf->iface_tree, itmp) {
@@ -1083,7 +1105,7 @@ ldp_config_normalize(struct ldpd_conf *xconf)
}
RB_FOREACH_SAFE(nbrp, nbrp_head, &xconf->nbrp_tree, ntmp) {
- if (nbrp->flags & (F_NBRP_KEEPALIVE|F_NBRP_GTSM))
+ if (CHECK_FLAG(nbrp->flags, (F_NBRP_KEEPALIVE|F_NBRP_GTSM)))
continue;
if (nbrp->auth.method != AUTH_NONE)
continue;
@@ -1096,7 +1118,7 @@ ldp_config_normalize(struct ldpd_conf *xconf)
RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) {
- if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+ if (!CHECK_FLAG(pw->flags, F_PW_STATIC_NBR_ADDR)) {
pw->af = AF_INET;
pw->addr.v4 = pw->lsr_id;
}
@@ -1106,9 +1128,10 @@ ldp_config_normalize(struct ldpd_conf *xconf)
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
}
+
RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree,
ptmp) {
- if (!(pw->flags & F_PW_STATIC_NBR_ADDR)) {
+ if (!CHECK_FLAG(pw->flags, F_PW_STATIC_NBR_ADDR)) {
pw->af = AF_INET;
pw->addr.v4 = pw->lsr_id;
}
@@ -1210,6 +1233,7 @@ ldp_config_reset_l2vpns(struct ldpd_conf *conf)
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
free(lif);
}
+
while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_tree)) {
pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_tree);
@@ -1217,6 +1241,7 @@ ldp_config_reset_l2vpns(struct ldpd_conf *conf)
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
free(pw);
}
+
while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_inactive_tree)) {
pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_inactive_tree);
@@ -1224,6 +1249,7 @@ ldp_config_reset_l2vpns(struct ldpd_conf *conf)
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
free(pw);
}
+
QOBJ_UNREG(l2vpn);
RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
free(l2vpn);
@@ -1244,18 +1270,21 @@ ldp_clear_config(struct ldpd_conf *xconf)
RB_REMOVE(iface_head, &xconf->iface_tree, iface);
free(iface);
}
+
while (!RB_EMPTY(tnbr_head, &xconf->tnbr_tree)) {
tnbr = RB_ROOT(tnbr_head, &xconf->tnbr_tree);
RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
free(tnbr);
}
+
while (!RB_EMPTY(nbrp_head, &xconf->nbrp_tree)) {
nbrp = RB_ROOT(nbrp_head, &xconf->nbrp_tree);
RB_REMOVE(nbrp_head, &xconf->nbrp_tree, nbrp);
free(nbrp);
}
+
while (!RB_EMPTY(l2vpn_head, &xconf->l2vpn_tree)) {
l2vpn = RB_ROOT(l2vpn_head, &xconf->l2vpn_tree);
@@ -1289,8 +1318,8 @@ static void
merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
/* Removing global LDP config requires resetting LDP IGP Sync FSM */
- if ((conf->flags & F_LDPD_ENABLED) &&
- (!(xconf->flags & F_LDPD_ENABLED)))
+ if (CHECK_FLAG(conf->flags, F_LDPD_ENABLED)
+ && (!CHECK_FLAG(xconf->flags, F_LDPD_ENABLED)))
{
if (ldpd_process == PROC_LDP_ENGINE)
ldp_sync_fsm_reset_all();
@@ -1313,8 +1342,8 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
* Configuration of ordered-control or independent-control
* requires resetting all neighborships.
*/
- if ((conf->flags & F_LDPD_ORDERED_CONTROL) !=
- (xconf->flags & F_LDPD_ORDERED_CONTROL))
+ if (CHECK_FLAG(conf->flags, F_LDPD_ORDERED_CONTROL) !=
+ CHECK_FLAG(xconf->flags, F_LDPD_ORDERED_CONTROL))
ldpe_reset_nbrs(AF_UNSPEC);
conf->lhello_holdtime = xconf->lhello_holdtime;
@@ -1329,8 +1358,8 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
conf->trans_pref = xconf->trans_pref;
}
- if ((conf->flags & F_LDPD_DS_CISCO_INTEROP) !=
- (xconf->flags & F_LDPD_DS_CISCO_INTEROP)) {
+ if (CHECK_FLAG(conf->flags, F_LDPD_DS_CISCO_INTEROP) !=
+ CHECK_FLAG(xconf->flags, F_LDPD_DS_CISCO_INTEROP)) {
if (ldpd_process == PROC_LDP_ENGINE)
ldpe_reset_ds_nbrs();
}
@@ -1339,8 +1368,8 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
* Configuration of allow-broken-lsp requires reprograming all
* labeled routes
*/
- if ((conf->flags & F_LDPD_ALLOW_BROKEN_LSP) !=
- (xconf->flags & F_LDPD_ALLOW_BROKEN_LSP)) {
+ if (CHECK_FLAG(conf->flags, F_LDPD_ALLOW_BROKEN_LSP) !=
+ CHECK_FLAG(xconf->flags, F_LDPD_ALLOW_BROKEN_LSP)) {
if (ldpd_process == PROC_LDE_ENGINE)
lde_allow_broken_lsp_update(xconf->flags);
}
@@ -1368,17 +1397,19 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
af_conf->keepalive = xa->keepalive;
stop_init_backoff = 1;
}
+
af_conf->lhello_holdtime = xa->lhello_holdtime;
af_conf->lhello_interval = xa->lhello_interval;
af_conf->thello_holdtime = xa->thello_holdtime;
af_conf->thello_interval = xa->thello_interval;
/* update flags */
- if ((af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) &&
- !(xa->flags & F_LDPD_AF_THELLO_ACCEPT))
+ if (CHECK_FLAG(af_conf->flags, F_LDPD_AF_THELLO_ACCEPT) &&
+ !CHECK_FLAG(xa->flags, F_LDPD_AF_THELLO_ACCEPT))
remove_dynamic_tnbrs = 1;
- if ((af_conf->flags & F_LDPD_AF_NO_GTSM) !=
- (xa->flags & F_LDPD_AF_NO_GTSM)) {
+
+ if (CHECK_FLAG(af_conf->flags, F_LDPD_AF_NO_GTSM) !=
+ CHECK_FLAG(xa->flags, F_LDPD_AF_NO_GTSM)) {
if (af == AF_INET6)
/* need to set/unset IPV6_MINHOPCOUNT */
update_sockets = 1;
@@ -1386,18 +1417,18 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
/* for LDPv4 just resetting the neighbors is enough */
reset_nbrs_ipv4 = 1;
}
- if ((af_conf->flags & F_LDPD_AF_EXPNULL) !=
- (xa->flags & F_LDPD_AF_EXPNULL))
+ if (CHECK_FLAG(af_conf->flags, F_LDPD_AF_EXPNULL) !=
+ CHECK_FLAG(xa->flags, F_LDPD_AF_EXPNULL))
change_egress_label = 1;
/* changing config of host only fec filtering */
- if ((af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY)
- != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
+ if (CHECK_FLAG(af_conf->flags, F_LDPD_AF_ALLOCHOSTONLY)
+ != CHECK_FLAG(xa->flags, F_LDPD_AF_ALLOCHOSTONLY))
change_host_label = 1;
/* disabling LDP for address family */
- if ((af_conf->flags & F_LDPD_AF_ENABLED) &&
- !(xa->flags & F_LDPD_AF_ENABLED))
+ if (CHECK_FLAG(af_conf->flags, F_LDPD_AF_ENABLED) &&
+ !CHECK_FLAG(xa->flags, F_LDPD_AF_ENABLED))
change_ldp_disabled = 1;
af_conf->flags = xa->flags;
@@ -1412,31 +1443,36 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
if (strcmp(af_conf->acl_label_allocate_for, xa->acl_label_allocate_for))
change_host_label = 1;
- if (strcmp(af_conf->acl_label_advertise_to,
- xa->acl_label_advertise_to) ||
- strcmp(af_conf->acl_label_advertise_for,
- xa->acl_label_advertise_for) ||
- strcmp(af_conf->acl_label_accept_from,
- xa->acl_label_accept_from) ||
- strcmp(af_conf->acl_label_accept_for,
- xa->acl_label_accept_for))
+ if (strcmp(af_conf->acl_label_advertise_to, xa->acl_label_advertise_to) ||
+ strcmp(af_conf->acl_label_advertise_for, xa->acl_label_advertise_for) ||
+ strcmp(af_conf->acl_label_accept_from, xa->acl_label_accept_from) ||
+ strcmp(af_conf->acl_label_accept_for, xa->acl_label_accept_for))
reset_nbrs = 1;
+
if (strcmp(af_conf->acl_thello_accept_from, xa->acl_thello_accept_from))
remove_dynamic_tnbrs = 1;
+
if (strcmp(af_conf->acl_label_expnull_for, xa->acl_label_expnull_for))
change_egress_label = 1;
+
strlcpy(af_conf->acl_thello_accept_from, xa->acl_thello_accept_from,
sizeof(af_conf->acl_thello_accept_from));
+
strlcpy(af_conf->acl_label_allocate_for, xa->acl_label_allocate_for,
sizeof(af_conf->acl_label_allocate_for));
+
strlcpy(af_conf->acl_label_advertise_to, xa->acl_label_advertise_to,
sizeof(af_conf->acl_label_advertise_to));
+
strlcpy(af_conf->acl_label_advertise_for, xa->acl_label_advertise_for,
sizeof(af_conf->acl_label_advertise_for));
+
strlcpy(af_conf->acl_label_accept_from, xa->acl_label_accept_from,
sizeof(af_conf->acl_label_accept_from));
+
strlcpy(af_conf->acl_label_accept_for, xa->acl_label_accept_for,
sizeof(af_conf->acl_label_accept_for));
+
strlcpy(af_conf->acl_label_expnull_for, xa->acl_label_expnull_for,
sizeof(af_conf->acl_label_expnull_for));
@@ -1445,8 +1481,10 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
case PROC_LDE_ENGINE:
if (change_egress_label)
lde_change_egress_label(af);
+
if (change_host_label)
lde_change_allocate_filter(af);
+
if (change_ldp_disabled)
lde_route_update_release_all(af);
@@ -1529,6 +1567,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
*/
if (iface->ipv4.enabled && !xi->ipv4.enabled)
lde_route_update_release(iface, AF_INET);
+
if (iface->ipv6.enabled && !xi->ipv6.enabled)
lde_route_update_release(iface, AF_INET6);
@@ -1537,6 +1576,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
*/
if (!iface->ipv4.enabled && xi->ipv4.enabled)
lde_route_update(iface, AF_INET);
+
if (!iface->ipv6.enabled && xi->ipv6.enabled)
lde_route_update(iface, AF_INET6);
}
@@ -1565,14 +1605,14 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
struct tnbr *tnbr, *ttmp, *xt;
RB_FOREACH_SAFE(tnbr, tnbr_head, &conf->tnbr_tree, ttmp) {
- if (!(tnbr->flags & F_TNBR_CONFIGURED))
+ if (!CHECK_FLAG(tnbr->flags, F_TNBR_CONFIGURED))
continue;
/* find deleted tnbrs */
if (tnbr_find(xconf, tnbr->af, &tnbr->addr) == NULL) {
switch (ldpd_process) {
case PROC_LDP_ENGINE:
- tnbr->flags &= ~F_TNBR_CONFIGURED;
+ UNSET_FLAG(tnbr->flags, F_TNBR_CONFIGURED);
tnbr_check(conf, tnbr);
break;
case PROC_LDE_ENGINE:
@@ -1601,8 +1641,8 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
/* update existing tnbrs */
- if (!(tnbr->flags & F_TNBR_CONFIGURED))
- tnbr->flags |= F_TNBR_CONFIGURED;
+ if (!CHECK_FLAG(tnbr->flags, F_TNBR_CONFIGURED))
+ SET_FLAG(tnbr->flags, F_TNBR_CONFIGURED);
}
}
@@ -1853,8 +1893,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
reinstall_tnbr = 0;
/* changes that require a session restart */
- if ((pw->flags & (F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF)) !=
- (xp->flags & (F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF)))
+ if (CHECK_FLAG(pw->flags, (F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF)) !=
+ CHECK_FLAG(xp->flags, (F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF)))
reset_nbr = 1;
else
reset_nbr = 0;
@@ -1883,20 +1923,24 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
pw->pwid = xp->pwid;
strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname));
pw->ifindex = xp->ifindex;
- if (xp->flags & F_PW_CWORD_CONF)
- pw->flags |= F_PW_CWORD_CONF;
+ if (CHECK_FLAG(xp->flags, F_PW_CWORD_CONF))
+ SET_FLAG(pw->flags, F_PW_CWORD_CONF);
else
- pw->flags &= ~F_PW_CWORD_CONF;
- if (xp->flags & F_PW_STATUSTLV_CONF)
- pw->flags |= F_PW_STATUSTLV_CONF;
+ UNSET_FLAG(pw->flags, F_PW_CWORD_CONF);
+
+ if (CHECK_FLAG(xp->flags, F_PW_STATUSTLV_CONF))
+ SET_FLAG(pw->flags, F_PW_STATUSTLV_CONF);
else
- pw->flags &= ~F_PW_STATUSTLV_CONF;
- if (xp->flags & F_PW_STATIC_NBR_ADDR)
- pw->flags |= F_PW_STATIC_NBR_ADDR;
+ UNSET_FLAG(pw->flags, F_PW_STATUSTLV_CONF);
+
+ if (CHECK_FLAG(xp->flags, F_PW_STATIC_NBR_ADDR))
+ SET_FLAG(pw->flags, F_PW_STATIC_NBR_ADDR);
else
- pw->flags &= ~F_PW_STATIC_NBR_ADDR;
+ UNSET_FLAG(pw->flags, F_PW_STATIC_NBR_ADDR);
+
if (ldpd_process == PROC_LDP_ENGINE && reinstall_tnbr)
ldpe_l2vpn_pw_init(pw);
+
if (ldpd_process == PROC_LDE_ENGINE && reinstall_pwfec) {
l2vpn->pw_type = xl->pw_type;
l2vpn->mtu = xl->mtu;
diff --git a/lib/asn.c b/lib/asn.c
new file mode 100644
index 0000000000..c64666375d
--- /dev/null
+++ b/lib/asn.c
@@ -0,0 +1,260 @@
+/*
+ * ASN functions
+ *
+ * Copyright 2022 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include "log.h"
+#include "asn.h"
+
+static bool relax_as_zero;
+
+static const struct message asnotation_mode_msg[] = {
+ {ASNOTATION_PLAIN, "plain"},
+ {ASNOTATION_DOT, "dot"},
+ {ASNOTATION_DOTPLUS, "dot+"},
+ {ASNOTATION_UNDEFINED, "undefined"},
+ {0}
+};
+
+/* converts a string into an Autonomous system number
+ * "1.1" => 65536
+ * "65500" => 65500
+ */
+static bool asn_str2asn_internal(const char *asstring, as_t *asn,
+ const char **next, bool *partial,
+ enum asnotation_mode *mode)
+{
+ uint32_t high = 0, low = 0;
+ uint64_t temp_val;
+ const char *p = asstring;
+ bool ret = false;
+ uint32_t digit;
+ enum asnotation_mode val = ASNOTATION_PLAIN;
+
+ if (!asstring)
+ goto end;
+
+ if (!isdigit((unsigned char)*p))
+ goto end;
+
+ temp_val = 0;
+ while (isdigit((unsigned char)*p)) {
+ digit = (*p) - '0';
+ temp_val *= 10;
+ temp_val += digit;
+ if (temp_val > UINT32_MAX)
+ /* overflow */
+ goto end;
+ p++;
+ }
+ high = (uint32_t)temp_val;
+ if (*p == '.') { /* dot format */
+ p++;
+ temp_val = 0;
+ if (*p == '\0' && partial) {
+ *partial = true;
+ goto end;
+ }
+ while (isdigit((unsigned char)*p)) {
+ digit = (*p) - '0';
+ temp_val *= 10;
+ temp_val += digit;
+ if (temp_val > UINT16_MAX)
+ /* overflow */
+ goto end;
+ p++;
+ }
+ low = (uint32_t)temp_val;
+
+ if (!next && *p != '\0' && !isdigit((unsigned char)*p))
+ goto end;
+ /* AS <AS4B>.<AS4B> is forbidden */
+ if (high > UINT16_MAX)
+ goto end;
+ /* AS 0.0 is authorised for some case only */
+ if (!relax_as_zero && high == 0 && low == 0) {
+ if (partial)
+ *partial = true;
+ goto end;
+ }
+ if (asn)
+ *asn = (high << 16) + low;
+ ret = true;
+ if (high == 0)
+ val = ASNOTATION_DOTPLUS;
+ else
+ val = ASNOTATION_DOT;
+ goto end;
+ }
+ /* AS 0 is forbidden */
+ if (!relax_as_zero && high == 0)
+ goto end;
+ if (!asn) {
+ ret = true;
+ goto end;
+ }
+ *asn = high;
+ ret = true;
+ end:
+ if (next)
+ *next = p;
+ if (mode)
+ *mode = val;
+ return ret;
+}
+
+static void asn_asn2asdot(as_t asn, char *asstring, size_t len)
+{
+ uint16_t low, high;
+
+ high = (asn >> 16) & 0xffff;
+ low = asn & 0xffff;
+ snprintf(asstring, len, "%hu.%hu", high, low);
+}
+
+bool asn_str2asn(const char *asstring, as_t *asn)
+{
+ return asn_str2asn_internal(asstring, asn, NULL, NULL, NULL);
+}
+
+const char *asn_asn2asplain(as_t asn)
+{
+ static char buf[ASN_STRING_MAX_SIZE];
+
+ snprintf(buf, sizeof(buf), "%u", asn);
+ return buf;
+}
+
+const char *asn_str2asn_parse(const char *asstring, as_t *asn, bool *found_ptr)
+{
+ const char *p = NULL;
+ const char **next = &p;
+ bool found;
+
+ found = asn_str2asn_internal(asstring, asn, next, NULL, NULL);
+ if (found_ptr)
+ *found_ptr = found;
+ return *next;
+}
+
+void asn_relax_as_zero(bool relax)
+{
+ relax_as_zero = relax;
+}
+
+enum match_type asn_str2asn_match(const char *str)
+{
+ bool found, partial = false;
+
+ found = asn_str2asn_internal(str, NULL, NULL, &partial, NULL);
+ if (found && !partial)
+ return exact_match;
+
+ if (partial)
+ return partly_match;
+
+ return no_match;
+}
+
+bool asn_str2asn_notation(const char *asstring, as_t *asn,
+ enum asnotation_mode *asnotation)
+{
+ return asn_str2asn_internal(asstring, asn, NULL, NULL, asnotation);
+}
+
+const char *asn_mode2str(enum asnotation_mode asnotation)
+{
+ return lookup_msg(asnotation_mode_msg, asnotation,
+ "Unrecognized AS notation mode");
+}
+
+void asn_asn2json(json_object *json, const char *attr,
+ as_t asn, enum asnotation_mode asnotation)
+{
+ static char as_str[ASN_STRING_MAX_SIZE];
+
+ if ((asnotation == ASNOTATION_PLAIN) ||
+ ((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
+ json_object_int_add(json, attr, asn);
+ else {
+ asn_asn2asdot(asn, as_str, sizeof(as_str));
+ json_object_string_add(json, attr, as_str);
+ }
+}
+
+void asn_asn2json_array(json_object *jseg_list, as_t asn,
+ enum asnotation_mode asnotation)
+{
+ static char as_str[ASN_STRING_MAX_SIZE];
+
+ if ((asnotation == ASNOTATION_PLAIN) ||
+ ((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX))
+ json_object_array_add(jseg_list,
+ json_object_new_int64(asn));
+ else {
+ asn_asn2asdot(asn, as_str, sizeof(as_str));
+ json_array_string_add(jseg_list, as_str);
+ }
+}
+
+char *asn_asn2string(const as_t *asn, char *buf, size_t len,
+ enum asnotation_mode asnotation)
+{
+ if ((asnotation == ASNOTATION_PLAIN) ||
+ ((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX))
+ snprintf(buf, len, "%u", *asn);
+ else
+ asn_asn2asdot(*asn, buf, len);
+ return buf;
+}
+
+static ssize_t printfrr_asnotation(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr,
+ enum asnotation_mode asnotation)
+{
+ /* for alignemnt up to 33 chars - %33pASD for instance - */
+ char as_str[ASN_STRING_MAX_SIZE*3];
+ const as_t *asn;
+
+ if (!ptr)
+ return bputs(buf, "(null)");
+ asn = ptr;
+ asn_asn2string(asn, as_str, sizeof(as_str), asnotation);
+ return bputs(buf, as_str);
+}
+
+printfrr_ext_autoreg_p("ASP", printfrr_asplain);
+static ssize_t printfrr_asplain(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_asnotation(buf, ea, ptr, ASNOTATION_PLAIN);
+}
+
+printfrr_ext_autoreg_p("ASD", printfrr_asdot);
+static ssize_t printfrr_asdot(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOT);
+}
+
+printfrr_ext_autoreg_p("ASE", printfrr_asdotplus);
+static ssize_t printfrr_asdotplus(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS);
+}
diff --git a/lib/asn.h b/lib/asn.h
new file mode 100644
index 0000000000..81a42c658d
--- /dev/null
+++ b/lib/asn.h
@@ -0,0 +1,81 @@
+/*
+ * AS number structure
+ * Copyright 2022 6WIND
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_ASN_H
+#define _FRR_ASN_H
+
+#include "zebra.h"
+#include "command_match.h"
+#include "json.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ASN_STRING_MAX_SIZE 12
+
+enum asnotation_mode {
+ ASNOTATION_PLAIN = 0,
+ ASNOTATION_DOT,
+ ASNOTATION_DOTPLUS,
+ ASNOTATION_UNDEFINED,
+};
+
+typedef uint32_t as_t;
+
+extern bool asn_str2asn(const char *asstring, as_t *asn);
+extern const char *asn_asn2asplain(as_t asn);
+extern const char *asn_str2asn_parse(const char *asstring, as_t *asn,
+ bool *found_ptr);
+extern enum match_type asn_str2asn_match(const char *str);
+extern bool asn_str2asn_notation(const char *asstring, as_t *asn,
+ enum asnotation_mode *asnotation);
+extern const char *asn_mode2str(enum asnotation_mode asnotation);
+void asn_asn2json_array(json_object *jseg_list, as_t asn,
+ enum asnotation_mode asnotation);
+void asn_asn2json(json_object *jseg_list, const char *attr,
+ as_t asn, enum asnotation_mode asnotation);
+extern char *asn_asn2string(const as_t *as, char *buf, size_t len,
+ enum asnotation_mode asnotation);
+/* display AS in appropriate format */
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pASP" (as_t *)
+#pragma FRR printfrr_ext "%pASD" (as_t *)
+#pragma FRR printfrr_ext "%pASE" (as_t *)
+#endif
+
+#define ASN_FORMAT(mode) \
+ ((mode == ASNOTATION_DOT) ? "%pASD" : \
+ ((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \
+ "%pASP"))
+#define ASN_FORMAT_SPACE(mode) \
+ ((mode == ASNOTATION_DOT) ? "%10pASD" : \
+ ((mode == ASNOTATION_DOTPLUS) ? "%10pASE" : \
+ "%10pASP"))
+
+/* for test */
+extern void asn_relax_as_zero(bool relax);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ASN_H */
diff --git a/lib/command.c b/lib/command.c
index cf96df6f95..ee5a3889e8 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -56,6 +56,7 @@ const struct message tokennames[] = {
item(IPV6_PREFIX_TKN),
item(MAC_TKN),
item(MAC_PREFIX_TKN),
+ item(ASNUM_TKN),
item(FORK_TKN),
item(JOIN_TKN),
item(START_TKN),
diff --git a/lib/command.h b/lib/command.h
index 2121bfd623..6538e56588 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -391,7 +391,8 @@ struct cmd_node {
#define DEBUG_STR "Debugging functions\n"
#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
#define ROUTER_STR "Enable a routing process\n"
-#define AS_STR "AS number\n"
+#define AS_STR \
+ "AS number in plain <1-4294967295> or dotted <0-65535>.<0-65535> format\n"
#define MAC_STR "MAC address\n"
#define MBGP_STR "MBGP information\n"
#define MATCH_STR "Match values from routing table\n"
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 850fdeafcd..ff3c11db69 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -266,6 +266,7 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb)
case END_TKN:
case NEG_ONLY_TKN:
case WORD_TKN:
+ case ASNUM_TKN:
return true;
}
@@ -535,6 +536,7 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
case MAC_PREFIX_TKN:
case END_TKN:
case VARIABLE_TKN:
+ case ASNUM_TKN:
color = "#ffffff";
break;
}
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 8e84fa928d..25aa47db7b 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -45,6 +45,7 @@ enum cmd_token_type {
IPV6_PREFIX_TKN, // IPV6 network prefixes
MAC_TKN, // Ethernet address
MAC_PREFIX_TKN, // Ethernet address w/ CIDR mask
+ ASNUM_TKN, // AS dot format
/* plumbing types */
FORK_TKN, // marks subgraph beginning
diff --git a/lib/command_lex.l b/lib/command_lex.l
index 64f74498b8..dc89191c13 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -38,6 +38,7 @@ VARIABLE [A-Z][-_A-Z:0-9]+
WORD (\-|\+)?[a-zA-Z0-9\*][-+_a-zA-Z0-9\*]*
NUMBER (\-|\+)?[0-9]{1,20}
RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
+ASNUM ASNUM
/* yytext shall be a pointer */
%pointer
@@ -57,6 +58,7 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
%}
[ \t]+ LOC_STEP /* ignore whitespace */;
+{ASNUM} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return ASNUM;}
{IPV4} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4;}
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4_PREFIX;}
{IPV6} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV6;}
diff --git a/lib/command_match.c b/lib/command_match.c
index 5ed643bc91..ff3c48fc31 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -10,6 +10,7 @@
#include "command_match.h"
#include "memory.h"
+#include "asn.h"
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
@@ -541,6 +542,7 @@ static enum match_type min_match_level(enum cmd_token_type type)
case END_TKN:
case NEG_ONLY_TKN:
case VARIABLE_TKN:
+ case ASNUM_TKN:
return exact_match;
}
@@ -564,6 +566,7 @@ static int score_precedence(enum cmd_token_type type)
case IPV6_PREFIX_TKN:
case MAC_TKN:
case MAC_PREFIX_TKN:
+ case ASNUM_TKN:
case RANGE_TKN:
return 2;
case WORD_TKN:
@@ -698,6 +701,8 @@ static enum match_type match_token(struct cmd_token *token, char *input_token)
return match_mac(input_token, false);
case MAC_PREFIX_TKN:
return match_mac(input_token, true);
+ case ASNUM_TKN:
+ return asn_str2asn_match(input_token);
case END_TKN:
case FORK_TKN:
case JOIN_TKN:
@@ -840,7 +845,6 @@ static enum match_type match_ipv4_prefix(const char *str)
return exact_match;
}
-
#define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
#define STATE_START 1
diff --git a/lib/command_parse.y b/lib/command_parse.y
index a29e090ef0..8867e98ccc 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -88,6 +88,7 @@
%token <string> RANGE
%token <string> MAC
%token <string> MAC_PREFIX
+%token <string> ASNUM
/* special syntax, value is irrelevant */
%token <string> EXCL_BRACKET
@@ -277,6 +278,11 @@ placeholder_token_real:
$$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
XFREE (MTYPE_LEX, $1);
}
+| ASNUM
+{
+ $$ = new_token_node (ctx, ASNUM_TKN, $1, doc_next(ctx));
+ XFREE (MTYPE_LEX, $1);
+}
placeholder_token:
placeholder_token_real varname_token
diff --git a/lib/command_py.c b/lib/command_py.c
index ceea5883d5..f8abcf8ef4 100644
--- a/lib/command_py.c
+++ b/lib/command_py.c
@@ -201,6 +201,7 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
item(IPV6_PREFIX_TKN); // IPV6 network prefixes
item(MAC_TKN); // MAC address
item(MAC_PREFIX_TKN); // MAC address with mask
+ item(ASNUM_TKN); // ASNUM
/* plumbing types */
item(FORK_TKN);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 0467dc1d7e..d1b7dd133e 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -992,7 +992,7 @@ static void frr_config_read_in(struct thread *t)
int ret;
context.client = NB_CLIENT_CLI;
- ret = nb_candidate_commit(&context, vty_shared_candidate_config,
+ ret = nb_candidate_commit(context, vty_shared_candidate_config,
true, "Read configuration file", NULL,
errmsg, sizeof(errmsg));
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
diff --git a/lib/log.h b/lib/log.h
index 8e94d3fd8c..b8452ac215 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -114,6 +114,21 @@ extern int proto_redistnum(int afi, const char *s);
extern const char *zserv_command_string(unsigned int command);
+#define OSPF_LOG(level, cond, fmt, ...) \
+ do { \
+ if (cond) \
+ zlog_##level(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define OSPF_LOG_ERR(fmt, ...) OSPF_LOG(err, true, fmt, ##__VA_ARGS__)
+
+#define OSPF_LOG_WARN(fmt, ...) OSPF_LOG(warn, true, fmt, ##__VA_ARGS__)
+
+#define OSPF_LOG_INFO(fmt, ...) OSPF_LOG(info, true, fmt, ##__VA_ARGS__)
+
+#define OSPF_LOG_DEBUG(cond, fmt, ...) OSPF_LOG(debug, cond, fmt, ##__VA_ARGS__)
+
+#define OSPF_LOG_NOTICE(fmt, ...) OSPF_LOG(notice, true, fmt, ##__VA_ARGS__)
/* structure useful for avoiding repeated rendering of the same timestamp */
struct timestamp_control {
diff --git a/lib/northbound.c b/lib/northbound.c
index b755264be1..6f2c522a29 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -61,7 +61,7 @@ static int nb_callback_configuration(struct nb_context *context,
struct nb_config_change *change,
char *errmsg, size_t errmsg_len);
static struct nb_transaction *
-nb_transaction_new(struct nb_context *context, struct nb_config *config,
+nb_transaction_new(struct nb_context context, struct nb_config *config,
struct nb_config_cbs *changes, const char *comment,
char *errmsg, size_t errmsg_len);
static void nb_transaction_free(struct nb_transaction *transaction);
@@ -835,7 +835,7 @@ int nb_candidate_validate(struct nb_context *context,
return ret;
}
-int nb_candidate_commit_prepare(struct nb_context *context,
+int nb_candidate_commit_prepare(struct nb_context context,
struct nb_config *candidate,
const char *comment,
struct nb_transaction **transaction,
@@ -860,9 +860,8 @@ int nb_candidate_commit_prepare(struct nb_context *context,
return NB_ERR_NO_CHANGES;
}
- if (nb_candidate_validate_code(context, candidate, &changes, errmsg,
- errmsg_len)
- != NB_OK) {
+ if (nb_candidate_validate_code(&context, candidate, &changes, errmsg,
+ errmsg_len) != NB_OK) {
flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
"%s: failed to validate candidate configuration",
__func__);
@@ -913,7 +912,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
nb_transaction_free(transaction);
}
-int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate,
+int nb_candidate_commit(struct nb_context context, struct nb_config *candidate,
bool save_transaction, const char *comment,
uint32_t *transaction_id, char *errmsg,
size_t errmsg_len)
@@ -1411,13 +1410,13 @@ static int nb_callback_configuration(struct nb_context *context,
}
static struct nb_transaction *
-nb_transaction_new(struct nb_context *context, struct nb_config *config,
+nb_transaction_new(struct nb_context context, struct nb_config *config,
struct nb_config_cbs *changes, const char *comment,
char *errmsg, size_t errmsg_len)
{
struct nb_transaction *transaction;
- if (nb_running_lock_check(context->client, context->user)) {
+ if (nb_running_lock_check(context.client, context.user)) {
strlcpy(errmsg,
"running configuration is locked by another client",
errmsg_len);
@@ -1469,7 +1468,7 @@ static int nb_transaction_process(enum nb_event event,
break;
/* Call the appropriate callback. */
- ret = nb_callback_configuration(transaction->context, event,
+ ret = nb_callback_configuration(&transaction->context, event,
change, errmsg, errmsg_len);
switch (event) {
case NB_EV_PREPARE:
@@ -1584,7 +1583,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
/* Call the 'apply_finish' callbacks, sorted by their priorities. */
RB_FOREACH (cb, nb_config_cbs, &cbs)
- nb_callback_apply_finish(transaction->context, cb->nb_node,
+ nb_callback_apply_finish(&transaction->context, cb->nb_node,
cb->dnode, errmsg, errmsg_len);
/* Release memory. */
diff --git a/lib/northbound.h b/lib/northbound.h
index c132daebdb..152810b3a9 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -622,22 +622,6 @@ struct nb_context {
/* Northbound user (can be NULL). */
const void *user;
-
- /* Client-specific data. */
-#if 0
- union {
- struct {
- } cli;
- struct {
- } confd;
- struct {
- } sysrepo;
- struct {
- } grpc;
- struct {
- } pcep;
- } client_data;
-#endif
};
/* Northbound configuration. */
@@ -666,7 +650,7 @@ struct nb_config_change {
/* Northbound configuration transaction. */
struct nb_transaction {
- struct nb_context *context;
+ struct nb_context context;
char comment[80];
struct nb_config *config;
struct nb_config_cbs changes;
@@ -927,7 +911,7 @@ extern int nb_candidate_validate(struct nb_context *context,
* the candidate configuration.
* - NB_ERR for other errors.
*/
-extern int nb_candidate_commit_prepare(struct nb_context *context,
+extern int nb_candidate_commit_prepare(struct nb_context context,
struct nb_config *candidate,
const char *comment,
struct nb_transaction **transaction,
@@ -1014,7 +998,7 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
* the candidate configuration.
* - NB_ERR for other errors.
*/
-extern int nb_candidate_commit(struct nb_context *context,
+extern int nb_candidate_commit(struct nb_context context,
struct nb_config *candidate,
bool save_transaction, const char *comment,
uint32_t *transaction_id, char *errmsg,
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 0dfa66b37e..fa5884fb78 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -46,7 +46,7 @@ static int nb_cli_classic_commit(struct vty *vty)
context.client = NB_CLIENT_CLI;
context.user = vty;
- ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL,
+ ret = nb_candidate_commit(context, vty->candidate_config, true, NULL,
NULL, errmsg, sizeof(errmsg));
switch (ret) {
case NB_OK:
@@ -313,7 +313,7 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty)
context.client = NB_CLIENT_CLI;
context.user = vty;
ret = nb_candidate_commit(
- &context, vty->confirmed_commit_rollback, true,
+ context, vty->confirmed_commit_rollback, true,
"Rollback to previous configuration - confirmed commit has timed out",
&transaction_id, errmsg, sizeof(errmsg));
if (ret == NB_OK) {
@@ -394,9 +394,8 @@ static int nb_cli_commit(struct vty *vty, bool force,
context.client = NB_CLIENT_CLI;
context.user = vty;
- ret = nb_candidate_commit(&context, vty->candidate_config, true,
- comment, &transaction_id, errmsg,
- sizeof(errmsg));
+ ret = nb_candidate_commit(context, vty->candidate_config, true, comment,
+ &transaction_id, errmsg, sizeof(errmsg));
/* Map northbound return code to CLI return code. */
switch (ret) {
@@ -1717,7 +1716,7 @@ static int nb_cli_rollback_configuration(struct vty *vty,
context.client = NB_CLIENT_CLI;
context.user = vty;
- ret = nb_candidate_commit(&context, candidate, true, comment, NULL,
+ ret = nb_candidate_commit(context, candidate, true, comment, NULL,
errmsg, sizeof(errmsg));
nb_config_free(candidate);
switch (ret) {
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index 81ba313e81..2b57ff2707 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -311,7 +311,7 @@ static void frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
*/
transaction = NULL;
context.client = NB_CLIENT_CONFD;
- ret = nb_candidate_commit_prepare(&context, candidate, NULL,
+ ret = nb_candidate_commit_prepare(context, candidate, NULL,
&transaction, errmsg, sizeof(errmsg));
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) {
enum confd_errcode errcode;
diff --git a/lib/northbound_db.c b/lib/northbound_db.c
index cefcfbcf1f..74abcde955 100644
--- a/lib/northbound_db.c
+++ b/lib/northbound_db.c
@@ -73,7 +73,7 @@ int nb_db_transaction_save(const struct nb_transaction *transaction,
if (!ss)
goto exit;
- client_name = nb_client_name(transaction->context->client);
+ client_name = nb_client_name(transaction->context.client);
/*
* Always record configurations in the XML format, save the default
* values too, as this covers the case where defaults may change.
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index f5d59d92d6..1459146eab 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -824,7 +824,7 @@ HandleUnaryCommit(UnaryRpcState<frr::CommitRequest, frr::CommitResponse> *tag)
case frr::CommitRequest::PREPARE:
grpc_debug("`-> Performing PREPARE");
ret = nb_candidate_commit_prepare(
- &context, candidate->config, comment.c_str(),
+ context, candidate->config, comment.c_str(),
&candidate->transaction, errmsg, sizeof(errmsg));
break;
case frr::CommitRequest::ABORT:
@@ -840,7 +840,7 @@ HandleUnaryCommit(UnaryRpcState<frr::CommitRequest, frr::CommitResponse> *tag)
break;
case frr::CommitRequest::ALL:
grpc_debug("`-> Performing ALL");
- ret = nb_candidate_commit(&context, candidate->config, true,
+ ret = nb_candidate_commit(context, candidate->config, true,
comment.c_str(), &transaction_id,
errmsg, sizeof(errmsg));
break;
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 824d81a51e..096414ff24 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -268,7 +268,7 @@ static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session,
* Validate the configuration changes and allocate all resources
* required to apply them.
*/
- ret = nb_candidate_commit_prepare(&context, candidate, NULL,
+ ret = nb_candidate_commit_prepare(context, candidate, NULL,
&transaction, errmsg, sizeof(errmsg));
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
flog_warn(
diff --git a/lib/prefix.c b/lib/prefix.c
index 655e28c9f0..a6aae08a6a 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -123,6 +123,23 @@ afi_t family2afi(int family)
return 0;
}
+const char *afi2str_lower(afi_t afi)
+{
+ switch (afi) {
+ case AFI_IP:
+ return "ipv4";
+ case AFI_IP6:
+ return "ipv6";
+ case AFI_L2VPN:
+ return "l2vpn";
+ case AFI_MAX:
+ case AFI_UNSPEC:
+ return "bad-value";
+ }
+
+ assert(!"Reached end of function we should never reach");
+}
+
const char *afi2str(afi_t afi)
{
switch (afi) {
@@ -1431,9 +1448,11 @@ int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to)
switch (addr->route_type) {
case BGP_EVPN_MAC_IP_ROUTE:
if (IS_IPADDR_V4(&addr->macip_addr.ip))
- ipaddr2prefix(&addr->macip_addr.ip, 32, to);
+ ipaddr2prefix(&addr->macip_addr.ip, IPV4_MAX_BITLEN,
+ to);
else if (IS_IPADDR_V6(&addr->macip_addr.ip))
- ipaddr2prefix(&addr->macip_addr.ip, 128, to);
+ ipaddr2prefix(&addr->macip_addr.ip, IPV6_MAX_BITLEN,
+ to);
else
return -1; /* mac only? */
diff --git a/lib/prefix.h b/lib/prefix.h
index 1fd652507f..9c57283706 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -383,6 +383,7 @@ extern afi_t family2afi(int);
extern const char *family2str(int family);
extern const char *safi2str(safi_t safi);
extern const char *afi2str(afi_t afi);
+extern const char *afi2str_lower(afi_t afi);
static inline afi_t prefix_afi(union prefixconstptr pu)
{
@@ -644,7 +645,10 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr)
#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *)
-#pragma FRR printfrr_ext "%pRD" (struct prefix_rd *)
+#pragma FRR printfrr_ext "%pRDP" (struct prefix_rd *)
+/* RD with AS4B with dot and dot+ format */
+#pragma FRR printfrr_ext "%pRDD" (struct prefix_rd *)
+#pragma FRR printfrr_ext "%pRDE" (struct prefix_rd *)
#pragma FRR printfrr_ext "%pPSG4" (struct prefix_sg *)
#endif
diff --git a/lib/routemap.c b/lib/routemap.c
index 6b4627082e..9f5c9e693e 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1804,26 +1804,24 @@ route_map_get_index(struct route_map *map, const struct prefix *prefix,
struct route_map_index *index = NULL, *best_index = NULL;
struct route_map_index *head_index = NULL;
struct route_table *table = NULL;
- struct prefix conv;
- unsigned char family;
- /*
- * Handling for matching evpn_routes in the prefix table.
- *
- * We convert type2/5 prefix to ipv4/6 prefix to do longest
- * prefix matching on.
+ /* Route-map optimization relies on LPM lookups of the prefix to reduce
+ * the amount of route-map clauses a given prefix needs to be processed
+ * against. These LPM trees are IPv4/IPv6-specific and prefix->family
+ * must be AF_INET or AF_INET6 in order for the lookup to succeed. So if
+ * the AF doesn't line up with the LPM trees, skip the optimization.
*/
- if (prefix->family == AF_EVPN) {
- if (evpn_prefix2prefix(prefix, &conv) != 0)
- return NULL;
-
- prefix = &conv;
+ if (map->optimization_disabled ||
+ (prefix->family == AF_INET && !map->ipv4_prefix_table) ||
+ (prefix->family == AF_INET6 && !map->ipv6_prefix_table)) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "Skipping route-map optimization for route-map: %s, pfx: %pFX, family: %d",
+ map->name, prefix, prefix->family);
+ return map->head;
}
-
- family = prefix->family;
-
- if (family == AF_INET)
+ if (prefix->family == AF_INET)
table = map->ipv4_prefix_table;
else
table = map->ipv6_prefix_table;
@@ -2545,6 +2543,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
struct route_map_index *index = NULL;
struct route_map_rule *set = NULL;
bool skip_match_clause = false;
+ struct prefix conv;
if (recursion > RMAP_RECURSION_LIMIT) {
flog_warn(
@@ -2562,37 +2561,53 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
map->applied++;
- if ((!map->optimization_disabled)
- && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
- index = route_map_get_index(map, prefix, match_object,
- &match_ret);
- if (index) {
- index->applied++;
- if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
+ /*
+ * Handling for matching evpn_routes in the prefix table.
+ *
+ * We convert type2/5 prefix to ipv4/6 prefix to do longest
+ * prefix matching on.
+ */
+ if (prefix->family == AF_EVPN) {
+ if (evpn_prefix2prefix(prefix, &conv) != 0) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
zlog_debug(
- "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
- map->name, index->pref, prefix,
- route_map_cmd_result_str(match_ret));
+ "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup",
+ prefix);
} else {
- if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
zlog_debug(
- "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
- prefix, map->name,
- route_map_cmd_result_str(match_ret));
- /*
- * No index matches this prefix. Return deny unless,
- * match_ret = RMAP_NOOP.
- */
- if (match_ret == RMAP_NOOP)
- ret = RMAP_PERMITMATCH;
- else
- ret = RMAP_DENYMATCH;
- goto route_map_apply_end;
+ "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup",
+ prefix, &conv);
+
+ prefix = &conv;
}
- skip_match_clause = true;
+ }
+
+ index = route_map_get_index(map, prefix, match_object, &match_ret);
+ if (index) {
+ index->applied++;
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
+ zlog_debug(
+ "Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
+ map->name, index->pref, prefix,
+ route_map_cmd_result_str(match_ret));
} else {
- index = map->head;
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
+ zlog_debug(
+ "No best match sequence for pfx: %pFX in route-map: %s, result: %s",
+ prefix, map->name,
+ route_map_cmd_result_str(match_ret));
+ /*
+ * No index matches this prefix. Return deny unless,
+ * match_ret = RMAP_NOOP.
+ */
+ if (match_ret == RMAP_NOOP)
+ ret = RMAP_PERMITMATCH;
+ else
+ ret = RMAP_DENYMATCH;
+ goto route_map_apply_end;
}
+ skip_match_clause = true;
for (; index; index = index->next) {
if (!skip_match_clause) {
diff --git a/lib/subdir.am b/lib/subdir.am
index 8d00668c8c..beef8675aa 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -13,6 +13,7 @@ lib_libfrr_la_SOURCES = \
lib/affinitymap_northbound.c \
lib/agg_table.c \
lib/atomlist.c \
+ lib/asn.c \
lib/base64.c \
lib/bfd.c \
lib/buffer.c \
@@ -169,6 +170,7 @@ pkginclude_HEADERS += \
lib/admin_group.h \
lib/affinitymap.h \
lib/agg_table.h \
+ lib/asn.h \
lib/atomlist.h \
lib/base64.h \
lib/bfd.h \
diff --git a/lib/vty.c b/lib/vty.c
index 76dfe9734e..786271abe8 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -297,6 +297,13 @@ int vty_json_no_pretty(struct vty *vty, struct json_object *json)
return vty_json_helper(vty, json, JSON_C_TO_STRING_NOSLASHESCAPE);
}
+void vty_json_empty(struct vty *vty)
+{
+ json_object *json = json_object_new_object();
+
+ vty_json(vty, json);
+}
+
/* Output current time to the vty. */
void vty_time_print(struct vty *vty, int cr)
{
@@ -2413,7 +2420,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
context.client = NB_CLIENT_CLI;
context.user = vty;
- ret = nb_candidate_commit(&context, vty->candidate_config, true,
+ ret = nb_candidate_commit(context, vty->candidate_config, true,
"Read configuration file", NULL,
errmsg, sizeof(errmsg));
if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
diff --git a/lib/vty.h b/lib/vty.h
index b8c677e354..3cab9590f1 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -344,7 +344,7 @@ extern bool vty_set_include(struct vty *vty, const char *regexp);
*/
extern int vty_json(struct vty *vty, struct json_object *json);
extern int vty_json_no_pretty(struct vty *vty, struct json_object *json);
-
+extern void vty_json_empty(struct vty *vty);
/* post fd to be passed to the vtysh client
* fd is owned by the VTY code after this and will be closed when done
*/
diff --git a/ospfclient/ospfclient.py b/ospfclient/ospfclient.py
index 7a7bfb13cf..7477ef8191 100755
--- a/ospfclient/ospfclient.py
+++ b/ospfclient/ospfclient.py
@@ -242,6 +242,16 @@ def nsm_name(state):
return names.get(state, str(state))
+class WithNothing:
+ "An object that does nothing when used with `with` statement."
+
+ async def __aenter__(self):
+ return
+
+ async def __aexit__(self, *args, **kwargs):
+ return
+
+
# --------------
# Client Classes
# --------------
@@ -547,15 +557,17 @@ class OspfOpaqueClient(OspfApiClient):
Args:
server: hostname or IP address of server default is "localhost"
+ wait_ready: if True then wait for OSPF to signal ready, in newer versions
+ FRR ospfd is always ready so this overhead can be skipped.
+ default is False.
Raises:
Will raise exceptions for failures with various `socket` modules
functions such as `socket.socket`, `socket.setsockopt`, `socket.bind`.
"""
- def __init__(self, server="localhost"):
+ def __init__(self, server="localhost", wait_ready=False):
handlers = {
- MSG_READY_NOTIFY: self._ready_msg,
MSG_LSA_UPDATE_NOTIFY: self._lsa_change_msg,
MSG_LSA_DELETE_NOTIFY: self._lsa_change_msg,
MSG_NEW_IF: self._if_msg,
@@ -565,9 +577,13 @@ class OspfOpaqueClient(OspfApiClient):
MSG_REACHABLE_CHANGE: self._reachable_msg,
MSG_ROUTER_ID_CHANGE: self._router_id_msg,
}
+ if wait_ready:
+ handlers[MSG_READY_NOTIFY] = self._ready_msg
+
super().__init__(server, handlers)
- self.ready_lock = Lock()
+ self.wait_ready = wait_ready
+ self.ready_lock = Lock() if wait_ready else WithNothing()
self.ready_cond = {
LSA_TYPE_OPAQUE_LINK: {},
LSA_TYPE_OPAQUE_AREA: {},
@@ -604,13 +620,9 @@ class OspfOpaqueClient(OspfApiClient):
mp = struct.pack(msg_fmt[mt], lsa_type, otype)
await self.msg_send_raises(mt, mp)
- async def _assure_opaque_ready(self, lsa_type, otype):
- async with self.ready_lock:
- if self.ready_cond[lsa_type].get(otype) is True:
- return
-
- await self._register_opaque_data(lsa_type, otype)
- await self.wait_opaque_ready(lsa_type, otype)
+ # If we are not waiting, mark ready for register check
+ if not self.wait_ready:
+ self.ready_cond[lsa_type][otype] = True
async def _handle_msg_loop(self):
try:
@@ -643,6 +655,8 @@ class OspfOpaqueClient(OspfApiClient):
return lsa
async def _ready_msg(self, mt, msg, extra, lsa_type, otype, addr):
+ assert self.wait_ready
+
if lsa_type == LSA_TYPE_OPAQUE_LINK:
e = "ifaddr {}".format(ip(addr))
elif lsa_type == LSA_TYPE_OPAQUE_AREA:
@@ -812,6 +826,7 @@ class OspfOpaqueClient(OspfApiClient):
Raises:
See `msg_send_raises`
"""
+ assert self.ready_cond.get(lsa_type, {}).get(otype) is True, "Not Registered!"
if lsa_type == LSA_TYPE_OPAQUE_LINK:
ifaddr, aid = int(addr), 0
@@ -829,7 +844,6 @@ class OspfOpaqueClient(OspfApiClient):
*OspfOpaqueClient._opaque_args(lsa_type, otype, oid, data),
)
msg += data
- await self._assure_opaque_ready(lsa_type, otype)
await self.msg_send_raises(mt, msg)
async def delete_opaque_data(self, addr, lsa_type, otype, oid, flags=0):
@@ -841,21 +855,31 @@ class OspfOpaqueClient(OspfApiClient):
Args:
addr: depends on lsa_type, LINK => ifaddr, AREA => area ID, AS => ignored
lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS}
- otype: (octet) opaque type. Note: the type will be registered if the user
- has not explicity done that yet with `register_opaque_data`.
+ otype: (octet) opaque type.
oid: (3 octets) ID of this opaque data
flags: (octet) optional flags (e.g., OSPF_API_DEL_ZERO_LEN_LSA, defaults to no flags)
Raises:
See `msg_send_raises`
"""
- if (lsa_type, otype) in self.opaque_change_cb:
- del self.opaque_change_cb[(lsa_type, otype)]
+ assert self.ready_cond.get(lsa_type, {}).get(otype) is True, "Not Registered!"
mt = MSG_DELETE_REQUEST
- await self._assure_opaque_ready(lsa_type, otype)
mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, flags, oid)
await self.msg_send_raises(mt, mp)
+ async def is_registered(self, lsa_type, otype):
+ """Determine if an (lsa_type, otype) tuple has been registered with FRR
+
+ This determines if the type has been registered, but not necessarily if it is
+ ready, if that is required use the `wait_opaque_ready` metheod.
+
+ Args:
+ lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS}
+ otype: (octet) opaque type.
+ """
+ async with self.ready_lock:
+ return self.ready_cond.get(lsa_type, {}).get(otype) is not None
+
async def register_opaque_data(self, lsa_type, otype, callback=None):
"""Register intent to advertise opaque data.
@@ -865,8 +889,7 @@ class OspfOpaqueClient(OspfApiClient):
Args:
lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS}
- otype: (octet) opaque type. Note: the type will be registered if the user
- has not explicity done that yet with `register_opaque_data`.
+ otype: (octet) opaque type.
callback: if given, callback will be called when changes are received for
LSA of the given (lsa_type, otype). The callbacks signature is:
@@ -882,6 +905,10 @@ class OspfOpaqueClient(OspfApiClient):
Raises:
See `msg_send_raises`
"""
+ assert not await self.is_registered(
+ lsa_type, otype
+ ), "Registering registered type"
+
if callback:
self.opaque_change_cb[(lsa_type, otype)] = callback
elif (lsa_type, otype) in self.opaque_change_cb:
@@ -900,6 +927,8 @@ class OspfOpaqueClient(OspfApiClient):
if cond is True:
return
+ assert self.wait_ready
+
logging.debug(
"waiting for ready %s opaque-type %s", lsa_typename(lsa_type), otype
)
@@ -920,8 +949,7 @@ class OspfOpaqueClient(OspfApiClient):
Args:
lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS}
- otype: (octet) opaque type. Note: the type will be registered if the user
- has not explicity done that yet with `register_opaque_data`.
+ otype: (octet) opaque type.
callback: if given, callback will be called when changes are received for
LSA of the given (lsa_type, otype). The callbacks signature is:
@@ -938,17 +966,8 @@ class OspfOpaqueClient(OspfApiClient):
See `msg_send_raises`
"""
- if callback:
- self.opaque_change_cb[(lsa_type, otype)] = callback
- elif (lsa_type, otype) in self.opaque_change_cb:
- logging.warning(
- "OSPFCLIENT: register: removing callback for %s opaque-type %s",
- lsa_typename(lsa_type),
- otype,
- )
- del self.opaque_change_cb[(lsa_type, otype)]
-
- return await self._assure_opaque_ready(lsa_type, otype)
+ await self.register_opaque_data(lsa_type, otype, callback)
+ await self.wait_opaque_ready(lsa_type, otype)
async def unregister_opaque_data(self, lsa_type, otype):
"""Unregister intent to advertise opaque data.
@@ -958,11 +977,13 @@ class OspfOpaqueClient(OspfApiClient):
Args:
lsa_type: LSA_TYPE_OPAQUE_{LINK,AREA,AS}
- otype: (octet) opaque type. Note: the type will be registered if the user
- has not explicity done that yet with `register_opaque_data`.
+ otype: (octet) opaque type.
Raises:
See `msg_send_raises`
"""
+ assert await self.is_registered(
+ lsa_type, otype
+ ), "Unregistering unregistered type"
if (lsa_type, otype) in self.opaque_change_cb:
del self.opaque_change_cb[(lsa_type, otype)]
@@ -1068,6 +1089,17 @@ class OspfOpaqueClient(OspfApiClient):
# ================
# CLI/Script Usage
# ================
+def next_action(action_list=None):
+ "Get next action from list or STDIN"
+ if action_list:
+ for action in action_list:
+ yield action
+ else:
+ while True:
+ action = input("")
+ if not action:
+ break
+ yield action.strip()
async def async_main(args):
@@ -1086,50 +1118,53 @@ async def async_main(args):
await c.req_ism_states()
await c.req_nsm_states()
- if args.actions:
- for action in args.actions:
- _s = action.split(",")
- what = _s.pop(False)
- if what.casefold() == "wait":
- stime = int(_s.pop(False))
- logging.info("waiting %s seconds", stime)
- await asyncio.sleep(stime)
- logging.info("wait complete: %s seconds", stime)
- continue
- ltype = int(_s.pop(False))
- if ltype == 11:
- addr = ip(0)
- else:
- aval = _s.pop(False)
- try:
- addr = ip(int(aval))
- except ValueError:
- addr = ip(aval)
- oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))]
- if what.casefold() == "add":
+ for action in next_action(args.actions):
+ _s = action.split(",")
+ what = _s.pop(False)
+ if what.casefold() == "wait":
+ stime = int(_s.pop(False))
+ logging.info("waiting %s seconds", stime)
+ await asyncio.sleep(stime)
+ logging.info("wait complete: %s seconds", stime)
+ continue
+ ltype = int(_s.pop(False))
+ if ltype == 11:
+ addr = ip(0)
+ else:
+ aval = _s.pop(False)
+ try:
+ addr = ip(int(aval))
+ except ValueError:
+ addr = ip(aval)
+ oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))]
+
+ if not await c.is_registered(oargs[1], oargs[2]):
+ await c.register_opaque_data_wait(oargs[1], oargs[2])
+
+ if what.casefold() == "add":
+ try:
+ b = bytes.fromhex(_s.pop(False))
+ except IndexError:
+ b = b""
+ logging.info("opaque data is %s octets", len(b))
+ # Needs to be multiple of 4 in length
+ mod = len(b) % 4
+ if mod:
+ b += b"\x00" * (4 - mod)
+ logging.info("opaque padding to %s octets", len(b))
+
+ await c.add_opaque_data(*oargs, b)
+ else:
+ assert what.casefold().startswith("del")
+ f = 0
+ if len(_s) >= 1:
try:
- b = bytes.fromhex(_s.pop(False))
+ f = int(_s.pop(False))
except IndexError:
- b = b""
- logging.info("opaque data is %s octets", len(b))
- # Needs to be multiple of 4 in length
- mod = len(b) % 4
- if mod:
- b += b"\x00" * (4 - mod)
- logging.info("opaque padding to %s octets", len(b))
-
- await c.add_opaque_data(*oargs, b)
- else:
- assert what.casefold().startswith("del")
- f = 0
- if len(_s) >= 1:
- try:
- f = int(_s.pop(False))
- except IndexError:
- f = 0
- await c.delete_opaque_data(*oargs, f)
- if args.exit:
- return 0
+ f = 0
+ await c.delete_opaque_data(*oargs, f)
+ if not args.actions or args.exit:
+ return 0
except Exception as error:
logging.error("async_main: unexpected error: %s", error, exc_info=True)
return 2
@@ -1145,19 +1180,23 @@ async def async_main(args):
def main(*args):
ap = argparse.ArgumentParser(args)
+ ap.add_argument("--logtag", default="CLIENT", help="tag to identify log messages")
ap.add_argument("--exit", action="store_true", help="Exit after commands")
ap.add_argument("--server", default="localhost", help="OSPF API server")
ap.add_argument("-v", "--verbose", action="store_true", help="be verbose")
ap.add_argument(
"actions",
nargs="*",
- help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]",
+ help="WAIT,SEC|(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]",
)
args = ap.parse_args()
level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(
- level=level, format="%(asctime)s %(levelname)s: CLIENT: %(name)s %(message)s"
+ level=level,
+ format="%(asctime)s %(levelname)s: {}: %(name)s %(message)s".format(
+ args.logtag
+ ),
)
logging.info("ospfclient: starting")
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index 55cb8b183a..8f177cbce1 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -1559,6 +1559,254 @@ static void ospf_abr_announce_stub_defaults(struct ospf *ospf)
zlog_debug("%s: Stop", __func__);
}
+/** @brief Function to check and generate indication
+ * LSA for area on which we received
+ * indication LSA flush.
+ * @param Ospf instance.
+ * @param Area on which indication lsa flush is to be generated.
+ * @return Void.
+ */
+void ospf_generate_indication_lsa(struct ospf *ospf, struct ospf_area *area)
+{
+ bool area_fr_not_supp = false;
+
+ /* Check if you have any area which doesn't support
+ * flood reduction.
+ */
+
+ area_fr_not_supp = ospf_check_fr_enabled_all(ospf) ? false : true;
+
+ /* If any one of the area doestn't support FR, generate
+ * indication LSA on behalf of that area.
+ */
+
+ if (area_fr_not_supp && !area->fr_info.area_ind_lsa_recvd &&
+ !area->fr_info.indication_lsa_self &&
+ !area->fr_info.area_dc_clear) {
+
+ struct prefix_ipv4 p;
+ struct ospf_lsa *new;
+
+ p.family = AF_INET;
+ p.prefix = ospf->router_id;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ new = ospf_summary_asbr_lsa_originate(&p, OSPF_LS_INFINITY,
+ area);
+ if (!new) {
+ zlog_debug("%s: Indication lsa originate failed",
+ __func__);
+ return;
+ }
+ /* save the indication lsa for that area */
+ area->fr_info.indication_lsa_self = new;
+ }
+}
+
+/** @brief Function to receive and process indication LSA
+ * flush from area.
+ * @param lsa being flushed.
+ * @return Void.
+ */
+void ospf_recv_indication_lsa_flush(struct ospf_lsa *lsa)
+{
+ if (!IS_LSA_SELF(lsa) && IS_LSA_MAXAGE(lsa) &&
+ ospf_check_indication_lsa(lsa)) {
+ lsa->area->fr_info.area_ind_lsa_recvd = false;
+
+ OSPF_LOG_INFO("%s: Received an ind lsa: %pI4 area %pI4",
+ __func__, &lsa->data->id, &lsa->area->area_id);
+
+ if (!IS_OSPF_ABR(lsa->area->ospf))
+ return;
+
+ /* If the LSA received is a indication LSA with maxage on
+ * the network, then check and regenerate indication
+ * LSA if any of our areas don't support flood reduction.
+ */
+ ospf_generate_indication_lsa(lsa->area->ospf, lsa->area);
+ }
+}
+
+/** @brief Function to generate indication LSAs.
+ * @param Ospf instance.
+ * @param Area on behalf of which indication
+ * LSA is generated LSA.
+ * @return Void.
+ */
+void ospf_abr_generate_indication_lsa(struct ospf *ospf,
+ const struct ospf_area *area)
+{
+ struct ospf_lsa *new;
+ struct listnode *node;
+ struct ospf_area *o_area;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, o_area)) {
+ if (o_area == area)
+ continue;
+
+ if (o_area->fr_info.indication_lsa_self ||
+ o_area->fr_info.area_ind_lsa_recvd ||
+ o_area->fr_info.area_dc_clear) {
+ /* if the area has already received an
+ * indication LSA or if area already has
+ * LSAs with DC bit 0 other than
+ * indication LSA then don't generate
+ * indication LSA in those areas.
+ */
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "Area %pI4 has LSAs with dc bit clear",
+ &o_area->area_id);
+ continue;
+
+ } else {
+
+ struct prefix_ipv4 p;
+
+ p.family = AF_INET;
+ p.prefix = ospf->router_id;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ new = ospf_summary_asbr_lsa_originate(
+ &p, OSPF_LS_INFINITY, o_area);
+ if (!new) {
+ zlog_debug(
+ "%s: Indication lsa originate Failed",
+ __func__);
+ return;
+ }
+ /* save the indication lsa for that area */
+ o_area->fr_info.indication_lsa_self = new;
+ }
+ }
+}
+
+/** @brief Flush the indication LSA from all the areas
+ * of ospf instance.
+ * @param Ospf instance.
+ * @return Void.
+ */
+void ospf_flush_indication_lsas(struct ospf *ospf)
+{
+ struct ospf_area *area;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
+ if (area->fr_info.indication_lsa_self) {
+ OSPF_LOG_INFO(
+ "Flushing ind lsa: %pI4 area %pI4",
+ &area->fr_info.indication_lsa_self->data->id,
+ &area->area_id);
+ ospf_schedule_lsa_flush_area(
+ area, area->fr_info.indication_lsa_self);
+ area->fr_info.indication_lsa_self = NULL;
+ }
+ }
+}
+
+/** @brief Check if flood reduction is enabled on
+ * all the areas.
+ * @param Ospf instance.
+ * @return Void.
+ */
+bool ospf_check_fr_enabled_all(struct ospf *ospf)
+{
+ const struct ospf_area *area;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
+ if (!ospf_check_area_fr_enabled(area))
+ return false;
+
+ return true;
+}
+
+/** @brief Abr function to check conditions for generation
+ * of indication. LSAs/announcing non-DNA routers
+ * in the area.
+ * @param thread
+ * @return 0.
+ */
+static void ospf_abr_announce_non_dna_routers(struct thread *thread)
+{
+ struct ospf_area *area;
+ struct listnode *node;
+ struct ospf *ospf = THREAD_ARG(thread);
+
+ THREAD_OFF(ospf->t_abr_fr);
+
+ if (!IS_OSPF_ABR(ospf))
+ return;
+
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "%s(): Start", __func__);
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "%s: Area %pI4 FR enabled: %d", __func__,
+ &area->area_id, area->fr_info.enabled);
+ OSPF_LOG_DEBUG(
+ IS_DEBUG_OSPF_EVENT,
+ "LSA with DC bit clear: %d Recived indication LSA: %d",
+ area->fr_info.area_dc_clear,
+ area->fr_info.area_ind_lsa_recvd);
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "FR state change: %d",
+ area->fr_info.state_changed);
+ if (!OSPF_IS_AREA_BACKBONE(area) &&
+ area->fr_info.area_dc_clear) {
+ /* rfc4136 rfc1793: Suppose if the abr is connected to
+ * a regular non-backbone OSPF area, Furthermore if
+ * the area has LSAs with the DC-bit clear, other
+ * than indication-LSAs. Then originate indication-LSAs
+ * into all other directly-connected "regular" areas,
+ * including the backbone area.
+ */
+ ospf_abr_generate_indication_lsa(ospf, area);
+ }
+
+ if (OSPF_IS_AREA_BACKBONE(area) &&
+ (area->fr_info.area_dc_clear ||
+ area->fr_info.area_ind_lsa_recvd)) {
+ /* rfc4136 rfc1793: Suppose if the abr is connected to
+ * backbone OSPF area. Furthermore, if backbone has
+ * LSAs with the DC-bit clear that are either
+ * a) not indication-LSAs or indication-LSAs or
+ * b) indication-LSAs that have been originated by
+ * other routers,
+ * then originate indication-LSAs into all other
+ * directly-connected "regular" non-backbone areas.
+ */
+ ospf_abr_generate_indication_lsa(ospf, area);
+ }
+
+ if (area->fr_info.enabled && area->fr_info.state_changed &&
+ area->fr_info.indication_lsa_self) {
+ /* Ospf area flood reduction state changed
+ * area now supports flood reduction.
+ * check if all other areas support flood reduction
+ * if yes then flush indication LSAs generated in
+ * all the areas.
+ */
+ if (ospf_check_fr_enabled_all(ospf))
+ ospf_flush_indication_lsas(ospf);
+
+ area->fr_info.state_changed = false;
+ }
+
+ /* If previously we had generated indication lsa
+ * but now area has lsas with dc bit set to 0
+ * apart from indication lsa, we'll clear indication lsa
+ */
+ if (area->fr_info.area_dc_clear &&
+ area->fr_info.indication_lsa_self) {
+ ospf_schedule_lsa_flush_area(
+ area, area->fr_info.indication_lsa_self);
+ area->fr_info.indication_lsa_self = NULL;
+ }
+ }
+
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "%s(): Stop", __func__);
+}
+
static int ospf_abr_remove_unapproved_translates_apply(struct ospf *ospf,
struct ospf_lsa *lsa)
{
@@ -1613,9 +1861,13 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf)
ospf_lsa_flush_area(lsa, area);
LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
- if (ospf_lsa_is_self_originated(ospf, lsa))
- if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
- ospf_lsa_flush_area(lsa, area);
+ if (ospf_lsa_is_self_originated(ospf, lsa) &&
+ !CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED) &&
+ /* Do not remove indication LSAs while
+ * flushing unapproved summaries.
+ */
+ !ospf_check_indication_lsa(lsa))
+ ospf_lsa_flush_area(lsa, area);
}
if (IS_DEBUG_OSPF_EVENT)
@@ -1778,6 +2030,20 @@ void ospf_abr_task(struct ospf *ospf)
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: announce stub defaults", __func__);
ospf_abr_announce_stub_defaults(ospf);
+
+ if (ospf->fr_configured) {
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "%s(): announce non-DNArouters",
+ __func__);
+ /*
+ * Schedule indication lsa generation timer,
+ * giving time for route synchronization in
+ * all the routers.
+ */
+ thread_add_timer(
+ master, ospf_abr_announce_non_dna_routers, ospf,
+ OSPF_ABR_DNA_TIMER, &ospf->t_abr_fr);
+ }
}
if (IS_DEBUG_OSPF_EVENT)
diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h
index 21e87669fa..19d444b125 100644
--- a/ospfd/ospf_abr.h
+++ b/ospfd/ospf_abr.h
@@ -8,6 +8,11 @@
#define _ZEBRA_OSPF_ABR_H
#define OSPF_ABR_TASK_DELAY 5
+#define OSPF_ABR_DNA_TIMER 10
+/* Delay in announceing Non-DNA routers
+ * so that LSAs are completely synced
+ * before generating indication LSAs.
+ */
#define OSPF_AREA_RANGE_ADVERTISE (1 << 0)
#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1)
@@ -69,4 +74,20 @@ extern void ospf_schedule_abr_task(struct ospf *);
extern void ospf_abr_announce_network_to_area(struct prefix_ipv4 *, uint32_t,
struct ospf_area *);
extern void ospf_abr_nssa_check_status(struct ospf *ospf);
+extern void ospf_abr_generate_indication_lsa(struct ospf *ospf,
+ const struct ospf_area *area);
+extern void ospf_flush_indication_lsas(struct ospf *ospf);
+extern void ospf_generate_indication_lsa(struct ospf *ospf,
+ struct ospf_area *area);
+extern bool ospf_check_fr_enabled_all(struct ospf *ospf);
+extern void ospf_recv_indication_lsa_flush(struct ospf_lsa *lsa);
+
+/** @brief Static inline functions.
+ * @param Area pointer.
+ * @return area Flood Reduction status.
+ */
+static inline bool ospf_check_area_fr_enabled(const struct ospf_area *area)
+{
+ return area->fr_info.enabled ? true : false;
+}
#endif /* _ZEBRA_OSPF_ABR_H */
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 728945032b..5e4fc30a28 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -2578,9 +2578,12 @@ static inline int cmp_route_nodes(struct route_node *orn,
return 1;
else if (!nrn)
return -1;
- else if (orn->p.u.prefix4.s_addr < nrn->p.u.prefix4.s_addr)
+
+ uint32_t opn = ntohl(orn->p.u.prefix4.s_addr);
+ uint32_t npn = ntohl(nrn->p.u.prefix4.s_addr);
+ if (opn < npn)
return -1;
- else if (orn->p.u.prefix4.s_addr > nrn->p.u.prefix4.s_addr)
+ else if (opn > npn)
return 1;
else
return 0;
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index de51500b0a..b74b84e37d 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -133,13 +133,6 @@ const char *ospf_if_name_string(struct ospf_interface *oi)
return buf;
}
-/* Display only the nbr state.*/
-void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size)
-{
- snprintf(buf, size, "%s",
- lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
-}
-
int ospf_nbr_ism_state(struct ospf_neighbor *nbr)
{
int state;
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 596d49256f..0f217971ee 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -140,8 +140,6 @@ extern const char *ospf_area_name_string(struct ospf_area *);
extern const char *ospf_area_desc_string(struct ospf_area *);
extern const char *ospf_if_name_string(struct ospf_interface *);
extern int ospf_nbr_ism_state(struct ospf_neighbor *nbr);
-extern void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf,
- size_t size);
extern void ospf_nbr_ism_state_message(struct ospf_neighbor *nbr, char *buf,
size_t size);
extern const char *ospf_timer_dump(struct thread *, char *, size_t);
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index debbcd964f..d0453bbc4a 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -35,6 +35,75 @@
extern struct zclient *zclient;
+/** @brief Function to refresh type-5 and type-7 DNA
+ * LSAs when we receive an indication LSA.
+ * @param Ospf instance.
+ * @return Void.
+ */
+void ospf_refresh_dna_type5_and_type7_lsas(struct ospf *ospf)
+{
+ struct route_node *rn;
+ struct ospf_lsa *lsa = NULL;
+
+ LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa) &&
+ CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+ ospf_lsa_refresh(ospf, lsa);
+
+ LSDB_LOOP (NSSA_LSDB(ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa) &&
+ CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+ ospf_lsa_refresh(ospf, lsa);
+}
+
+/** @brief Function to update area flood reduction states.
+ * @param area pointer.
+ * @return Void.
+ */
+void ospf_area_update_fr_state(struct ospf_area *area)
+{
+ unsigned int count_router_lsas = 0;
+
+ if (area == NULL)
+ return;
+
+ count_router_lsas =
+ (unsigned int)(ospf_lsdb_count(area->lsdb, OSPF_ROUTER_LSA) -
+ ospf_lsdb_count_self(area->lsdb,
+ OSPF_ROUTER_LSA));
+
+ if (count_router_lsas >
+ (unsigned int)area->fr_info.router_lsas_recv_dc_bit) {
+ area->fr_info.enabled = false;
+ area->fr_info.area_dc_clear = true;
+ return;
+ } else if (count_router_lsas <
+ (unsigned int)area->fr_info.router_lsas_recv_dc_bit) {
+ /* This can never happen, total number of router lsas received
+ * can never be less than router lsas received with dc bit set
+ */
+ OSPF_LOG_ERR("%s: Counter mismatch for area %pI4", __func__,
+ &area->area_id);
+ OSPF_LOG_ERR(
+ "%s: router LSAs in lsdb %d router LSAs recvd with dc bit set %d",
+ __func__, count_router_lsas,
+ area->fr_info.router_lsas_recv_dc_bit);
+ return;
+ }
+
+ area->fr_info.area_dc_clear = false;
+
+ if (OSPF_FR_CONFIG(area->ospf, area)) {
+ if (!area->fr_info.enabled) {
+ area->fr_info.enabled = true;
+ area->fr_info.state_changed = true;
+ }
+ } else {
+ area->fr_info.enabled = false;
+ area->fr_info.area_dc_clear = true;
+ }
+}
+
/* Do the LSA acking specified in table 19, Section 13.5, row 2
* This get called from ospf_flood_out_interface. Declared inline
* for speed. */
@@ -413,6 +482,55 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr,
if (!(new = ospf_lsa_install(ospf, oi, new)))
return -1; /* unknown LSA type or any other error condition */
+ /* check if the installed LSA is an indication LSA */
+ if (ospf_check_indication_lsa(new) && !IS_LSA_SELF(new) &&
+ !IS_LSA_MAXAGE(new)) {
+ new->area->fr_info.area_ind_lsa_recvd = true;
+ /* check if there are already type 5 LSAs originated
+ * with DNA bit set, if yes reoriginate those LSAs.
+ */
+ ospf_refresh_dna_type5_and_type7_lsas(ospf);
+ }
+
+ /* Check if we recived an indication LSA flush on backbone
+ * network.
+ */
+ ospf_recv_indication_lsa_flush(new);
+
+ if (new->area && OSPF_FR_CONFIG(ospf, new->area)) {
+ struct lsa_header const *lsah = new->data;
+
+ if (!CHECK_FLAG(lsah->options, OSPF_OPTION_DC) &&
+ !ospf_check_indication_lsa(new)) {
+
+ new->area->fr_info.area_dc_clear = true;
+ /* check of previously area supported flood reduction */
+ if (new->area->fr_info.enabled) {
+ new->area->fr_info.enabled = false;
+ OSPF_LOG_DEBUG(
+ IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction STATE on -> off by %s LSA",
+ dump_lsa_key(new));
+ /* if yes update all the lsa to the area the
+ * new LSAs will have DNA bit set to 0.
+ */
+ ospf_refresh_area_self_lsas(new->area);
+ }
+ } else if (!new->area->fr_info.enabled) {
+ /* check again after installing new LSA that area
+ * supports flood reduction.
+ */
+ ospf_area_update_fr_state(new->area);
+ if (new->area->fr_info.enabled) {
+ OSPF_LOG_DEBUG(
+ IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction STATE off -> on by %s LSA",
+ dump_lsa_key(new));
+ ospf_refresh_area_self_lsas(new->area);
+ }
+ }
+ }
+
/* Acknowledge the receipt of the LSA by sending a Link State
Acknowledgment packet back out the receiving interface. */
if (lsa_ack_flag)
@@ -450,6 +568,25 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
if (!ospf_if_is_enable(oi))
return 0;
+ /* If flood reduction is configured, set the DC bit on the lsa. */
+ if (IS_LSA_SELF(lsa)) {
+ if (OSPF_FR_CONFIG(oi->area->ospf, oi->area)) {
+ if (!ospf_check_indication_lsa(lsa)) {
+ SET_FLAG(lsa->data->options, OSPF_OPTION_DC);
+ ospf_lsa_checksum(lsa->data);
+ }
+ } else if (CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC)) {
+ UNSET_FLAG(lsa->data->options, OSPF_OPTION_DC);
+ ospf_lsa_checksum(lsa->data);
+ }
+
+ /* If flood reduction is enabled then set DNA bit on the
+ * self lsas.
+ */
+ if (oi->area->fr_info.enabled)
+ SET_FLAG(lsa->data->ls_age, DO_NOT_AGE);
+ }
+
/* Remember if new LSA is added to a retransmit list. */
retx_flag = 0;
diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h
index 6dce6937bf..3757400d0c 100644
--- a/ospfd/ospf_flood.h
+++ b/ospfd/ospf_flood.h
@@ -53,5 +53,7 @@ extern struct external_info *ospf_external_info_check(struct ospf *,
struct ospf_lsa *);
extern void ospf_lsdb_init(struct ospf_lsdb *);
+extern void ospf_area_update_fr_state(struct ospf_area *area);
+extern void ospf_refresh_dna_type5_and_type7_lsas(struct ospf *ospf);
#endif /* _ZEBRA_OSPF_FLOOD_H */
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index ffbfc2af27..49e342d72b 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -70,6 +70,16 @@ uint32_t get_metric(uint8_t *metric)
return m;
}
+/** @brief The Function checks self generated DoNotAge.
+ * @param lsa pointer.
+ * @return true or false.
+ */
+bool ospf_check_dna_lsa(const struct ospf_lsa *lsa)
+{
+ return ((IS_LSA_SELF(lsa) && CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE))
+ ? true
+ : false);
+}
struct timeval int2tv(int a)
{
@@ -121,6 +131,16 @@ int get_age(struct ospf_lsa *lsa)
{
struct timeval rel;
+ /* As per rfc4136, the self-originated LSAs in their
+ * own database keep aging, however rfc doesn't tell
+ * till how long the LSA should be aged, as of now
+ * we are capping it for OSPF_LSA_MAXAGE.
+ */
+
+ /* If LSA is marked as donotage */
+ if (CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE) && !IS_LSA_SELF(lsa))
+ return ntohs(lsa->data->ls_age);
+
monotime_since(&lsa->tv_recv, &rel);
return ntohs(lsa->data->ls_age) + rel.tv_sec;
}
@@ -1119,6 +1139,10 @@ static struct ospf_lsa *ospf_network_lsa_refresh(struct ospf_lsa *lsa)
}
return NULL;
}
+
+ if (oi->state != ISM_DR)
+ return NULL;
+
/* Delete LSA from neighbor retransmit-list. */
ospf_ls_retransmit_delete_nbr_area(area, lsa);
@@ -1518,10 +1542,15 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
struct ospf_lsa *new;
struct summary_lsa *sl;
struct prefix p;
+ bool ind_lsa = false;
/* Sanity check. */
assert(lsa->data);
+ if (lsa->area->fr_info.indication_lsa_self &&
+ (lsa->area->fr_info.indication_lsa_self == lsa))
+ ind_lsa = true;
+
sl = (struct summary_lsa *)lsa->data;
p.prefixlen = ip_masklen(sl->mask);
new = ospf_summary_asbr_lsa_new(lsa->area, &p, GET_METRIC(sl->metric),
@@ -1536,6 +1565,9 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
/* Flood LSA through area. */
ospf_flood_through_area(new->area, NULL, new);
+ if (ind_lsa)
+ new->area->fr_info.indication_lsa_self = new;
+
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
zlog_debug("LSA[Type%d:%pI4]: summary-ASBR-LSA refresh",
new->data->type, &new->data->id);
@@ -3626,6 +3658,49 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
return;
}
+/** @brief Function to refresh all the self originated
+ * LSAs for area, when FR state change happens.
+ * @param area pointer.
+ * @return Void.
+ */
+void ospf_refresh_area_self_lsas(struct ospf_area *area)
+{
+ struct listnode *node2;
+ struct listnode *nnode2;
+ struct ospf_interface *oi;
+ struct route_node *rn;
+ struct ospf_lsa *lsa;
+
+ if (!area)
+ return;
+
+ if (area->router_lsa_self)
+ ospf_lsa_refresh(area->ospf, area->router_lsa_self);
+
+ for (ALL_LIST_ELEMENTS(area->oiflist, node2, nnode2, oi))
+ if (oi->network_lsa_self)
+ ospf_lsa_refresh(oi->ospf, oi->network_lsa_self);
+
+ LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (EXTERNAL_LSDB(area->ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+ LSDB_LOOP (OPAQUE_AS_LSDB(area->ospf), rn, lsa)
+ if (IS_LSA_SELF(lsa))
+ ospf_lsa_refresh(area->ospf, lsa);
+}
+
/* If there is self-originated LSA, then return 1, otherwise return 0. */
/* An interface-independent version of ospf_lsa_is_self_originated */
int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *lsa)
@@ -3961,6 +4036,7 @@ void ospf_lsa_refresh_walker(struct thread *t)
struct ospf_lsa *lsa;
int i;
struct list *lsa_to_refresh = list_new();
+ bool dna_lsa;
if (IS_DEBUG_OSPF(lsa, LSA_REFRESH))
zlog_debug("LSA[Refresh]: %s: start", __func__);
@@ -4019,10 +4095,14 @@ void ospf_lsa_refresh_walker(struct thread *t)
ospf->lsa_refresher_started = monotime(NULL);
for (ALL_LIST_ELEMENTS(lsa_to_refresh, node, nnode, lsa)) {
- ospf_lsa_refresh(ospf, lsa);
- assert(lsa->lock > 0);
- ospf_lsa_unlock(
- &lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/
+ dna_lsa = ospf_check_dna_lsa(lsa);
+ if (!dna_lsa) { /* refresh only non-DNA LSAs */
+ ospf_lsa_refresh(ospf, lsa);
+ assert(lsa->lock > 0);
+ ospf_lsa_unlock(&lsa); /* lsa_refresh_queue & temp for
+ * lsa_to_refresh.
+ */
+ }
}
list_delete(&lsa_to_refresh);
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 6fa6399a90..3c7ea3fda5 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -45,6 +45,7 @@
/* OSPF LSA header. */
struct lsa_header {
uint16_t ls_age;
+#define DO_NOT_AGE 0x8000
uint8_t options;
uint8_t type;
struct in_addr id;
@@ -218,6 +219,9 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
|| (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \
|| (type == OSPF_AS_EXTERNAL_LSA) || (type == OSPF_AS_NSSA_LSA))
+#define OSPF_FR_CONFIG(o, a) \
+ (o->fr_configured || ((a != NULL) ? a->fr_info.configured : 0))
+
/* Prototypes. */
/* XXX: Eek, time functions, similar are in lib/thread.c */
extern struct timeval int2tv(int);
@@ -343,4 +347,24 @@ extern void ospf_check_and_gen_init_seq_lsa(struct ospf_interface *oi,
extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id,
int type);
extern void ospf_maxage_lsa_remover(struct thread *thread);
+extern bool ospf_check_dna_lsa(const struct ospf_lsa *lsa);
+extern void ospf_refresh_area_self_lsas(struct ospf_area *area);
+
+/** @brief Check if the LSA is an indication LSA.
+ * @param lsa pointer.
+ * @return true or false based on lsa info.
+ */
+static inline bool ospf_check_indication_lsa(struct ospf_lsa *lsa)
+{
+ struct summary_lsa *sl = NULL;
+
+ if (lsa->data->type == OSPF_ASBR_SUMMARY_LSA) {
+ sl = (struct summary_lsa *)lsa->data;
+ if ((GET_METRIC(sl->metric) == OSPF_LS_INFINITY) &&
+ !CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
+ return true;
+ }
+
+ return false;
+}
#endif /* _ZEBRA_OSPF_LSA_H */
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index 0d18e9f77e..0111c4924e 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -77,6 +77,21 @@ static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb,
lsdb->type[lsa->data->type].count--;
lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum);
lsdb->total--;
+
+ /* Decrement number of router LSAs received with DC bit set */
+ if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) &&
+ (lsa->data->type == OSPF_ROUTER_LSA) &&
+ CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
+ lsa->area->fr_info.router_lsas_recv_dc_bit--;
+
+ /*
+ * If the LSA being deleted is indication LSA, then set the
+ * pointer to NULL.
+ */
+ if (lsa->area && lsa->area->fr_info.indication_lsa_self &&
+ (lsa->area->fr_info.indication_lsa_self == lsa))
+ lsa->area->fr_info.indication_lsa_self = NULL;
+
rn->info = NULL;
route_unlock_node(rn);
#ifdef MONITOR_LSDB_CHANGE
@@ -113,6 +128,12 @@ void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
lsdb->type[lsa->data->type].count++;
lsdb->total++;
+ /* Increment number of router LSAs received with DC bit set */
+ if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) &&
+ (lsa->data->type == OSPF_ROUTER_LSA) &&
+ CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC))
+ lsa->area->fr_info.router_lsas_recv_dc_bit++;
+
#ifdef MONITOR_LSDB_CHANGE
if (lsdb->new_lsa_hook != NULL)
(*lsdb->new_lsa_hook)(lsa);
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 2af5d09edc..2e8e48bb5a 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -19,6 +19,7 @@
#include "thread.h"
#include "hash.h"
#include "sockunion.h" /* for inet_aton() */
+#include "printfrr.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
@@ -1147,11 +1148,13 @@ void ospf_opaque_config_write_debug(struct vty *vty)
void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
json_object *json)
{
+ char buf[128], *bp;
struct lsa_header *lsah = lsa->data;
uint32_t lsid = ntohl(lsah->id.s_addr);
uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
uint32_t opaque_id = GET_OPAQUE_ID(lsid);
struct ospf_opaque_functab *functab;
+ int len, lenValid;
/* Switch output functionality by vty address. */
if (vty != NULL) {
@@ -1170,11 +1173,19 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
json, "opaqueType",
ospf_opaque_type_name(opaque_type));
json_object_int_add(json, "opaqueId", opaque_id);
- json_object_int_add(json, "opaqueDataLength",
- ntohs(lsah->length)
- - OSPF_LSA_HEADER_SIZE);
+ len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+ json_object_int_add(json, "opaqueDataLength", len);
+ lenValid = VALID_OPAQUE_INFO_LEN(lsah);
json_object_boolean_add(json, "opaqueDataLengthValid",
- VALID_OPAQUE_INFO_LEN(lsah));
+ lenValid);
+ if (lenValid) {
+ bp = asnprintfrr(MTYPE_TMP, buf, sizeof(buf),
+ "%*pHXn", (int)len,
+ (lsah + 1));
+ json_object_string_add(json, "opaqueData", buf);
+ if (bp != buf)
+ XFREE(MTYPE_TMP, bp);
+ }
}
} else {
zlog_debug(" Opaque-Type %u (%s)", opaque_type,
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 4c2f5d72b3..5268c9896b 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -28,6 +28,7 @@
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_interface.h"
#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
@@ -3317,6 +3318,14 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
else
stream_putw(s, 0); /* hello-interval of 0 for fast-hellos */
+ /* Check if flood-reduction is enabled,
+ * if yes set the DC bit in the options.
+ */
+ if (OSPF_FR_CONFIG(oi->ospf, oi->area))
+ SET_FLAG(OPTIONS(oi), OSPF_OPTION_DC);
+ else if (CHECK_FLAG(OPTIONS(oi), OSPF_OPTION_DC))
+ UNSET_FLAG(OPTIONS(oi), OSPF_OPTION_DC);
+
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: options: %x, int: %s", __func__, OPTIONS(oi),
IF_NAME(oi));
@@ -3405,6 +3414,8 @@ static int ospf_make_db_desc(struct ospf_interface *oi,
options = OPTIONS(oi);
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE))
SET_FLAG(options, OSPF_OPTION_O);
+ if (OSPF_FR_CONFIG(oi->ospf, oi->area))
+ SET_FLAG(options, OSPF_OPTION_DC);
stream_putc(s, options);
/* DD flags */
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index bcedd36ce2..5f18bff1cf 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -348,44 +348,49 @@ void ospf_route_install(struct ospf *ospf, struct route_table *rt)
/* RFC2328 16.1. (4). For "router". */
void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
- struct ospf_area *area, bool add_all)
+ struct ospf_area *area, bool add_only)
{
struct route_node *rn;
struct ospf_route * or ;
struct prefix_ipv4 p;
struct router_lsa *lsa;
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("%s: Start", __func__);
-
+ if (IS_DEBUG_OSPF_EVENT) {
+ if (!add_only)
+ zlog_debug("%s: Start", __func__);
+ else
+ zlog_debug("%s: REACHRUN: Start", __func__);
+ }
lsa = (struct router_lsa *)v->lsa;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: LS ID: %pI4", __func__, &lsa->header.id);
- if (!OSPF_IS_AREA_BACKBONE(area))
- ospf_vl_up_check(area, lsa->header.id, v);
+ if (!add_only) {
+ if (!OSPF_IS_AREA_BACKBONE(area))
+ ospf_vl_up_check(area, lsa->header.id, v);
- if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT))
- area->shortcut_capability = 0;
+ if (!CHECK_FLAG(lsa->flags, ROUTER_LSA_SHORTCUT))
+ area->shortcut_capability = 0;
- /* If the newly added vertex is an area border router or AS boundary
- router, a routing table entry is added whose destination type is
- "router". */
- if (!add_all && !IS_ROUTER_LSA_BORDER(lsa) &&
- !IS_ROUTER_LSA_EXTERNAL(lsa)) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "%s: this router is neither ASBR nor ABR, skipping it",
- __func__);
- return;
- }
+ /* If the newly added vertex is an area border router or AS
+ boundary router, a routing table entry is added whose
+ destination type is "router". */
+ if (!IS_ROUTER_LSA_BORDER(lsa) &&
+ !IS_ROUTER_LSA_EXTERNAL(lsa)) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "%s: this router is neither ASBR nor ABR, skipping it",
+ __func__);
+ return;
+ }
- /* Update ABR and ASBR count in this area. */
- if (IS_ROUTER_LSA_BORDER(lsa))
- area->abr_count++;
- if (IS_ROUTER_LSA_EXTERNAL(lsa))
- area->asbr_count++;
+ /* Update ABR and ASBR count in this area. */
+ if (IS_ROUTER_LSA_BORDER(lsa))
+ area->abr_count++;
+ if (IS_ROUTER_LSA_EXTERNAL(lsa))
+ area->asbr_count++;
+ }
/* The Options field found in the associated router-LSA is copied
into the routing table entry's Optional capabilities field. Call
@@ -433,8 +438,12 @@ void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
listnode_add(rn->info, or);
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("%s: Stop", __func__);
+ if (IS_DEBUG_OSPF_EVENT) {
+ if (!add_only)
+ zlog_debug("%s: Stop", __func__);
+ else
+ zlog_debug("%s: REACHRUN: Stop", __func__);
+ }
}
/* RFC2328 16.1. (4). For transit network. */
@@ -971,6 +980,16 @@ void ospf_prune_unreachable_routers(struct route_table *rtrs)
&or->u.std.area_id);
}
+ /* Unset the DNA flag on lsa, if the router
+ * which generated this lsa is no longer
+ * reachabele.
+ */
+ (CHECK_FLAG(or->u.std.origin->ls_age,
+ DO_NOT_AGE))
+ ? UNSET_FLAG(or->u.std.origin->ls_age,
+ DO_NOT_AGE)
+ : 0;
+
listnode_delete(paths, or);
ospf_route_free(or);
}
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index b3e543d225..eb03a9c3a7 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -3038,6 +3038,43 @@ static void show_ip_ospf_area(struct vty *vty, struct ospf_area *area,
ospf_lsdb_checksum(area->lsdb, OSPF_OPAQUE_AREA_LSA));
}
+ if (area->fr_info.configured) {
+ if (use_json)
+ json_object_string_add(json_area, "areaFloodReduction",
+ "configured");
+ else
+ vty_out(vty, " Flood Reduction is configured.\n");
+ }
+
+ if (area->fr_info.enabled) {
+ if (use_json) {
+ json_object_boolean_true_add(
+ json_area, "areaFloodReductionEnabled");
+ if (area->fr_info.router_lsas_recv_dc_bit)
+ json_object_boolean_true_add(
+ json_area, "lsasRecvDCbitSet");
+ if (area->fr_info.area_ind_lsa_recvd)
+ json_object_string_add(json_area,
+ "areaIndicationLsaRecv",
+ "received");
+ if (area->fr_info.indication_lsa_self)
+ json_object_string_addf(
+ json_area, "areaIndicationLsa", "%pI4",
+ &area->fr_info.indication_lsa_self->data
+ ->id);
+ } else {
+ vty_out(vty, " Flood Reduction is enabled.\n");
+ vty_out(vty, " No of LSAs rcv'd with DC bit set %d\n",
+ area->fr_info.router_lsas_recv_dc_bit);
+ if (area->fr_info.area_ind_lsa_recvd)
+ vty_out(vty, " Ind LSA by other abr.\n");
+ if (area->fr_info.indication_lsa_self)
+ vty_out(vty, " Ind LSA generated %pI4\n",
+ &area->fr_info.indication_lsa_self->data
+ ->id);
+ }
+ }
+
if (use_json)
json_object_object_add(json_areas,
inet_ntop(AF_INET, &area->area_id,
@@ -3273,6 +3310,14 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
: ZEBRA_OSPF_DISTANCE_DEFAULT);
}
+ if (ospf->fr_configured) {
+ if (json)
+ json_object_string_add(json_vrf, "floodReduction",
+ "configured");
+ else
+ vty_out(vty, " Flood Reduction is configured.\n");
+ }
+
/* Show ABR/ASBR flags. */
if (CHECK_FLAG(ospf->flags, OSPF_FLAG_ABR)) {
if (json)
@@ -4855,9 +4900,8 @@ DEFUN (show_ip_ospf_instance_neighbor_all,
}
static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf,
- int arg_base,
- struct cmd_token **argv,
- bool use_json, uint8_t use_vrf)
+ const char *ifname, bool use_json,
+ uint8_t use_vrf)
{
struct interface *ifp;
struct route_node *rn;
@@ -4876,7 +4920,7 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf,
ospf_show_vrf_name(ospf, vty, json, use_vrf);
- ifp = if_lookup_by_name(argv[arg_base]->arg, ospf->vrf_id);
+ ifp = if_lookup_by_name(ifname, ospf->vrf_id);
if (!ifp) {
if (use_json)
json_object_boolean_true_add(json, "noSuchIface");
@@ -4902,76 +4946,22 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf,
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_neighbor_int,
- show_ip_ospf_neighbor_int_cmd,
- "show ip ospf [vrf <NAME>] neighbor IFNAME [json]",
- SHOW_STR
- IP_STR
- "OSPF information\n"
- VRF_CMD_HELP_STR
- "Neighbor list\n"
- "Interface name\n"
- JSON_STR)
-{
- struct ospf *ospf;
- int idx_ifname = 0;
- int idx_vrf = 0;
- bool uj = use_json(argc, argv);
- int ret = CMD_SUCCESS;
- struct interface *ifp = NULL;
- char *vrf_name = NULL;
- vrf_id_t vrf_id = VRF_DEFAULT;
- struct vrf *vrf = NULL;
-
- if (argv_find(argv, argc, "vrf", &idx_vrf))
- vrf_name = argv[idx_vrf + 1]->arg;
- if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME))
- vrf_name = NULL;
- if (vrf_name) {
- vrf = vrf_lookup_by_name(vrf_name);
- if (vrf)
- vrf_id = vrf->vrf_id;
- }
- ospf = ospf_lookup_by_vrf_id(vrf_id);
-
- if (!ospf || !ospf->oi_running)
- return ret;
-
- if (!uj)
- show_ip_ospf_neighbour_header(vty);
-
- argv_find(argv, argc, "IFNAME", &idx_ifname);
-
- ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id);
- if (!ifp)
- return ret;
-
- ret = show_ip_ospf_neighbor_int_common(vty, ospf, idx_ifname,
- argv, uj, 0);
- return ret;
-}
-
-DEFUN (show_ip_ospf_instance_neighbor_int,
- show_ip_ospf_instance_neighbor_int_cmd,
- "show ip ospf (1-65535) neighbor IFNAME [json]",
- SHOW_STR
- IP_STR
- "OSPF information\n"
- "Instance ID\n"
- "Neighbor list\n"
- "Interface name\n"
- JSON_STR)
+DEFPY(show_ip_ospf_instance_neighbor_int,
+ show_ip_ospf_instance_neighbor_int_cmd,
+ "show ip ospf (1-65535)$instance neighbor IFNAME$ifname [json$json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Neighbor list\n"
+ "Interface name\n"
+ JSON_STR)
{
- int idx_number = 3;
- int idx_ifname = 5;
struct ospf *ospf;
- unsigned short instance = 0;
- bool uj = use_json(argc, argv);
- if (!uj)
+ if (!json)
show_ip_ospf_neighbour_header(vty);
- instance = strtoul(argv[idx_number]->arg, NULL, 10);
if (instance != ospf_instance)
return CMD_NOT_MY_INSTANCE;
@@ -4979,11 +4969,10 @@ DEFUN (show_ip_ospf_instance_neighbor_int,
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
- if (!uj)
+ if (!json)
show_ip_ospf_neighbour_header(vty);
- return show_ip_ospf_neighbor_int_common(vty, ospf, idx_ifname, argv, uj,
- 0);
+ return show_ip_ospf_neighbor_int_common(vty, ospf, ifname, !!json, 0);
}
static void show_ip_ospf_nbr_nbma_detail_sub(struct vty *vty,
@@ -5123,19 +5112,36 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
json_object_string_add(json_neigh, "areaId",
ospf_area_desc_string(oi->area));
json_object_string_add(json_neigh, "ifaceName", oi->ifp->name);
- } else
- vty_out(vty, " In the area %s via interface %s\n",
+ if (oi->address)
+ json_object_string_addf(json_neigh, "localIfaceAddress",
+ "%pI4",
+ &oi->address->u.prefix4);
+ } else {
+ vty_out(vty, " In the area %s via interface %s",
ospf_area_desc_string(oi->area), oi->ifp->name);
+ if (oi->address)
+ vty_out(vty, " local interface IP %pI4\n",
+ &oi->address->u.prefix4);
+ else
+ vty_out(vty, "\n");
+ }
/* Show neighbor priority and state. */
ospf_nbr_ism_state_message(nbr, neigh_state, sizeof(neigh_state));
if (use_json) {
json_object_int_add(json_neigh, "nbrPriority", nbr->priority);
json_object_string_add(json_neigh, "nbrState", neigh_state);
- } else
- vty_out(vty, " Neighbor priority is %d, State is %s,",
- nbr->priority, neigh_state);
-
+ json_object_string_add(json_neigh, "role",
+ lookup_msg(ospf_ism_state_msg,
+ ospf_nbr_ism_state(nbr),
+ NULL));
+ } else {
+ vty_out(vty,
+ " Neighbor priority is %d, State is %s, Role is %s,",
+ nbr->priority, neigh_state,
+ lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr),
+ NULL));
+ }
/* Show state changes. */
if (use_json)
json_object_int_add(json_neigh, "stateChangeCounter",
@@ -5369,7 +5375,8 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf,
struct in_addr *router_id,
bool use_json, uint8_t use_vrf,
- bool is_detail)
+ bool is_detail,
+ json_object *json_vrf)
{
struct listnode *node;
struct ospf_neighbor *nbr;
@@ -5403,6 +5410,14 @@ static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf,
use_json);
}
+ if (json_vrf && use_json) {
+ json_object_object_add(
+ json_vrf,
+ (ospf->vrf_id == VRF_DEFAULT) ? "default" : ospf->name,
+ json);
+ return CMD_SUCCESS;
+ }
+
if (use_json)
vty_json(vty, json);
else
@@ -5411,23 +5426,50 @@ static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf,
return CMD_SUCCESS;
}
-DEFPY(show_ip_ospf_neighbor_id, show_ip_ospf_neighbor_id_cmd,
- "show ip ospf neighbor A.B.C.D$router_id [detail$detail] [json$json]",
- SHOW_STR IP_STR
+DEFPY(show_ip_ospf_neighbor_id,
+ show_ip_ospf_neighbor_id_cmd,
+ "show ip ospf [vrf NAME$vrf_name] neighbor A.B.C.D$router_id [detail$detail] [json$json]",
+ SHOW_STR
+ IP_STR
"OSPF information\n"
+ VRF_CMD_HELP_STR
"Neighbor list\n"
"Neighbor ID\n"
- "Detailed output\n" JSON_STR)
+ "Detailed output\n"
+ JSON_STR)
{
struct ospf *ospf;
struct listnode *node;
int ret = CMD_SUCCESS;
+ int inst = 0;
- for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
- if (!ospf->oi_running)
- continue;
- ret = show_ip_ospf_neighbor_id_common(vty, ospf, &router_id,
- !!json, 0, !!detail);
+ if (vrf_name && !strmatch(vrf_name, "all")) {
+ ospf = ospf_lookup_by_inst_name(inst, vrf_name);
+ if (ospf == NULL || !ospf->oi_running) {
+ if (!json)
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf %s\n",
+ vrf_name);
+ else
+ vty_json_empty(vty);
+ return CMD_SUCCESS;
+ }
+ ret = show_ip_ospf_neighbor_id_common(
+ vty, ospf, &router_id, !!json, 0, !!detail, NULL);
+ } else {
+ json_object *json_vrf = NULL;
+
+ if (json)
+ json_vrf = json_object_new_object();
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+ ret = show_ip_ospf_neighbor_id_common(
+ vty, ospf, &router_id, !!json, 0, !!detail,
+ json_vrf);
+ }
+ if (json)
+ vty_json(vty, json_vrf);
}
return ret;
@@ -5452,7 +5494,7 @@ DEFPY(show_ip_ospf_instance_neighbor_id, show_ip_ospf_instance_neighbor_id_cmd,
return CMD_SUCCESS;
return show_ip_ospf_neighbor_id_common(vty, ospf, &router_id, !!json, 0,
- !!detail);
+ !!detail, NULL);
}
static int show_ip_ospf_neighbor_detail_common(struct vty *vty,
@@ -5517,77 +5559,71 @@ static int show_ip_ospf_neighbor_detail_common(struct vty *vty,
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_neighbor_detail,
- show_ip_ospf_neighbor_detail_cmd,
- "show ip ospf [vrf <NAME|all>] neighbor detail [json]",
- SHOW_STR
- IP_STR
- "OSPF information\n"
- VRF_CMD_HELP_STR
- "All VRFs\n"
- "Neighbor list\n"
- "detail of all neighbors\n"
- JSON_STR)
+DEFPY(show_ip_ospf_neighbor_detail,
+ show_ip_ospf_neighbor_detail_cmd,
+ "show ip ospf [vrf <NAME|all>$vrf_name] neighbor detail [json$json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Neighbor list\n"
+ "detail of all neighbors\n"
+ JSON_STR)
{
struct ospf *ospf;
- bool uj = use_json(argc, argv);
struct listnode *node = NULL;
- char *vrf_name = NULL;
- bool all_vrf = false;
int ret = CMD_SUCCESS;
int inst = 0;
- int idx_vrf = 0;
uint8_t use_vrf = 0;
- json_object *json = NULL;
-
- OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ json_object *json_vrf = NULL;
- if (uj)
- json = json_object_new_object();
+ if (json)
+ json_vrf = json_object_new_object();
/* vrf input is provided could be all or specific vrf*/
if (vrf_name) {
use_vrf = 1;
- if (all_vrf) {
+ if (strmatch(vrf_name, "all")) {
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
if (!ospf->oi_running)
continue;
ret = show_ip_ospf_neighbor_detail_common(
- vty, ospf, json, uj, use_vrf);
+ vty, ospf, json_vrf, !!json, use_vrf);
}
- if (uj)
- vty_json(vty, json);
+ if (json)
+ vty_json(vty, json_vrf);
return ret;
}
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
if (ospf == NULL || !ospf->oi_running) {
- if (uj)
- json_object_free(json);
+ if (json)
+ vty_json(vty, json_vrf);
+ else
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf %s\n",
+ vrf_name);
return CMD_SUCCESS;
}
} else {
/* Display default ospf (instance 0) info */
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
- if (uj)
- json_object_free(json);
+ if (json)
+ vty_json(vty, json_vrf);
+ else
+ vty_out(vty, "%% OSPF is not enabled\n");
return CMD_SUCCESS;
}
}
- if (ospf) {
- ret = show_ip_ospf_neighbor_detail_common(vty, ospf, json, uj,
- use_vrf);
- if (uj) {
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- }
- }
+ if (ospf)
+ ret = show_ip_ospf_neighbor_detail_common(vty, ospf, json_vrf,
+ !!json, use_vrf);
- if (uj)
- json_object_free(json);
+ if (json)
+ vty_json(vty, json_vrf);
return ret;
}
@@ -5816,9 +5852,9 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all,
static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty,
struct ospf *ospf,
- int arg_base,
- struct cmd_token **argv,
- bool use_json)
+ const char *ifname,
+ bool use_json,
+ json_object *json_vrf)
{
struct ospf_interface *oi;
struct interface *ifp;
@@ -5826,8 +5862,15 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty,
struct ospf_neighbor *nbr;
json_object *json = NULL;
- if (use_json)
+ if (use_json) {
json = json_object_new_object();
+ if (json_vrf)
+ json_object_object_add(json_vrf,
+ (ospf->vrf_id == VRF_DEFAULT)
+ ? "default"
+ : ospf->name,
+ json);
+ }
if (ospf->instance) {
if (use_json)
@@ -5837,13 +5880,13 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty,
vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
}
- ifp = if_lookup_by_name(argv[arg_base]->arg, ospf->vrf_id);
+ ifp = if_lookup_by_name(ifname, ospf->vrf_id);
if (!ifp) {
- if (!use_json)
+ if (!use_json) {
vty_out(vty, "No such interface.\n");
- else {
- vty_out(vty, "{}\n");
- json_object_free(json);
+ } else {
+ if (!json_vrf)
+ vty_json(vty, json);
}
return CMD_WARNING;
}
@@ -5871,37 +5914,114 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty,
}
}
- if (use_json)
- vty_json(vty, json);
- else
+ if (use_json) {
+ if (!json_vrf)
+ vty_json(vty, json);
+ } else {
vty_out(vty, "\n");
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_neighbor_int_detail,
- show_ip_ospf_neighbor_int_detail_cmd,
- "show ip ospf neighbor IFNAME detail [json]",
- SHOW_STR
- IP_STR
- "OSPF information\n"
- "Neighbor list\n"
- "Interface name\n"
- "detail of all neighbors\n"
- JSON_STR)
+DEFPY(show_ip_ospf_neighbor_int,
+ show_ip_ospf_neighbor_int_cmd,
+ "show ip ospf [vrf NAME$vrf_name] neighbor IFNAME$ifname [json$json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ VRF_CMD_HELP_STR
+ "Neighbor list\n"
+ "Interface name\n"
+ JSON_STR)
+{
+ struct ospf *ospf;
+ int ret = CMD_SUCCESS;
+ struct interface *ifp = NULL;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+ struct vrf *vrf = NULL;
+
+ if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME))
+ vrf_name = NULL;
+ if (vrf_name) {
+ vrf = vrf_lookup_by_name(vrf_name);
+ if (vrf)
+ vrf_id = vrf->vrf_id;
+ }
+ ospf = ospf_lookup_by_vrf_id(vrf_id);
+
+ if (!ospf || !ospf->oi_running) {
+ if (json)
+ vty_json_empty(vty);
+ return ret;
+ }
+
+ if (!json)
+ show_ip_ospf_neighbour_header(vty);
+
+ ifp = if_lookup_by_name(ifname, vrf_id);
+ if (!ifp) {
+ if (json)
+ vty_json_empty(vty);
+ else
+ vty_out(vty, "No such interface.\n");
+ return ret;
+ }
+
+ ret = show_ip_ospf_neighbor_int_common(vty, ospf, ifname, !!json, 0);
+ return ret;
+}
+
+DEFPY(show_ip_ospf_neighbor_int_detail,
+ show_ip_ospf_neighbor_int_detail_cmd,
+ "show ip ospf [vrf NAME$vrf_name] neighbor IFNAME$ifname detail [json$json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ VRF_CMD_HELP_STR
+ "Neighbor list\n"
+ "Interface name\n"
+ "detail of all neighbors\n"
+ JSON_STR)
{
struct ospf *ospf;
- bool uj = use_json(argc, argv);
struct listnode *node = NULL;
int ret = CMD_SUCCESS;
bool ospf_output = false;
+ if (vrf_name && !strmatch(vrf_name, "all")) {
+ int inst = 0;
+
+ ospf = ospf_lookup_by_inst_name(inst, vrf_name);
+ if (ospf == NULL || !ospf->oi_running) {
+ if (!json)
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf %s\n",
+ vrf_name);
+ else
+ vty_json_empty(vty);
+ return CMD_SUCCESS;
+ }
+ return show_ip_ospf_neighbor_int_detail_common(
+ vty, ospf, ifname, !!json, NULL);
+ }
+
+ json_object *json_vrf = NULL;
+
+ if (json)
+ json_vrf = json_object_new_object();
+
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
if (!ospf->oi_running)
continue;
ospf_output = true;
- ret = show_ip_ospf_neighbor_int_detail_common(vty, ospf, 4,
- argv, uj);
+ ret = show_ip_ospf_neighbor_int_detail_common(vty, ospf, ifname,
+ !!json, json_vrf);
+ }
+
+ if (json) {
+ vty_json(vty, json_vrf);
+ return ret;
}
if (!ospf_output)
@@ -5910,25 +6030,20 @@ DEFUN (show_ip_ospf_neighbor_int_detail,
return ret;
}
-DEFUN (show_ip_ospf_instance_neighbor_int_detail,
- show_ip_ospf_instance_neighbor_int_detail_cmd,
- "show ip ospf (1-65535) neighbor IFNAME detail [json]",
- SHOW_STR
- IP_STR
- "OSPF information\n"
- "Instance ID\n"
- "Neighbor list\n"
- "Interface name\n"
- "detail of all neighbors\n"
- JSON_STR)
+DEFPY(show_ip_ospf_instance_neighbor_int_detail,
+ show_ip_ospf_instance_neighbor_int_detail_cmd,
+ "show ip ospf (1-65535)$instance neighbor IFNAME$ifname detail [json$json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Neighbor list\n"
+ "Interface name\n"
+ "detail of all neighbors\n"
+ JSON_STR)
{
- int idx_number = 3;
- int idx_ifname = 5;
struct ospf *ospf;
- unsigned short instance = 0;
- bool uj = use_json(argc, argv);
- instance = strtoul(argv[idx_number]->arg, NULL, 10);
if (instance != ospf_instance)
return CMD_NOT_MY_INSTANCE;
@@ -5936,8 +6051,8 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail,
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname,
- argv, uj);
+ return show_ip_ospf_neighbor_int_detail_common(vty, ospf, ifname,
+ !!json, NULL);
}
/* Show functions */
@@ -5949,118 +6064,109 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self,
struct as_external_lsa *asel;
struct prefix_ipv4 p;
- if (lsa != NULL) {
- /* If self option is set, check LSA self flag. */
- if (self == 0 || IS_LSA_SELF(lsa)) {
+ if (lsa == NULL)
+ return 0;
- if (!json_lsa) {
- /* LSA common part show. */
- vty_out(vty, "%-15pI4",
- &lsa->data->id);
- vty_out(vty, "%-15pI4 %4d 0x%08lx 0x%04x",
- &lsa->data->adv_router, LS_AGE(lsa),
- (unsigned long)ntohl(
- lsa->data->ls_seqnum),
- ntohs(lsa->data->checksum));
- } else {
- char seqnum[10];
- char checksum[10];
-
- snprintf(seqnum, sizeof(seqnum), "%x",
- ntohl(lsa->data->ls_seqnum));
- snprintf(checksum, sizeof(checksum), "%x",
- ntohs(lsa->data->checksum));
- json_object_string_addf(json_lsa, "lsId",
- "%pI4", &lsa->data->id);
- json_object_string_addf(
- json_lsa, "advertisedRouter", "%pI4",
- &lsa->data->adv_router);
- json_object_int_add(json_lsa, "lsaAge",
- LS_AGE(lsa));
- json_object_string_add(
- json_lsa, "sequenceNumber", seqnum);
- json_object_string_add(json_lsa, "checksum",
- checksum);
- }
+ /* If self option is set, check LSA self flag. */
+ if (self == 0 || IS_LSA_SELF(lsa)) {
- /* LSA specific part show. */
- switch (lsa->data->type) {
- case OSPF_ROUTER_LSA:
- rl = (struct router_lsa *)lsa->data;
+ if (!json_lsa) {
+ /* LSA common part show. */
+ vty_out(vty, "%-15pI4", &lsa->data->id);
+ vty_out(vty, "%-15pI4 %4d 0x%08lx 0x%04x",
+ &lsa->data->adv_router, LS_AGE(lsa),
+ (unsigned long)ntohl(lsa->data->ls_seqnum),
+ ntohs(lsa->data->checksum));
+ } else {
+ char seqnum[10];
+ char checksum[10];
+
+ snprintf(seqnum, sizeof(seqnum), "%x",
+ ntohl(lsa->data->ls_seqnum));
+ snprintf(checksum, sizeof(checksum), "%x",
+ ntohs(lsa->data->checksum));
+ json_object_string_addf(json_lsa, "lsId", "%pI4",
+ &lsa->data->id);
+ json_object_string_addf(json_lsa, "advertisedRouter",
+ "%pI4", &lsa->data->adv_router);
+ json_object_int_add(json_lsa, "lsaAge", LS_AGE(lsa));
+ json_object_string_add(json_lsa, "sequenceNumber",
+ seqnum);
+ json_object_string_add(json_lsa, "checksum", checksum);
+ }
+
+ /* LSA specific part show. */
+ switch (lsa->data->type) {
+ case OSPF_ROUTER_LSA:
+ rl = (struct router_lsa *)lsa->data;
- if (!json_lsa)
- vty_out(vty, " %-d", ntohs(rl->links));
- else
- json_object_int_add(json_lsa,
- "numOfRouterLinks",
- ntohs(rl->links));
- break;
- case OSPF_SUMMARY_LSA:
- sl = (struct summary_lsa *)lsa->data;
+ if (!json_lsa)
+ vty_out(vty, " %-d", ntohs(rl->links));
+ else
+ json_object_int_add(json_lsa,
+ "numOfRouterLinks",
+ ntohs(rl->links));
+ break;
+ case OSPF_SUMMARY_LSA:
+ sl = (struct summary_lsa *)lsa->data;
- p.family = AF_INET;
- p.prefix = sl->header.id;
- p.prefixlen = ip_masklen(sl->mask);
- apply_mask_ipv4(&p);
+ p.family = AF_INET;
+ p.prefix = sl->header.id;
+ p.prefixlen = ip_masklen(sl->mask);
+ apply_mask_ipv4(&p);
- if (!json_lsa)
- vty_out(vty, " %pFX", &p);
- else {
- json_object_string_addf(
- json_lsa, "summaryAddress",
- "%pFX", &p);
- }
- break;
- case OSPF_AS_EXTERNAL_LSA:
- case OSPF_AS_NSSA_LSA:
- asel = (struct as_external_lsa *)lsa->data;
-
- p.family = AF_INET;
- p.prefix = asel->header.id;
- p.prefixlen = ip_masklen(asel->mask);
- apply_mask_ipv4(&p);
-
- if (!json_lsa)
- vty_out(vty, " %s %pFX [0x%lx]",
- IS_EXTERNAL_METRIC(
- asel->e[0].tos)
- ? "E2"
- : "E1",
- &p,
- (unsigned long)ntohl(
- asel->e[0].route_tag));
- else {
- json_object_string_add(
- json_lsa, "metricType",
- IS_EXTERNAL_METRIC(
- asel->e[0].tos)
- ? "E2"
- : "E1");
- json_object_string_addf(
- json_lsa, "route", "%pFX", &p);
- json_object_int_add(
- json_lsa, "tag",
- (unsigned long)ntohl(
- asel->e[0].route_tag));
- }
- break;
- case OSPF_NETWORK_LSA:
- case OSPF_ASBR_SUMMARY_LSA:
- case OSPF_OPAQUE_LINK_LSA:
- case OSPF_OPAQUE_AREA_LSA:
- case OSPF_OPAQUE_AS_LSA:
- default:
- break;
+ if (!json_lsa)
+ vty_out(vty, " %pFX", &p);
+ else {
+ json_object_string_addf(
+ json_lsa, "summaryAddress", "%pFX", &p);
}
+ break;
+ case OSPF_AS_EXTERNAL_LSA:
+ case OSPF_AS_NSSA_LSA:
+ asel = (struct as_external_lsa *)lsa->data;
+
+ p.family = AF_INET;
+ p.prefix = asel->header.id;
+ p.prefixlen = ip_masklen(asel->mask);
+ apply_mask_ipv4(&p);
if (!json_lsa)
- vty_out(vty, "\n");
+ vty_out(vty, " %s %pFX [0x%lx]",
+ IS_EXTERNAL_METRIC(asel->e[0].tos)
+ ? "E2"
+ : "E1",
+ &p,
+ (unsigned long)ntohl(
+ asel->e[0].route_tag));
+ else {
+ json_object_string_add(
+ json_lsa, "metricType",
+ IS_EXTERNAL_METRIC(asel->e[0].tos)
+ ? "E2"
+ : "E1");
+ json_object_string_addf(json_lsa, "route",
+ "%pFX", &p);
+ json_object_int_add(
+ json_lsa, "tag",
+ (unsigned long)ntohl(
+ asel->e[0].route_tag));
+ }
+ break;
+ case OSPF_NETWORK_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ default:
+ break;
}
- return 1;
+ if (!json_lsa)
+ vty_out(vty, "\n");
}
- return 0;
+ return 1;
}
static const char *const show_database_desc[] = {
@@ -6129,7 +6235,16 @@ static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa,
struct router_lsa *rlsa = (struct router_lsa *)lsa->data;
if (!json) {
- vty_out(vty, " LS age: %d\n", LS_AGE(lsa));
+ if (IS_LSA_SELF(lsa))
+ vty_out(vty, " LS age: %d%s\n", LS_AGE(lsa),
+ CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE)
+ ? "(S-DNA)"
+ : "");
+ else
+ vty_out(vty, " LS age: %d%s\n", LS_AGE(lsa),
+ CHECK_FLAG(lsa->data->ls_age, DO_NOT_AGE)
+ ? "(DNA)"
+ : "");
vty_out(vty, " Options: 0x%-2x : %s\n", lsa->data->options,
ospf_options_dump(lsa->data->options));
vty_out(vty, " LS Flags: 0x%-2x %s\n", lsa->flags,
@@ -12188,6 +12303,9 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf)
if (PREFIX_NAME_OUT(area))
vty_out(vty, " area %s filter-list prefix %s out\n",
buf, PREFIX_NAME_OUT(area));
+
+ if (area->fr_info.configured)
+ vty_out(vty, " area %s flood-reduction\n", buf);
}
return 0;
@@ -12565,6 +12683,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
if (ospf->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
vty_out(vty, " refresh timer %d\n", ospf->lsa_refresh_interval);
+ if (ospf->fr_configured)
+ vty_out(vty, " flood-reduction\n");
+
/* Redistribute information print. */
config_write_ospf_redistribute(vty, ospf);
@@ -12947,6 +13068,143 @@ DEFPY_HIDDEN(ospf_maxage_delay_timer, ospf_maxage_delay_timer_cmd,
return CMD_SUCCESS;
}
+/*
+ * ------------------------------------------------------------------------*
+ * Following is (vty) configuration functions for flood-reduction handling.
+ * ------------------------------------------------------------------------
+ */
+
+DEFPY(flood_reduction, flood_reduction_cmd, "flood-reduction",
+ "flood reduction feature\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
+ struct ospf_area *area;
+ struct listnode *node;
+
+ /* Turn on the Flood Reduction feature for the router. */
+ if (!ospf->fr_configured) {
+ ospf->fr_configured = true;
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction: OFF -> ON");
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
+ if (area) {
+ ospf_area_update_fr_state(area);
+ ospf_refresh_area_self_lsas(area);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(flood_reduction_area, flood_reduction_area_cmd,
+ "area <A.B.C.D|(0-4294967295)> flood-reduction",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Enable flood reduction for area\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
+ struct ospf_area *oa;
+ int idx = 1;
+ int format;
+ int ret;
+ const char *areaid;
+ struct in_addr area_id;
+
+ areaid = argv[idx]->arg;
+
+ ret = str2area_id(areaid, &area_id, &format);
+ if (ret < 0) {
+ vty_out(vty, "Please specify area by A.B.C.D|<0-4294967295>\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ oa = ospf_area_lookup_by_area_id(ospf, area_id);
+ if (!oa) {
+ vty_out(vty, "OSPF area ID not present\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Turn on the Flood Reduction feature for the area. */
+ if (!oa->fr_info.configured) {
+ oa->fr_info.configured = true;
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction area %pI4 : OFF -> ON",
+ &oa->area_id);
+ ospf_area_update_fr_state(oa);
+ ospf_refresh_area_self_lsas(oa);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_flood_reduction, no_flood_reduction_cmd, "no flood-reduction",
+ NO_STR "flood reduction feature\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
+ struct listnode *node;
+ struct ospf_area *area;
+
+ /* Turn off the Flood Reduction feature for the router. */
+ if (ospf->fr_configured) {
+ ospf->fr_configured = false;
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction: ON -> OFF");
+ for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
+ if (area) {
+ ospf_area_update_fr_state(area);
+ ospf_refresh_area_self_lsas(area);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_flood_reduction_area, no_flood_reduction_area_cmd,
+ "no area <A.B.C.D|(0-4294967295)> flood-reduction",
+ NO_STR
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Disable flood reduction for area\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf)
+ struct ospf_area *oa;
+ int idx = 2;
+ int format;
+ int ret;
+ const char *areaid;
+ struct in_addr area_id;
+
+ areaid = argv[idx]->arg;
+
+ ret = str2area_id(areaid, &area_id, &format);
+ if (ret < 0) {
+ vty_out(vty, "Please specify area by A.B.C.D|<0-4294967295>\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ oa = ospf_area_lookup_by_area_id(ospf, area_id);
+ if (!oa) {
+ vty_out(vty, "OSPF area ID not present\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Turn off the Flood Reduction feature for the area. */
+ if (oa->fr_info.configured) {
+ oa->fr_info.configured = false;
+ OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT,
+ "Flood Reduction area %pI4 : ON -> OFF",
+ &oa->area_id);
+ ospf_area_update_fr_state(oa);
+ ospf_refresh_area_self_lsas(oa);
+ }
+
+ return CMD_SUCCESS;
+}
+
void ospf_vty_clear_init(void)
{
install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd);
@@ -13107,6 +13365,12 @@ void ospf_vty_init(void)
install_element(OSPF_NODE, &ospf_lsa_refresh_timer_cmd);
install_element(OSPF_NODE, &ospf_maxage_delay_timer_cmd);
+ /* Flood Reduction commands */
+ install_element(OSPF_NODE, &flood_reduction_cmd);
+ install_element(OSPF_NODE, &no_flood_reduction_cmd);
+ install_element(OSPF_NODE, &flood_reduction_area_cmd);
+ install_element(OSPF_NODE, &no_flood_reduction_area_cmd);
+
/* Init interface related vty commands. */
ospf_vty_if_init();
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 1c8ebccea3..0296d9d9f5 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -452,6 +452,8 @@ static struct ospf *ospf_new(unsigned short instance, const char *name)
*/
ospf_gr_nvm_read(new);
+ new->fr_configured = false;
+
return new;
}
@@ -802,6 +804,7 @@ static void ospf_finish_final(struct ospf *ospf)
THREAD_OFF(ospf->t_maxage);
THREAD_OFF(ospf->t_maxage_walker);
THREAD_OFF(ospf->t_abr_task);
+ THREAD_OFF(ospf->t_abr_fr);
THREAD_OFF(ospf->t_asbr_check);
THREAD_OFF(ospf->t_asbr_nssa_redist_update);
THREAD_OFF(ospf->t_distribute_update);
@@ -947,6 +950,15 @@ struct ospf_area *ospf_area_new(struct ospf *ospf, struct in_addr area_id)
/* Self-originated LSAs initialize. */
new->router_lsa_self = NULL;
+ /* Initialize FR field */
+ new->fr_info.enabled = false;
+ new->fr_info.configured = false;
+ new->fr_info.state_changed = false;
+ new->fr_info.router_lsas_recv_dc_bit = 0;
+ new->fr_info.indication_lsa_self = NULL;
+ new->fr_info.area_ind_lsa_recvd = false;
+ new->fr_info.area_dc_clear = false;
+
ospf_opaque_type10_lsa_init(new);
new->oiflist = list_new();
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index cb26ef5fbf..4df65ea759 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -101,7 +101,25 @@ struct ospf_redist {
struct route_map *map;
} route_map; /* +1 is for default-information */
#define ROUTEMAP_NAME(R) (R->route_map.name)
-#define ROUTEMAP(R) (R->route_map.map)
+#define ROUTEMAP(R) (R->route_map.map)
+};
+
+/* OSPF area flood reduction info */
+struct ospf_area_fr_info {
+ bool enabled; /* Area support for Flood Reduction */
+ bool configured; /* Flood Reduction configured per area knob */
+ bool state_changed; /* flood reduction state change info */
+ int router_lsas_recv_dc_bit; /* Number of unique router lsas
+ * received with DC bit set.
+ * (excluding self)
+ */
+ bool area_ind_lsa_recvd; /* Indication lsa received in this area */
+ bool area_dc_clear; /* Area has atleast one lsa with dc bit 0(
+ * excluding indication lsa)
+ */
+ struct ospf_lsa *indication_lsa_self; /* Indication LSA generated
+ * in the area.
+ */
};
/* ospf->config */
@@ -240,6 +258,7 @@ struct ospf {
/* Threads. */
struct thread *t_abr_task; /* ABR task timer. */
+ struct thread *t_abr_fr; /* ABR FR timer. */
struct thread *t_asbr_check; /* ASBR check timer. */
struct thread *t_asbr_nssa_redist_update; /* ASBR NSSA redistribution
update timer. */
@@ -391,6 +410,9 @@ struct ospf {
bool ti_lfa_enabled;
enum protection_type ti_lfa_protection_type;
+ /* Flood Reduction configuration state */
+ bool fr_configured;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf);
@@ -576,6 +598,8 @@ struct ospf_area {
uint32_t act_ints; /* Active interfaces. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
+
+ struct ospf_area_fr_info fr_info; /* Flood reduction info. */
};
/* OSPF config network structure. */
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index af510ce29e..02b50c9af2 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -34,6 +34,8 @@
#include "pim_msg.h"
static void mroute_read_on(struct pim_instance *pim);
+static int pim_upstream_mroute_update(struct channel_oil *c_oil,
+ const char *name);
int pim_mroute_set(struct pim_instance *pim, int enable)
{
@@ -145,45 +147,66 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
{
struct pim_interface *pim_ifp = ifp->info;
struct pim_upstream *up;
- struct pim_rpf *rpg;
pim_sgaddr sg;
+ bool desync = false;
- rpg = pim_ifp ? RP(pim_ifp->pim, msg->msg_im_dst) : NULL;
- /*
- * If the incoming interface is unknown OR
- * the Interface type is SSM we don't need to
- * do anything here
- */
- if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) {
- if (PIM_DEBUG_MROUTE_DETAIL)
- zlog_debug(
- "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
- __func__);
+ memset(&sg, 0, sizeof(sg));
+ sg.src = msg->msg_im_src;
+ sg.grp = msg->msg_im_dst;
+ if (!pim_ifp) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug(
+ "%s: PIM not enabled on interface, dropping packet to %pSG",
+ ifp->name, &sg);
return 0;
}
+ if (!pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
+ /* for ASM, check that we have enough information (i.e. path
+ * to RP) to make a decision on what to do with this packet.
+ *
+ * for SSM, this is meaningless, everything is join-driven,
+ * and for NOCACHE we need to install an empty OIL MFC entry
+ * so the kernel doesn't keep nagging us.
+ */
+ struct pim_rpf *rpg;
+
+ rpg = RP(pim_ifp->pim, msg->msg_im_dst);
+ if (!rpg) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: no RPF for packet to %pSG",
+ ifp->name, &sg);
+ return 0;
+ }
+ if (pim_rpf_addr_is_inaddr_any(rpg)) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: null RPF for packet to %pSG",
+ ifp->name, &sg);
+ return 0;
+ }
+ }
+
/*
* If we've received a multicast packet that isn't connected to
* us
*/
if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
- if (PIM_DEBUG_MROUTE_DETAIL)
+ if (PIM_DEBUG_MROUTE)
zlog_debug(
- "%s: Received incoming packet that doesn't originate on our seg",
- __func__);
+ "%s: incoming packet to %pSG from non-connected source",
+ ifp->name, &sg);
return 0;
}
- memset(&sg, 0, sizeof(sg));
- sg.src = msg->msg_im_src;
- sg.grp = msg->msg_im_dst;
-
if (!(PIM_I_am_DR(pim_ifp))) {
+ /* unlike the other debug messages, this one is further in the
+ * "normal operation" category and thus under _DETAIL
+ */
if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug(
- "%s: Interface is not the DR blackholing incoming traffic for %pSG",
- __func__, &sg);
+ "%s: not DR on interface, not forwarding traffic for %pSG",
+ ifp->name, &sg);
/*
* We are not the DR, but we are still receiving packets
@@ -204,6 +227,12 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
__func__);
+ if (up->channel_oil->installed) {
+ zlog_warn(
+ "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
+ ifp->name, &sg);
+ desync = true;
+ }
/*
* I moved this debug till after the actual add because
@@ -227,6 +256,11 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
/* if we have receiver, inherit from parent */
pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
+ /* we just got NOCACHE from the kernel, so... MFC is not in the
+ * kernel for some reason or another. Try installing again.
+ */
+ if (desync)
+ pim_upstream_mroute_update(up->channel_oil, __func__);
return 0;
}
diff --git a/python/clidef.py b/python/clidef.py
index d71b482a99..244a8205bf 100644
--- a/python/clidef.py
+++ b/python/clidef.py
@@ -51,6 +51,12 @@ _fail = (_end == argv[_i]->arg) || (*_end != '\\0');"""
)
+class AsDotHandler(RenderHandler):
+ argtype = "as_t"
+ decl = Template("as_t $varname = 0;")
+ code = Template("_fail = !asn_str2asn(argv[_i]->arg, &$varname);")
+
+
# A.B.C.D/M (prefix_ipv4) and
# X:X::X:X/M (prefix_ipv6) are "compatible" and can merge into a
# struct prefix:
@@ -152,6 +158,7 @@ handlers = {
"IPV6_PREFIX_TKN": Prefix6Handler,
"MAC_TKN": PrefixEthHandler,
"MAC_PREFIX_TKN": PrefixEthHandler,
+ "ASNUM_TKN": AsDotHandler,
}
# core template invoked for each occurence of DEFPY.
diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c
index 8806bcd8fc..926097f571 100644
--- a/tests/bgpd/test_aspath.c
+++ b/tests/bgpd/test_aspath.c
@@ -55,6 +55,7 @@ static struct test_segment {
const uint8_t asdata[1024];
int len;
struct test_spec sp;
+ enum asnotation_mode asnotation;
} test_segments[] = {
{
/* 0 */
@@ -64,6 +65,7 @@ static struct test_segment {
10,
{"8466 3 52737 4096", "8466 3 52737 4096", 4, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
+ 0,
},
{
/* 1 */
@@ -72,8 +74,16 @@ static struct test_segment {
{0x2, 0x1, 0x22, 0x12, 0x2, 0x1, 0x00, 0x04},
8,
{
- "8722 4", "8722 4", 2, 0, NOT_ALL_PRIVATE, 4, 5, 8722,
+ "8722 4",
+ "8722 4",
+ 2,
+ 0,
+ NOT_ALL_PRIVATE,
+ 4,
+ 5,
+ 8722,
},
+ 0,
},
{
/* 2 */
@@ -84,6 +94,7 @@ static struct test_segment {
14,
{"8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0,
NOT_ALL_PRIVATE, 3, 5, 8466},
+ 0,
},
{
/* 3 */
@@ -93,6 +104,7 @@ static struct test_segment {
10,
{"8482 51457 {5204}", "8482 51457 {5204}", 3, 0,
NOT_ALL_PRIVATE, 5204, 51456, 8482},
+ 0,
},
{
/* 4 */
@@ -104,6 +116,7 @@ static struct test_segment {
{"8467 59649 {4196,48658} {17322,30745}",
"8467 59649 {4196,48658} {17322,30745}", 4, 0, NOT_ALL_PRIVATE,
48658, 1, 8467},
+ 0,
},
{
/* 5 */
@@ -116,6 +129,7 @@ static struct test_segment {
{"6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
"6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0,
NOT_ALL_PRIVATE, 51793, 1, 6435},
+ 0,
},
{
/* 6 */
@@ -124,6 +138,7 @@ static struct test_segment {
{0x3, 0x3, 0x00, 0x7b, 0x01, 0xc8, 0x03, 0x15},
8,
{"(123 456 789)", "", 0, 3, NOT_ALL_PRIVATE, 789, 1, NULL_ASN},
+ 0,
},
{
/* 7 */
@@ -134,6 +149,7 @@ static struct test_segment {
14,
{"(123 456 789) (111 222)", "", 0, 5, NOT_ALL_PRIVATE, 111, 1,
NULL_ASN},
+ 0,
},
{
/* 8 */
@@ -142,6 +158,7 @@ static struct test_segment {
{0x4, 0x3, 0x01, 0xc8, 0x00, 0x7b, 0x03, 0x15},
8,
{"[123,456,789]", "", 0, 1, NOT_ALL_PRIVATE, 123, 1, NULL_ASN},
+ 0,
},
{
/* 9 */
@@ -153,6 +170,7 @@ static struct test_segment {
24,
{"(123 456 789) [111,222] 8722 {4196,48658}",
"8722 {4196,48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1, NULL_ASN},
+ 0,
},
{
/* 10 */
@@ -163,6 +181,7 @@ static struct test_segment {
14,
{"8466 2 52737 4096 8722 4", "8466 2 52737 4096 8722 4", 6, 0,
NOT_ALL_PRIVATE, 4096, 1, 8466},
+ 0,
},
{
/* 11 */
@@ -174,6 +193,7 @@ static struct test_segment {
{"8466 2 52737 4096 8722 4 8722",
"8466 2 52737 4096 8722 4 8722", 7, 0, NOT_ALL_PRIVATE, 4096,
1, 8466},
+ 0,
},
{
/* 12 */
@@ -183,6 +203,7 @@ static struct test_segment {
10,
{"8466 64512 52737 65535", "8466 64512 52737 65535", 4, 0,
NOT_ALL_PRIVATE, 65535, 4, 8466},
+ 0,
},
{
/* 13 */
@@ -192,6 +213,7 @@ static struct test_segment {
10,
{"65534 64512 64513 65535", "65534 64512 64513 65535", 4, 0,
ALL_PRIVATE, 65534, 4, 65534},
+ 0,
},
{
/* 14 */
@@ -260,6 +282,7 @@ static struct test_segment {
"8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285 8466 3 52737 4096 34285",
250, 0, NOT_ALL_PRIVATE, 4096, 4, 8466},
+ 0,
},
{
/* 15 */
@@ -270,6 +293,7 @@ static struct test_segment {
12,
{"8466 3 52737 4096 3456", "8466 3 52737 4096 3456", 5, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
+ 0,
},
{
/* 16 */
@@ -278,6 +302,7 @@ static struct test_segment {
{},
0,
{"", "", 0, 0, 0, 0, 0, 0},
+ 0,
},
{
/* 17 */
@@ -293,6 +318,7 @@ static struct test_segment {
"8466 3 52737 4096 3456 {7099,8153}",
"8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE,
4096, 4, 8466},
+ 0,
},
{
/* 18 */
@@ -305,6 +331,7 @@ static struct test_segment {
{"6435 59408 21665 {23456} 23456 23456 23456",
"6435 59408 21665 {23456} 23456 23456 23456", 7, 0,
NOT_ALL_PRIVATE, 23456, 1, 6435},
+ 0,
},
{
/* 19 */
@@ -316,6 +343,7 @@ static struct test_segment {
{"{2457,4369,61697} 1842 41591 51793",
"{2457,4369,61697} 1842 41591 51793", 4, 0, NOT_ALL_PRIVATE,
51793, 1, 2457},
+ 0,
},
{
/* 20 */
@@ -329,44 +357,88 @@ static struct test_segment {
{"(123 456 789) [124,456,788] 6435 59408 21665 {23456} 23456 23456 23456",
"6435 59408 21665 {23456} 23456 23456 23456", 7, 4,
NOT_ALL_PRIVATE, 23456, 1, 6435},
+ 0,
},
{
/* 21 */
"reconcile_start_trans",
"seq(23456,23456,23456) seq(6435,59408,21665)",
{
- 0x2, 0x3, 0x5b, 0xa0, 0x5b, 0xa0, 0x5b, 0xa0, 0x2, 0x3,
- 0x19, 0x23, 0xe8, 0x10, 0x54, 0xa1,
+ 0x2,
+ 0x3,
+ 0x5b,
+ 0xa0,
+ 0x5b,
+ 0xa0,
+ 0x5b,
+ 0xa0,
+ 0x2,
+ 0x3,
+ 0x19,
+ 0x23,
+ 0xe8,
+ 0x10,
+ 0x54,
+ 0xa1,
},
16,
{"23456 23456 23456 6435 59408 21665",
"23456 23456 23456 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE,
21665, 1, 23456},
+ 0,
},
{
/* 22 */
"reconcile_start_trans4",
"seq(1842,41591,51793) seq(6435,59408,21665)",
{
- 0x2, 0x3, 0x07, 0x32, 0xa2, 0x77, 0xca, 0x51, 0x2, 0x3,
- 0x19, 0x23, 0xe8, 0x10, 0x54, 0xa1,
+ 0x2,
+ 0x3,
+ 0x07,
+ 0x32,
+ 0xa2,
+ 0x77,
+ 0xca,
+ 0x51,
+ 0x2,
+ 0x3,
+ 0x19,
+ 0x23,
+ 0xe8,
+ 0x10,
+ 0x54,
+ 0xa1,
},
16,
{"1842 41591 51793 6435 59408 21665",
"1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE,
41591, 1, 1842},
+ 0,
},
{
/* 23 */
"reconcile_start_trans_error",
"seq(23456,23456,23456) seq(6435,59408)",
{
- 0x2, 0x3, 0x5b, 0xa0, 0x5b, 0xa0, 0x5b, 0xa0, 0x2, 0x2,
- 0x19, 0x23, 0xe8, 0x10,
+ 0x2,
+ 0x3,
+ 0x5b,
+ 0xa0,
+ 0x5b,
+ 0xa0,
+ 0x5b,
+ 0xa0,
+ 0x2,
+ 0x2,
+ 0x19,
+ 0x23,
+ 0xe8,
+ 0x10,
},
14,
{"23456 23456 23456 6435 59408", "23456 23456 23456 6435 59408",
5, 0, NOT_ALL_PRIVATE, 59408, 1, 23456},
+ 0,
},
{
/* 24 */
@@ -382,6 +454,7 @@ static struct test_segment {
"8466 3 52737 4096 3456 {7099,8153}",
"8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE,
4096, 4, 8466},
+ 0,
},
{
/* 25 */
@@ -391,6 +464,7 @@ static struct test_segment {
0x80},
12,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
+ 0,
},
{
/* 26 */
@@ -400,6 +474,7 @@ static struct test_segment {
0x00, 0x0d, 0x80},
14,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
+ 0,
},
{
/* 27 */
@@ -408,20 +483,66 @@ static struct test_segment {
{0x8, 0x2, 0x10, 0x00, 0x0d, 0x80},
14,
{NULL, NULL, 0, 0, 0, 0, 0, 0},
+ 0,
},
{
/* 28 */
"BGP_AS_ZERO",
"seq(8466,3,52737,0,4096)",
- {0x2, 0x5,
- 0x21, 0x12,
- 0x00, 0x03,
- 0xce, 0x01,
- 0x00, 0x00,
- 0x10, 0x00},
+ {0x2, 0x5, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x00, 0x00, 0x10,
+ 0x00},
12,
{"8466 3 52737 0 4096", "8466 3 52737 0 4096", 5, 0,
NOT_ALL_PRIVATE, 4096, 4, 8466},
+ 0,
+ },
+ {
+ /* 29 */
+ "seq3_asdot+",
+ "seq(0.8466,0.3,0.52737,0.4096,0.8722,0.4)",
+ {0x2, 0x6, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x10, 0x00, 0x22,
+ 0x12, 0x00, 0x04},
+ 14,
+ {"0.8466 0.3 0.52737 0.4096 0.8722 0.4",
+ "0.8466 0.3 0.52737 0.4096 0.8722 0.4", 6, 0, NOT_ALL_PRIVATE,
+ 3, 5, 8466},
+ ASNOTATION_DOTPLUS,
+ },
+ {
+ /* 30 */
+ "confmulti_asdot+",
+ "confseq(0.123,0.456,0.789) confset(0.222,0.111) seq(0.8722) set(0.4196,0.48658)",
+ {0x3, 0x3, 0x00, 0x7b, 0x01, 0xc8, 0x03, 0x15,
+ 0x4, 0x2, 0x00, 0xde, 0x00, 0x6f, 0x2, 0x1,
+ 0x22, 0x12, 0x1, 0x2, 0x10, 0x64, 0xbe, 0x12},
+ 24,
+ {"(0.123 0.456 0.789) [0.111,0.222] 0.8722 {0.4196,0.48658}",
+ "0.8722 {0.4196,0.48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1,
+ NULL_ASN},
+ ASNOTATION_DOTPLUS,
+ },
+ {
+ /* 31 */
+ "someprivate asdot+",
+ "seq(0.8466,0.64512,0.52737,0.65535)",
+ {0x2, 0x4, 0x21, 0x12, 0xfc, 0x00, 0xce, 0x01, 0xff, 0xff},
+ 10,
+ {"0.8466 0.64512 0.52737 0.65535",
+ "0.8466 0.64512 0.52737 0.65535", 4, 0, NOT_ALL_PRIVATE, 65535,
+ 4, 8466},
+ ASNOTATION_DOTPLUS,
+ },
+ {
+ /* 32 */
+ "BGP_AS_ZERO asdot+",
+ "seq(0.8466,0.3,0.52737,0.0,0.4096)",
+ {0x2, 0x5, 0x21, 0x12, 0x00, 0x03, 0xce, 0x01, 0x00, 0x00, 0x10,
+ 0x00},
+ 12,
+ {"0.8466 0.3 0.52737 0.0 0.4096",
+ "0.8466 0.3 0.52737 0.0 0.4096", 5, 0, NOT_ALL_PRIVATE, 4096,
+ 4, 8466},
+ ASNOTATION_DOTPLUS,
},
{NULL, NULL, {0}, 0, {NULL, 0, 0}}};
@@ -856,16 +977,16 @@ struct compare_tests {
};
/* make an aspath from a data stream */
-static struct aspath *make_aspath(const uint8_t *data, size_t len, int use32bit)
+static struct aspath *make_aspath(const uint8_t *data, size_t len, int use32bit,
+ enum asnotation_mode asnotation)
{
struct stream *s = NULL;
struct aspath *as;
-
if (len) {
s = stream_new(len);
stream_put(s, data, len);
}
- as = aspath_parse(s, len, use32bit);
+ as = aspath_parse(s, len, use32bit, asnotation);
if (s)
stream_free(s);
@@ -901,15 +1022,16 @@ static int validate(struct aspath *as, const struct test_spec *sp)
}
out = aspath_snmp_pathseg(as, &bytes);
- asinout = make_aspath(out, bytes, 0);
-
+ asinout = make_aspath(out, bytes, 0, as->asnotation);
/* Excercise AS4 parsing a bit, with a dogfood test */
if (!s)
s = stream_new(BGP_MAX_PACKET_SIZE);
bytes4 = aspath_put(s, as, 1);
- as4 = make_aspath(STREAM_DATA(s), bytes4, 1);
+ as4 = make_aspath(STREAM_DATA(s), bytes4, 1, as->asnotation);
- asstr = aspath_str2aspath(sp->shouldbe);
+ asn_relax_as_zero(true);
+ asstr = aspath_str2aspath(sp->shouldbe, as->asnotation);
+ asn_relax_as_zero(false);
asconfeddel = aspath_delete_confed_seq(aspath_dup(asinout));
@@ -1036,7 +1158,7 @@ static void parse_test(struct test_segment *t)
printf("%s: %s\n", t->name, t->desc);
- asp = make_aspath(t->asdata, t->len, 0);
+ asp = make_aspath(t->asdata, t->len, 0, t->asnotation);
printf("aspath: %s\nvalidating...:\n", aspath_print(asp));
@@ -1058,8 +1180,10 @@ static void prepend_test(struct tests *t)
printf("prepend %s: %s\n", t->test1->name, t->test1->desc);
printf("to %s: %s\n", t->test2->name, t->test2->desc);
- asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
- asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
+ asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
+ ASNOTATION_PLAIN);
+ asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
+ ASNOTATION_PLAIN);
ascratch = aspath_dup(asp2);
aspath_unintern(&asp2);
@@ -1085,8 +1209,8 @@ static void empty_prepend_test(struct test_segment *t)
printf("empty prepend %s: %s\n", t->name, t->desc);
- asp1 = make_aspath(t->asdata, t->len, 0);
- asp2 = aspath_empty();
+ asp1 = make_aspath(t->asdata, t->len, 0, t->asnotation);
+ asp2 = aspath_empty(t->asnotation);
ascratch = aspath_dup(asp2);
aspath_unintern(&asp2);
@@ -1113,8 +1237,10 @@ static void as4_reconcile_test(struct tests *t)
printf("reconciling %s:\n %s\n", t->test1->name, t->test1->desc);
printf("with %s:\n %s\n", t->test2->name, t->test2->desc);
- asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
- asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
+ asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
+ ASNOTATION_PLAIN);
+ asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
+ ASNOTATION_PLAIN);
ascratch = aspath_reconcile_as4(asp1, asp2);
@@ -1138,8 +1264,10 @@ static void aggregate_test(struct tests *t)
printf("aggregate %s: %s\n", t->test1->name, t->test1->desc);
printf("with %s: %s\n", t->test2->name, t->test2->desc);
- asp1 = make_aspath(t->test1->asdata, t->test1->len, 0);
- asp2 = make_aspath(t->test2->asdata, t->test2->len, 0);
+ asp1 = make_aspath(t->test1->asdata, t->test1->len, 0,
+ ASNOTATION_PLAIN);
+ asp2 = make_aspath(t->test2->asdata, t->test2->len, 0,
+ ASNOTATION_PLAIN);
ascratch = aspath_aggregate(asp1, asp2);
@@ -1171,8 +1299,8 @@ static void cmp_test(void)
printf("left cmp %s: %s\n", t1->name, t1->desc);
printf("and %s: %s\n", t2->name, t2->desc);
- asp1 = make_aspath(t1->asdata, t1->len, 0);
- asp2 = make_aspath(t2->asdata, t2->len, 0);
+ asp1 = make_aspath(t1->asdata, t1->len, 0, ASNOTATION_PLAIN);
+ asp2 = make_aspath(t2->asdata, t2->len, 0, ASNOTATION_PLAIN);
if (aspath_cmp_left(asp1, asp2) != left_compare[i].shouldbe_cmp
|| aspath_cmp_left(asp2, asp1)
@@ -1210,7 +1338,9 @@ static int handle_attr_test(struct aspath_tests *t)
struct aspath *asp;
size_t datalen;
- asp = make_aspath(t->segment->asdata, t->segment->len, 0);
+ asp = make_aspath(t->segment->asdata, t->segment->len, 0,
+ t->segment->asnotation);
+ bgp.asnotation = t->segment->asnotation;
peer.curr = stream_new(BGP_MAX_PACKET_SIZE);
peer.obuf = stream_fifo_new();
@@ -1286,8 +1416,8 @@ int main(void)
parse_test(&test_segments[i]);
empty_prepend_test(&test_segments[i++]);
}
-
i = 0;
+
while (prepend_tests[i].test1) {
printf("prepend test %u\n", i);
prepend_test(&prepend_tests[i++]);
diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c
index 01b0740b87..8ef5748671 100644
--- a/tests/bgpd/test_capability.c
+++ b/tests/bgpd/test_capability.c
@@ -937,7 +937,8 @@ int main(void)
if (fileno(stdout) >= 0)
tty = isatty(fileno(stdout));
- if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
+ if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index 3abf7bd141..b1f3314f1f 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -1079,7 +1079,8 @@ int main(void)
if (fileno(stdout) >= 0)
tty = isatty(fileno(stdout));
- if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
+ if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);
diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c
index 1a2d21ad22..aeebbd9a35 100644
--- a/tests/bgpd/test_packet.c
+++ b/tests/bgpd/test_packet.c
@@ -50,7 +50,8 @@ int main(int argc, char *argv[])
vrf_init(NULL, NULL, NULL, NULL);
bgp_option_set(BGP_OPT_NO_LISTEN);
- if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0)
+ if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+ ASNOTATION_PLAIN) < 0)
return -1;
peer = peer_create_accept(bgp);
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index 090fb9a9f9..652aaa25d4 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -650,21 +650,14 @@ static const char *str_from_afi(afi_t afi)
return "ipv4";
case AFI_IP6:
return "ipv6";
- default:
- return "<unknown AFI>";
+ case AFI_L2VPN:
+ return "l2vpn";
+ case AFI_MAX:
+ case AFI_UNSPEC:
+ return "bad-value";
}
-}
-static const char *str_from_safi(safi_t safi)
-{
- switch (safi) {
- case SAFI_UNICAST:
- return "unicast";
- case SAFI_MULTICAST:
- return "multicast";
- default:
- return "<unknown SAFI>";
- }
+ assert(!"Reached end of function we should never reach");
}
static const char *str_from_attr_type(enum test_peer_attr_type at)
@@ -1150,7 +1143,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
test_log(test, "prepare: switch address-family to [%s]",
get_afi_safi_str(pa->afi, pa->safi, false));
test_execute(test, "address-family %s %s",
- str_from_afi(pa->afi), str_from_safi(pa->safi));
+ str_from_afi(pa->afi), safi2str(pa->safi));
test_execute(test, "neighbor %s activate", g->name);
test_execute(test, "neighbor %s activate", p->host);
}
@@ -1217,7 +1210,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
test_log(test, "prepare: switch address-family to [%s]",
get_afi_safi_str(pa->afi, pa->safi, false));
test_execute(test, "address-family %s %s",
- str_from_afi(pa->afi), str_from_safi(pa->safi));
+ str_from_afi(pa->afi), safi2str(pa->safi));
test_execute(test, "neighbor %s activate", g->name);
test_execute(test, "neighbor %s activate", p->host);
}
@@ -1265,7 +1258,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
test_log(test, "prepare: switch address-family to [%s]",
get_afi_safi_str(pa->afi, pa->safi, false));
test_execute(test, "address-family %s %s",
- str_from_afi(pa->afi), str_from_safi(pa->safi));
+ str_from_afi(pa->afi), safi2str(pa->safi));
test_execute(test, "neighbor %s activate", g->name);
test_execute(test, "neighbor %s activate", p->host);
}
@@ -1464,7 +1457,7 @@ int main(void)
if (pa->afi && pa->safi)
desc = asprintfrr(MTYPE_TMP, "peer\\%s-%s\\%s",
str_from_afi(pa->afi),
- str_from_safi(pa->safi), pa->cmd);
+ safi2str(pa->safi), pa->cmd);
else
desc = asprintfrr(MTYPE_TMP, "peer\\%s", pa->cmd);
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 9cabae8f20..0ab40b2ecd 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -12,6 +12,7 @@
#include "lib/memory.h"
#include "lib/prefix.h"
#include "lib/nexthop.h"
+#include "lib/asn.h"
static int errors;
@@ -145,6 +146,7 @@ int main(int argc, char **argv)
struct in_addr ip;
char *p;
char buf[256];
+ as_t asn;
printcmp("%d %u %d %u", 123, 123, -456, -456);
printcmp("%lld %llu %lld %llu", 123LL, 123LL, -456LL, -456LL);
@@ -392,6 +394,13 @@ int main(int argc, char **argv)
printchk("-00:09", "%pTSIm", &ts);
printchk("--:--", "%pTVImx", &tv);
printchk("--:--", "%pTTImx", &tt);
+ /* ASN checks */
+ asn = 65536;
+ printchk("1.0", "%pASD", &asn);
+ asn = 65400;
+ printchk("65400", "%pASP", &asn);
+ printchk("0.65400", "%pASE", &asn);
+ printchk("65400", "%pASD", &asn);
return !!errors;
}
diff --git a/tests/topotests/bgp_asdot_regex/__init__.py b/tests/topotests/bgp_asdot_regex/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/__init__.py
diff --git a/tests/topotests/bgp_asdot_regex/r1/bgpd.conf b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf
new file mode 100644
index 0000000000..4dd95dd8b7
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/bgpd.conf
@@ -0,0 +1,27 @@
+router bgp 1.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.255.2 remote-as 1.2
+ address-family ipv4 unicast
+ network 172.31.1.0/24 route-map rmapout
+ network 172.31.2.0/24 route-map rmapout
+ neighbor 192.168.255.2 route-map rmapin in
+ neighbor 192.168.255.2 activate
+ exit-address-family
+exit
+bgp as-path access-list only1_4 permit _1.4_
+bgp as-path access-list only65540 permit _65540_
+access-list 172313 permit 172.31.3.0/24
+access-list 172314 permit 172.31.4.0/24
+route-map rmapout permit 1
+ set as-path prepend 1.4
+exit
+route-map rmapin permit 1
+ match ip address 172313
+ match as-path only1_4
+exit
+route-map rmapin permit 2
+ match ip address 172314
+ match as-path only65540
+exit
+
diff --git a/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
new file mode 100644
index 0000000000..e3703bf953
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json
@@ -0,0 +1,80 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 3,
+ "routerId": "192.168.255.1",
+ "defaultLocPrf": 100,
+ "localAS": "1.1",
+ "routes": { "172.31.1.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.1.0",
+ "prefixLen":24,
+ "network":"172.31.1.0/24",
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"1.4",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "hostname":"r1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+,"172.31.2.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.2.0",
+ "prefixLen":24,
+ "network":"172.31.2.0/24",
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"1.4",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "hostname":"r1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+,"172.31.3.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.3.0",
+ "prefixLen":24,
+ "network":"172.31.3.0/24",
+ "metric":0,
+ "weight":0,
+ "peerId":"192.168.255.2",
+ "path":"1.2 1.4",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.168.255.2",
+ "hostname":"r2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+ } }
diff --git a/tests/topotests/bgp_asdot_regex/r1/zebra.conf b/tests/topotests/bgp_asdot_regex/r1/zebra.conf
new file mode 100644
index 0000000000..6e9b0b4a7e
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_asdot_regex/r2/bgpd.conf b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf
new file mode 100644
index 0000000000..216dbd19ef
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/bgpd.conf
@@ -0,0 +1,26 @@
+router bgp 65538
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.255.1 remote-as 65537
+ address-family ipv4 unicast
+ network 172.31.3.0/24 route-map rmapout
+ network 172.31.4.0/24 route-map rmapout
+ neighbor 192.168.255.1 route-map rmapin in
+ neighbor 192.168.255.1 activate
+ exit-address-family
+exit
+bgp as-path access-list only65540 permit _65540_
+bgp as-path access-list only1_4 permit _1.4_
+access-list 172311 permit 172.31.1.0/24
+access-list 172312 permit 172.31.2.0/24
+route-map rmapout permit 1
+ set as-path prepend 65540
+exit
+route-map rmapin permit 1
+ match ip address 172311
+ match as-path only65540
+exit
+route-map rmapin permit 2
+ match ip address 172312
+ match as-path only1_4
+exit
diff --git a/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
new file mode 100644
index 0000000000..1af4ff7e3d
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json
@@ -0,0 +1,80 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 3,
+ "routerId": "192.168.255.2",
+ "defaultLocPrf": 100,
+ "localAS": 65538,
+ "routes": { "172.31.1.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.1.0",
+ "prefixLen":24,
+ "network":"172.31.1.0/24",
+ "metric":0,
+ "weight":0,
+ "peerId":"192.168.255.1",
+ "path":"65537 65540",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"192.168.255.1",
+ "hostname":"r1",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+,"172.31.3.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.3.0",
+ "prefixLen":24,
+ "network":"172.31.3.0/24",
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"65540",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "hostname":"r2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+,"172.31.4.0/24": [
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"172.31.4.0",
+ "prefixLen":24,
+ "network":"172.31.4.0/24",
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"65540",
+ "origin":"IGP",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "hostname":"r2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+]
+ } }
diff --git a/tests/topotests/bgp_asdot_regex/r2/zebra.conf b/tests/topotests/bgp_asdot_regex/r2/zebra.conf
new file mode 100644
index 0000000000..6c14de583b
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
new file mode 100644
index 0000000000..5d5f1659e9
--- /dev/null
+++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_asdot_regex.py
+# Part of Topotests
+#
+# Copyright 2022 6WIND S.A.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_asdot_regex.py:
+
+Test how regex applies when asnotation to forge bgp config is based on dot or not.
+"""
+
+import os
+import sys
+import json
+import pytest
+from functools import partial
+
+# add after imports, before defining classes or functions:
+pytestmark = [pytest.mark.bgpd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_asdot_regex():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
+ expected = {
+ "192.168.255.2": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ logger.info("Check if neighbor sessions are up in {}".format(router1.name))
+ test_func = partial(_bgp_converge, router1)
+ success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5)
+ assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name)
+
+ logger.info("BGP neighbor session is up in {}".format(router1.name))
+
+ logger.info("waiting for bgp peers exchanging UPDATES")
+
+ for router in tgen.routers().values():
+ ref_file = "{}/{}/show_bgp_ipv4.json".format(CWD, router.name)
+ expected = json.loads(open(ref_file).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show bgp ipv4 unicast json", expected
+ )
+ _, res = topotest.run_and_expect(test_func, None, count=40, wait=2.5)
+ assertmsg = "{}: BGP UPDATE exchange failure".format(router.name)
+ assert res is None, assertmsg
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
index 7db6a51c92..324f53f3a6 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
@@ -11,7 +11,7 @@
Following tests are covered to test bgp community functionality:
1. Verify that BGP well known communities work fine for
eBGP and iBGP peers.
- Well known communities tested: no-export, local-AS, internet
+ Well known communities tested: no-export, local-AS
"""
@@ -140,11 +140,11 @@ def teardown_module(mod):
#####################################################
-def test_bgp_no_export_local_as_and_internet_communities_p0(request):
+def test_bgp_no_export_local_as_communities_p0(request):
"""
Verify that BGP well known communities work fine for
eBGP and iBGP peers.
- Well known communities tested: no-export, local-AS, internet
+ Well known communities tested: no-export, local-AS
"""
tc_name = request.node.name
@@ -170,7 +170,7 @@ def test_bgp_no_export_local_as_and_internet_communities_p0(request):
tc_name, result
)
- for comm_type in ["no-export", "local-AS", "internet"]:
+ for comm_type in ["no-export", "local-AS"]:
step("Create a route-map on R1 to set community as {}".format(comm_type))
@@ -258,45 +258,23 @@ def test_bgp_no_export_local_as_and_internet_communities_p0(request):
tc_name, result
)
- if comm_type == "internet":
- step(
- "Verify that these prefixes, originated on R1, are"
- "received on both R2 and R3"
- )
-
- result = verify_rib(
- tgen,
- addr_type,
- "r3",
- input_dict_4,
- next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[
- 0
- ],
- )
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
- )
- else:
- step(
- "Verify that these prefixes, originated on R1, are not"
- "received on R3 but received on R2"
- )
-
- result = verify_rib(
- tgen,
- addr_type,
- "r3",
- input_dict_4,
- next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[
- 0
- ],
- expected=False,
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Expected: Routes are still present in rib of r3 \n "
- "Found: {}".format(tc_name, result)
- )
+ step(
+ "Verify that these prefixes, originated on R1, are not"
+ "received on R3 but received on R2"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ "r3",
+ input_dict_4,
+ next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[0],
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes are still present in rib of r3 \n "
+ "Found: {}".format(tc_name, result)
+ )
step("Remove route-map from redistribute static on R1")
input_dict_2 = {
diff --git a/tests/topotests/bgp_confederation_astype/__init__.py b/tests/topotests/bgp_confederation_astype/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/__init__.py
diff --git a/tests/topotests/bgp_confederation_astype/r1/bgpd.conf b/tests/topotests/bgp_confederation_astype/r1/bgpd.conf
new file mode 100644
index 0000000000..1859a1b942
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r1/bgpd.conf
@@ -0,0 +1,12 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ bgp confederation identifier 65300
+ bgp confederation peers 65002 65003
+ neighbor fabric peer-group
+ neighbor fabric remote-as external
+ neighbor 192.168.1.2 peer-group fabric
+ neighbor 192.168.2.2 remote-as external
+ address-family ipv4 unicast
+ neighbor fabric activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confederation_astype/r1/zebra.conf b/tests/topotests/bgp_confederation_astype/r1/zebra.conf
new file mode 100644
index 0000000000..608a2411a3
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+int r1-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_confederation_astype/r2/bgpd.conf b/tests/topotests/bgp_confederation_astype/r2/bgpd.conf
new file mode 100644
index 0000000000..697af9743c
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r2/bgpd.conf
@@ -0,0 +1,13 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ bgp confederation identifier 65300
+ bgp confederation peers 65001
+ neighbor fabric peer-group
+ neighbor fabric remote-as external
+ neighbor 192.168.1.1 peer-group fabric
+ address-family ipv4 unicast
+ network 172.16.255.254/32
+ neighbor fabric activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confederation_astype/r2/zebra.conf b/tests/topotests/bgp_confederation_astype/r2/zebra.conf
new file mode 100644
index 0000000000..cffe827363
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/bgp_confederation_astype/r3/bgpd.conf b/tests/topotests/bgp_confederation_astype/r3/bgpd.conf
new file mode 100644
index 0000000000..c1f93f66e9
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r3/bgpd.conf
@@ -0,0 +1,10 @@
+router bgp 65003
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ bgp confederation identifier 65300
+ bgp confederation peers 65001
+ neighbor 192.168.2.1 remote-as external
+ address-family ipv4 unicast
+ network 172.16.255.254/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_confederation_astype/r3/zebra.conf b/tests/topotests/bgp_confederation_astype/r3/zebra.conf
new file mode 100644
index 0000000000..e5a37c98ca
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/r3/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r3-eth0
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py
new file mode 100644
index 0000000000..5310d3b595
--- /dev/null
+++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Test if BGP confederation works properly when using
+remote-as internal/external.
+
+Also, check if the same works with peer-groups as well.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")}
+ tgen = Topogen(topodef, 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_confederation_astype():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp summary json"))
+ expected = {
+ "ipv4Unicast": {
+ "peerCount": 2,
+ "peers": {
+ "192.168.1.2": {
+ "hostname": "r2",
+ "remoteAs": 65002,
+ "localAs": 65001,
+ "pfxRcd": 1,
+ "state": "Established",
+ },
+ "192.168.2.2": {
+ "hostname": "r3",
+ "remoteAs": 65003,
+ "localAs": 65001,
+ "pfxRcd": 1,
+ "state": "Established",
+ },
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge"
+
+ def _bgp_check_neighbors():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbors json"))
+ expected = {
+ "192.168.1.2": {
+ "nbrCommonAdmin": True,
+ "nbrConfedExternalLink": True,
+ "hostname": "r2",
+ },
+ "192.168.2.2": {
+ "nbrCommonAdmin": True,
+ "nbrConfedExternalLink": True,
+ "hostname": "r3",
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_neighbors)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't see neighbors to be in BGP confederation"
+
+ def _bgp_check_routes():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.254/32": [
+ {
+ "valid": True,
+ "pathFrom": "external",
+ "path": "(65003)",
+ },
+ {
+ "valid": True,
+ "pathFrom": "external",
+ "path": "(65002)",
+ },
+ ]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_routes)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't see routes to be in BGP confederation"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py b/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/__init__.py
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf
new file mode 100644
index 0000000000..1846df24f3
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 0.65000 as-notation dot+
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 0.1000
+ neighbor 192.168.255.2 timers 3 10
+ neighbor 192.168.255.2 local-as 0.500
+ address-family ipv4 unicast
+ neighbor 192.168.255.2 remove-private-AS
+ redistribute connected
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf
new file mode 100644
index 0000000000..0a283c06d5
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf
new file mode 100644
index 0000000000..c9adfa4671
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/bgpd.conf
@@ -0,0 +1,5 @@
+router bgp 0.1000 as-notation dot+
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 0.500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf
new file mode 100644
index 0000000000..9a831270b4
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 3000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 timers 3 10
+ neighbor 192.168.255.2 local-as 500
+ address-family ipv4 unicast
+ neighbor 192.168.255.2 remove-private-AS
+ redistribute connected
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf
new file mode 100644
index 0000000000..39499a198d
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r3/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r3-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf
new file mode 100644
index 0000000000..c9adfa4671
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/bgpd.conf
@@ -0,0 +1,5 @@
+router bgp 0.1000 as-notation dot+
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 0.500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf
new file mode 100644
index 0000000000..b85911504e
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/r4/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r4-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py
new file mode 100644
index 0000000000..efecad3eb2
--- /dev/null
+++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+#
+# bgp_local_as_private_remove.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_local_as_private_remove.py:
+Test if primary AS number is not removed in cases when `local-as`
+used together with `remove-private-AS`.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_remove_private_as():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge(router):
+ while True:
+ output = json.loads(
+ tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
+ )
+ if output["192.168.255.1"]["bgpState"] == "Established":
+ time.sleep(1)
+ return True
+
+ def _bgp_as_path(router):
+ output = json.loads(
+ tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
+ )
+ if output["prefix"] == "172.16.255.254/32":
+ return output["paths"][0]["aspath"]["segments"][0]["list"]
+
+ if _bgp_converge("r2"):
+ assert len(_bgp_as_path("r2")) == 1
+ assert '0.65000' not in _bgp_as_path("r2")
+
+ if _bgp_converge("r4"):
+ assert len(_bgp_as_path("r4")) == 2
+ assert '0.3000' in _bgp_as_path("r4")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
new file mode 100644
index 0000000000..b481932449
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_agg.json
@@ -0,0 +1,147 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.1.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::1:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.2.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::2:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
new file mode 100644
index 0000000000..afacab4946
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_ecmp.json
@@ -0,0 +1,317 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:DB8:F::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "1.100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ],
+ "static_routes":[
+ {
+ "network":"10.0.0.1/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10::1/128",
+ "next_hop":"Null0"
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "1.200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link8": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {},
+ "r3-link5": {},
+ "r3-link6": {},
+ "r3-link7": {},
+ "r3-link8": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {},
+ "r3-link5": {},
+ "r3-link6": {},
+ "r3-link7": {},
+ "r3-link8": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link8": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "1.400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {},
+ "r4-link5": {},
+ "r4-link6": {},
+ "r4-link7": {},
+ "r4-link8": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {},
+ "r4-link5": {},
+ "r4-link6": {},
+ "r4-link7": {},
+ "r4-link8": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
new file mode 100644
index 0000000000..02aacf791a
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/bgp_local_asn_dot_topo1.json
@@ -0,0 +1,132 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.1.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::1:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "1.400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
new file mode 100644
index 0000000000..cb8fa1e9f9
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py
@@ -0,0 +1,420 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
+1. Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
+"""
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK_1_1 = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NETWORK_1_2 = {"ipv4": "10.1.2.0/32", "ipv6": "10:1::2:0/128"}
+AGGREGATE_NW = {"ipv4": "10.1.0.0/16", "ipv6": "10:1::/96"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_local_asn_dot_agg.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ ADDR_TYPES = check_address_types()
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+####################################################################################################################
+#
+# Testcases
+#
+####################################################################################################################
+
+
+def test_verify_bgp_local_as_agg_in_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Done in base config: Advertise prefix 10.1.1.0/24 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/120 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK_1_1[addr_type]}]}
+ }
+
+ input_static_verify_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK_1_2[addr_type]}]}
+ }
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r2", input_static_verify_r2)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure aggregate-address to summarise all the advertised routes.")
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": AGGREGATE_NW[addr_type],
+ "summary": True,
+ "as_set": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that we see a summarised route on advertising router R3 "
+ "and receiving router R4 for both AFIs"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ input_static_r1 = {
+ "r1": {"static_routes": [{"network": [NETWORK_1_1[addr_type]]}]}
+ }
+
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": [NETWORK_1_2[addr_type]]}]}
+ }
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_agg_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1", "r2"], [input_static_r1, input_static_r2]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 1.110 {1.100,1.110,1.200} by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "{1.100,1.110,1.200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "{1.100,1.200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 {1.100,1.200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
new file mode 100644
index 0000000000..6937a61c33
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py
@@ -0,0 +1,524 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+#
+##########################################################################################################################################
+#
+# Testcases
+#
+###########################################################################################################################################
+###########################################################################################################################################
+#
+# 1.10.1.7. Verify the BGP Local AS functionality with ECMP on 8 links by adding no-prepend and replace-as command in between eBGP Peers.
+#
+#################################################################################################################################################
+
+import os
+import sys
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_local_asn_dot_ecmp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ ADDR_TYPES = check_address_types()
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+##########################################################################################################################################
+#
+# Testcases
+#
+###########################################################################################################################################
+
+
+def test_verify_bgp_local_as_in_ecmp_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality with ECMP on 8 links by
+ adding no-prepend and replace-as command in between eBGP Peers.
+ """
+
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {"local_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"local_as": "1.110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r4-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"remote_as": "1.110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "1.400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r3": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 1.110 1.200 1.100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"local_as": "1.110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {
+ "local_asn": {"local_as": "1.110", "no_prepend": True, "replace_as": True}
+ }
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
new file mode 100644
index 0000000000..e9234f5172
--- /dev/null
+++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py
@@ -0,0 +1,3655 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+##########################################################################################################
+#
+# Functionality Testcases
+#
+##########################################################################################################
+"""
+1. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between eBGP Peers.
+2. Verify the BGP Local AS functionality by configuring 4 Byte AS at R3 and 2 Byte AS at R2 & R4 in between eBGP Peers.
+3. Verify that BGP Local AS functionality by performing graceful restart in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend command in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP Peers.
+5. Verify the BGP Local AS functionality with allowas-in in between iBGP Peers.
+6. Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+7. Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+8. Verify the BGP Local AS functionality with different AS configurations.
+9. Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+"""
+
+import os
+import sys
+import time
+import pytest
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ get_frr_ipv6_linklocal,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+ create_route_maps,
+ kill_router_daemons,
+ start_router_daemons,
+ shutdown_bringup_interface,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ clear_bgp_and_verify,
+ verify_bgp_rib,
+ modify_as_number,
+ create_router_bgp,
+ verify_bgp_advertised_routes_from_neighbor,
+ verify_graceful_restart,
+ verify_r_bit,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+NEXT_HOP_IP_GR = {"ipv4": "10.0.0.5", "ipv6": "fd00:0:0:1::2/64"}
+NEXT_HOP_IP_1 = {"ipv4": "10.0.0.101", "ipv6": "fd00::1"}
+NEXT_HOP_IP_2 = {"ipv4": "10.0.0.102", "ipv6": "fd00::2"}
+
+BGP_CONVERGENCE = False
+PREFERRED_NEXT_HOP = "link_local"
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_local_asn_dot_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ ADDR_TYPES = check_address_types()
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+##########################################################################################################
+#
+# Local APIs
+#
+##########################################################################################################
+
+
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
+ """
+ This function groups the repetitive function calls into one function.
+ """
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = clear_bgp_and_verify(tgen, topo, dut)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ return True
+
+
+def next_hop_per_address_family(
+ tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP
+):
+ """
+ This function returns link_local or global next_hop per address-family
+ """
+ intferface = topo["routers"][peer]["links"]["{}".format(dut)]["interface"]
+ if addr_type == "ipv6" and "link_local" in preferred_next_hop:
+ next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface)
+ else:
+ next_hop = next_hop_dict[addr_type]
+
+ return next_hop
+
+
+##########################################################################################################
+#
+# Testcases
+#
+##########################################################################################################
+
+
+def test_verify_bgp_local_as_in_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding no-prepend and
+ replace-as command in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_4B_AS_mid_4B_AS_p0(request):
+ """
+ Verify the BGP Local AS functionality by configuring 4 Byte AS
+ at R3 and 4 Byte AS at R2 & R4 in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "183.2926"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {
+ "local_asn": {
+ "remote_as": "183.2926"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-183.2926 is got added in the AS list 183.2926 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "183.2926 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "183.2926",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "183.2926",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "183.2926 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_GR_EBGP_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing graceful restart in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP_GR[addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "1.400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP_GR[addr_type],
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ """
+ GR Steps : Helper BGP router R2, mark and unmark IPV4 routes
+ as stale as the restarting router R3 come up within the restart time
+ """
+ # Create route-map to prefer global next-hop
+ input_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ "r3": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_neigh_rm = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_neigh_rm)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure graceful-restart
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "1.110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "1.110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r3", peer="r2")
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying BGP RIB routes
+ dut = "r2"
+ peer = "r3"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, "bgp")
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Phase 2] : R3 goes for reload ")
+
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R3 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB"
+ " and ZEBRA"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Phase 5] : R3 is about to come up now ")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info("[Phase 5] : R3 is UP Now ! ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_bgp_convergence(tgen, topo)
+ assert (
+ result is True
+ ), "BGP Convergence after BGPd restart" " :Failed \n Error:{}".format(result)
+
+ # Verifying GR stats
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r3")
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_aspath_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend command in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure a route-map on R3 to prepend AS 2 times.")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "1.1000 1.1000", "as_action": "prepend"}
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure route map in out direction on R4")
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "ASP_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-1.300 is got replaced with 1.200 in the AS list 1.110 1.1000 1.1000 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r4"
+ aspath = "1.110 1.1000 1.1000 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Modify AS Number for R3")
+ input_dict_modify_as_number = {"r3": {"bgp": {"local_as": "1.200"}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ step("Base config is done as part of JSON")
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "1.400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "next_hop_self": True,
+ "local_asn": {
+ "remote_as": "1.200",
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_allow_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality with allowas-in in between iBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Modidy AS Number for R4")
+ input_dict_modify_as_number = {"r4": {"bgp": {"local_as": "1.100"}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ step("Base config is done as part of JSON")
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure allow-as at R4")
+ for addr_type in ADDR_TYPES:
+ allow_as_config_r4 = {
+ "r4": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "allowas-in": {
+ "number_occurences": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+
+ step(
+ "Configuring allow-as for {} address-family on router R4 ".format(addr_type)
+ )
+ result = create_router_bgp(tgen, topo, allow_as_config_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # now modify the as in r4 and reconfig bgp in r3 with new remote as.
+ topo1 = deepcopy(topo)
+ topo1["routers"]["r4"]["bgp"]["local_as"] = "1.100"
+
+ delete_bgp = {"r3": {"bgp": {"delete": True}}}
+ result = create_router_bgp(tgen, topo1, delete_bgp)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ build_config_from_json(tgen, topo1, save_bkup=False)
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "1.200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "1.100",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "1.110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_port_reset_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Api call to modfiy BGP timers at R3")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_timers = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_timers)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for count in range(1, 1):
+ step("Iteration {}".format(count))
+ step("Shut down connecting interface between R3<<>>R4 on R3.")
+
+ intf1 = topo["routers"]["r3"]["links"]["r4"]["interface"]
+
+ interfaces = [intf1]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r3", intf, False)
+
+ step(
+ "On R3, all BGP peering in respective vrf instances go down"
+ " when the interface is shut"
+ )
+
+ result = verify_bgp_convergence(tgen, topo, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: BGP will not be converged \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("BGP neighborship is verified after restart of r3")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative2_p0(request):
+ """
+ Verify the BGP Local AS functionality with different AS configurations.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ step("Verify that AS-1.300 is replaced with AS-1.110 at R3 router.")
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # configure negative scenarios
+ step("Configure local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.110",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative3_p0(request):
+ """
+ Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Perform Negative scenarios
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_restart_daemons_p0(request):
+ """
+ Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["1.200", "1.400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "1.110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-1.100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-1.100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-1.110 is got added in the AS list 1.110 1.200 1.100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.200 1.100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-1.110 is not prepended in the AS list 1.200 1.100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "1.300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "1.110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verified that AS-1.300 is got replaced with original AS-1.110 at R4 by following commands"
+ )
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verified that AS-1.300 is got replaced with original AS-1.110 at R4 by following commands"
+ )
+ dut = "r4"
+ aspath = "1.110 1.200 1.100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index f1937f45be..7609c7f899 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -8,6 +8,7 @@
import ipaddress
import sys
from copy import deepcopy
+from time import sleep
# Import common_config to use commomnly used APIs
from lib.common_config import (
@@ -188,6 +189,24 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
cmd = "no maximum-paths"
config_data.append(cmd)
+ # Flood reduction.
+ flood_data = ospf_data.setdefault("flood-reduction", {})
+ if flood_data:
+ cmd = "flood-reduction"
+ del_action = ospf_data.setdefault("del_flood_reduction", False)
+ if del_action:
+ cmd = "no flood-reduction"
+ config_data.append(cmd)
+
+ # LSA refresh timer - A hidden command.
+ refresh_data = ospf_data.setdefault("lsa-refresh", {})
+ if refresh_data:
+ cmd = "ospf lsa-refresh {}".format(refresh_data)
+ del_action = ospf_data.setdefault("del_lsa_refresh", False)
+ if del_action:
+ cmd = "no ospf lsa-refresh"
+ config_data.append(cmd)
+
# redistribute command
redistribute_data = ospf_data.setdefault("redistribute", {})
if redistribute_data:
@@ -220,6 +239,9 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
if "type" in area:
cmd = cmd + " {}".format(area["type"])
+ if "flood-reduction" in area:
+ cmd = cmd + " flood-reduction"
+
del_action = area.setdefault("delete", False)
if del_action:
cmd = "no {}".format(cmd)
@@ -724,9 +746,6 @@ def verify_ospf_neighbor(
return result
-################################
-# Verification procs
-################################
@retry(retry_timeout=50)
def verify_ospf6_neighbor(tgen, topo=None, dut=None, input_dict=None, lan=False):
"""
@@ -1339,8 +1358,10 @@ def verify_ospf_interface(
return result
-@retry(retry_timeout=20)
-def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
+@retry(retry_timeout=40)
+def verify_ospf_database(
+ tgen, topo, dut, input_dict, vrf=None, lsatype=None, rid=None, expected=True
+):
"""
This API is to verify ospf lsa's by running
show ip ospf database command.
@@ -1398,7 +1419,23 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
rnode = tgen.routers()[dut]
logger.info("Verifying OSPF interface on router %s:", dut)
- show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json", isjson=True)
+
+ if not rid:
+ rid = "self-originate"
+ if lsatype:
+ if vrf is None:
+ command = "show ip ospf database {} {} json".format(lsatype, rid)
+ else:
+ command = "show ip ospf database {} {} vrf {} json".format(
+ lsatype, rid, vrf
+ )
+ else:
+ if vrf is None:
+ command = "show ip ospf database json"
+ else:
+ command = "show ip ospf database vrf {} json".format(vrf)
+
+ show_ospf_json = run_frr_cmd(rnode, command, isjson=True)
# Verifying output dictionary show_ospf_json is empty or not
if not bool(show_ospf_json):
errormsg = "OSPF is not running"
@@ -1407,26 +1444,40 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
# for inter and inter lsa's
ospf_db_data = input_dict.setdefault("areas", None)
ospf_external_lsa = input_dict.setdefault("AS External Link States", None)
+ # import pdb; pdb.set_trace()
if ospf_db_data:
for ospf_area, area_lsa in ospf_db_data.items():
- if ospf_area in show_ospf_json["areas"]:
- if "Router Link States" in area_lsa:
- for lsa in area_lsa["Router Link States"]:
+ if ospf_area in show_ospf_json["routerLinkStates"]["areas"]:
+ if "routerLinkStates" in area_lsa:
+ for lsa in area_lsa["routerLinkStates"]:
+ _advrtr = lsa.setdefault("advertisedRouter", None)
+ _options = lsa.setdefault("options", None)
+
if (
- lsa
- in show_ospf_json["areas"][ospf_area]["Router Link States"]
+ _options
+ and lsa["lsaId"]
+ == show_ospf_json["routerLinkStates"]["areas"][ospf_area][
+ 0
+ ]["linkStateId"]
+ and lsa["options"]
+ == show_ospf_json["routerLinkStates"]["areas"][ospf_area][
+ 0
+ ]["options"]
):
- logger.info(
- "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
- router,
- ospf_area,
- lsa,
- )
result = True
+ break
else:
- errormsg = (
- "[DUT: {}] OSPF LSDB area {}: expected"
- " Router LSA is {}".format(router, ospf_area, lsa)
+ errormsg = '[DUT: {}] OSPF LSA options: expected {}, Received Options are {} lsa["options"] {} OSPF LSAID: expected lsaid {}, Received lsaid {}'.format(
+ dut,
+ show_ospf_json["routerLinkStates"]["areas"][ospf_area][
+ 0
+ ]["options"],
+ _options,
+ lsa["options"],
+ show_ospf_json["routerLinkStates"]["areas"][ospf_area][
+ 0
+ ]["linkStateId"],
+ lsa["lsaId"],
)
return errormsg
if "Net Link States" in area_lsa:
@@ -2476,3 +2527,495 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
+
+
+def get_ospf_database(tgen, topo, dut, input_dict, vrf=None, lsatype=None, rid=None):
+ """
+ This API is to return ospf lsa's by running
+ show ip ospf database command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `topo` : next to be verified
+ * `vrf` : vrf to be checked
+ * `lsatype` : type of lsa to be checked
+ * `rid` : router id for lsa to be checked
+ Usage
+ -----
+ input_dict = {
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": {
+ "100.1.1.0-100.1.1.0": {
+ "LSID": "100.1.1.0",
+ "Advertised router": "100.1.1.0",
+ "LSA Age": 130,
+ "Sequence Number": "80000006",
+ "Checksum": "a703",
+ "Router links": 3
+ }
+ },
+ "networkLinkStates": {
+ "10.0.0.2-100.1.1.1": {
+ "LSID": "10.0.0.2",
+ "Advertised router": "100.1.1.1",
+ "LSA Age": 137,
+ "Sequence Number": "80000001",
+ "Checksum": "9583"
+ }
+ },
+ },
+ }
+ }
+ result = get_ospf_database(tgen, topo, dut, input_dict)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ result = False
+ router = dut
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ sleep(10)
+ if "ospf" not in topo["routers"][dut]:
+ errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
+ return errormsg
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("Verifying OSPF interface on router %s:", dut)
+ if not rid:
+ rid = "self-originate"
+ if lsatype:
+ if vrf is None:
+ command = "show ip ospf database {} {} json".format(lsatype, rid)
+ else:
+ command = "show ip ospf database {} {} vrf {} json".format(
+ lsatype, rid, vrf
+ )
+ else:
+ if vrf is None:
+ command = "show ip ospf database json"
+ else:
+ command = "show ip ospf database vrf {} json".format(vrf)
+
+ show_ospf_json = run_frr_cmd(rnode, command, isjson=True)
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ # for inter and inter lsa's
+ ospf_db_data = input_dict.setdefault("areas", None)
+ ospf_external_lsa = input_dict.setdefault("asExternalLinkStates", None)
+
+ if ospf_db_data:
+ for ospf_area, area_lsa in ospf_db_data.items():
+ if "areas" in show_ospf_json and ospf_area in show_ospf_json["areas"]:
+ if "routerLinkStates" in area_lsa:
+ for lsa in area_lsa["routerLinkStates"]:
+ for rtrlsa in show_ospf_json["areas"][ospf_area][
+ "routerLinkStates"
+ ]:
+ _advrtr = lsa.setdefault("advertisedRouter", None)
+ _options = lsa.setdefault("options", None)
+ if (
+ _advrtr
+ and lsa["lsaId"] == rtrlsa["lsaId"]
+ and lsa["advertisedRouter"]
+ == rtrlsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if (
+ _options
+ and lsa["lsaId"] == rtrlsa["lsaId"]
+ and lsa["options"] == rtrlsa["options"]
+ ):
+ result = True
+ break
+
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Router LSA is {}\n found Router LSA: {}".format(
+ router, ospf_area, lsa, rtrlsa
+ )
+ )
+ return errormsg
+
+ if "networkLinkStates" in area_lsa:
+ for lsa in area_lsa["networkLinkStates"]:
+ for netlsa in show_ospf_json["areas"][ospf_area][
+ "networkLinkStates"
+ ]:
+ if (
+ lsa
+ in show_ospf_json["areas"][ospf_area][
+ "networkLinkStates"
+ ]
+ ):
+ if (
+ lsa["lsaId"] == netlsa["lsaId"]
+ and lsa["advertisedRouter"]
+ == netlsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Network LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "summaryLinkStates" in area_lsa:
+ for lsa in area_lsa["summaryLinkStates"]:
+ for t3lsa in show_ospf_json["areas"][ospf_area][
+ "summaryLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t3lsa["lsaId"]
+ and lsa["advertisedRouter"] == t3lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Summary LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "nssaExternalLinkStates" in area_lsa:
+ for lsa in area_lsa["nssaExternalLinkStates"]:
+ for t7lsa in show_ospf_json["areas"][ospf_area][
+ "nssaExternalLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t7lsa["lsaId"]
+ and lsa["advertisedRouter"] == t7lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Type7 LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "asbrSummaryLinkStates" in area_lsa:
+ for lsa in area_lsa["asbrSummaryLinkStates"]:
+ for t4lsa in show_ospf_json["areas"][ospf_area][
+ "asbrSummaryLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t4lsa["lsaId"]
+ and lsa["advertisedRouter"] == t4lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ result = True
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " ASBR Summary LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "linkLocalOpaqueLsa" in area_lsa:
+ for lsa in area_lsa["linkLocalOpaqueLsa"]:
+ try:
+ for lnklsa in show_ospf_json["areas"][ospf_area][
+ "linkLocalOpaqueLsa"
+ ]:
+ if (
+ lsa["lsaId"] in lnklsa["lsaId"]
+ and "linkLocalOpaqueLsa"
+ in show_ospf_json["areas"][ospf_area]
+ ):
+ logger.info(
+ (
+ "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
+ "%s",
+ ospf_area,
+ lsa,
+ )
+ )
+ result = True
+ else:
+ errormsg = (
+ "[DUT: FRR] OSPF LSDB area: {} "
+ "expected Opaque-LSA is {}, Found is {}".format(
+ ospf_area, lsa, show_ospf_json
+ )
+ )
+ raise ValueError(errormsg)
+ return errormsg
+ except KeyError:
+ errormsg = "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
+ return errormsg
+ else:
+ if "routerLinkStates" in area_lsa:
+ for lsa in area_lsa["routerLinkStates"]:
+ for rtrlsa in show_ospf_json["routerLinkStates"]:
+ _advrtr = lsa.setdefault("advertisedRouter", None)
+ _options = lsa.setdefault("options", None)
+ _age = lsa.setdefault("lsaAge", None)
+ if (
+ _options
+ and lsa["options"]
+ == show_ospf_json["routerLinkStates"][rtrlsa][
+ ospf_area
+ ][0]["options"]
+ ):
+ result = True
+ break
+ if (
+ _age is not "get"
+ and lsa["lsaAge"]
+ == show_ospf_json["routerLinkStates"][rtrlsa][
+ ospf_area
+ ][0]["lsaAge"]
+ ):
+ result = True
+ break
+
+ if _age == "get":
+ return "{}".format(
+ show_ospf_json["routerLinkStates"][rtrlsa][
+ ospf_area
+ ][0]["lsaAge"]
+ )
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Router LSA is {}\n found Router LSA: {}".format(
+ router,
+ ospf_area,
+ lsa,
+ show_ospf_json["routerLinkStates"],
+ )
+ )
+ return errormsg
+
+ if "networkLinkStates" in area_lsa:
+ for lsa in area_lsa["networkLinkStates"]:
+ for netlsa in show_ospf_json["areas"][ospf_area][
+ "networkLinkStates"
+ ]:
+ if (
+ lsa
+ in show_ospf_json["areas"][ospf_area][
+ "networkLinkStates"
+ ]
+ ):
+ if (
+ lsa["lsaId"] == netlsa["lsaId"]
+ and lsa["advertisedRouter"]
+ == netlsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Network LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "summaryLinkStates" in area_lsa:
+ for lsa in area_lsa["summaryLinkStates"]:
+ for t3lsa in show_ospf_json["areas"][ospf_area][
+ "summaryLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t3lsa["lsaId"]
+ and lsa["advertisedRouter"] == t3lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Summary LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "nssaExternalLinkStates" in area_lsa:
+ for lsa in area_lsa["nssaExternalLinkStates"]:
+ for t7lsa in show_ospf_json["areas"][ospf_area][
+ "nssaExternalLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t7lsa["lsaId"]
+ and lsa["advertisedRouter"] == t7lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ break
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " Type7 LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "asbrSummaryLinkStates" in area_lsa:
+ for lsa in area_lsa["asbrSummaryLinkStates"]:
+ for t4lsa in show_ospf_json["areas"][ospf_area][
+ "asbrSummaryLinkStates"
+ ]:
+ if (
+ lsa["lsaId"] == t4lsa["lsaId"]
+ and lsa["advertisedRouter"] == t4lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ if result:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
+ router,
+ ospf_area,
+ lsa,
+ )
+ result = True
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB area {}: expected"
+ " ASBR Summary LSA is {}".format(router, ospf_area, lsa)
+ )
+ return errormsg
+
+ if "linkLocalOpaqueLsa" in area_lsa:
+ for lsa in area_lsa["linkLocalOpaqueLsa"]:
+ try:
+ for lnklsa in show_ospf_json["areas"][ospf_area][
+ "linkLocalOpaqueLsa"
+ ]:
+ if (
+ lsa["lsaId"] in lnklsa["lsaId"]
+ and "linkLocalOpaqueLsa"
+ in show_ospf_json["areas"][ospf_area]
+ ):
+ logger.info(
+ (
+ "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
+ "%s",
+ ospf_area,
+ lsa,
+ )
+ )
+ result = True
+ else:
+ errormsg = (
+ "[DUT: FRR] OSPF LSDB area: {} "
+ "expected Opaque-LSA is {}, Found is {}".format(
+ ospf_area, lsa, show_ospf_json
+ )
+ )
+ raise ValueError(errormsg)
+ return errormsg
+ except KeyError:
+ errormsg = "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
+ return errormsg
+
+ if ospf_external_lsa:
+ for lsa in ospf_external_lsa:
+ try:
+ for t5lsa in show_ospf_json["asExternalLinkStates"]:
+ if (
+ lsa["lsaId"] == t5lsa["lsaId"]
+ and lsa["advertisedRouter"] == t5lsa["advertisedRouter"]
+ ):
+ result = True
+ break
+ except KeyError:
+ result = False
+ if result:
+ logger.info("[DUT: %s] OSPF LSDB:External LSA %s", router, lsa)
+ result = True
+ else:
+ errormsg = (
+ "[DUT: {}] OSPF LSDB : expected"
+ " External LSA is {}".format(router, lsa)
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
diff --git a/tests/topotests/ospf_basic_functionality/ospf_flood_reduction.json b/tests/topotests/ospf_basic_functionality/ospf_flood_reduction.json
new file mode 100644
index 0000000000..74443cdc7d
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_flood_reduction.json
@@ -0,0 +1,214 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ },
+ "graceful-restart": {
+ "helper-only": []
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.1",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ },
+ "graceful-restart": {
+ "helper-only": []
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.1",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "broadcast"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ },
+ "graceful-restart": {
+ "helper-only": []
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "broadcast"
+ }
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.0"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ },
+ "graceful-restart": {
+ "helper-only": []
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py
new file mode 100644
index 0000000000..bd7db644d1
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py
@@ -0,0 +1,1066 @@
+#!/usr/bin/python
+
+#
+# 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+from time import sleep
+
+# 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/"))
+
+pytestmark = [pytest.mark.ospfd, pytest.mark.staticd]
+# Global variables
+topo = None
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topolog import logger
+from lib.topojson import build_config_from_json
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ step,
+ topo_daemons,
+ shutdown_bringup_interface,
+ check_router_status,
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ step,
+ shutdown_bringup_interface,
+ check_router_status,
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ stop_router,
+ start_router,
+ step,
+ create_static_routes,
+ kill_router_daemons,
+ check_router_status,
+ start_router_daemons,
+)
+from lib.topolog import logger
+from lib.topogen import Topogen, get_topogen
+
+from lib.topojson import build_config_from_json
+from lib.ospf import (
+ verify_ospf_neighbor,
+ clear_ospf,
+ create_router_ospf,
+ verify_ospf_database,
+ get_ospf_database,
+)
+
+# Global variables
+topo = None
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. Verify OSPF Flood reduction functionality with ospf enabled on process level.
+2. Verify OSPF Flood reduction functionality with ospf enabled on area level.
+3. Verify OSPF Flood reduction functionality between different area's.
+4. Verify OSPF Flood reduction functionality with ospf enabled on process level with default lsa refresh timer.
+5. Chaos - Verify OSPF TTL GTSM and flood reduction functionality in chaos scenarios.
+"""
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ 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 = "{}/ospf_flood_reduction.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen)
+
+ # 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)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ 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)
+
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+def test_ospf_flood_red_tc1_p0(request):
+ """Verify OSPF Flood reduction functionality with ospf enabled on process level."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ global topo
+
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ red_static("r0")
+ step("Base config should be up, verify using OSPF convergence on all the routers")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Enable flood reduction in process level on R0")
+ ospf_flood = {"r0": {"ospf": {"flood-reduction": True}}}
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure the custom refresh timer")
+ ospf_flood = {"r0": {"ospf": {"lsa-refresh": 120}}}
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("Enable flood. reduction in all the routers of the topology.")
+ for rtr in topo["routers"].keys():
+ ospf_flood = {rtr: {"ospf": {"lsa-refresh": 120, "flood-reduction": True}}}
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ for rtr in topo["routers"]:
+ dut = rtr
+ lsid = "{}".format(topo["routers"][rtr]["ospf"]["router_id"])
+ input_dict_db = {
+ "routerId": lsid,
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": lsid,
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid=lsid
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ # this wait is put so that we wait for 5secs to check if lsa is refreshed.
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ assert (result1 == result2) is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Disable flood reduction in R0.")
+ ospf_flood = {
+ "r0": {"ospf": {"flood-reduction": True, "del_flood_reduction": True}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ clear_ospf(tgen, "r0")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lea's are not set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: OSPF LSA should not be set with DC bit in {} \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ if result2 is not result1:
+ result = True
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Enable flood reduction on each router with 10 secs delay of between each router."
+ )
+ for rtr in topo["routers"].keys():
+ ospf_flood = {rtr: {"ospf": {"lsa-refresh": 120, "flood-reduction": True}}}
+ sleep(10)
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that LSA's are not refreshed. Do not age bit should be set to 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify OSPF neighborship when OSPF flood reduction is configured and ospf process is restarted"
+ )
+
+ step("Kill OSPFd daemon on R0.")
+ kill_router_daemons(tgen, "r0", ["ospfd"])
+ start_router_daemons(tgen, "r0", ["ospfd"])
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that LSA's are not refreshed. Do not age bit should be set to 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_flood_red_tc2_p0(request):
+ """Verify OSPF Flood reduction functionality with ospf enabled on area level."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ global topo
+
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ red_static("r0")
+ step("Base config should be up, verify using OSPF convergence on all the routers")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Enable flood reduction in area level on R0 in area 0")
+ ospf_flood = {
+ "r0": {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure the custom refresh timer")
+ ospf_flood = {"r0": {"ospf": {"lsa-refresh": 120}}}
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("Enable flood. reduction in all the routers of the topology.")
+ for rtr in topo["routers"].keys():
+ ospf_flood = {
+ rtr: {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ for rtr in topo["routers"]:
+ dut = rtr
+ lsid = "{}".format(topo["routers"][rtr]["ospf"]["router_id"])
+ input_dict_db = {
+ "routerId": lsid,
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": lsid,
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid=lsid
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ assert (result1 == result2) is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Disable flood reduction in R0.")
+ ospf_flood = {
+ "r0": {
+ "ospf": {
+ "area": [{"id": "0.0.0.0", "flood-reduction": True, "delete": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ clear_ospf(tgen, "r0")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lea's are not set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: OSPF LSA should not be set with DC bit in {} \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ if result2 is not result1:
+ result = True
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Enable flood reduction on each router with 10 secs delay of between each router."
+ )
+ for rtr in topo["routers"].keys():
+ ospf_flood = {
+ rtr: {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ sleep(10)
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that LSA's are not refreshed. Do not age bit should be set to 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_flood_red_tc3_p0(request):
+ """Verify OSPF Flood reduction functionality between different area's"""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ global topo
+
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ red_static("r0")
+ step("Base config should be up, verify using OSPF convergence on all the routers")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Enable flood reduction in area level on R0 in area 0")
+ ospf_flood = {
+ "r0": {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure the custom refresh timer")
+ ospf_flood = {"r0": {"ospf": {"lsa-refresh": 120}}}
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step(
+ "Enable flood. reduction in all the routers of the topology in area 0. Redistribute static route in area 0 R1 and area1 in R2."
+ )
+ for rtr in topo["routers"].keys():
+ ospf_flood = {
+ rtr: {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ sleep(10)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lsa's are set with dc bit 1.")
+ for rtr in topo["routers"]:
+ dut = rtr
+ lsid = "{}".format(topo["routers"][rtr]["ospf"]["router_id"])
+ input_dict_db = {
+ "routerId": lsid,
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": lsid,
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid=lsid
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ assert (result1 == result2) is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Enable flood reduction in area 1.")
+
+ ospf_flood = {
+ "r0": {"ospf": {"area": [{"id": "0.0.0.0", "flood-reduction": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r1": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True},
+ {"id": "0.0.0.1", "flood-reduction": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r2": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True},
+ {"id": "0.0.0.1", "flood-reduction": True},
+ {"id": "0.0.0.2", "flood-reduction": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r3": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True},
+ {"id": "0.0.0.2", "flood-reduction": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lea's are set with dc bit 1.")
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.1",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.1",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.1",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.1", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.1"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.1"
+ )
+
+ if result2 is result1:
+ result = True
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Disable flood reduction in R0.")
+
+ ospf_flood = {
+ "r0": {
+ "ospf": {
+ "area": [{"id": "0.0.0.0", "flood-reduction": True, "delete": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r1": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True, "delete": True},
+ {"id": "0.0.0.1", "flood-reduction": True, "delete": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r2": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True, "delete": True},
+ {"id": "0.0.0.1", "flood-reduction": True, "delete": True},
+ {"id": "0.0.0.2", "flood-reduction": True, "delete": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_flood = {
+ "r3": {
+ "ospf": {
+ "area": [
+ {"id": "0.0.0.0", "flood-reduction": True, "delete": True},
+ {"id": "0.0.0.2", "flood-reduction": True, "delete": True},
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_flood)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ clear_ospf(tgen, "r0")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that ospf lea's are not set with dc bit 1.")
+ dut = "r0"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsaId": "100.1.1.0",
+ "options": "*|-|DC|-|-|-|E|-",
+ },
+ ]
+ }
+ },
+ }
+ result = verify_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False
+ )
+
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: OSPF LSA should not be set with DC bit in {} \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+
+ step("Wait for 120 secs and verify that LSA's are not refreshed. ")
+ # get LSA age
+ dut = "r1"
+ input_dict_db = {
+ "routerId": "100.1.1.0",
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {"lsaId": "100.1.1.0", "lsaAge": "get"},
+ ]
+ }
+ },
+ }
+ sleep(10)
+
+ result1 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+ sleep(5)
+ result2 = get_ospf_database(
+ tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0"
+ )
+
+ if result2 is not result1:
+ result = True
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospfapi/r1/ospfd.conf b/tests/topotests/ospfapi/r1/ospfd.conf
index 8d13556847..338691bbf3 100644
--- a/tests/topotests/ospfapi/r1/ospfd.conf
+++ b/tests/topotests/ospfapi/r1/ospfd.conf
@@ -4,7 +4,12 @@ interface r1-eth0
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
+interface r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf area 1.2.3.4
+!
router ospf
- ospf router-id 192.168.0.1
+ ospf router-id 1.0.0.0
capability opaque
!
diff --git a/tests/topotests/ospfapi/r1/zebra.conf b/tests/topotests/ospfapi/r1/zebra.conf
index aae87408c3..745159141d 100644
--- a/tests/topotests/ospfapi/r1/zebra.conf
+++ b/tests/topotests/ospfapi/r1/zebra.conf
@@ -2,3 +2,5 @@
interface r1-eth0
ip address 10.0.1.1/24
!
+interface r1-eth1
+ ip address 10.0.4.1/24
diff --git a/tests/topotests/ospfapi/r2/ospfd.conf b/tests/topotests/ospfapi/r2/ospfd.conf
index be0712742b..1bf2a0c7f2 100644
--- a/tests/topotests/ospfapi/r2/ospfd.conf
+++ b/tests/topotests/ospfapi/r2/ospfd.conf
@@ -10,6 +10,6 @@ interface r2-eth1
ip ospf area 1.2.3.4
!
router ospf
- ospf router-id 192.168.0.2
+ ospf router-id 2.0.0.0
capability opaque
!
diff --git a/tests/topotests/ospfapi/r3/ospfd.conf b/tests/topotests/ospfapi/r3/ospfd.conf
index 77cd86a975..ecf2042b42 100644
--- a/tests/topotests/ospfapi/r3/ospfd.conf
+++ b/tests/topotests/ospfapi/r3/ospfd.conf
@@ -10,6 +10,6 @@ interface r3-eth1
ip ospf area 1.2.3.4
!
router ospf
- ospf router-id 192.168.0.3
+ ospf router-id 3.0.0.0
capability opaque
!
diff --git a/tests/topotests/ospfapi/r4/ospfd.conf b/tests/topotests/ospfapi/r4/ospfd.conf
index 32e55d546b..4de8caeb17 100644
--- a/tests/topotests/ospfapi/r4/ospfd.conf
+++ b/tests/topotests/ospfapi/r4/ospfd.conf
@@ -4,7 +4,12 @@ interface r4-eth0
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
+interface r4-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+ ip ospf area 1.2.3.4
+!
router ospf
- ospf router-id 192.168.0.4
+ ospf router-id 4.0.0.0
capability opaque
!
diff --git a/tests/topotests/ospfapi/r4/zebra.conf b/tests/topotests/ospfapi/r4/zebra.conf
index 702219720d..233ffa5c7b 100644
--- a/tests/topotests/ospfapi/r4/zebra.conf
+++ b/tests/topotests/ospfapi/r4/zebra.conf
@@ -2,3 +2,5 @@
interface r4-eth0
ip address 10.0.3.4/24
!
+interface r4-eth1
+ ip address 10.0.4.4/24 \ No newline at end of file
diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py
index 7622a4ca54..b01c96226e 100644
--- a/tests/topotests/ospfapi/test_ospf_clientapi.py
+++ b/tests/topotests/ospfapi/test_ospf_clientapi.py
@@ -21,7 +21,7 @@ from datetime import datetime, timedelta
import pytest
from lib.common_config import retry, run_frr_cmd, step
-from lib.micronet import comm_error
+from lib.micronet import Timeout, comm_error
from lib.topogen import Topogen, TopoRouter
from lib.topotest import interface_set_status, json_cmp
@@ -43,15 +43,20 @@ assert os.path.exists(
# Test Setup
# ----------
+#
+# r1 - r2
+# | |
+# r4 - r3
+#
+
@pytest.fixture(scope="function", name="tgen")
def _tgen(request):
"Setup/Teardown the environment and provide tgen argument to tests"
nrouters = request.param
- if nrouters == 1:
- topodef = {"sw1:": ("r1",)}
- else:
- topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)}
+ topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)}
+ if nrouters == 4:
+ topodef["sw4"] = ("r4", "r1")
tgen = Topogen(topodef, request.module.__name__)
tgen.start_topology()
@@ -94,23 +99,23 @@ def verify_ospf_database(tgen, dut, input_dict, cmd="show ip ospf database json"
def myreadline(f):
buf = b""
while True:
- # logging.info("READING 1 CHAR")
+ # logging.debug("READING 1 CHAR")
c = f.read(1)
if not c:
return buf if buf else None
buf += c
- # logging.info("READ CHAR: '%s'", c)
+ # logging.debug("READ CHAR: '%s'", c)
if c == b"\n":
return buf
-def _wait_output(p, regex, timeout=120):
- retry_until = datetime.now() + timedelta(seconds=timeout)
- while datetime.now() < retry_until:
+def _wait_output(p, regex, maxwait=120):
+ timeout = Timeout(maxwait)
+ while not timeout.is_expired():
# line = p.stdout.readline()
line = myreadline(p.stdout)
if not line:
- assert None, "Timeout waiting for '{}'".format(regex)
+ assert None, "EOF waiting for '{}'".format(regex)
line = line.decode("utf-8")
line = line.rstrip()
if line:
@@ -118,7 +123,9 @@ def _wait_output(p, regex, timeout=120):
m = re.search(regex, line)
if m:
return m
- assert None, "Failed to get output withint {}s".format(timeout)
+ assert None, "Failed to get output matching '{}' withint {} actual {}s".format(
+ regex, maxwait, timeout.elapsed()
+ )
# -----
@@ -128,12 +135,13 @@ def _wait_output(p, regex, timeout=120):
def _test_reachability(tgen, testbin):
waitlist = [
- "192.168.0.1,192.168.0.2,192.168.0.4",
- "192.168.0.2,192.168.0.4",
- "192.168.0.1,192.168.0.2,192.168.0.4",
+ "1.0.0.0,2.0.0.0,4.0.0.0",
+ "2.0.0.0,4.0.0.0",
+ "1.0.0.0,2.0.0.0,4.0.0.0",
]
r2 = tgen.gears["r2"]
r3 = tgen.gears["r3"]
+ r4 = tgen.gears["r4"]
wait_args = [f"--wait={x}" for x in waitlist]
@@ -151,10 +159,12 @@ def _test_reachability(tgen, testbin):
step("reachable: check for modified reachability")
interface_set_status(r2, "r2-eth0", False)
+ interface_set_status(r4, "r4-eth1", False)
_wait_output(p, "SUCCESS: {}".format(waitlist[1]))
step("reachable: check for restored reachability")
interface_set_status(r2, "r2-eth0", True)
+ interface_set_status(r4, "r4-eth1", True)
_wait_output(p, "SUCCESS: {}".format(waitlist[2]))
except Exception as error:
logging.error("ERROR: %s", error)
@@ -169,16 +179,16 @@ def _test_reachability(tgen, testbin):
def test_ospf_reachability(tgen):
testbin = os.path.join(TESTDIR, "ctester.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([testbin, "--help"])
- logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
+ logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
_test_reachability(tgen, testbin)
def _test_router_id(tgen, testbin):
r1 = tgen.gears["r1"]
waitlist = [
- "192.168.0.1",
+ "1.0.0.0",
"1.1.1.1",
- "192.168.0.1",
+ "1.0.0.0",
]
mon_args = [f"--monitor={x}" for x in waitlist]
@@ -200,7 +210,7 @@ def _test_router_id(tgen, testbin):
_wait_output(p, "SUCCESS: {}".format(waitlist[1]))
step("router id: check for restored router id")
- r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 192.168.0.1")
+ r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.0.0.0")
_wait_output(p, "SUCCESS: {}".format(waitlist[2]))
except Exception as error:
logging.error("ERROR: %s", error)
@@ -215,7 +225,7 @@ def _test_router_id(tgen, testbin):
def test_ospf_router_id(tgen):
testbin = os.path.join(TESTDIR, "ctester.py")
rc, o, e = tgen.gears["r1"].net.cmd_status([testbin, "--help"])
- logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
+ logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
_test_router_id(tgen, testbin)
@@ -230,13 +240,13 @@ def _test_add_data(tgen, apibin):
try:
p = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,2,00000202"])
input_dict = {
- "routerId": "192.168.0.1",
+ "routerId": "1.0.0.0",
"areas": {
"1.2.3.4": {
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
}
],
@@ -252,7 +262,7 @@ def _test_add_data(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "230.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
"opaqueData": "00000202",
},
@@ -272,13 +282,13 @@ def _test_add_data(tgen, apibin):
p = None
p = r1.popen([apibin, "-v", "add,10,1.2.3.4,231,1,00010101"])
input_dict = {
- "routerId": "192.168.0.1",
+ "routerId": "1.0.0.0",
"areas": {
"1.2.3.4": {
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
"lsaAge": 3600,
}
@@ -286,7 +296,7 @@ def _test_add_data(tgen, apibin):
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
},
],
@@ -302,7 +312,7 @@ def _test_add_data(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "231.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
"opaqueData": "00010101",
},
@@ -323,13 +333,13 @@ def _test_add_data(tgen, apibin):
p = r1.popen([apibin, "-v", "add,11,232,3,deadbeaf01234567"])
input_dict = {
- "routerId": "192.168.0.1",
+ "routerId": "1.0.0.0",
"areas": {
"1.2.3.4": {
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
"lsaAge": 3600,
},
@@ -339,7 +349,7 @@ def _test_add_data(tgen, apibin):
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
},
],
@@ -351,7 +361,7 @@ def _test_add_data(tgen, apibin):
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.3",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
"opaqueData": "deadbeaf01234567",
},
@@ -369,11 +379,11 @@ def _test_add_data(tgen, apibin):
p = None
input_dict = {
- "routerId": "192.168.0.1",
+ "routerId": "1.0.0.0",
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
"lsaAge": 3600,
},
@@ -387,11 +397,11 @@ def _test_add_data(tgen, apibin):
# Originate it again
p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
input_dict = {
- "routerId": "192.168.0.1",
+ "routerId": "1.0.0.0",
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000002",
},
],
@@ -402,7 +412,7 @@ def _test_add_data(tgen, apibin):
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.3",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000002",
"opaqueData": "ebadf00d",
},
@@ -412,6 +422,7 @@ def _test_add_data(tgen, apibin):
json_cmd = "show ip ospf da opaque-as json"
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
+ logging.debug("sending interrupt to writer api client")
p.send_signal(signal.SIGINT)
time.sleep(2)
p.wait()
@@ -426,6 +437,7 @@ def _test_add_data(tgen, apibin):
raise
finally:
if p:
+ logging.debug("cleanup: sending interrupt to writer api client")
p.terminate()
p.wait()
@@ -434,7 +446,7 @@ def _test_add_data(tgen, apibin):
def test_ospf_opaque_add_data3(tgen):
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
- logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
+ logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
_test_add_data(tgen, apibin)
@@ -446,10 +458,12 @@ def _test_opaque_add_del(tgen, apibin):
p = None
pread = None
+ # Log to our stdin, stderr
+ pout = open(os.path.join(r1.net.logdir, "r1/add-del.log"), "a+")
try:
step("reachable: check for add notification")
pread = r2.popen(
- ["/usr/bin/timeout", "120", apibin, "-v"],
+ ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"],
encoding=None, # don't buffer
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
@@ -479,30 +493,30 @@ def _test_opaque_add_del(tgen, apibin):
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "6d5f",
+ "checksum": "76bf",
},
{
"lsId": "230.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "8142",
+ "checksum": "8aa2",
},
],
"linkLocalOpaqueLsaCount": 2,
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "5278",
+ "checksum": "5bd8",
},
{
"lsId": "231.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "6d30",
+ "checksum": "7690",
},
],
"areaLocalOpaqueLsaCount": 2,
@@ -511,15 +525,15 @@ def _test_opaque_add_del(tgen, apibin):
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "5575",
+ "checksum": "5ed5",
},
{
"lsId": "232.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "d05d",
+ "checksum": "d9bd",
},
],
"asExternalOpaqueLsaCount": 2,
@@ -543,17 +557,17 @@ def _test_opaque_add_del(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "230.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "6d5f",
+ "checksum": "76bf",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "230.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "8142",
+ "checksum": "8aa2",
"length": 24,
"opaqueId": 2,
"opaqueDataLength": 4,
@@ -568,17 +582,17 @@ def _test_opaque_add_del(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "231.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "5278",
+ "checksum": "5bd8",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "231.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "6d30",
+ "checksum": "7690",
"length": 28,
"opaqueDataLength": 8,
},
@@ -590,17 +604,17 @@ def _test_opaque_add_del(tgen, apibin):
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "5575",
+ "checksum": "5ed5",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "232.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "d05d",
+ "checksum": "d9bd",
"length": 24,
"opaqueDataLength": 4,
},
@@ -642,32 +656,32 @@ def _test_opaque_add_del(tgen, apibin):
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "6d5f",
+ "checksum": "76bf",
},
{
"lsId": "230.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"lsaAge": 3600,
"sequenceNumber": "80000001",
- "checksum": "8142",
+ "checksum": "8aa2",
},
],
"linkLocalOpaqueLsaCount": 2,
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "5278",
+ "checksum": "5bd8",
},
{
"lsId": "231.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"lsaAge": 3600,
"sequenceNumber": "80000002",
- "checksum": "4682",
+ "checksum": "4fe2",
},
],
"areaLocalOpaqueLsaCount": 2,
@@ -676,16 +690,16 @@ def _test_opaque_add_del(tgen, apibin):
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.1",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"lsaAge": 3600,
"sequenceNumber": "80000001",
- "checksum": "5575",
+ "checksum": "5ed5",
},
{
"lsId": "232.0.0.2",
- "advertisedRouter": "192.168.0.1",
+ "advertisedRouter": "1.0.0.0",
"sequenceNumber": "80000001",
- "checksum": "d05d",
+ "checksum": "d9bd",
},
],
"asExternalOpaqueLsaCount": 2,
@@ -703,18 +717,18 @@ def _test_opaque_add_del(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "230.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "6d5f",
+ "checksum": "76bf",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "230.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "8142",
+ "checksum": "8aa2",
"length": 24,
"opaqueId": 2,
"opaqueDataLength": 4,
@@ -729,18 +743,18 @@ def _test_opaque_add_del(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "231.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "5278",
+ "checksum": "5bd8",
"length": 20,
"opaqueDataLength": 0,
},
{
"lsaAge": 3600,
"linkStateId": "231.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000002",
- "checksum": "4682",
+ "checksum": "4fe2",
# data removed
"length": 20,
"opaqueDataLength": 0,
@@ -753,18 +767,18 @@ def _test_opaque_add_del(tgen, apibin):
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "5575",
+ "checksum": "5ed5",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "232.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "d05d",
+ "checksum": "d9bd",
"length": 24,
"opaqueDataLength": 4,
},
@@ -795,19 +809,19 @@ def _test_opaque_add_del(tgen, apibin):
"1.2.3.4": [
{
"linkStateId": "230.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "6d5f",
+ "checksum": "76bf",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "230.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "8142",
+ "checksum": "8aa2",
"length": 24,
"opaqueId": 2,
"opaqueDataLength": 4,
@@ -823,18 +837,18 @@ def _test_opaque_add_del(tgen, apibin):
{
"lsaAge": 3600,
"linkStateId": "231.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "checksum": "5278",
+ "checksum": "5bd8",
"length": 20,
"opaqueDataLength": 0,
},
{
"lsaAge": 3600,
"linkStateId": "231.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000002",
- "checksum": "4682",
+ "checksum": "4fe2",
# data removed
"length": 20,
"opaqueDataLength": 0,
@@ -847,19 +861,19 @@ def _test_opaque_add_del(tgen, apibin):
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.1",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "5575",
+ "checksum": "5ed5",
"length": 20,
"opaqueDataLength": 0,
},
{
"linkStateId": "232.0.0.2",
- "advertisingRouter": "192.168.0.1",
+ "advertisingRouter": "1.0.0.0",
"lsaAge": 3600,
"lsaSeqNumber": "80000001",
- "checksum": "d05d",
+ "checksum": "d9bd",
"length": 24,
"opaqueDataLength": 4,
},
@@ -918,7 +932,7 @@ def _test_opaque_add_del(tgen, apibin):
def test_ospf_opaque_delete_data3(tgen):
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
- logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
+ logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
_test_opaque_add_del(tgen, apibin)
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index a17ee812e4..200427fb6e 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1673,10 +1673,14 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd,
#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
- "router bgp [(1-4294967295) [<view|vrf> VIEWVRFNAME]]",
+ "router bgp [ASNUM [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
ROUTER_STR BGP_STR AS_STR
"BGP view\nBGP VRF\n"
- "View/VRF name\n")
+ "View/VRF name\n"
+ "Force the AS notation output\n"
+ "use 'AA.BB' format for AS 4 byte values\n"
+ "use 'AA.BB' format for all AS values\n"
+ "use plain format for all AS values\n")
{
vty->node = BGP_NODE;
return CMD_SUCCESS;
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index ad2a142fef..8e288194ec 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -356,6 +356,102 @@ module frr-bgp-route-map {
}
}
+ typedef route-distinguisher {
+ type string {
+ pattern
+ '(0:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ + '42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ + '42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ + '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))|'
+ + '(1:((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ + '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ + '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ + '655[0-2][0-9]|'
+ + '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(2:(429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '(6(:[a-fA-F0-9]{2}){6})|'
+ + '(([3-57-9a-fA-F]|[1-9a-fA-F][0-9a-fA-F]{1,3}):'
+ + '[0-9a-fA-F]{1,12})|'
+ + '((6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(429496729[0-5]|'
+ + '42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|429496[0-6][0-9]{3}|'
+ + '42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|429[0-3][0-9]{6}|'
+ + '42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0)|'
+ + '((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|'
+ + '25[0-5])\.){3}([0-9]|[1-9][0-9]|'
+ + '1[0-9]{2}|2[0-4][0-9]|25[0-5])):(6553[0-5]|'
+ + '655[0-2][0-9]|'
+ + '65[0-4][0-9]{2}|6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '((429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|'
+ + '((6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0).'
+ + '(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|'
+ + '6[0-4][0-9]{3}|'
+ + '[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):'
+ + '(429496729[0-5]|42949672[0-8][0-9]|'
+ + '4294967[01][0-9]{2}|'
+ + '429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|'
+ + '4294[0-8][0-9]{5}|'
+ + '429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|'
+ + '[1-3][0-9]{9}|[1-9][0-9]{0,8}|0))';
+ }
+
+ description
+ "A Route Distinguisher is an 8-octet value used to
+ distinguish routes from different BGP VPNs (RFC 4364).
+ A Route Distinguisher will have the same format as a
+ Route Target as per RFC 4360 and will consist of
+ two or three fields: a 2-octet Type field, an administrator
+ field, and, optionally, an assigned number field.
+ According to the data formats for types 0, 1, 2, and 6 as
+ defined in RFC 4360, RFC 5668, and RFC 7432, the encoding
+ pattern is defined as:
+ 0:2-octet-asn:4-octet-number
+ 1:4-octet-ipv4addr:2-octet-number
+ 2:4-octet-asn:2-octet-number
+ 6:6-octet-mac-address
+ Additionally, a generic pattern is defined for future
+ route discriminator types:
+ 2-octet-other-hex-number:6-octet-hex-number
+ Some valid examples are 0:100:100, 1:1.1.1.1:100,
+ 2:1234567890:203, and 6:26:00:08:92:78:00.
+ The following route distinguisher with two fields are also
+ accepted : 10000:44 1.2.3.4:44.";
+ reference
+ "RFC 4360: BGP Extended Communities Attribute.
+ RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs).
+ RFC 5668: 4-Octet AS Specific BGP Extended Community.
+ RFC 7432: BGP MPLS-Based Ethernet VPN.";
+ }
+
typedef extcommunity-lb-type {
type enumeration {
enum "explicit-bandwidth" {
@@ -598,7 +694,7 @@ module frr-bgp-route-map {
description
"Match eVPN route-distinguisher";
leaf route-distinguisher {
- type rt-types:route-distinguisher;
+ type route-distinguisher;
}
}
diff --git a/zebra/rib.h b/zebra/rib.h
index 53ae63354e..70968d3900 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -392,12 +392,9 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
const union g_addr *addr,
struct route_node **rn_out);
-extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
- struct in_addr addr,
- struct route_node **rn_out);
-extern struct route_entry *rib_match_ipv6_multicast(vrf_id_t vrf_id,
- struct in6_addr addr,
- struct route_node **rn_out);
+extern struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id,
+ union g_addr *gaddr,
+ struct route_node **rn_out);
extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
vrf_id_t vrf_id);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index b7344d7cc1..59152df2f1 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2236,17 +2236,18 @@ static void zread_nexthop_lookup_mrib(ZAPI_HANDLER_ARGS)
{
struct ipaddr addr;
struct route_entry *re = NULL;
+ union g_addr gaddr;
STREAM_GET_IPADDR(msg, &addr);
switch (addr.ipa_type) {
case IPADDR_V4:
- re = rib_match_ipv4_multicast(zvrf_id(zvrf), addr.ipaddr_v4,
- NULL);
+ gaddr.ipv4 = addr.ipaddr_v4;
+ re = rib_match_multicast(AFI_IP, zvrf_id(zvrf), &gaddr, NULL);
break;
case IPADDR_V6:
- re = rib_match_ipv6_multicast(zvrf_id(zvrf), addr.ipaddr_v6,
- NULL);
+ gaddr.ipv6 = addr.ipaddr_v6;
+ re = rib_match_multicast(AFI_IP6, zvrf_id(zvrf), &gaddr, NULL);
break;
case IPADDR_NONE:
/* ??? */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index fc3f57eeb8..6c499b77d7 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -509,31 +509,28 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
return NULL;
}
-struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
- struct in_addr addr,
- struct route_node **rn_out)
+struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id,
+ union g_addr *gaddr,
+ struct route_node **rn_out)
{
struct route_entry *re = NULL, *mre = NULL, *ure = NULL;
struct route_node *m_rn = NULL, *u_rn = NULL;
- union g_addr gaddr = {.ipv4 = addr};
switch (zrouter.ipv4_multicast_mode) {
case MCAST_MRIB_ONLY:
- return rib_match(AFI_IP, SAFI_MULTICAST, vrf_id, &gaddr,
- rn_out);
+ return rib_match(afi, SAFI_MULTICAST, vrf_id, gaddr, rn_out);
case MCAST_URIB_ONLY:
- return rib_match(AFI_IP, SAFI_UNICAST, vrf_id, &gaddr, rn_out);
+ return rib_match(afi, SAFI_UNICAST, vrf_id, gaddr, rn_out);
case MCAST_NO_CONFIG:
case MCAST_MIX_MRIB_FIRST:
- re = mre = rib_match(AFI_IP, SAFI_MULTICAST, vrf_id, &gaddr,
- &m_rn);
+ re = mre = rib_match(afi, SAFI_MULTICAST, vrf_id, gaddr, &m_rn);
if (!mre)
- re = ure = rib_match(AFI_IP, SAFI_UNICAST, vrf_id,
- &gaddr, &u_rn);
+ re = ure = rib_match(afi, SAFI_UNICAST, vrf_id, gaddr,
+ &u_rn);
break;
case MCAST_MIX_DISTANCE:
- mre = rib_match(AFI_IP, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn);
- ure = rib_match(AFI_IP, SAFI_UNICAST, vrf_id, &gaddr, &u_rn);
+ mre = rib_match(afi, SAFI_MULTICAST, vrf_id, gaddr, &m_rn);
+ ure = rib_match(afi, SAFI_UNICAST, vrf_id, gaddr, &u_rn);
if (mre && ure)
re = ure->distance < mre->distance ? ure : mre;
else if (mre)
@@ -542,8 +539,8 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
re = ure;
break;
case MCAST_MIX_PFXLEN:
- mre = rib_match(AFI_IP, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn);
- ure = rib_match(AFI_IP, SAFI_UNICAST, vrf_id, &gaddr, &u_rn);
+ mre = rib_match(afi, SAFI_MULTICAST, vrf_id, gaddr, &m_rn);
+ ure = rib_match(afi, SAFI_UNICAST, vrf_id, gaddr, &u_rn);
if (mre && ure)
re = u_rn->p.prefixlen > m_rn->p.prefixlen ? ure : mre;
else if (mre)
@@ -558,10 +555,12 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[BUFSIZ];
- inet_ntop(AF_INET, &addr, buf, BUFSIZ);
+ inet_ntop(afi == AFI_IP ? AF_INET : AF_INET6, gaddr, buf,
+ BUFSIZ);
- zlog_debug("%s: %s: vrf: %s(%u) found %s, using %s", __func__,
- buf, vrf_id_to_name(vrf_id), vrf_id,
+ zlog_debug("%s: %s: %pRN vrf: %s(%u) found %s, using %s",
+ __func__, buf, (re == mre) ? m_rn : u_rn,
+ vrf_id_to_name(vrf_id), vrf_id,
mre ? (ure ? "MRIB+URIB" : "MRIB")
: ure ? "URIB" : "nothing",
re == ure ? "URIB" : re == mre ? "MRIB" : "none");
@@ -569,62 +568,6 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
return re;
}
-struct route_entry *rib_match_ipv6_multicast(vrf_id_t vrf_id,
- struct in6_addr addr,
- struct route_node **rn_out)
-{
- struct route_entry *re = NULL, *mre = NULL, *ure = NULL;
- struct route_node *m_rn = NULL, *u_rn = NULL;
- union g_addr gaddr = {.ipv6 = addr};
-
- switch (zrouter.ipv4_multicast_mode) {
- case MCAST_MRIB_ONLY:
- return rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr,
- rn_out);
- case MCAST_URIB_ONLY:
- return rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, rn_out);
- case MCAST_NO_CONFIG:
- case MCAST_MIX_MRIB_FIRST:
- re = mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr,
- &m_rn);
- if (!mre)
- re = ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id,
- &gaddr, &u_rn);
- break;
- case MCAST_MIX_DISTANCE:
- mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn);
- ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, &u_rn);
- if (mre && ure)
- re = ure->distance < mre->distance ? ure : mre;
- else if (mre)
- re = mre;
- else if (ure)
- re = ure;
- break;
- case MCAST_MIX_PFXLEN:
- mre = rib_match(AFI_IP6, SAFI_MULTICAST, vrf_id, &gaddr, &m_rn);
- ure = rib_match(AFI_IP6, SAFI_UNICAST, vrf_id, &gaddr, &u_rn);
- if (mre && ure)
- re = u_rn->p.prefixlen > m_rn->p.prefixlen ? ure : mre;
- else if (mre)
- re = mre;
- else if (ure)
- re = ure;
- break;
- }
-
- if (rn_out)
- *rn_out = (re == mre) ? m_rn : u_rn;
-
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%s: %pI6: vrf: %s(%u) found %s, using %s", __func__,
- &addr, vrf_id_to_name(vrf_id), vrf_id,
- mre ? (ure ? "MRIB+URIB" : "MRIB")
- : ure ? "URIB" : "nothing",
- re == ure ? "URIB" : re == mre ? "MRIB" : "none");
- return re;
-}
-
struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
{
struct route_table *table;
@@ -3924,7 +3867,9 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
rmap_name = zebra_get_import_table_route_map(afi, re->table);
zebra_add_import_table_entry(zvrf, rn, re, rmap_name);
- } else if (process)
+ }
+
+ if (process)
rib_queue_add(rn);
}
@@ -3999,11 +3944,9 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
zlog_debug("%s(%u):%pRN: Freeing route rn %p, re %p (%s)",
vrf_id_to_name(re->vrf_id), re->vrf_id, rn,
rn, re, zebra_route_string(re->type));
-
- rib_unlink(rn, re);
- } else {
- rib_queue_add(rn);
}
+
+ rib_queue_add(rn);
}
/*
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index a4aef36dbd..6d61430029 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -131,11 +131,12 @@ DEFUN (no_ip_multicast_mode,
}
-DEFUN (show_ip_rpf,
+DEFPY (show_ip_rpf,
show_ip_rpf_cmd,
- "show ip rpf [json]",
+ "show [ip$ip|ipv6$ipv6] rpf [json]",
SHOW_STR
IP_STR
+ IPV6_STR
"Display RPF information for multicast source\n"
JSON_STR)
{
@@ -144,32 +145,46 @@ DEFUN (show_ip_rpf,
.multi = false,
};
- return do_show_ip_route(vty, VRF_DEFAULT_NAME, AFI_IP, SAFI_MULTICAST,
- false, uj, 0, NULL, false, 0, 0, 0, false,
- &ctx);
+ return do_show_ip_route(vty, VRF_DEFAULT_NAME, ip ? AFI_IP : AFI_IP6,
+ SAFI_MULTICAST, false, uj, 0, NULL, false, 0, 0,
+ 0, false, &ctx);
}
-DEFUN (show_ip_rpf_addr,
+DEFPY (show_ip_rpf_addr,
show_ip_rpf_addr_cmd,
- "show ip rpf A.B.C.D",
+ "show ip rpf A.B.C.D$address",
SHOW_STR
IP_STR
"Display RPF information for multicast source\n"
"IP multicast source address (e.g. 10.0.0.0)\n")
{
- int idx_ipv4 = 3;
- struct in_addr addr;
struct route_node *rn;
struct route_entry *re;
- int ret;
- ret = inet_aton(argv[idx_ipv4]->arg, &addr);
- if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING;
- }
+ re = rib_match_multicast(AFI_IP, VRF_DEFAULT, (union g_addr *)&address,
+ &rn);
+
+ if (re)
+ vty_show_ip_route_detail(vty, rn, 1, false, false);
+ else
+ vty_out(vty, "%% No match for RPF lookup\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ipv6_rpf_addr,
+ show_ipv6_rpf_addr_cmd,
+ "show ipv6 rpf X:X::X:X$address",
+ SHOW_STR
+ IPV6_STR
+ "Display RPF information for multicast source\n"
+ "IPv6 multicast source address\n")
+{
+ struct route_node *rn;
+ struct route_entry *re;
- re = rib_match_ipv4_multicast(VRF_DEFAULT, addr, &rn);
+ re = rib_match_multicast(AFI_IP6, VRF_DEFAULT, (union g_addr *)&address,
+ &rn);
if (re)
vty_show_ip_route_detail(vty, rn, 1, false, false);
@@ -4576,6 +4591,7 @@ void zebra_vty_init(void)
install_element(VIEW_NODE, &show_ip_rpf_cmd);
install_element(VIEW_NODE, &show_ip_rpf_addr_cmd);
+ install_element(VIEW_NODE, &show_ipv6_rpf_addr_cmd);
install_element(CONFIG_NODE, &ip_nht_default_route_cmd);
install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd);