summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/babeld.c2
-rw-r--r--bgpd/bgp_advertise.c5
-rw-r--r--bgpd/bgp_aspath.c125
-rw-r--r--bgpd/bgp_damp.c5
-rw-r--r--bgpd/bgp_damp.h2
-rw-r--r--bgpd/bgp_evpn_mh.c8
-rw-r--r--bgpd/bgp_evpn_vty.c12
-rw-r--r--bgpd/bgp_flowspec_util.c13
-rw-r--r--bgpd/bgp_route.c338
-rw-r--r--bgpd/bgp_route.h4
-rw-r--r--bgpd/bgp_routemap.c9
-rw-r--r--bgpd/bgp_table.h13
-rw-r--r--bgpd/bgp_vty.c194
-rw-r--r--bgpd/bgp_vty.h2
-rw-r--r--bgpd/bgpd.c9
-rw-r--r--bgpd/rfapi/rfapi.c2
-rw-r--r--bgpd/rfapi/rfapi_import.c6
-rw-r--r--doc/developer/topotests.rst14
-rw-r--r--doc/user/basic.rst4
-rw-r--r--doc/user/bgp.rst11
-rw-r--r--doc/user/ospf6d.rst15
-rw-r--r--docker/alpine/Dockerfile11
-rwxr-xr-xdocker/alpine/docker-start14
-rw-r--r--docker/centos-7/Dockerfile16
-rwxr-xr-xdocker/centos-7/docker-start14
-rw-r--r--docker/centos-8/Dockerfile16
-rwxr-xr-xdocker/centos-8/docker-start11
-rw-r--r--docker/debian/Dockerfile16
-rwxr-xr-xdocker/debian/docker-start14
-rw-r--r--eigrpd/eigrp_cli.c2
-rw-r--r--isisd/isis_adjacency.c6
-rw-r--r--isisd/isis_circuit.c14
-rw-r--r--isisd/isis_dynhn.c49
-rw-r--r--isisd/isis_dynhn.h14
-rw-r--r--isisd/isis_lsp.c12
-rw-r--r--isisd/isis_misc.c9
-rw-r--r--isisd/isis_nb_notifications.c2
-rw-r--r--isisd/isis_snmp.c8
-rw-r--r--isisd/isisd.c76
-rw-r--r--isisd/isisd.h1
-rw-r--r--lib/bitfield.h6
-rw-r--r--lib/compiler.h9
-rw-r--r--lib/if.c19
-rw-r--r--lib/link_state.c4
-rw-r--r--lib/memory.c1
-rw-r--r--lib/northbound.c4
-rw-r--r--lib/northbound_grpc.cpp42
-rw-r--r--lib/srv6.c9
-rw-r--r--lib/table.h44
-rw-r--r--lib/vrf.c47
-rw-r--r--lib/vty.c52
-rw-r--r--lib/vty.h1
-rw-r--r--nhrpd/nhrp_main.c1
-rw-r--r--nhrpd/nhrp_vty.c2
-rw-r--r--ospf6d/ospf6_abr.c8
-rw-r--r--ospf6d/ospf6_abr.h2
-rw-r--r--ospf6d/ospf6_area.c22
-rw-r--r--ospf6d/ospf6_area.h16
-rw-r--r--ospf6d/ospf6_asbr.c13
-rw-r--r--ospf6d/ospf6_flood.c23
-rw-r--r--ospf6d/ospf6_interface.c192
-rw-r--r--ospf6d/ospf6_interface.h7
-rw-r--r--ospf6d/ospf6_intra.c7
-rw-r--r--ospf6d/ospf6_lsa.c1
-rw-r--r--ospf6d/ospf6_message.c246
-rw-r--r--ospf6d/ospf6_neighbor.c23
-rw-r--r--ospf6d/ospf6_neighbor.h3
-rw-r--r--ospf6d/ospf6_nssa.c12
-rw-r--r--ospf6d/ospf6_snmp.c7
-rw-r--r--ospf6d/ospf6_spf.c12
-rw-r--r--ospf6d/ospf6_top.c67
-rw-r--r--ospfd/ospf_asbr.c3
-rw-r--r--ospfd/ospf_lsa.c40
-rw-r--r--ospfd/ospf_neighbor.c3
-rw-r--r--ospfd/ospf_routemap.c21
-rw-r--r--ospfd/ospf_vty.c2
-rw-r--r--pbrd/pbr_main.c1
-rw-r--r--pbrd/pbr_vty.c4
-rw-r--r--pimd/pim_cmd.c449
-rw-r--r--pimd/pim_msdp.c314
-rw-r--r--pimd/pim_msdp.h55
-rw-r--r--pimd/pim_nb.c25
-rw-r--r--pimd/pim_nb.h22
-rw-r--r--pimd/pim_nb_config.c341
-rw-r--r--ripd/ripd.c2
-rw-r--r--ripngd/ripngd.c2
-rw-r--r--tests/isisd/test_common.c3
-rw-r--r--tests/isisd/test_isis_spf.c5
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py84
-rw-r--r--tests/topotests/bfd_topo2/r4/ipv6_routes.json2
-rwxr-xr-xtests/topotests/conftest.py60
-rw-r--r--tests/topotests/lib/bgp.py54
-rw-r--r--tests/topotests/lib/common_config.py20
-rwxr-xr-xtests/topotests/lib/mcast-tester.py129
-rw-r--r--tests/topotests/lib/ospf.py983
-rw-r--r--tests/topotests/lib/pim.py57
-rw-r--r--tests/topotests/lib/topogen.py18
-rw-r--r--tests/topotests/lib/topotest.py9
-rw-r--r--tests/topotests/msdp_mesh_topo1/__init__.py0
-rw-r--r--tests/topotests/msdp_mesh_topo1/r1/bgpd.conf7
-rw-r--r--tests/topotests/msdp_mesh_topo1/r1/ospfd.conf8
-rw-r--r--tests/topotests/msdp_mesh_topo1/r1/pimd.conf15
-rw-r--r--tests/topotests/msdp_mesh_topo1/r1/zebra.conf11
-rw-r--r--tests/topotests/msdp_mesh_topo1/r2/bgpd.conf10
-rw-r--r--tests/topotests/msdp_mesh_topo1/r2/ospfd.conf13
-rw-r--r--tests/topotests/msdp_mesh_topo1/r2/pimd.conf14
-rw-r--r--tests/topotests/msdp_mesh_topo1/r2/zebra.conf11
-rw-r--r--tests/topotests/msdp_mesh_topo1/r3/bgpd.conf7
-rw-r--r--tests/topotests/msdp_mesh_topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/msdp_mesh_topo1/r3/pimd.conf15
-rw-r--r--tests/topotests/msdp_mesh_topo1/r3/zebra.conf11
-rw-r--r--tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot88
-rw-r--r--tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.pngbin0 -> 35201 bytes
-rw-r--r--tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py296
-rw-r--r--tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref4
-rw-r--r--tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref4
-rw-r--r--tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref6
-rw-r--r--tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref2
-rw-r--r--tests/topotests/ospf6_topo1_vrf/README.md10
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf8
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref4
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf8
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref4
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf12
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref6
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf8
-rw-r--r--tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref2
-rw-r--r--tests/topotests/ospf_topo1/r1/ospf6route.txt14
-rw-r--r--tests/topotests/ospf_topo1/r1/ospf6route_down.txt4
-rw-r--r--tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt12
-rw-r--r--tests/topotests/ospf_topo1/r2/ospf6route.txt14
-rw-r--r--tests/topotests/ospf_topo1/r2/ospf6route_down.txt4
-rw-r--r--tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt12
-rw-r--r--tests/topotests/ospf_topo1/r3/ospf6route.txt12
-rw-r--r--tests/topotests/ospf_topo1/r3/ospf6route_down.txt4
-rw-r--r--tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt10
-rw-r--r--tests/topotests/ospf_topo1/r4/ospf6route.txt14
-rw-r--r--tests/topotests/ospf_topo1/r4/ospf6route_down.txt4
-rw-r--r--tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt12
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json173
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json190
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py374
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py417
-rwxr-xr-xtools/frr-reload.py2
-rw-r--r--vrrpd/vrrp_vty.c1
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--yang/frr-pim.yang34
-rw-r--r--zebra/zapi_msg.c4
-rw-r--r--zebra/zebra_mlag.c29
-rw-r--r--zebra/zebra_rnh.c1
-rw-r--r--zebra/zebra_srte.c1
-rw-r--r--zebra/zebra_srv6.c6
-rw-r--r--zebra/zserv.c31
153 files changed, 4916 insertions, 1765 deletions
diff --git a/babeld/babeld.c b/babeld/babeld.c
index 4d4dd2e194..b9623b64b5 100644
--- a/babeld/babeld.c
+++ b/babeld/babeld.c
@@ -819,6 +819,8 @@ babeld_quagga_init(void)
install_element(BABEL_NODE, &babel_ipv6_distribute_list_cmd);
install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_cmd);
+ vrf_cmd_init(NULL, &babeld_privs);
+
babel_if_init();
/* Access list install. */
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 1ebe4e5b53..9da97d110f 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -205,6 +205,7 @@ void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai)
{
bgp_attr_unintern(&bai->attr);
BGP_ADJ_IN_DEL(dest, bai);
+ bgp_dest_unlock_node(dest);
peer_unlock(bai->peer); /* adj_in peer reference */
XFREE(MTYPE_BGP_ADJ_IN, bai);
}
@@ -223,10 +224,8 @@ bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
while (adj) {
adj_next = adj->next;
- if (adj->peer == peer && adj->addpath_rx_id == addpath_id) {
+ if (adj->peer == peer && adj->addpath_rx_id == addpath_id)
bgp_adj_in_remove(dest, adj);
- bgp_dest_unlock_node(dest);
- }
adj = adj_next;
}
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 5cf3c60fa2..25109e030b 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -910,77 +910,70 @@ size_t aspath_put(struct stream *s, struct aspath *as, int use32bit)
if (!seg || seg->length == 0)
return 0;
- if (seg) {
- /*
- * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
- * At the moment, we would write out a partial aspath, and our
- * peer
- * will complain and drop the session :-/
- *
- * The general assumption here is that many things tested will
- * never happen. And, in real live, up to now, they have not.
- */
- while (seg && (ASSEGMENT_LEN(seg, use32bit)
- <= STREAM_WRITEABLE(s))) {
- struct assegment *next = seg->next;
- int written = 0;
- int asns_packed = 0;
- size_t lenp;
-
- /* Overlength segments have to be split up */
- while ((seg->length - written) > AS_SEGMENT_MAX) {
- assegment_header_put(s, seg->type,
- AS_SEGMENT_MAX);
- assegment_data_put(s, (seg->as + written), AS_SEGMENT_MAX,
- use32bit);
- written += AS_SEGMENT_MAX;
- bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX,
- use32bit);
- }
-
- /* write the final segment, probably is also the first
- */
- lenp = assegment_header_put(s, seg->type,
- seg->length - written);
+ /*
+ * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
+ * At the moment, we would write out a partial aspath, and our
+ * peer
+ * will complain and drop the session :-/
+ *
+ * The general assumption here is that many things tested will
+ * never happen. And, in real live, up to now, they have not.
+ */
+ while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) {
+ struct assegment *next = seg->next;
+ int written = 0;
+ int asns_packed = 0;
+ size_t lenp;
+
+ /* Overlength segments have to be split up */
+ while ((seg->length - written) > AS_SEGMENT_MAX) {
+ assegment_header_put(s, seg->type, AS_SEGMENT_MAX);
assegment_data_put(s, (seg->as + written),
- seg->length - written, use32bit);
+ AS_SEGMENT_MAX, use32bit);
+ written += AS_SEGMENT_MAX;
+ bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX, use32bit);
+ }
- /* Sequence-type segments can be 'packed' together
- * Case of a segment which was overlength and split up
- * will be missed here, but that doesn't matter.
+ /* write the final segment, probably is also the first
+ */
+ lenp = assegment_header_put(s, seg->type,
+ seg->length - written);
+ assegment_data_put(s, (seg->as + written),
+ seg->length - written, use32bit);
+
+ /* Sequence-type segments can be 'packed' together
+ * Case of a segment which was overlength and split up
+ * will be missed here, but that doesn't matter.
+ */
+ while (next && ASSEGMENTS_PACKABLE(seg, next)) {
+ /* NB: We should never normally get here given
+ * we
+ * normalise aspath data when parse them.
+ * However, better
+ * safe than sorry. We potentially could call
+ * assegment_normalise here instead, but it's
+ * cheaper and
+ * easier to do it on the fly here rather than
+ * go through
+ * the segment list twice every time we write
+ * out
+ * aspath's.
*/
- while (next && ASSEGMENTS_PACKABLE(seg, next)) {
- /* NB: We should never normally get here given
- * we
- * normalise aspath data when parse them.
- * However, better
- * safe than sorry. We potentially could call
- * assegment_normalise here instead, but it's
- * cheaper and
- * easier to do it on the fly here rather than
- * go through
- * the segment list twice every time we write
- * out
- * aspath's.
- */
-
- /* Next segment's data can fit in this one */
- assegment_data_put(s, next->as, next->length,
- use32bit);
-
- /* update the length of the segment header */
- stream_putc_at(s, lenp,
- seg->length - written
- + next->length);
- asns_packed += next->length;
-
- next = next->next;
- }
- bytes += ASSEGMENT_SIZE(
- seg->length - written + asns_packed, use32bit);
- seg = next;
+ /* Next segment's data can fit in this one */
+ assegment_data_put(s, next->as, next->length, use32bit);
+
+ /* update the length of the segment header */
+ stream_putc_at(s, lenp,
+ seg->length - written + next->length);
+ asns_packed += next->length;
+
+ next = next->next;
}
+
+ bytes += ASSEGMENT_SIZE(seg->length - written + asns_packed,
+ use32bit);
+ seg = next;
}
return bytes;
}
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 3db142b8cf..2a372c0ba4 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -245,7 +245,6 @@ static int bgp_reuse_timer(struct thread *t)
* list head entry. */
assert(bdc->reuse_offset < bdc->reuse_list_size);
plist = bdc->reuse_list[bdc->reuse_offset];
- node = SLIST_FIRST(&plist);
SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
@@ -788,7 +787,7 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
/* If dampening is not enabled or there is no dampening information,
return immediately. */
- if (!bdc || !bdi)
+ if (!bdi)
return NULL;
/* Calculate new penalty. */
@@ -822,7 +821,7 @@ static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
}
int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
- uint8_t show_flags)
+ uint16_t show_flags)
{
struct bgp *bgp;
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 3c8f138d6a..c03a0cc5c9 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -166,7 +166,7 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
safi_t safi, bool use_json,
json_object *json);
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t,
- uint8_t);
+ uint16_t);
extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
time_t half, unsigned int reuse,
unsigned int suppress, time_t max);
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 59bced6f93..b191840f63 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -2070,9 +2070,8 @@ int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
/* Lookup ESI hash - should exist. */
es = bgp_evpn_es_find(esi);
if (!es) {
- flog_warn(EC_BGP_EVPN_ESI,
- "%u: ES %s missing at local ES DEL",
- bgp->vrf_id, es->esi_str);
+ flog_warn(EC_BGP_EVPN_ESI, "%u: ES missing at local ES DEL",
+ bgp->vrf_id);
return -1;
}
@@ -3317,9 +3316,6 @@ bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
{
struct bgpevpn *vpn = es_evi->vpn;
- if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
- return es_evi;
-
UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index fb3ba2c0ec..2a7c2ec853 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -768,13 +768,13 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
json_object *json, int detail)
{
- return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false);
+ bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false);
}
static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
json_object *json, int detail)
{
- return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
+ bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
}
static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
@@ -4310,7 +4310,7 @@ DEFPY(show_bgp_l2vpn_evpn_nh,
* Display EVPN neighbor summary.
*/
DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
- "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [wide] [json]",
+ "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [json]",
SHOW_STR BGP_STR
"bgp vrf\n"
"vrf name\n" L2VPN_HELP_STR EVPN_HELP_STR
@@ -4325,6 +4325,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
"AS number\n"
"Internal (iBGP) AS sessions\n"
"External (eBGP) AS sessions\n"
+ "Shorten the information on BGP instances\n"
"Increase table width for longer output\n" JSON_STR)
{
int idx_vrf = 0;
@@ -4333,7 +4334,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
char *neighbor = NULL;
as_t as = 0; /* 0 means AS filter not set */
int as_type = AS_UNSPECIFIED;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (argv_find(argv, argc, "vrf", &idx_vrf))
vrf = argv[++idx_vrf]->arg;
@@ -4357,6 +4358,9 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
as = (as_t)atoi(argv[idx + 1]->arg);
}
+ if (argv_find(argv, argc, "terse", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
+
if (argv_find(argv, argc, "wide", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index b244c87258..23baa0184e 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -641,13 +641,12 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
__func__, type);
}
}
- if (bpem->match_packet_length_num || bpem->match_fragment_num ||
- bpem->match_tcpflags_num || bpem->match_dscp_num ||
- bpem->match_packet_length_num || bpem->match_icmp_code_num ||
- bpem->match_icmp_type_num || bpem->match_port_num ||
- bpem->match_src_port_num || bpem->match_dst_port_num ||
- bpem->match_protocol_num || bpem->match_bitmask ||
- bpem->match_flowlabel_num)
+ if (bpem->match_packet_length_num || bpem->match_fragment_num
+ || bpem->match_tcpflags_num || bpem->match_dscp_num
+ || bpem->match_icmp_code_num || bpem->match_icmp_type_num
+ || bpem->match_port_num || bpem->match_src_port_num
+ || bpem->match_dst_port_num || bpem->match_protocol_num
+ || bpem->match_bitmask || bpem->match_flowlabel_num)
bpem->type = BGP_PBR_IPSET;
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 8438621f68..cf651185ab 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -125,6 +125,7 @@ static const struct message bgp_pmsi_tnltype_str[] = {
};
#define VRFID_NONE_STR "-"
+#define SOFT_RECONFIG_TASK_MAX_PREFIX 25000
DEFINE_HOOK(bgp_process,
(struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
@@ -3141,6 +3142,14 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi)
return;
}
+ if (CHECK_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug(
+ "Soft reconfigure table in progress for route %p",
+ dest);
+ return;
+ }
+
if (wq == NULL)
return;
@@ -4591,6 +4600,60 @@ void bgp_announce_route_all(struct peer *peer)
bgp_announce_route(peer, afi, safi);
}
+/* Flag or unflag bgp_dest to determine whether it should be treated by
+ * bgp_soft_reconfig_table_task.
+ * Flag if flag is true. Unflag if flag is false.
+ */
+static void bgp_soft_reconfig_table_flag(struct bgp_table *table, bool flag)
+{
+ struct bgp_dest *dest;
+ struct bgp_adj_in *ain;
+
+ if (!table)
+ return;
+
+ for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
+ for (ain = dest->adj_in; ain; ain = ain->next) {
+ if (ain->peer != NULL)
+ break;
+ }
+ if (flag && ain != NULL && ain->peer != NULL)
+ SET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+ else
+ UNSET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+ }
+}
+
+static int bgp_soft_reconfig_table_update(struct peer *peer,
+ struct bgp_dest *dest,
+ struct bgp_adj_in *ain, afi_t afi,
+ safi_t safi, struct prefix_rd *prd)
+{
+ struct bgp_path_info *pi;
+ uint32_t num_labels = 0;
+ mpls_label_t *label_pnt = NULL;
+ struct bgp_route_evpn evpn;
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+ if (pi->peer == peer)
+ break;
+
+ if (pi && pi->extra)
+ num_labels = pi->extra->num_labels;
+ if (num_labels)
+ label_pnt = &pi->extra->label[0];
+ if (pi)
+ memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
+ sizeof(evpn));
+ else
+ memset(&evpn, 0, sizeof(evpn));
+
+ return bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
+ ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, prd, label_pnt, num_labels, 1,
+ &evpn);
+}
+
static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
struct bgp_table *table,
struct prefix_rd *prd)
@@ -4607,32 +4670,8 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
if (ain->peer != peer)
continue;
- struct bgp_path_info *pi;
- uint32_t num_labels = 0;
- mpls_label_t *label_pnt = NULL;
- struct bgp_route_evpn evpn;
-
- for (pi = bgp_dest_get_bgp_path_info(dest); pi;
- pi = pi->next)
- if (pi->peer == peer)
- break;
-
- if (pi && pi->extra)
- num_labels = pi->extra->num_labels;
- if (num_labels)
- label_pnt = &pi->extra->label[0];
- if (pi)
- memcpy(&evpn,
- bgp_attr_get_evpn_overlay(pi->attr),
- sizeof(evpn));
- else
- memset(&evpn, 0, sizeof(evpn));
-
- ret = bgp_update(peer, bgp_dest_get_prefix(dest),
- ain->addpath_rx_id, ain->attr, afi,
- safi, ZEBRA_ROUTE_BGP,
- BGP_ROUTE_NORMAL, prd, label_pnt,
- num_labels, 1, &evpn);
+ ret = bgp_soft_reconfig_table_update(peer, dest, ain,
+ afi, safi, prd);
if (ret < 0) {
bgp_dest_unlock_node(dest);
@@ -4641,18 +4680,201 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
}
}
+/* Do soft reconfig table per bgp table.
+ * Walk on SOFT_RECONFIG_TASK_MAX_PREFIX bgp_dest,
+ * when BGP_NODE_SOFT_RECONFIG is set,
+ * reconfig bgp_dest for list of table->soft_reconfig_peers peers.
+ * Schedule a new thread to continue the job.
+ * Without splitting the full job into several part,
+ * vtysh waits for the job to finish before responding to a BGP command
+ */
+static int bgp_soft_reconfig_table_task(struct thread *thread)
+{
+ uint32_t iter, max_iter;
+ int ret;
+ struct bgp_dest *dest;
+ struct bgp_adj_in *ain;
+ struct peer *peer;
+ struct bgp_table *table;
+ struct prefix_rd *prd;
+ struct listnode *node, *nnode;
+
+ table = THREAD_ARG(thread);
+ prd = NULL;
+
+ max_iter = SOFT_RECONFIG_TASK_MAX_PREFIX;
+ if (table->soft_reconfig_init) {
+ /* first call of the function with a new srta structure.
+ * Don't do any treatment this time on nodes
+ * in order vtysh to respond quickly
+ */
+ max_iter = 0;
+ }
+
+ for (iter = 0, dest = bgp_table_top(table); (dest && iter < max_iter);
+ dest = bgp_route_next(dest)) {
+ if (!CHECK_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG))
+ continue;
+
+ UNSET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+
+ for (ain = dest->adj_in; ain; ain = ain->next) {
+ for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node,
+ nnode, peer)) {
+ if (ain->peer != peer)
+ continue;
+
+ ret = bgp_soft_reconfig_table_update(
+ peer, dest, ain, table->afi,
+ table->safi, prd);
+ iter++;
+
+ if (ret < 0) {
+ bgp_dest_unlock_node(dest);
+ listnode_delete(
+ table->soft_reconfig_peers,
+ peer);
+ bgp_announce_route(peer, table->afi,
+ table->safi);
+ if (list_isempty(
+ table->soft_reconfig_peers)) {
+ list_delete(
+ &table->soft_reconfig_peers);
+ bgp_soft_reconfig_table_flag(
+ table, false);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+
+ /* we're either starting the initial iteration,
+ * or we're going to continue an ongoing iteration
+ */
+ if (dest || table->soft_reconfig_init) {
+ table->soft_reconfig_init = false;
+ thread_add_event(bm->master, bgp_soft_reconfig_table_task,
+ table, 0, &table->soft_reconfig_thread);
+ return 0;
+ }
+ /* we're done, clean up the background iteration context info and
+ schedule route annoucement
+ */
+ for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node, nnode, peer)) {
+ listnode_delete(table->soft_reconfig_peers, peer);
+ bgp_announce_route(peer, table->afi, table->safi);
+ }
+
+ list_delete(&table->soft_reconfig_peers);
+
+ return 0;
+}
+
+
+/* Cancel soft_reconfig_table task matching bgp instance, bgp_table
+ * and peer.
+ * - bgp cannot be NULL
+ * - if table and peer are NULL, cancel all threads within the bgp instance
+ * - if table is NULL and peer is not,
+ * remove peer in all threads within the bgp instance
+ * - if peer is NULL, cancel all threads matching table within the bgp instance
+ */
+void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
+ const struct bgp_table *table,
+ const struct peer *peer)
+{
+ struct peer *npeer;
+ struct listnode *node, *nnode;
+ int afi, safi;
+ struct bgp_table *ntable;
+
+ if (!bgp)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ ntable = bgp->rib[afi][safi];
+ if (!ntable)
+ continue;
+ if (table && table != ntable)
+ continue;
+
+ for (ALL_LIST_ELEMENTS(ntable->soft_reconfig_peers, node, nnode,
+ npeer)) {
+ if (peer && peer != npeer)
+ continue;
+ listnode_delete(ntable->soft_reconfig_peers, npeer);
+ }
+
+ if (!ntable->soft_reconfig_peers
+ || !list_isempty(ntable->soft_reconfig_peers))
+ continue;
+
+ list_delete(&ntable->soft_reconfig_peers);
+ bgp_soft_reconfig_table_flag(ntable, false);
+ BGP_TIMER_OFF(ntable->soft_reconfig_thread);
+ }
+}
+
void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
struct bgp_table *table;
+ struct listnode *node, *nnode;
+ struct peer *npeer;
+ struct peer_af *paf;
if (!peer_established(peer))
return;
if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)
- && (safi != SAFI_EVPN))
- bgp_soft_reconfig_table(peer, afi, safi, NULL, NULL);
- else
+ && (safi != SAFI_EVPN)) {
+ table = peer->bgp->rib[afi][safi];
+ if (!table)
+ return;
+
+ table->soft_reconfig_init = true;
+
+ if (!table->soft_reconfig_peers)
+ table->soft_reconfig_peers = list_new();
+ npeer = NULL;
+ /* add peer to the table soft_reconfig_peers if not already
+ * there
+ */
+ for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node, nnode,
+ npeer)) {
+ if (peer == npeer)
+ break;
+ }
+ if (peer != npeer)
+ listnode_add(table->soft_reconfig_peers, peer);
+
+ /* (re)flag all bgp_dest in table. Existing soft_reconfig_in job
+ * on table would start back at the beginning.
+ */
+ bgp_soft_reconfig_table_flag(table, true);
+
+ if (!table->soft_reconfig_thread)
+ thread_add_event(bm->master,
+ bgp_soft_reconfig_table_task, table, 0,
+ &table->soft_reconfig_thread);
+ /* Cancel bgp_announce_route_timer_expired threads.
+ * bgp_announce_route_timer_expired threads have been scheduled
+ * to announce routes as soon as the soft_reconfigure process
+ * finishes.
+ * In this case, soft_reconfigure is also scheduled by using
+ * a thread but is planned after the
+ * bgp_announce_route_timer_expired threads. It means that,
+ * without cancelling the threads, the route announcement task
+ * would run before the soft reconfiguration one. That would
+ * useless and would block vtysh during several seconds. Route
+ * announcements are rescheduled as soon as the soft_reconfigure
+ * process finishes.
+ */
+ paf = peer_af_find(peer, afi, safi);
+ if (paf)
+ bgp_stop_announce_route_timer(paf);
+ } else
for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
@@ -4826,10 +5048,8 @@ static void bgp_clear_route_table(struct peer *peer, afi_t afi, safi_t safi,
while (ain) {
ain_next = ain->next;
- if (ain->peer == peer) {
+ if (ain->peer == peer)
bgp_adj_in_remove(dest, ain);
- bgp_dest_unlock_node(dest);
- }
ain = ain_next;
}
@@ -4935,10 +5155,8 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi)
while (ain) {
ain_next = ain->next;
- if (ain->peer == peer) {
+ if (ain->peer == peer)
bgp_adj_in_remove(dest, ain);
- bgp_dest_unlock_node(dest);
- }
ain = ain_next;
}
@@ -5964,6 +6182,7 @@ void bgp_static_add(struct bgp *bgp)
struct bgp_table *table;
struct bgp_static *bgp_static;
+ SET_FLAG(bgp->flags, BGP_FLAG_FORCE_STATIC_PROCESS);
FOREACH_AFI_SAFI (afi, safi)
for (dest = bgp_table_top(bgp->route[afi][safi]); dest;
dest = bgp_route_next(dest)) {
@@ -5990,6 +6209,7 @@ void bgp_static_add(struct bgp *bgp)
safi);
}
}
+ UNSET_FLAG(bgp->flags, BGP_FLAG_FORCE_STATIC_PROCESS);
}
/* Called from bgp_delete(). Delete all static routes from the BGP
@@ -10569,13 +10789,13 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
bool use_json);
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi, uint8_t show_flags);
+ safi_t safi, uint16_t show_flags);
static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, enum bgp_show_type type,
void *output_arg, char *rd, int is_last,
unsigned long *output_cum, unsigned long *total_cum,
- unsigned long *json_header_depth, uint8_t show_flags,
+ unsigned long *json_header_depth, uint16_t show_flags,
enum rpki_states rpki_target_state)
{
struct bgp_path_info *pi;
@@ -10994,7 +11214,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
unsigned long json_header_depth = 0;
struct bgp_table *itable;
bool show_msg;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
show_msg = (!use_json && type == bgp_show_type_normal);
@@ -11036,7 +11256,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
}
static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
enum bgp_show_type type, void *output_arg,
- uint8_t show_flags, enum rpki_states rpki_target_state)
+ uint16_t show_flags, enum rpki_states rpki_target_state)
{
struct bgp_table *table;
unsigned long json_header_depth = 0;
@@ -11076,7 +11296,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
}
static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
- safi_t safi, uint8_t show_flags)
+ safi_t safi, uint16_t show_flags)
{
struct listnode *node, *nnode;
struct bgp *bgp;
@@ -11582,7 +11802,7 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
int i;
char *str;
int first = 0;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
int ret;
if (uj)
@@ -11625,7 +11845,7 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
safi_t safi, bool uj)
{
struct community_list *list;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj)
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -11705,7 +11925,7 @@ DEFUN (show_ip_bgp_large_community,
bool exact_match = 0;
struct bgp *bgp = NULL;
bool uj = use_json(argc, argv);
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj) {
argc--;
@@ -11909,7 +12129,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
int exact_match = 0;
struct bgp *bgp = NULL;
int idx = 0;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
/* [<ipv4|ipv6> [all]] */
if (all) {
@@ -12022,7 +12242,7 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd,
char *prefix_version = NULL;
char *bgp_community_alias = NULL;
bool first = true;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
if (uj) {
@@ -12343,7 +12563,7 @@ DEFPY (show_ip_bgp_instance_all,
safi_t safi = SAFI_UNICAST;
struct bgp *bgp = NULL;
int idx = 0;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj) {
argc--;
@@ -12368,7 +12588,7 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
{
regex_t *regex;
int rc;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (use_json)
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -12396,7 +12616,7 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp,
safi_t safi, enum bgp_show_type type)
{
struct prefix_list *plist;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
plist = prefix_list_lookup(afi, prefix_list_str);
if (plist == NULL) {
@@ -12414,7 +12634,7 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
enum bgp_show_type type)
{
struct as_list *as_list;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
as_list = as_list_lookup(filter);
if (as_list == NULL) {
@@ -12432,7 +12652,7 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
enum bgp_show_type type)
{
struct route_map *rmap;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
rmap = route_map_lookup_by_name(rmap_str);
if (!rmap) {
@@ -12446,7 +12666,7 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi, uint8_t show_flags)
+ safi_t safi, uint16_t show_flags)
{
struct community *com;
int ret = 0;
@@ -12471,7 +12691,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
safi_t safi)
{
struct community_list *list;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
list = community_list_lookup(bgp_clist, com, 0, COMMUNITY_LIST_MASTER);
if (list == NULL) {
@@ -12491,7 +12711,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
{
int ret;
struct prefix *p;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
p = prefix_new();
@@ -13284,7 +13504,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
afi_t afi, safi_t safi, enum bgp_show_adj_route_type type,
const char *rmap_name, json_object *json, json_object *json_ar,
json_object *json_scode, json_object *json_ocode,
- uint8_t show_flags, int *header1, int *header2, char *rd_str,
+ uint16_t show_flags, int *header1, int *header2, char *rd_str,
unsigned long *output_count, unsigned long *filtered_count)
{
struct bgp_adj_in *ain;
@@ -13494,7 +13714,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi, enum bgp_show_adj_route_type type,
- const char *rmap_name, uint8_t show_flags)
+ const char *rmap_name, uint16_t show_flags)
{
struct bgp *bgp;
struct bgp_table *table;
@@ -13685,7 +13905,7 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
struct peer *peer;
enum bgp_show_adj_route_type type = bgp_show_adj_route_bestpath;
int idx = 0;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj)
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -13741,7 +13961,7 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
enum bgp_show_adj_route_type type = bgp_show_adj_route_advertised;
int idx = 0;
bool first = true;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj) {
argc--;
@@ -13923,7 +14143,7 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi,
enum bgp_show_type type, bool use_json)
{
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (use_json)
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -13968,7 +14188,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed,
struct bgp *bgp = NULL;
int idx = 0;
bool uj = use_json(argc, argv);
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
if (uj) {
argc--;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 6d6008ff55..3e3b018e83 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -591,6 +591,7 @@ DECLARE_HOOK(bgp_process,
#define BGP_SHOW_OPT_ESTABLISHED (1 << 5)
#define BGP_SHOW_OPT_FAILED (1 << 6)
#define BGP_SHOW_OPT_DETAIL (1 << 7)
+#define BGP_SHOW_OPT_TERSE (1 << 8)
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
@@ -603,6 +604,9 @@ extern void bgp_announce_route(struct peer *, afi_t, safi_t);
extern void bgp_stop_announce_route_timer(struct peer_af *paf);
extern void bgp_announce_route_all(struct peer *);
extern void bgp_default_originate(struct peer *, afi_t, safi_t, int);
+extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
+ const struct bgp_table *table,
+ const struct peer *peer);
extern void bgp_soft_reconfig_in(struct peer *, afi_t, safi_t);
extern void bgp_clear_route(struct peer *, afi_t, safi_t);
extern void bgp_clear_route_all(struct peer *);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 921a3e0dd9..806a771cfb 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3767,7 +3767,6 @@ static void bgp_route_map_process_update_cb(char *rmap_name)
bgp_route_map_process_update(bgp, rmap_name, 1);
#ifdef ENABLE_BGP_VNC
- /* zlog_debug("%s: calling vnc_routemap_update", __func__); */
vnc_routemap_update(bgp, __func__);
#endif
}
@@ -3807,12 +3806,14 @@ static void bgp_route_map_mark_update(const char *rmap_name)
BGP_POLICY_ROUTE_MAP,
rmap_name, 1, 1);
} else {
- for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
bgp_route_map_process_update(bgp, rmap_name, 0);
#ifdef ENABLE_BGP_VNC
- zlog_debug("%s: calling vnc_routemap_update", __func__);
- vnc_routemap_update(bgp, __func__);
+ vnc_routemap_update(bgp, __func__);
#endif
+ }
+
+ vpn_policy_routemap_event(rmap_name);
}
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 68b460149c..8a5ed2442f 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -31,6 +31,7 @@
#include "linklist.h"
#include "bgpd.h"
#include "bgp_advertise.h"
+#include "bgpd/bgp_trace.h"
struct bgp_table {
/* table belongs to this instance */
@@ -42,6 +43,13 @@ struct bgp_table {
int lock;
+ /* soft_reconfig_table in progress */
+ bool soft_reconfig_init;
+ struct thread *soft_reconfig_thread;
+
+ /* list of peers on which soft_reconfig_table has to run */
+ struct list *soft_reconfig_peers;
+
struct route_table *route_table;
uint64_t version;
};
@@ -96,7 +104,7 @@ struct bgp_node {
mpls_label_t local_label;
- uint8_t flags;
+ uint16_t flags;
#define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
#define BGP_NODE_USER_CLEAR (1 << 1)
#define BGP_NODE_LABEL_CHANGED (1 << 2)
@@ -105,6 +113,7 @@ struct bgp_node {
#define BGP_NODE_FIB_INSTALL_PENDING (1 << 5)
#define BGP_NODE_FIB_INSTALLED (1 << 6)
#define BGP_NODE_LABEL_REQUESTED (1 << 7)
+#define BGP_NODE_SOFT_RECONFIG (1 << 8)
struct bgp_addpath_node_data tx_addpath;
@@ -175,6 +184,7 @@ static inline struct bgp_dest *bgp_dest_parent_nolock(struct bgp_dest *dest)
*/
static inline void bgp_dest_unlock_node(struct bgp_dest *dest)
{
+ frrtrace(1, frr_bgp, bgp_dest_unlock, dest);
bgp_delete_listnode(dest);
route_unlock_node(bgp_dest_to_rnode(dest));
}
@@ -248,6 +258,7 @@ bgp_node_lookup(const struct bgp_table *const table, const struct prefix *p)
*/
static inline struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest)
{
+ frrtrace(1, frr_bgp, bgp_dest_lock, dest);
struct route_node *rn = route_lock_node(bgp_dest_to_rnode(dest));
return bgp_dest_from_rnode(rn);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index a78afdd871..de4f5a59b6 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -10901,7 +10901,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
/* Show BGP peer's summary information. */
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
struct peer *fpeer, int as_type, as_t as,
- uint8_t show_flags)
+ uint16_t show_flags)
{
struct peer *peer;
struct listnode *node, *nnode;
@@ -10910,6 +10910,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
char neighbor_buf[VTY_BUFSIZ];
int neighbor_col_default_width = 16;
int len, failed_count = 0;
+ unsigned int filtered_count = 0;
int max_neighbor_width = 0;
int pfx_rcd_safi;
json_object *json = NULL;
@@ -10922,6 +10923,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
bool show_established =
CHECK_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
bool show_wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
+ bool show_terse = CHECK_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
/* labeled-unicast routes are installed in the unicast table so in order
* to
@@ -10939,6 +10941,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (bgp_show_summary_is_peer_filtered(peer, fpeer,
as_type, as)) {
+ filtered_count++;
count++;
continue;
}
@@ -10964,6 +10967,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (bgp_show_summary_is_peer_filtered(peer, fpeer,
as_type, as)) {
+ filtered_count++;
count++;
continue;
}
@@ -11018,12 +11022,12 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_free(json);
} else {
vty_out(vty, "%% No failed BGP neighbors found\n");
- vty_out(vty, "\nTotal number of neighbors %d\n", count);
}
return CMD_SUCCESS;
}
count = 0; /* Reset the value as its used again */
+ filtered_count = 0;
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
@@ -11180,63 +11184,75 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_object_boolean_true_add(
json, "dampeningEnabled");
} else {
- if (bgp_maxmed_onstartup_configured(bgp)
- && bgp->maxmed_active)
- vty_out(vty,
- "Max-med on-startup active\n");
- if (bgp->v_maxmed_admin)
- vty_out(vty,
- "Max-med administrative active\n");
+ if (!show_terse) {
+ if (bgp_maxmed_onstartup_configured(bgp)
+ && bgp->maxmed_active)
+ vty_out(vty,
+ "Max-med on-startup active\n");
+ if (bgp->v_maxmed_admin)
+ vty_out(vty,
+ "Max-med administrative active\n");
- vty_out(vty, "BGP table version %" PRIu64 "\n",
- bgp_table_version(bgp->rib[afi][safi]));
+ vty_out(vty,
+ "BGP table version %" PRIu64
+ "\n",
+ bgp_table_version(
+ bgp->rib[afi][safi]));
- ents = bgp_table_count(bgp->rib[afi][safi]);
- vty_out(vty,
- "RIB entries %ld, using %s of memory\n",
- ents,
- mtype_memstr(
- memstrbuf, sizeof(memstrbuf),
- ents
- * sizeof(struct
- bgp_dest)));
-
- /* Peer related usage */
- ents = bgp->af_peer_count[afi][safi];
- vty_out(vty, "Peers %ld, using %s of memory\n",
- ents,
- mtype_memstr(
- memstrbuf, sizeof(memstrbuf),
- ents * sizeof(struct peer)));
+ ents = bgp_table_count(
+ bgp->rib[afi][safi]);
+ vty_out(vty,
+ "RIB entries %ld, using %s of memory\n",
+ ents,
+ mtype_memstr(
+ memstrbuf,
+ sizeof(memstrbuf),
+ ents
+ * sizeof(
+ struct
+ bgp_dest)));
- if ((ents = listcount(bgp->group)))
+ /* Peer related usage */
+ ents = bgp->af_peer_count[afi][safi];
vty_out(vty,
- "Peer groups %ld, using %s of memory\n",
+ "Peers %ld, using %s of memory\n",
ents,
mtype_memstr(
memstrbuf,
sizeof(memstrbuf),
- ents * sizeof(struct
- peer_group)));
+ ents
+ * sizeof(
+ struct
+ peer)));
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_DAMPENING))
- vty_out(vty, "Dampening enabled.\n");
- vty_out(vty, "\n");
+ if ((ents = listcount(bgp->group)))
+ vty_out(vty,
+ "Peer groups %ld, using %s of memory\n",
+ ents,
+ mtype_memstr(
+ memstrbuf,
+ sizeof(memstrbuf),
+ ents
+ * sizeof(
+ struct
+ peer_group)));
+
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_DAMPENING))
+ vty_out(vty,
+ "Dampening enabled.\n");
+ }
+ if (show_failed) {
+ vty_out(vty, "\n");
- /* Subtract 8 here because 'Neighbor' is
- * 8 characters */
- vty_out(vty, "Neighbor");
- vty_out(vty, "%*s", max_neighbor_width - 8,
- " ");
- if (show_failed)
+ /* Subtract 8 here because 'Neighbor' is
+ * 8 characters */
+ vty_out(vty, "Neighbor");
+ vty_out(vty, "%*s",
+ max_neighbor_width - 8, " ");
vty_out(vty,
BGP_SHOW_SUMMARY_HEADER_FAILED);
- else
- vty_out(vty,
- show_wide
- ? BGP_SHOW_SUMMARY_HEADER_ALL_WIDE
- : BGP_SHOW_SUMMARY_HEADER_ALL);
+ }
}
}
@@ -11250,11 +11266,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (use_json) {
json_peer = NULL;
-
if (bgp_show_summary_is_peer_filtered(peer, fpeer,
- as_type, as))
+ as_type, as)) {
+ filtered_count++;
continue;
-
+ }
if (show_failed &&
bgp_has_peer_failed(peer, afi, safi)) {
json_peer = json_object_new_object();
@@ -11262,8 +11278,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_peer, 0, use_json);
} else if (!show_failed) {
if (show_established
- && bgp_has_peer_failed(peer, afi, safi))
+ && bgp_has_peer_failed(peer, afi, safi)) {
+ filtered_count++;
continue;
+ }
json_peer = json_object_new_object();
if (peer_dynamic_neighbor(peer)) {
@@ -11405,8 +11423,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json_peer);
} else {
if (bgp_show_summary_is_peer_filtered(peer, fpeer,
- as_type, as))
+ as_type, as)) {
+ filtered_count++;
continue;
+ }
if (show_failed &&
bgp_has_peer_failed(peer, afi, safi)) {
bgp_show_failed_summary(vty, bgp, peer, NULL,
@@ -11414,8 +11434,27 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
use_json);
} else if (!show_failed) {
if (show_established
- && bgp_has_peer_failed(peer, afi, safi))
+ && bgp_has_peer_failed(peer, afi, safi)) {
+ filtered_count++;
continue;
+ }
+
+ if ((count - filtered_count) == 1) {
+ /* display headline before the first
+ * neighbor line */
+ vty_out(vty, "\n");
+
+ /* Subtract 8 here because 'Neighbor' is
+ * 8 characters */
+ vty_out(vty, "Neighbor");
+ vty_out(vty, "%*s",
+ max_neighbor_width - 8, " ");
+ vty_out(vty,
+ show_wide
+ ? BGP_SHOW_SUMMARY_HEADER_ALL_WIDE
+ : BGP_SHOW_SUMMARY_HEADER_ALL);
+ }
+
memset(dn_flag, '\0', sizeof(dn_flag));
if (peer_dynamic_neighbor(peer)) {
dn_flag[0] = '*';
@@ -11540,6 +11579,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
if (use_json) {
json_object_object_add(json, "peers", json_peers);
json_object_int_add(json, "failedPeers", failed_count);
+ json_object_int_add(json, "displayedPeers",
+ count - filtered_count);
json_object_int_add(json, "totalPeers", count);
json_object_int_add(json, "dynamicPeers", dn_count);
@@ -11550,9 +11591,22 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
- if (count)
- vty_out(vty, "\nTotal number of neighbors %d\n", count);
- else {
+ if (count) {
+ if (filtered_count == count)
+ vty_out(vty, "\n%% No matching neighbor\n");
+ else {
+ if (show_failed)
+ vty_out(vty, "\nDisplayed neighbors %d",
+ failed_count);
+ else if (as_type != AS_UNSPECIFIED || as
+ || fpeer || show_established)
+ vty_out(vty, "\nDisplayed neighbors %d",
+ count - filtered_count);
+
+ vty_out(vty, "\nTotal number of neighbors %d\n",
+ count);
+ }
+ } else {
vty_out(vty, "No %s neighbor is configured\n",
get_afi_safi_str(afi, safi, false));
}
@@ -11569,7 +11623,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
int safi, struct peer *fpeer, int as_type,
- as_t as, uint8_t show_flags)
+ as_t as, uint16_t show_flags)
{
int is_first = 1;
int afi_wildcard = (afi == AFI_MAX);
@@ -11607,10 +11661,12 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
safi,
true));
} else {
- vty_out(vty, "\n%s Summary:\n",
+ vty_out(vty,
+ "\n%s Summary (%s):\n",
get_afi_safi_str(afi,
safi,
- false));
+ false),
+ bgp->name_pretty);
}
}
bgp_show_summary(vty, bgp, afi, safi, fpeer,
@@ -11631,7 +11687,8 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
if (use_json)
vty_out(vty, "{}\n");
else
- vty_out(vty, "%% No BGP neighbors found\n");
+ vty_out(vty, "%% No BGP neighbors found in %s\n",
+ bgp->name_pretty);
}
}
@@ -11639,7 +11696,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
safi_t safi,
const char *neighbor,
int as_type, as_t as,
- uint8_t show_flags)
+ uint16_t show_flags)
{
struct listnode *node, *nnode;
struct bgp *bgp;
@@ -11663,11 +11720,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
? VRF_DEFAULT_NAME
: bgp->name);
- } else {
- vty_out(vty, "\nInstance %s:\n",
- (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- ? VRF_DEFAULT_NAME
- : bgp->name);
}
if (neighbor) {
fpeer = peer_lookup_in_view(vty, bgp, neighbor,
@@ -11687,7 +11739,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, const char *neighbor, int as_type,
- as_t as, uint8_t show_flags)
+ as_t as, uint16_t show_flags)
{
struct bgp *bgp;
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -11749,7 +11801,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>>] [wide] [json$uj]",
+ "]] [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]",
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"
@@ -11764,6 +11816,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
"AS number\n"
"Internal (iBGP) AS sessions\n"
"External (eBGP) AS sessions\n"
+ "Shorten the information on BGP instances\n"
"Increase table width for longer output\n" JSON_STR)
{
char *vrf = NULL;
@@ -11771,7 +11824,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
safi_t safi = SAFI_MAX;
as_t as = 0; /* 0 means AS filter not set */
int as_type = AS_UNSPECIFIED;
- uint8_t show_flags = 0;
+ uint16_t show_flags = 0;
int idx = 0;
@@ -11806,6 +11859,9 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
as = (as_t)atoi(argv[idx + 1]->arg);
}
+ if (argv_find(argv, argc, "terse", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
+
if (argv_find(argv, argc, "wide", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 2531488d0d..04a47f6f62 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -186,7 +186,7 @@ int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
int argc, struct bgp **bgp, bool use_json);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, const char *neighbor, int as_type,
- as_t as, uint8_t show_flags);
+ as_t as, uint16_t show_flags);
extern int bgp_clear_star_soft_in(const char *name, char *errmsg,
size_t errmsg_len);
extern int bgp_clear_star_soft_out(const char *name, char *errmsg,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 81375e37ed..49562e5874 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -892,6 +892,8 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
return -1;
bgp = peer->bgp;
+ bgp_soft_reconfig_table_task_cancel(bgp, bgp->rib[afi][safi], peer);
+
bgp_stop_announce_route_timer(af);
if (PAF_SUBGRP(af)) {
@@ -2406,6 +2408,8 @@ int peer_delete(struct peer *peer)
bgp = peer->bgp;
accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
+ bgp_soft_reconfig_table_task_cancel(bgp, NULL, peer);
+
bgp_keepalives_off(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
@@ -3572,6 +3576,8 @@ int bgp_delete(struct bgp *bgp)
assert(bgp);
+ bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL);
+
/* make sure we withdraw any exported routes */
vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
bgp);
@@ -7885,7 +7891,8 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
json_no, JSON_C_TO_STRING_PRETTY));
json_object_free(json_no);
} else
- vty_out(vty, "No such neighbor in this view/vrf\n");
+ vty_out(vty, "No such neighbor in %s\n",
+ bgp->name_pretty);
return NULL;
}
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 8c455c6ea5..f89ef7b0d2 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -2179,7 +2179,7 @@ int rfapi_close(void *handle)
vnc_zlog_debug_verbose("%s administrative close rfd=%p",
__func__, rfd);
- if (h && h->rfp_methods.close_cb) {
+ if (h->rfp_methods.close_cb) {
vnc_zlog_debug_verbose(
"%s calling close callback rfd=%p", __func__,
rfd);
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index b2732a40b4..51e051d688 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2592,10 +2592,8 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
* instrumentation to debug segfault of 091127
*/
vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
- if (vpn_bpi) {
- vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p",
- __func__, vpn_bpi->extra);
- }
+ vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
+ vpn_bpi->extra);
vpn_bpi->extra->vnc.import.un_family = AF_INET;
vpn_bpi->extra->vnc.import.un.addr4 =
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 8885dcfce3..ba03aa9045 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -312,6 +312,20 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
--gdb-breakpoints=nb_config_diff \
all-protocol-startup
+Detecting Memleaks with Valgrind
+""""""""""""""""""""""""""""""""
+
+Topotest can automatically launch all daemons with ``valgrind`` to check for
+memleaks. This is enabled by specifying 1 or 2 CLI arguments.
+``--valgrind-memleaks`` will enable general memleak detection, and
+``--valgrind-extra`` enables extra functionality including generating a
+suppression file. The suppression file ``tools/valgrind.supp`` is used when
+memleak detection is enabled.
+
+.. code:: shell
+
+ pytest --valgrind-memleaks all-protocol-startup
+
.. _topotests_docker:
Running Tests with Docker
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 3e85a08179..452794e3a8 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -66,6 +66,10 @@ Basic Config Commands
Set domainname of the router. It is only for current ``vtysh``, it will not
be saved to any configuration file even with ``write file``.
+.. clicmd:: domainname DOMAINNAME
+
+ Set domainname of the router.
+
.. clicmd:: password PASSWORD
Set password for vty interface. The ``no`` form of the command deletes the
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 0e01b8c3e4..4e78900e8d 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -442,7 +442,7 @@ Require policy on EBGP
exit1# show bgp summary
- IPv4 Unicast Summary:
+ IPv4 Unicast Summary (VRF default):
BGP router identifier 10.10.10.1, local AS number 65001 vrf-id 0
BGP table version 4
RIB entries 7, using 1344 bytes of memory
@@ -3258,7 +3258,7 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
exit1# show ip bgp summary wide
- IPv4 Unicast Summary:
+ IPv4 Unicast Summary (VRF default):
BGP router identifier 192.168.100.1, local AS number 65534 vrf-id 0
BGP table version 3
RIB entries 5, using 920 bytes of memory
@@ -3310,6 +3310,13 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
address-family. The remote-as filter can be used in combination with the
failed, established filters.
+.. clicmd:: show bgp [afi] [safi] [all] summary terse [json]
+
+ Shorten the output. Do not show the following information about the BGP
+ instances: the number of RIB entries, the table version and the used memory.
+ The ``terse`` option can be used in combination with the remote-as, neighbor,
+ failed and established filters, and with the ``wide`` option as well.
+
.. clicmd:: show bgp [afi] [safi] [neighbor [PEER] [routes|advertised-routes|received-routes] [json]
This command shows information on a specific BGP peer of the relevant
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 59a3af7645..d26062e2b9 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -18,13 +18,6 @@ OSPF6 router
Set router's Router-ID.
-.. clicmd:: interface IFNAME area (0-4294967295)
-
-.. clicmd:: interface IFNAME area A.B.C.D
-
- Bind interface to specified area, and start sending OSPF packets. `area` can
- be specified as 0.
-
.. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000)
This command sets the initial `delay`, the `initial-holdtime`
@@ -108,6 +101,10 @@ The following functionalities are implemented as per RFC 3101:
OSPF6 interface
===============
+.. clicmd:: ipv6 ospf6 area <A.B.C.D|(0-4294967295)>
+
+ Enable OSPFv3 on the interface and add it to the specified area.
+
.. clicmd:: ipv6 ospf6 cost COST
Sets interface's output cost. Default value depends on the interface
@@ -265,12 +262,12 @@ Example of ospf6d configured on one interface and area:
.. code-block:: frr
interface eth0
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 instance-id 0
!
router ospf6
ospf6 router-id 212.17.55.53
area 0.0.0.0 range 2001:770:105:2::/64
- interface eth0 area 0.0.0.0
!
@@ -282,6 +279,7 @@ Larger example with policy and various options set:
debug ospf6 neighbor state
!
interface fxp0
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 cost 1
ipv6 ospf6 hello-interval 10
ipv6 ospf6 dead-interval 40
@@ -302,7 +300,6 @@ Larger example with policy and various options set:
router ospf6
router-id 255.1.1.1
redistribute static route-map static-ospf6
- interface fxp0 area 0.0.0.0
!
access-list access4 permit 127.0.0.1/32
!
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index cb2b3eb69e..8fc36c0e5f 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -55,5 +55,14 @@ RUN apk add \
--no-cache \
--allow-untrusted /pkgs/apk/*/*.apk \
&& rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
COPY docker/alpine/docker-start /usr/lib/frr/docker-start
-CMD [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
diff --git a/docker/alpine/docker-start b/docker/alpine/docker-start
index 3f7737d3bf..c20df42e8e 100755
--- a/docker/alpine/docker-start
+++ b/docker/alpine/docker-start
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/ash
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr || true
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile
index 748b5345a1..303a33fe4a 100644
--- a/docker/centos-7/Dockerfile
+++ b/docker/centos-7/Dockerfile
@@ -39,5 +39,19 @@ COPY --from=centos-7-builder /rpmbuild/RPMS/ /pkgs/rpm/
RUN yum install -y /pkgs/rpm/*/*.rpm \
&& rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Add tini because no CentOS7 package
+ENV TINI_VERSION v0.19.0
+ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
+RUN chmod +x /sbin/tini
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
COPY docker/centos-7/docker-start /usr/lib/frr/docker-start
-CMD [ "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
diff --git a/docker/centos-7/docker-start b/docker/centos-7/docker-start
index a3913245b6..d954142ab9 100755
--- a/docker/centos-7/docker-start
+++ b/docker/centos-7/docker-start
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/bash
-set -e
-
-##
-# Change owner for docker volume mount
-##
-chown -R frr:frr /etc/frr
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
diff --git a/docker/centos-8/Dockerfile b/docker/centos-8/Dockerfile
index e273be055b..8a0c28e13b 100644
--- a/docker/centos-8/Dockerfile
+++ b/docker/centos-8/Dockerfile
@@ -40,5 +40,19 @@ COPY --from=centos-8-builder /rpmbuild/RPMS/ /pkgs/rpm/
RUN yum install -y /pkgs/rpm/*/*.rpm \
&& rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Add tini because no CentOS8 package
+ENV TINI_VERSION v0.19.0
+ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
+RUN chmod +x /sbin/tini
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
COPY docker/centos-8/docker-start /usr/lib/frr/docker-start
-CMD [ "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
diff --git a/docker/centos-8/docker-start b/docker/centos-8/docker-start
index 935b22209e..d954142ab9 100755
--- a/docker/centos-8/docker-start
+++ b/docker/centos-8/docker-start
@@ -1,9 +1,4 @@
-#!/bin/sh
+#!/bin/bash
-set -e
-
-chown -R frr:frr /etc/frr
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile
index cc9217f103..7476e5fe3e 100644
--- a/docker/debian/Dockerfile
+++ b/docker/debian/Dockerfile
@@ -6,8 +6,8 @@ ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
RUN apt-get update && \
apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \
- libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils && \
- rm -rf /var/lib/apt/lists/*
+ libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils \
+ tini && rm -rf /var/lib/apt/lists/*
RUN curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add -
RUN echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list
@@ -16,5 +16,13 @@ RUN apt-get update && \
apt-get install -y frr frr-pythontools && \
rm -rf /var/lib/apt/lists/*
-ADD docker-start /usr/sbin/docker-start
-CMD ["/usr/sbin/docker-start"]
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/usr/bin/tini", "--"]
+
+# Default CMD starts watchfrr
+COPY docker-start /usr/lib/frr/docker-start
+CMD ["/usr/lib/frr/docker-start"]
diff --git a/docker/debian/docker-start b/docker/debian/docker-start
index a0f31f5ac5..d954142ab9 100755
--- a/docker/debian/docker-start
+++ b/docker/debian/docker-start
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/bash
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr
-/etc/init.d/frr start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c
index 3a978cae33..47de929fc3 100644
--- a/eigrpd/eigrp_cli.c
+++ b/eigrpd/eigrp_cli.c
@@ -919,6 +919,8 @@ eigrp_cli_init(void)
install_element(EIGRP_NODE, &eigrp_neighbor_cmd);
install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
+ vrf_cmd_init(NULL, &eigrpd_privs);
+
install_node(&eigrp_interface_node);
if_cmd_init();
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index c1f5e49eca..ffda0f8643 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -270,7 +270,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj)
struct isis_dynhn *dyn;
- dyn = dynhn_find_by_id(adj->sysid);
+ dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
if (dyn)
return dyn->hostname;
else
@@ -401,7 +401,7 @@ void isis_adj_print(struct isis_adjacency *adj)
if (!adj)
return;
- dyn = dynhn_find_by_id(adj->sysid);
+ dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
if (dyn)
zlog_debug("%s", dyn->hostname);
@@ -537,7 +537,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
if (adj->circuit
&& (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
- dyn = dynhn_find_by_id(adj->lanid);
+ dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
if (dyn)
vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
adj->lanid[ISIS_SYS_ID_LEN]);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 4fa28a4ad9..bccb9065f4 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -78,12 +78,14 @@ DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
static void isis_circuit_enable(struct isis_circuit *circuit)
{
- struct isis_area *area;
+ struct isis_area *area = circuit->area;
struct interface *ifp = circuit->interface;
- area = isis_area_lookup(circuit->tag, ifp->vrf_id);
- if (area)
- isis_area_add_circuit(area, circuit);
+ if (!area) {
+ area = isis_area_lookup(circuit->tag, ifp->vrf_id);
+ if (area)
+ isis_area_add_circuit(area, circuit);
+ }
if (if_is_operative(ifp))
isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
@@ -1074,10 +1076,8 @@ static int isis_interface_config_write(struct vty *vty)
isis = isis_lookup_by_vrfid(vrf->vrf_id);
- if (isis == NULL) {
- vty_out(vty, "ISIS routing instance not found");
+ if (isis == NULL)
return 0;
- }
FOR_ALL_INTERFACES (vrf, ifp) {
/* IF name */
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
index decd3e8922..ade6e82220 100644
--- a/isisd/isis_dynhn.c
+++ b/isisd/isis_dynhn.c
@@ -42,30 +42,29 @@
DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname");
-extern struct host host;
-
-struct list *dyn_cache = NULL;
static int dyn_cache_cleanup(struct thread *);
void dyn_cache_init(struct isis *isis)
{
- if (dyn_cache == NULL)
- dyn_cache = list_new();
+ isis->dyn_cache = list_new();
if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
thread_add_timer(master, dyn_cache_cleanup, isis, 120,
&isis->t_dync_clean);
- return;
}
-void dyn_cache_cleanup_all(void)
+void dyn_cache_finish(struct isis *isis)
{
struct listnode *node, *nnode;
struct isis_dynhn *dyn;
- for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
- list_delete_node(dyn_cache, node);
+ thread_cancel(&isis->t_dync_clean);
+
+ for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
+ list_delete_node(isis->dyn_cache, node);
XFREE(MTYPE_ISIS_DYNHN, dyn);
}
+
+ list_delete(&isis->dyn_cache);
}
static int dyn_cache_cleanup(struct thread *thread)
@@ -79,10 +78,10 @@ static int dyn_cache_cleanup(struct thread *thread)
isis->t_dync_clean = NULL;
- for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
+ for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
continue;
- list_delete_node(dyn_cache, node);
+ list_delete_node(isis->dyn_cache, node);
XFREE(MTYPE_ISIS_DYNHN, dyn);
}
@@ -92,54 +91,55 @@ static int dyn_cache_cleanup(struct thread *thread)
return ISIS_OK;
}
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id)
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id)
{
struct listnode *node = NULL;
struct isis_dynhn *dyn = NULL;
- for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+ for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
if (memcmp(dyn->id, id, ISIS_SYS_ID_LEN) == 0)
return dyn;
return NULL;
}
-struct isis_dynhn *dynhn_find_by_name(const char *hostname)
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname)
{
struct listnode *node = NULL;
struct isis_dynhn *dyn = NULL;
- for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+ for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
if (strncmp(dyn->hostname, hostname, 255) == 0)
return dyn;
return NULL;
}
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level)
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+ const char *hostname, int level)
{
struct isis_dynhn *dyn;
- dyn = dynhn_find_by_id(id);
+ dyn = dynhn_find_by_id(isis, id);
if (!dyn) {
dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
dyn->level = level;
- listnode_add(dyn_cache, dyn);
+ listnode_add(isis->dyn_cache, dyn);
}
snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname);
dyn->refresh = time(NULL);
}
-void isis_dynhn_remove(const uint8_t *id)
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id)
{
struct isis_dynhn *dyn;
- dyn = dynhn_find_by_id(id);
+ dyn = dynhn_find_by_id(isis, id);
if (!dyn)
return;
- listnode_delete(dyn_cache, dyn);
+ listnode_delete(isis->dyn_cache, dyn);
XFREE(MTYPE_ISIS_DYNHN, dyn);
}
@@ -158,7 +158,7 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
if (!isis->sysid_set)
return;
vty_out(vty, "Level System ID Dynamic Hostname\n");
- for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
vty_out(vty, "%-7d", dyn->level);
vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id),
dyn->hostname);
@@ -169,14 +169,15 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
return;
}
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level)
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+ int level)
{
struct listnode *node = NULL;
struct isis_dynhn *dyn = NULL;
struct isis_dynhn *found_dyn = NULL;
int res;
- for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+ for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
res = memcmp(dyn->id, id, ISIS_SYS_ID_LEN);
if (res < 0)
diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h
index 8d25582e49..afb8b51b1f 100644
--- a/isisd/isis_dynhn.h
+++ b/isisd/isis_dynhn.h
@@ -31,14 +31,16 @@ struct isis_dynhn {
};
void dyn_cache_init(struct isis *isis);
-void dyn_cache_cleanup_all(void);
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level);
-void isis_dynhn_remove(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_name(const char *hostname);
+void dyn_cache_finish(struct isis *isis);
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+ const char *hostname, int level);
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname);
void dynhn_print_all(struct vty *vty, struct isis *isis);
/* Snmp support */
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level);
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+ int level);
#endif /* _ZEBRA_ISIS_DYNHN_H */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 056e29e8de..814ba8fc2a 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -533,11 +533,11 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
if (area->dynhostname && lsp->tlvs->hostname
&& lsp->hdr.rem_lifetime) {
- isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
- (lsp->hdr.lsp_bits & LSPBIT_IST)
- == IS_LEVEL_1_AND_2
- ? IS_LEVEL_2
- : IS_LEVEL_1);
+ isis_dynhn_insert(
+ area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
+ (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
+ ? IS_LEVEL_2
+ : IS_LEVEL_1);
}
return;
@@ -700,7 +700,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
char id[SYSID_STRLEN];
if (dynhost)
- dyn = dynhn_find_by_id(lsp_id);
+ dyn = dynhn_find_by_id(isis, lsp_id);
else
dyn = NULL;
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
index d3d081d376..d49ad8485e 100644
--- a/isisd/isis_misc.c
+++ b/isisd/isis_misc.c
@@ -458,6 +458,7 @@ const char *print_sys_hostname(const uint8_t *sysid)
{
struct isis_dynhn *dyn;
struct isis *isis = NULL;
+ struct listnode *node;
if (!sysid)
return "nullsysid";
@@ -467,9 +468,11 @@ const char *print_sys_hostname(const uint8_t *sysid)
if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
return cmd_hostname_get();
- dyn = dynhn_find_by_id(sysid);
- if (dyn)
- return dyn->hostname;
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+ dyn = dynhn_find_by_id(isis, sysid);
+ if (dyn)
+ return dyn->hostname;
+ }
return sysid_print(sysid);
}
diff --git a/isisd/isis_nb_notifications.c b/isisd/isis_nb_notifications.c
index 755378a9b7..f219632acf 100644
--- a/isisd/isis_nb_notifications.c
+++ b/isisd/isis_nb_notifications.c
@@ -315,7 +315,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
struct yang_data *data;
struct isis_circuit *circuit = adj->circuit;
struct isis_area *area = circuit->area;
- struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid);
+ struct isis_dynhn *dyn = dynhn_find_by_id(circuit->isis, adj->sysid);
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c
index fa2f9a7669..d530faa151 100644
--- a/isisd/isis_snmp.c
+++ b/isisd/isis_snmp.c
@@ -1654,6 +1654,10 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
oid *oid_idx;
size_t oid_idx_len;
size_t off = 0;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
*write_method = NULL;
@@ -1687,7 +1691,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
- dyn = dynhn_find_by_id(cmp_buf);
+ dyn = dynhn_find_by_id(isis, cmp_buf);
if (dyn == NULL || dyn->level != cmp_level)
return NULL;
@@ -1739,7 +1743,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
*/
cmp_level = (int)(IS_LEVEL_2 + 1);
- dyn = dynhn_snmp_next(cmp_buf, cmp_level);
+ dyn = dynhn_snmp_next(isis, cmp_buf, cmp_level);
if (dyn == NULL)
return NULL;
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 77b18f9cf7..7e78e0ce69 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -229,6 +229,7 @@ void isis_finish(struct isis *isis)
isis_redist_free(isis);
list_delete(&isis->area_list);
+ dyn_cache_finish(isis);
XFREE(MTYPE_ISIS, isis);
}
@@ -402,7 +403,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
continue;
circuit = ifp->info;
- if (circuit)
+ if (circuit && strmatch(circuit->tag, area->area_tag))
isis_area_add_circuit(area, circuit);
}
}
@@ -715,6 +716,8 @@ void isis_vrf_init(void)
{
vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable,
isis_vrf_delete, isis_vrf_enable);
+
+ vrf_cmd_init(NULL, &isisd_privs);
}
void isis_terminate()
@@ -1076,6 +1079,23 @@ DEFUN(show_isis_interface_arg,
vrf_name, all_vrf);
}
+static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
+{
+ struct isis_dynhn *dynhn;
+
+ memset(sysid, 0, ISIS_SYS_ID_LEN);
+ if (id) {
+ if (sysid2buff(sysid, id) == 0) {
+ dynhn = dynhn_find_by_name(isis, id);
+ if (dynhn == NULL)
+ return -1;
+ memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
+ }
+ }
+
+ return 0;
+}
+
static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
struct isis *isis, uint8_t *sysid)
{
@@ -1131,7 +1151,6 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
const char *vrf_name, bool all_vrf)
{
struct listnode *node;
- struct isis_dynhn *dynhn;
uint8_t sysid[ISIS_SYS_ID_LEN];
struct isis *isis;
@@ -1140,29 +1159,27 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
return CMD_SUCCESS;
}
- memset(sysid, 0, ISIS_SYS_ID_LEN);
- if (id) {
- if (sysid2buff(sysid, id) == 0) {
- dynhn = dynhn_find_by_name(id);
- if (dynhn == NULL) {
- vty_out(vty, "Invalid system id %s\n", id);
- return CMD_SUCCESS;
- }
- memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
- }
- }
-
if (vrf_name) {
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+ if (id_to_sysid(isis, id, sysid)) {
+ vty_out(vty, "Invalid system id %s\n",
+ id);
+ return CMD_SUCCESS;
+ }
isis_neighbor_common(vty, id, detail, isis,
sysid);
}
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
- if (isis != NULL)
+ if (isis != NULL) {
+ if (id_to_sysid(isis, id, sysid)) {
+ vty_out(vty, "Invalid system id %s\n", id);
+ return CMD_SUCCESS;
+ }
isis_neighbor_common(vty, id, detail, isis, sysid);
+ }
}
return CMD_SUCCESS;
@@ -1218,7 +1235,6 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
bool all_vrf)
{
struct listnode *node;
- struct isis_dynhn *dynhn;
uint8_t sysid[ISIS_SYS_ID_LEN];
struct isis *isis;
@@ -1227,27 +1243,27 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
return CMD_SUCCESS;
}
- memset(sysid, 0, ISIS_SYS_ID_LEN);
- if (id) {
- if (sysid2buff(sysid, id) == 0) {
- dynhn = dynhn_find_by_name(id);
- if (dynhn == NULL) {
- vty_out(vty, "Invalid system id %s\n", id);
- return CMD_SUCCESS;
- }
- memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
- }
- }
if (vrf_name) {
if (all_vrf) {
- for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+ if (id_to_sysid(isis, id, sysid)) {
+ vty_out(vty, "Invalid system id %s\n",
+ id);
+ return CMD_SUCCESS;
+ }
isis_neighbor_common_clear(vty, id, sysid,
isis);
+ }
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
- if (isis != NULL)
+ if (isis != NULL) {
+ if (id_to_sysid(isis, id, sysid)) {
+ vty_out(vty, "Invalid system id %s\n", id);
+ return CMD_SUCCESS;
+ }
isis_neighbor_common_clear(vty, id, sysid, isis);
+ }
}
return CMD_SUCCESS;
@@ -2204,7 +2220,7 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
*/
if (sysid2buff(lspid, sysid)) {
lsp = lsp_search(head, lspid);
- } else if ((dynhn = dynhn_find_by_name(sysid))) {
+ } else if ((dynhn = dynhn_find_by_name(isis, sysid))) {
memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN);
lsp = lsp_search(head, lspid);
} else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) {
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 9d0b57e9f6..b2c9af55b7 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -95,6 +95,7 @@ struct isis {
struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
int snmp_notifications;
+ struct list *dyn_cache;
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
};
diff --git a/lib/bitfield.h b/lib/bitfield.h
index 244938933b..a3f361ed9d 100644
--- a/lib/bitfield.h
+++ b/lib/bitfield.h
@@ -60,6 +60,8 @@ typedef unsigned int word_t;
*/
typedef struct {word_t *data; size_t n, m; } bitfield_t;
+DECLARE_MTYPE(BITFIELD);
+
/**
* Initialize the bits.
* @v: an instance of bitfield_t struct.
@@ -70,7 +72,7 @@ typedef struct {word_t *data; size_t n, m; } bitfield_t;
do { \
(v).n = 0; \
(v).m = ((N) / WORD_SIZE + 1); \
- (v).data = calloc(1, ((v).m * sizeof(word_t))); \
+ (v).data = XCALLOC(MTYPE_BITFIELD, ((v).m * sizeof(word_t))); \
} while (0)
/**
@@ -193,7 +195,7 @@ static inline unsigned int bf_find_next_set_bit(bitfield_t v,
*/
#define bf_free(v) \
do { \
- free((v).data); \
+ XFREE(MTYPE_BITFIELD, (v).data); \
(v).data = NULL; \
} while (0)
diff --git a/lib/compiler.h b/lib/compiler.h
index bbfe01b569..e805eb8be4 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -123,15 +123,6 @@ extern "C" {
#define assume(x)
#endif
-/* pure = function does not modify memory & return value is the same if
- * memory hasn't changed (=> allows compiler to optimize)
- *
- * Mostly autodetected by the compiler if function body is available (i.e.
- * static inline functions in headers). Since that implies it should only be
- * used in headers for non-inline functions, the "extern" is included here.
- */
-#define ext_pure extern __attribute__((pure))
-
/* for helper functions defined inside macros */
#define macro_inline static inline __attribute__((unused))
#define macro_pure static inline __attribute__((unused, pure))
diff --git a/lib/if.c b/lib/if.c
index b3803141df..e37b4f55b0 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -266,20 +266,23 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
char oldpath[XPATH_MAXLEN];
char newpath[XPATH_MAXLEN];
- if_dnode = yang_dnode_getf(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
- ifp->name, old_vrf->name);
+ snprintf(oldpath, sizeof(oldpath),
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, old_vrf->name);
+ snprintf(newpath, sizeof(newpath),
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+
+ if_dnode = yang_dnode_getf(running_config->dnode, "%s/vrf",
+ oldpath);
if (if_dnode) {
- yang_dnode_get_path(lyd_parent(if_dnode), oldpath,
- sizeof(oldpath));
yang_dnode_change_leaf(if_dnode, vrf->name);
- yang_dnode_get_path(lyd_parent(if_dnode), newpath,
- sizeof(newpath));
nb_running_move_tree(oldpath, newpath);
running_config->version++;
}
+
+ vty_update_xpath(oldpath, newpath);
}
}
diff --git a/lib/link_state.c b/lib/link_state.c
index afeb89c592..e8a6b89f89 100644
--- a/lib/link_state.c
+++ b/lib/link_state.c
@@ -79,7 +79,6 @@ void ls_node_del(struct ls_node *node)
return;
XFREE(MTYPE_LS_DB, node);
- node = NULL;
}
int ls_node_same(struct ls_node *n1, struct ls_node *n2)
@@ -168,7 +167,6 @@ void ls_attributes_del(struct ls_attributes *attr)
ls_attributes_srlg_del(attr);
XFREE(MTYPE_LS_DB, attr);
- attr = NULL;
}
int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
@@ -221,7 +219,6 @@ void ls_prefix_del(struct ls_prefix *pref)
return;
XFREE(MTYPE_LS_DB, pref);
- pref = NULL;
}
int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2)
@@ -839,7 +836,6 @@ void ls_ted_del(struct ls_ted *ted)
subnets_fini(&ted->subnets);
XFREE(MTYPE_LS_DB, ted);
- ted = NULL;
}
void ls_ted_del_all(struct ls_ted *ted)
diff --git a/lib/memory.c b/lib/memory.c
index 0dc8e90524..18811777ae 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -36,6 +36,7 @@ struct memgroup **mg_insert = &mg_first;
DEFINE_MGROUP(LIB, "libfrr");
DEFINE_MTYPE(LIB, TMP, "Temporary memory");
+DEFINE_MTYPE(LIB, BITFIELD, "Bitfield memory");
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
diff --git a/lib/northbound.c b/lib/northbound.c
index 47af770189..6edd5184ef 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -696,14 +696,14 @@ int nb_candidate_edit(struct nb_config *candidate,
NULL, LYD_NEW_PATH_UPDATE,
&dep_dnode);
/* Create default nodes */
- if (!err)
+ if (!err && dep_dnode)
err = lyd_new_implicit_tree(
dep_dnode,
LYD_IMPLICIT_NO_STATE, NULL);
if (err) {
flog_warn(
EC_LIB_LIBYANG,
- "%s: lyd_new_path(%s) failed: %d",
+ "%s: dependency: lyd_new_path(%s) failed: %d",
__func__, dep_xpath, err);
return NB_ERR;
}
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 807d1252c4..71f07dfe86 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -1222,7 +1222,7 @@ void HandleUnaryExecute(
frr::NAME##Response>( \
(cdb), &frr::Northbound::AsyncService::Request##NAME, \
&HandleUnary##NAME, #NAME); \
- _rpcState->do_request(service, _cq); \
+ _rpcState->do_request(service, s_cq); \
} while (0)
#define REQUEST_NEWRPC_STREAMING(NAME, cdb) \
@@ -1231,7 +1231,7 @@ void HandleUnaryExecute(
frr::NAME##Response>( \
(cdb), &frr::Northbound::AsyncService::Request##NAME, \
&HandleStreaming##NAME, #NAME); \
- _rpcState->do_request(service, _cq); \
+ _rpcState->do_request(service, s_cq); \
} while (0)
struct grpc_pthread_attr {
@@ -1239,6 +1239,10 @@ struct grpc_pthread_attr {
unsigned long port;
};
+// Capture these objects so we can try to shut down cleanly
+static std::unique_ptr<grpc::Server> s_server;
+static grpc::ServerCompletionQueue *s_cq;
+
static void *grpc_pthread_start(void *arg)
{
struct frr_pthread *fpt = static_cast<frr_pthread *>(arg);
@@ -1249,7 +1253,6 @@ static void *grpc_pthread_start(void *arg)
std::stringstream server_address;
frr::Northbound::AsyncService *service =
new frr::Northbound::AsyncService();
- grpc::ServerCompletionQueue *_cq;
frr_pthread_set_name(fpt);
@@ -1258,8 +1261,8 @@ static void *grpc_pthread_start(void *arg)
grpc::InsecureServerCredentials());
builder.RegisterService(service);
auto cq = builder.AddCompletionQueue();
- _cq = cq.get();
- auto server = builder.BuildAndStart();
+ s_cq = cq.get();
+ s_server = builder.BuildAndStart();
/* Schedule all RPC handlers */
REQUEST_NEWRPC(GetCapabilities, NULL);
@@ -1284,10 +1287,12 @@ static void *grpc_pthread_start(void *arg)
void *tag;
bool ok;
- _cq->Next(&tag, &ok);
+ s_cq->Next(&tag, &ok);
+ if (!ok)
+ break;
+
grpc_debug("%s: Got next from CompletionQueue, %p %d", __func__,
tag, ok);
- GPR_ASSERT(ok);
RpcStateBase *rpc = static_cast<RpcStateBase *>(tag);
CallState state = rpc->doCallback();
@@ -1302,10 +1307,9 @@ static void *grpc_pthread_start(void *arg)
* user indicating Finish() for cleanup.
*/
if (state == FINISH)
- rpc->do_request(service, _cq);
+ rpc->do_request(service, s_cq);
}
- /*NOTREACHED*/
return NULL;
}
@@ -1326,16 +1330,30 @@ static int frr_grpc_init(uint port)
__func__, safe_strerror(errno));
return -1;
}
- pthread_detach(fpt->thread);
return 0;
}
static int frr_grpc_finish(void)
{
- if (fpt)
+ // Shutdown the grpc server
+ if (s_server) {
+ s_server->Shutdown();
+ s_cq->Shutdown();
+
+ // And drain the queue
+ void *ignore;
+ bool ok;
+
+ while (s_cq->Next(&ignore, &ok))
+ ;
+ }
+
+ if (fpt) {
+ pthread_join(fpt->thread, NULL);
frr_pthread_destroy(fpt);
- // TODO: cancel the gRPC pthreads gracefully.
+ }
+
return 0;
}
diff --git a/lib/srv6.c b/lib/srv6.c
index ceb769ef76..ccb94b2f76 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -129,6 +129,8 @@ struct srv6_locator *srv6_locator_alloc(const char *name)
locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator));
strlcpy(locator->name, name, sizeof(locator->name));
locator->chunks = list_new();
+ locator->chunks->del = (void (*)(void *))srv6_locator_chunk_free;
+
QOBJ_REG(locator, srv6_locator);
return locator;
}
@@ -144,7 +146,12 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void)
void srv6_locator_free(struct srv6_locator *locator)
{
- XFREE(MTYPE_SRV6_LOCATOR, locator);
+ if (locator) {
+ QOBJ_UNREG(locator);
+ list_delete(&locator->chunks);
+
+ XFREE(MTYPE_SRV6_LOCATOR, locator);
+ }
}
void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk)
diff --git a/lib/table.h b/lib/table.h
index 7e383dce80..5dec69ee7e 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -197,29 +197,25 @@ static inline void route_table_set_info(struct route_table *table, void *d)
table->info = d;
}
-/* ext_pure => extern __attribute__((pure))
- * does not modify memory (but depends on mem), allows compiler to optimize
- */
-
extern void route_table_finish(struct route_table *table);
-ext_pure struct route_node *route_top(struct route_table *table);
-ext_pure struct route_node *route_next(struct route_node *node);
-ext_pure struct route_node *route_next_until(struct route_node *node,
- const struct route_node *limit);
+extern struct route_node *route_top(struct route_table *table);
+extern struct route_node *route_next(struct route_node *node);
+extern struct route_node *route_next_until(struct route_node *node,
+ const struct route_node *limit);
extern struct route_node *route_node_get(struct route_table *table,
union prefixconstptr pu);
-ext_pure struct route_node *route_node_lookup(struct route_table *table,
- union prefixconstptr pu);
-ext_pure struct route_node *route_node_lookup_maynull(struct route_table *table,
- union prefixconstptr pu);
-ext_pure struct route_node *route_node_match(struct route_table *table,
- union prefixconstptr pu);
-ext_pure struct route_node *route_node_match_ipv4(struct route_table *table,
- const struct in_addr *addr);
-ext_pure struct route_node *route_node_match_ipv6(struct route_table *table,
- const struct in6_addr *addr);
-
-ext_pure unsigned long route_table_count(struct route_table *table);
+extern struct route_node *route_node_lookup(struct route_table *table,
+ union prefixconstptr pu);
+extern struct route_node *route_node_lookup_maynull(struct route_table *table,
+ union prefixconstptr pu);
+extern struct route_node *route_node_match(struct route_table *table,
+ union prefixconstptr pu);
+extern struct route_node *route_node_match_ipv4(struct route_table *table,
+ const struct in_addr *addr);
+extern struct route_node *route_node_match_ipv6(struct route_table *table,
+ const struct in6_addr *addr);
+
+extern unsigned long route_table_count(struct route_table *table);
extern struct route_node *route_node_create(route_table_delegate_t *delegate,
struct route_table *table);
@@ -228,10 +224,10 @@ extern void route_node_destroy(route_table_delegate_t *delegate,
struct route_table *table,
struct route_node *node);
-ext_pure struct route_node *route_table_get_next(struct route_table *table,
- union prefixconstptr pu);
-ext_pure int route_table_prefix_iter_cmp(const struct prefix *p1,
- const struct prefix *p2);
+extern struct route_node *route_table_get_next(struct route_table *table,
+ union prefixconstptr pu);
+extern int route_table_prefix_iter_cmp(const struct prefix *p1,
+ const struct prefix *p2);
/*
* Iterator functions.
diff --git a/lib/vrf.c b/lib/vrf.c
index de29f45f8f..03d9a62c0f 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -582,29 +582,38 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
cmd_variable_handler_register(vrf_var_handlers);
}
+static void vrf_terminate_single(struct vrf *vrf)
+{
+ /* Clear configured flag and invoke delete. */
+ UNSET_FLAG(vrf->status, VRF_CONFIGURED);
+ vrf_delete(vrf);
+}
+
/* Terminate VRF module. */
void vrf_terminate(void)
{
- struct vrf *vrf;
+ struct vrf *vrf, *tmp;
if (debug_vrf)
zlog_debug("%s: Shutting down vrf subsystem", __func__);
- while (!RB_EMPTY(vrf_id_head, &vrfs_by_id)) {
- vrf = RB_ROOT(vrf_id_head, &vrfs_by_id);
+ RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) {
+ if (vrf->vrf_id == VRF_DEFAULT)
+ continue;
- /* Clear configured flag and invoke delete. */
- UNSET_FLAG(vrf->status, VRF_CONFIGURED);
- vrf_delete(vrf);
+ vrf_terminate_single(vrf);
}
- while (!RB_EMPTY(vrf_name_head, &vrfs_by_name)) {
- vrf = RB_ROOT(vrf_name_head, &vrfs_by_name);
+ RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) {
+ if (vrf->vrf_id == VRF_DEFAULT)
+ continue;
- /* Clear configured flag and invoke delete. */
- UNSET_FLAG(vrf->status, VRF_CONFIGURED);
- vrf_delete(vrf);
+ vrf_terminate_single(vrf);
}
+
+ /* Finally terminate default VRF */
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ vrf_terminate_single(vrf);
}
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
@@ -818,10 +827,24 @@ DEFUN_YANG (no_vrf,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
+ /*
+ * Remove the VRF interface config. Currently, we allow to
+ * remove only inactive VRFs, so we use VRF_DEFAULT_NAME here,
+ * because when the VRF is removed from kernel, the interface
+ * is moved to the default VRF. If we ever allow removing
+ * active VRFs, this code have to be updated accordingly.
+ */
+ snprintf(xpath_list, sizeof(xpath_list),
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ vrfname, VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL);
+ }
+
snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname);
nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, xpath_list);
+ return nb_cli_apply_changes(vty, NULL);
}
diff --git a/lib/vty.c b/lib/vty.c
index 6853fc3301..50d116c564 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -82,6 +82,9 @@ extern struct host host;
/* Vector which store each vty structure. */
static vector vtyvec;
+/* Vector for vtysh connections. */
+static vector vtyshvec;
+
/* Vty timeout value. */
static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
@@ -2038,6 +2041,7 @@ static int vtysh_accept(struct thread *thread)
vty->wfd = sock;
vty->type = VTY_SHELL_SERV;
vty->node = VIEW_NODE;
+ vector_set_index(vtyshvec, sock, vty);
vty_event(VTYSH_READ, vty);
@@ -2211,8 +2215,12 @@ void vty_close(struct vty *vty)
}
/* Unset vector. */
- if (vty->fd != -1)
- vector_unset(vtyvec, vty->fd);
+ if (vty->fd != -1) {
+ if (vty->type == VTY_SHELL_SERV)
+ vector_unset(vtyshvec, vty->fd);
+ else
+ vector_unset(vtyvec, vty->fd);
+ }
if (vty->wfd > 0 && vty->type == VTY_FILE)
fsync(vty->wfd);
@@ -2571,6 +2579,41 @@ void vty_log_fixed(char *buf, size_t len)
}
}
+static void update_xpath(struct vty *vty, const char *oldpath,
+ const char *newpath)
+{
+ int i;
+
+ for (i = 0; i < vty->xpath_index; i++) {
+ if (!frrstr_startswith(vty->xpath[i], oldpath))
+ break;
+
+ char *tmp = frrstr_replace(vty->xpath[i], oldpath, newpath);
+ strlcpy(vty->xpath[i], tmp, sizeof(vty->xpath[0]));
+ XFREE(MTYPE_TMP, tmp);
+ }
+}
+
+void vty_update_xpath(const char *oldpath, const char *newpath)
+{
+ struct vty *vty;
+ unsigned int i;
+
+ for (i = 0; i < vector_active(vtyshvec); i++) {
+ if ((vty = vector_slot(vtyshvec, i)) == NULL)
+ continue;
+
+ update_xpath(vty, oldpath, newpath);
+ }
+
+ for (i = 0; i < vector_active(vtyvec); i++) {
+ if ((vty = vector_slot(vtyvec, i)) == NULL)
+ continue;
+
+ update_xpath(vty, oldpath, newpath);
+ }
+}
+
int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
{
if (exclusive && nb_running_lock(NB_CLIENT_CLI, vty)) {
@@ -3114,6 +3157,7 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging)
vty_save_cwd();
vtyvec = vector_init(VECTOR_MIN_SIZE);
+ vtyshvec = vector_init(VECTOR_MIN_SIZE);
vty_master = master_thread;
@@ -3165,4 +3209,8 @@ void vty_terminate(void)
vtyvec = NULL;
Vvty_serv_thread = NULL;
}
+ if (vtyshvec) {
+ vector_free(vtyshvec);
+ vtyshvec = NULL;
+ }
}
diff --git a/lib/vty.h b/lib/vty.h
index 10fbb16a47..70ec4fcd84 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -327,6 +327,7 @@ extern void vty_close(struct vty *);
extern char *vty_get_cwd(void);
extern void vty_log(const char *level, const char *proto, const char *msg,
struct timestamp_control *);
+extern void vty_update_xpath(const char *oldpath, const char *newpath);
extern int vty_config_enter(struct vty *vty, bool private_config,
bool exclusive);
extern void vty_config_exit(struct vty *);
diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c
index c2111a7706..54b7850207 100644
--- a/nhrpd/nhrp_main.c
+++ b/nhrpd/nhrp_main.c
@@ -118,6 +118,7 @@ static struct quagga_signal_t sighandlers[] = {
static const struct frr_yang_module_info *const nhrpd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
+ &frr_vrf_info,
};
FRR_DAEMON_INFO(nhrpd, NHRP, .vty_port = NHRP_VTY_PORT,
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 420ea12ec1..963fa4d995 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -1260,6 +1260,8 @@ void nhrp_config_init(void)
install_element(CONFIG_NODE, &nhrp_multicast_nflog_group_cmd);
install_element(CONFIG_NODE, &no_nhrp_multicast_nflog_group_cmd);
+ vrf_cmd_init(NULL, &nhrpd_privs);
+
/* interface specific commands */
install_node(&nhrp_interface_node);
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index a43118cb21..f289bf26b9 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -53,7 +53,7 @@
unsigned char conf_debug_ospf6_abr;
-int ospf6_is_router_abr(struct ospf6 *o)
+bool ospf6_check_and_set_router_abr(struct ospf6 *o)
{
struct listnode *node;
struct ospf6_area *oa;
@@ -74,12 +74,12 @@ int ospf6_is_router_abr(struct ospf6 *o)
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__);
SET_FLAG(o->flag, OSPF6_FLAG_ABR);
- return 1;
+ return true;
} else {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
- return 0;
+ return false;
}
}
@@ -1359,7 +1359,7 @@ void ospf6_abr_reexport(struct ospf6_area *oa)
struct ospf6_route *route;
/* if not a ABR return success */
- if (!ospf6_is_router_abr(oa->ospf6))
+ if (!ospf6_check_and_set_router_abr(oa->ospf6))
return;
/* Redo summaries if required */
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
index 7c1ff4d389..a5f0f124b9 100644
--- a/ospf6d/ospf6_abr.h
+++ b/ospf6d/ospf6_abr.h
@@ -58,7 +58,7 @@ struct ospf6_inter_router_lsa {
#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
#define IS_OSPF6_ABR(o) ((o)->flag & OSPF6_FLAG_ABR)
-extern int ospf6_is_router_abr(struct ospf6 *o);
+extern bool ospf6_check_and_set_router_abr(struct ospf6 *o);
extern void ospf6_abr_enable_area(struct ospf6_area *oa);
extern void ospf6_abr_disable_area(struct ospf6_area *oa);
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 92934d3764..355b8441bd 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -50,20 +50,28 @@
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
-/* Utility functions. */
-int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt)
+int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt)
{
char *ep;
- area_id->s_addr = htonl(strtoul(str, &ep, 10));
- if (*ep && !inet_aton(str, area_id))
+ *area_id = htonl(strtoul(str, &ep, 10));
+ if (*ep && inet_pton(AF_INET, str, area_id) != 1)
return -1;
- *area_id_fmt = *ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD;
+ *area_id_fmt =
+ !*ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD;
return 0;
}
+void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt)
+{
+ if (area_id_fmt == OSPF6_AREA_FMT_DECIMAL)
+ snprintf(buf, len, "%u", ntohl(area_id));
+ else
+ inet_ntop(AF_INET, &area_id, buf, len);
+}
+
int ospf6_area_cmp(void *va, void *vb)
{
struct ospf6_area *oa = (struct ospf6_area *)va;
@@ -538,7 +546,7 @@ DEFUN (area_range,
ospf6_route_add(range, oa->range_table);
}
- if (ospf6_is_router_abr(ospf6)) {
+ if (ospf6_check_and_set_router_abr(ospf6)) {
/* Redo summaries if required */
ospf6_abr_prefix_resummarize(ospf6);
}
@@ -584,7 +592,7 @@ DEFUN (no_area_range,
return CMD_SUCCESS;
}
- if (ospf6_is_router_abr(oa->ospf6)) {
+ if (ospf6_check_and_set_router_abr(oa->ospf6)) {
/* Blow away the aggregated LSA and route */
SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE);
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index fa761d732d..dd4d019015 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -31,6 +31,7 @@ struct ospf6_area {
/* Area-ID */
in_addr_t area_id;
+#define OSPF6_AREA_FMT_UNSET 0
#define OSPF6_AREA_FMT_DOTTEDQUAD 1
#define OSPF6_AREA_FMT_DECIMAL 2
/* Area-ID string */
@@ -130,20 +131,22 @@ struct ospf6_area {
#define OSPF6_CMD_AREA_GET(str, oa, ospf6) \
{ \
- char *ep; \
- uint32_t area_id = htonl(strtoul(str, &ep, 10)); \
- if (*ep && inet_pton(AF_INET, str, &area_id) != 1) { \
+ uint32_t area_id; \
+ int format, ret; \
+ ret = str2area_id(str, &area_id, &format); \
+ if (ret) { \
vty_out(vty, "Malformed Area-ID: %s\n", str); \
- return CMD_SUCCESS; \
+ return CMD_WARNING; \
} \
- int format = !*ep ? OSPF6_AREA_FMT_DECIMAL \
- : OSPF6_AREA_FMT_DOTTEDQUAD; \
oa = ospf6_area_lookup(area_id, ospf6); \
if (oa == NULL) \
oa = ospf6_area_create(area_id, ospf6, format); \
}
/* prototypes */
+extern int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt);
+extern void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt);
+
extern int ospf6_area_cmp(void *va, void *vb);
extern struct ospf6_area *ospf6_area_create(uint32_t, struct ospf6 *, int);
@@ -163,6 +166,5 @@ extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
extern void ospf6_area_init(void);
struct ospf6_interface;
extern void ospf6_area_interface_delete(struct ospf6_interface *oi);
-int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt);
#endif /* OSPF_AREA_H */
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index e22e6560d0..c17af758b0 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -687,7 +687,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
zlog_debug("%s: Withdraw AS-External route for %s",
__func__, lsa->name);
- if (ospf6_is_router_abr(ospf6))
+ if (ospf6_check_and_set_router_abr(ospf6))
oa = ospf6->backbone;
else
oa = listgetdata(listhead(ospf6->area_list));
@@ -1174,6 +1174,8 @@ static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
red->instance = instance;
+ red->dmetric.type = -1;
+ red->dmetric.value = -1;
ROUTEMAP_NAME(red) = NULL;
ROUTEMAP(red) = NULL;
@@ -1376,8 +1378,13 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
if (troute.path.metric_type)
match->path.metric_type =
troute.path.metric_type;
+ else
+ match->path.metric_type =
+ metric_type(ospf6, type, 0);
if (troute.path.cost)
match->path.cost = troute.path.cost;
+ else
+ match->path.cost = metric_value(ospf6, type, 0);
if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
memcpy(&info->forwarding, &tinfo.forwarding,
sizeof(struct in6_addr));
@@ -1438,8 +1445,12 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
if (ROUTEMAP(red)) {
if (troute.path.metric_type)
route->path.metric_type = troute.path.metric_type;
+ else
+ route->path.metric_type = metric_type(ospf6, type, 0);
if (troute.path.cost)
route->path.cost = troute.path.cost;
+ else
+ route->path.cost = metric_value(ospf6, type, 0);
if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
memcpy(&info->forwarding, &tinfo.forwarding,
sizeof(struct in6_addr));
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index ac16e53d63..05b43189e9 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -811,6 +811,18 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
ismore_recent = 1;
assert(from);
+ /* if we receive a LSA with invalid seqnum drop it */
+ if (ntohl(lsa_header->seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) {
+ if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa_header->type)) {
+ zlog_debug(
+ "received lsa [%s Id:%pI4 Adv:%pI4] with invalid seqnum 0x%x, ignore",
+ ospf6_lstype_name(lsa_header->type),
+ &lsa_header->id, &lsa_header->adv_router,
+ ntohl(lsa_header->seqnum));
+ }
+ return;
+ }
+
/* make lsa structure for received lsa */
new = ospf6_lsa_create(lsa_header);
@@ -974,11 +986,12 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
/* if no database copy, should go above state (5) */
assert(old);
- if (is_debug) {
- zlog_debug(
- "Received is not newer, on the neighbor's request-list");
- zlog_debug("BadLSReq, discard the received LSA");
- }
+ zlog_warn(
+ "Received is not newer, on the neighbor %s request-list",
+ from->name);
+ zlog_warn(
+ "BadLSReq, discard the received LSA lsa %s send badLSReq",
+ new->name);
/* BadLSReq */
thread_add_event(master, bad_lsreq, from, 0, NULL);
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index b71d884fdc..6763e7457f 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -36,6 +36,7 @@
#include "ospf6_message.h"
#include "ospf6_route.h"
#include "ospf6_area.h"
+#include "ospf6_abr.h"
#include "ospf6_interface.h"
#include "ospf6_neighbor.h"
#include "ospf6_intra.h"
@@ -330,31 +331,6 @@ ospf6_interface_get_linklocal_address(struct interface *ifp)
return l;
}
-void ospf6_interface_if_add(struct interface *ifp)
-{
- struct ospf6_interface *oi;
- unsigned int iobuflen;
-
- oi = (struct ospf6_interface *)ifp->info;
- if (oi == NULL)
- return;
-
- /* Try to adjust I/O buffer size with IfMtu */
- if (oi->ifmtu == 0)
- oi->ifmtu = ifp->mtu6;
- iobuflen = ospf6_iobuf_size(ifp->mtu6);
- if (oi->ifmtu > iobuflen) {
- if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
- ifp->name, iobuflen);
- oi->ifmtu = iobuflen;
- }
-
- /* interface start */
- ospf6_interface_state_update(oi->interface);
-}
-
void ospf6_interface_state_update(struct interface *ifp)
{
struct ospf6_interface *oi;
@@ -725,20 +701,17 @@ int interface_up(struct thread *thread)
/* check physical interface is up */
if (!if_is_operative(oi->interface)) {
- if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "Interface %s is down, can't execute [InterfaceUp]",
- oi->interface->name);
+ zlog_warn("Interface %s is down, can't execute [InterfaceUp]",
+ oi->interface->name);
return 0;
}
/* check interface has a link-local address */
if (!(ospf6_interface_get_linklocal_address(oi->interface)
|| if_is_loopback_or_vrf(oi->interface))) {
- if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "Interface %s has no link local address, can't execute [InterfaceUp]",
- oi->interface->name);
+ zlog_warn(
+ "Interface %s has no link local address, can't execute [InterfaceUp]",
+ oi->interface->name);
return 0;
}
@@ -755,7 +728,7 @@ int interface_up(struct thread *thread)
/* If no area assigned, return */
if (oi->area == NULL) {
- zlog_debug(
+ zlog_warn(
"%s: Not scheduleing Hello for %s as there is no area assigned yet",
__func__, oi->interface->name);
return 0;
@@ -1638,7 +1611,143 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
return CMD_SUCCESS;
}
+void ospf6_interface_start(struct ospf6_interface *oi)
+{
+ struct ospf6 *ospf6;
+ struct ospf6_area *oa;
+
+ if (oi->area_id_format == OSPF6_AREA_FMT_UNSET)
+ return;
+
+ ospf6 = ospf6_lookup_by_vrf_id(oi->interface->vrf_id);
+ if (!ospf6)
+ return;
+
+ oa = ospf6_area_lookup(oi->area_id, ospf6);
+ if (oa == NULL)
+ oa = ospf6_area_create(oi->area_id, ospf6, oi->area_id_format);
+
+ /* attach interface to area */
+ listnode_add(oa->if_list, oi);
+ oi->area = oa;
+
+ SET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
+
+ /* start up */
+ ospf6_interface_enable(oi);
+
+ /* If the router is ABR, originate summary routes */
+ if (ospf6_check_and_set_router_abr(ospf6))
+ ospf6_abr_enable_area(oa);
+}
+
+void ospf6_interface_stop(struct ospf6_interface *oi)
+{
+ struct ospf6_area *oa;
+
+ oa = oi->area;
+ if (!oa)
+ return;
+
+ ospf6_interface_disable(oi);
+
+ listnode_delete(oa->if_list, oi);
+ oi->area = NULL;
+
+ if (oa->if_list->count == 0) {
+ UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
+ ospf6_abr_disable_area(oa);
+ }
+}
+
/* interface variable set command */
+DEFUN (ipv6_ospf6_area,
+ ipv6_ospf6_area_cmd,
+ "ipv6 ospf6 area <A.B.C.D|(0-4294967295)>",
+ IP6_STR
+ OSPF6_STR
+ "Specify the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "OSPF6 area ID in decimal notation\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi;
+ int idx_ipv4 = 3;
+ uint32_t area_id;
+ int format;
+ int ipv6_count = 0;
+
+ assert(ifp);
+
+ oi = (struct ospf6_interface *)ifp->info;
+ if (oi == NULL)
+ oi = ospf6_interface_create(ifp);
+ assert(oi);
+
+ if (oi->area) {
+ vty_out(vty, "%s already attached to Area %s\n",
+ oi->interface->name, oi->area->name);
+ return CMD_SUCCESS;
+ }
+
+ /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface
+ * then don't allow ospfv3 to be configured
+ */
+ ipv6_count = connected_count_by_family(ifp, AF_INET6);
+ if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) {
+ vty_out(vty,
+ "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
+ ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count);
+ return CMD_WARNING_CONFIG_FAILED;
+ } else if (oi->ifmtu >= OSPF6_JUMBO_MTU
+ && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) {
+ vty_out(vty,
+ "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
+ ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
+ vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ oi->area_id = area_id;
+ oi->area_id_format = format;
+
+ ospf6_interface_start(oi);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_area,
+ no_ipv6_ospf6_area_cmd,
+ "no ipv6 ospf6 area [<A.B.C.D|(0-4294967295)>]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Specify the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "OSPF6 area ID in decimal notation\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi;
+
+ assert(ifp);
+
+ oi = (struct ospf6_interface *)ifp->info;
+ if (oi == NULL)
+ oi = ospf6_interface_create(ifp);
+ assert(oi);
+
+ ospf6_interface_stop(oi);
+
+ oi->area_id = 0;
+ oi->area_id_format = OSPF6_AREA_FMT_UNSET;
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ipv6_ospf6_ifmtu,
ipv6_ospf6_ifmtu_cmd,
"ipv6 ospf6 ifmtu (1-65535)",
@@ -2334,6 +2443,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
{
struct ospf6_interface *oi;
struct interface *ifp;
+ char buf[INET_ADDRSTRLEN];
FOR_ALL_INTERFACES (vrf, ifp) {
oi = (struct ospf6_interface *)ifp->info;
@@ -2348,6 +2458,11 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
+ if (oi->area_id_format != OSPF6_AREA_FMT_UNSET) {
+ area_id2str(buf, sizeof(buf), oi->area_id,
+ oi->area_id_format);
+ vty_out(vty, " ipv6 ospf6 area %s\n", buf);
+ }
if (oi->c_ifmtu)
vty_out(vty, " ipv6 ospf6 ifmtu %d\n", oi->c_ifmtu);
@@ -2427,7 +2542,9 @@ static int ospf6_ifp_create(struct interface *ifp)
if (IS_OSPF6_DEBUG_ZEBRA(RECV))
zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu6);
- ospf6_interface_if_add(ifp);
+
+ if (ifp->info)
+ ospf6_interface_start(ifp->info);
return 0;
}
@@ -2468,6 +2585,9 @@ static int ospf6_ifp_destroy(struct interface *ifp)
zlog_debug("Zebra Interface delete: %s index %d mtu %d",
ifp->name, ifp->ifindex, ifp->mtu6);
+ if (ifp->info)
+ ospf6_interface_stop(ifp->info);
+
return 0;
}
@@ -2485,6 +2605,8 @@ void ospf6_interface_init(void)
&show_ipv6_ospf6_interface_ifname_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_cmd);
+ install_element(INTERFACE_NODE, &ipv6_ospf6_area_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_area_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd);
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index fb1b947cf8..796d75e897 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -39,6 +39,9 @@ struct ospf6_interface {
/* back pointer */
struct ospf6_area *area;
+ uint32_t area_id;
+ int area_id_format;
+
/* list of ospf6 neighbor */
struct list *neighbor_list;
@@ -177,6 +180,9 @@ extern const char *const ospf6_interface_state_str[];
/* Function Prototypes */
+extern void ospf6_interface_start(struct ospf6_interface *oi);
+extern void ospf6_interface_stop(struct ospf6_interface *oi);
+
extern struct ospf6_interface *
ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);
extern struct ospf6_interface *ospf6_interface_create(struct interface *);
@@ -185,7 +191,6 @@ extern void ospf6_interface_delete(struct ospf6_interface *);
extern void ospf6_interface_enable(struct ospf6_interface *);
extern void ospf6_interface_disable(struct ospf6_interface *);
-extern void ospf6_interface_if_add(struct interface *);
extern void ospf6_interface_state_update(struct interface *);
extern void ospf6_interface_connected_route_update(struct interface *);
extern void ospf6_interface_connected_route_add(struct connected *);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 524edd3fae..c971c6180e 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -182,7 +182,7 @@ static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
OSPF6_OPT_CLEAR_ALL(router_lsa->options);
memcpy(router_lsa->options, oa->options, 3);
- if (ospf6_is_router_abr(oa->ospf6))
+ if (ospf6_check_and_set_router_abr(oa->ospf6))
SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
else
UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
@@ -289,9 +289,8 @@ int ospf6_router_lsa_originate(struct thread *thread)
if ((caddr_t)lsdesc
== (caddr_t)router_lsa
+ sizeof(struct ospf6_router_lsa)) {
- if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
- zlog_debug(
- "Size limit setting for Router-LSA too short");
+ zlog_warn(
+ "Size limit setting for Router-LSA too short");
return 0;
}
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index a8f523295b..d627194252 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -654,6 +654,7 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
ospf6_lsa_age_current(lsa));
json_object_string_add(json_obj, "type",
ospf6_lstype_name(lsa->header->type));
+ json_object_string_add(json_obj, "linkStateId", id);
json_object_string_add(json_obj, "advertisingRouter",
adv_router);
json_object_int_add(json_obj, "lsSequenceNumber",
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 9a1d8b79bc..1cf4585c95 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -442,34 +442,34 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Master/Slave bit mismatch");
+ zlog_warn(
+ "DbDesc recv: Master/Slave bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Initialize bit mismatch");
+ zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Option field mismatch");
+ zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug(
- "Sequence number mismatch (%#lx expected)",
- (unsigned long)on->dbdesc_seqnum);
+ zlog_warn(
+ "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)",
+ on->name, (unsigned long)on->dbdesc_seqnum);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
@@ -488,9 +488,9 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Not duplicate dbdesc in state %s",
- ospf6_neighbor_state_str[on->state]);
+ zlog_warn(
+ "DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
+ ospf6_neighbor_state_str[on->state], on->name);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
return;
@@ -663,34 +663,36 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
}
if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Master/Slave bit mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Initialize bit mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Initialize bit mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Option field mismatch");
+ zlog_warn(
+ "DbDesc slave recv: Option field mismatch Nbr %s",
+ on->name);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug(
- "Sequence number mismatch (%#lx expected)",
- (unsigned long)on->dbdesc_seqnum + 1);
+ zlog_warn(
+ "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)",
+ on->name, (unsigned long)on->dbdesc_seqnum + 1);
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
return;
@@ -712,9 +714,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
- zlog_debug("Not duplicate dbdesc in state %s",
- ospf6_neighbor_state_str[on->state]);
+ zlog_warn(
+ "DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
+ ospf6_neighbor_state_str[on->state], on->name);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
return;
@@ -888,12 +890,10 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
/* Find database copy */
lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb);
if (lsa == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) {
- zlog_debug(
- "Can't find requested [%s Id:%pI4 Adv:%pI4]",
- ospf6_lstype_name(e->type), &e->id,
- &e->adv_router);
- }
+ zlog_warn(
+ "Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
+ ospf6_lstype_name(e->type), &e->id,
+ &e->adv_router);
thread_add_event(master, bad_lsreq, on, 0, NULL);
return;
}
@@ -923,18 +923,14 @@ static unsigned ospf6_prefixes_examin(
while (length) {
if (length < OSPF6_PREFIX_MIN_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized IPv6 prefix header",
- __func__);
+ zlog_warn("%s: undersized IPv6 prefix header",
+ __func__);
return MSG_NG;
}
/* safe to look deeper */
if (current->prefix_length > IPV6_MAX_BITLEN) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid PrefixLength (%u bits)",
- __func__, current->prefix_length);
+ zlog_warn("%s: invalid PrefixLength (%u bits)",
+ __func__, current->prefix_length);
return MSG_NG;
}
/* covers both fixed- and variable-sized fields */
@@ -942,10 +938,7 @@ static unsigned ospf6_prefixes_examin(
OSPF6_PREFIX_MIN_SIZE
+ OSPF6_PREFIX_SPACE(current->prefix_length);
if (requested_pfx_bytes > length) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized IPv6 prefix",
- __func__);
+ zlog_warn("%s: undersized IPv6 prefix", __func__);
return MSG_NG;
}
/* next prefix */
@@ -955,11 +948,9 @@ static unsigned ospf6_prefixes_examin(
real_num_pfxs++;
}
if (real_num_pfxs != req_num_pfxs) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: IPv6 prefix number mismatch (%u required, %u real)",
- __func__, req_num_pfxs, real_num_pfxs);
+ zlog_warn(
+ "%s: IPv6 prefix number mismatch (%u required, %u real)",
+ __func__, req_num_pfxs, real_num_pfxs);
return MSG_NG;
}
return MSG_OK;
@@ -988,10 +979,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
&& lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA", __func__,
- lsalen);
+ zlog_warn("%s: undersized (%u B) LSA", __func__, lsalen);
return MSG_NG;
}
switch (lsatype) {
@@ -1001,11 +989,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
by N>=0 interface descriptions. */
if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
% OSPF6_ROUTER_LSDESC_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: interface description alignment error",
- __func__);
+ zlog_warn(
+ "%s: Router LSA interface description alignment error",
+ __func__);
return MSG_NG;
}
break;
@@ -1015,11 +1001,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
if ((lsalen - OSPF6_LSA_HEADER_SIZE
- OSPF6_NETWORK_LSA_MIN_SIZE)
% OSPF6_NETWORK_LSDESC_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: router description alignment error",
- __func__);
+ zlog_warn(
+ "%s: Network LSA router description alignment error",
+ __func__);
return MSG_NG;
}
break;
@@ -1040,10 +1024,8 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
/* RFC5340 A.4.6, fixed-size LSA. */
if (lsalen
> OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: oversized (%u B) LSA", __func__,
- lsalen);
+ zlog_warn("%s: Inter Router LSA oversized (%u B) LSA",
+ __func__, lsalen);
return MSG_NG;
}
break;
@@ -1069,10 +1051,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
IPv6
prefix before ospf6_prefix_examin() confirms its sizing. */
if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA header",
- __func__, lsalen);
+ zlog_warn(
+ "%s: AS External undersized (%u B) LSA header",
+ __func__, lsalen);
return MSG_NG;
}
/* forwarding address */
@@ -1088,10 +1069,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
I.e.,
this check does not include any IPv6 prefix fields. */
if (exp_length > lsalen) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) LSA header",
- __func__, lsalen);
+ zlog_warn(
+ "%s: AS External undersized (%u B) LSA header",
+ __func__, lsalen);
return MSG_NG;
}
/* The last call completely covers the remainder (IPv6 prefix).
@@ -1157,34 +1137,26 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
while (length) {
uint16_t lsalen;
if (length < OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: undersized (%zu B) trailing (#%u) LSA header",
- __func__, length, counted_lsas);
+ zlog_warn(
+ "%s: undersized (%zu B) trailing (#%u) LSA header",
+ __func__, length, counted_lsas);
return MSG_NG;
}
/* save on ntohs() calls here and in the LSA validator */
lsalen = OSPF6_LSA_SIZE(lsah);
if (lsalen < OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: malformed LSA header #%u, declared length is %u B",
- __func__, counted_lsas, lsalen);
+ zlog_warn(
+ "%s: malformed LSA header #%u, declared length is %u B",
+ __func__, counted_lsas, lsalen);
return MSG_NG;
}
if (headeronly) {
/* less checks here and in ospf6_lsa_examin() */
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in header-only %s LSA #%u",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas);
+ zlog_warn(
+ "%s: anomaly in header-only %s LSA #%u",
+ __func__, ospf6_lstype_name(lsah->type),
+ counted_lsas);
return MSG_NG;
}
lsah = (struct ospf6_lsa_header
@@ -1195,25 +1167,16 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
/* make sure the input buffer is deep enough before
* further checks */
if (lsalen > length) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas, lsalen, length);
+ zlog_warn(
+ "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
+ __func__, ospf6_lstype_name(lsah->type),
+ counted_lsas, lsalen, length);
return MSG_NG;
}
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
- if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: anomaly in %s LSA #%u",
- __func__,
- ospf6_lstype_name(lsah->type),
- counted_lsas);
+ zlog_warn("%s: anomaly in %s LSA #%u", __func__,
+ ospf6_lstype_name(lsah->type),
+ counted_lsas);
return MSG_NG;
}
lsah = (struct ospf6_lsa_header *)((caddr_t)lsah
@@ -1224,11 +1187,8 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
}
if (declared_num_lsas && counted_lsas != declared_num_lsas) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: #LSAs declared (%u) does not match actual (%u)",
- __func__, declared_num_lsas, counted_lsas);
+ zlog_warn("%s: #LSAs declared (%u) does not match actual (%u)",
+ __func__, declared_num_lsas, counted_lsas);
return MSG_NG;
}
return MSG_OK;
@@ -1243,41 +1203,31 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
/* length, 1st approximation */
if (bytesonwire < OSPF6_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) packet", __func__,
- bytesonwire);
+ zlog_warn("%s: undersized (%u B) packet", __func__,
+ bytesonwire);
return MSG_NG;
}
/* Now it is safe to access header fields. */
if (bytesonwire != ntohs(oh->length)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug(
- "%s: %s packet length error (%u real, %u declared)",
- __func__, lookup_msg(ospf6_message_type_str,
- oh->type, NULL),
- bytesonwire, ntohs(oh->length));
+ zlog_warn("%s: %s packet length error (%u real, %u declared)",
+ __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL),
+ bytesonwire, ntohs(oh->length));
return MSG_NG;
}
/* version check */
if (oh->version != OSPFV3_VERSION) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid (%u) protocol version",
- __func__, oh->version);
+ zlog_warn("%s: invalid (%u) protocol version", __func__,
+ oh->version);
return MSG_NG;
}
/* length, 2nd approximation */
if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
&& bytesonwire
< OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: undersized (%u B) %s packet", __func__,
- bytesonwire,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: undersized (%u B) %s packet", __func__,
+ bytesonwire,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
}
/* type-specific deeper validation */
@@ -1290,11 +1240,8 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
% 4)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: alignment error in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: alignment error in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
case OSPF6_MESSAGE_TYPE_DBDESC:
/* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes
@@ -1314,11 +1261,8 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
% OSPF6_LSREQ_LSDESC_FIX_SIZE)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: alignment error in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type,
- NULL));
+ zlog_warn("%s: alignment error in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return MSG_NG;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
/* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes
@@ -1343,16 +1287,12 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
1, 0);
break;
default:
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV_HDR))
- zlog_debug("%s: invalid (%u) message type", __func__,
- oh->type);
+ zlog_warn("%s: invalid (%u) message type", __func__, oh->type);
return MSG_NG;
}
- if (test != MSG_OK
- && IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV_HDR))
- zlog_debug("%s: anomaly in %s packet", __func__,
- lookup_msg(ospf6_message_type_str, oh->type, NULL));
+ if (test != MSG_OK)
+ zlog_warn("%s: anomaly in %s packet", __func__,
+ lookup_msg(ospf6_message_type_str, oh->type, NULL));
return test;
}
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 9323da8be3..a08ca904ea 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -145,6 +145,8 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
THREAD_OFF(on->inactivity_timer);
+ THREAD_OFF(on->last_dbdesc_release_timer);
+
THREAD_OFF(on->thread_send_dbdesc);
THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate);
@@ -350,6 +352,16 @@ int negotiation_done(struct thread *thread)
return 0;
}
+static int ospf6_neighbor_last_dbdesc_release(struct thread *thread)
+{
+ struct ospf6_neighbor *on = THREAD_ARG(thread);
+
+ assert(on);
+ memset(&on->dbdesc_last, 0, sizeof(struct ospf6_dbdesc));
+
+ return 0;
+}
+
int exchange_done(struct thread *thread)
{
struct ospf6_neighbor *on;
@@ -366,10 +378,13 @@ int exchange_done(struct thread *thread)
THREAD_OFF(on->thread_send_dbdesc);
ospf6_lsdb_remove_all(on->dbdesc_list);
- /* XXX
- thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on,
- on->ospf6_if->dead_interval);
- */
+ /* RFC 2328 (10.8): Release the last dbdesc after dead_interval */
+ if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) {
+ THREAD_OFF(on->last_dbdesc_release_timer);
+ thread_add_timer(master, ospf6_neighbor_last_dbdesc_release, on,
+ on->ospf6_if->dead_interval,
+ &on->last_dbdesc_release_timer);
+ }
if (on->request_list->count == 0)
ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on,
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index 47f8c834e2..85b8e4b8ae 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -89,6 +89,9 @@ struct ospf6_neighbor {
/* Inactivity timer */
struct thread *inactivity_timer;
+ /* Timer to release the last dbdesc packet */
+ struct thread *last_dbdesc_release_timer;
+
/* Thread for sending message */
struct thread *thread_send_dbdesc;
struct thread *thread_send_lsreq;
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index 4d9b0a1978..dfae51cec1 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -1093,7 +1093,7 @@ static int ospf6_abr_task_timer(struct thread *thread)
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("Running ABR task on timer");
- ospf6_is_router_abr(ospf6);
+ (void)ospf6_check_and_set_router_abr(ospf6);
ospf6_abr_nssa_check_status(ospf6);
ospf6_abr_task(ospf6);
/* if nssa-abr, then scan Type-7 LSDB */
@@ -1137,7 +1137,7 @@ static void ospf6_nssa_flush_area(struct ospf6_area *area)
SET_FLAG(lsa->flag, OSPF6_LSA_FLUSH);
ospf6_flood(NULL, lsa);
/* Flush the translated LSA */
- if (ospf6_is_router_abr(ospf6)) {
+ if (ospf6_check_and_set_router_abr(ospf6)) {
type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
type5 = ospf6_lsdb_lookup(
htons(type), lsa->external_lsa_id,
@@ -1158,7 +1158,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area)
struct ospf6_route *route;
if (IS_AREA_NSSA(area)) {
- if (!ospf6_is_router_abr(area->ospf6))
+ if (!ospf6_check_and_set_router_abr(area->ospf6))
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
area->ospf6->anyNSSA++;
OSPF6_OPT_SET(area->options, OSPF6_OPT_N);
@@ -1167,7 +1167,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area)
if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
zlog_debug("Normal area for if %s", area->name);
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_N);
- if (ospf6_is_router_abr(area->ospf6))
+ if (ospf6_check_and_set_router_abr(area->ospf6))
OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
area->ospf6->anyNSSA--;
area->NSSATranslatorState = OSPF6_NSSA_TRANSLATE_DISABLED;
@@ -1178,7 +1178,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area)
OSPF6_ROUTER_LSA_SCHEDULE(area);
/* Check if router is ABR */
- if (ospf6_is_router_abr(area->ospf6)) {
+ if (ospf6_check_and_set_router_abr(area->ospf6)) {
if (IS_OSPF6_DEBUG_NSSA)
zlog_debug("Router is ABR area %s", area->name);
ospf6_schedule_abr_task(area->ospf6);
@@ -1353,7 +1353,7 @@ void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
lsa->external_lsa_id, ospf6->router_id,
ospf6->lsdb);
- if (ospf6_is_router_abr(ospf6) && (type5 == NULL)) {
+ if (ospf6_check_and_set_router_abr(ospf6) && (type5 == NULL)) {
if (IS_OSPF6_DEBUG_NSSA)
zlog_debug("%s : Originating type5 LSA", __func__);
ospf6_lsa_translated_nssa_new(area, lsa);
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index dcf76c7038..92922567e8 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -664,9 +664,10 @@ static uint8_t *ospfv3GeneralGroup(struct variable *v, oid *name,
return SNMP_INTEGER(3);
case OSPFv3AREABDRRTRSTATUS:
if (ospf6)
- return SNMP_INTEGER(ospf6_is_router_abr(ospf6)
- ? SNMP_TRUE
- : SNMP_FALSE);
+ return SNMP_INTEGER(
+ ospf6_check_and_set_router_abr(ospf6)
+ ? SNMP_TRUE
+ : SNMP_FALSE);
return SNMP_INTEGER(SNMP_FALSE);
case OSPFv3ASBDRRTRSTATUS:
if (ospf6)
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index b0a8f01bcc..032484e288 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -284,9 +284,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (oi == NULL) {
- if (IS_OSPF6_DEBUG_SPF(PROCESS))
- zlog_debug("Can't find interface in SPF: ifindex %d",
- ifindex);
+ zlog_warn("Can't find interface in SPF: ifindex %d", ifindex);
return;
}
@@ -475,9 +473,7 @@ void ospf6_spf_calculation(uint32_t router_id,
/* construct root vertex */
lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
if (lsa == NULL) {
- if (IS_OSPF6_DEBUG_SPF(PROCESS))
- zlog_debug("%s: No router LSA for area %s", __func__,
- oa->name);
+ zlog_warn("%s: No router LSA for area %s", __func__, oa->name);
return;
}
@@ -605,7 +601,7 @@ static int ospf6_spf_calculation_thread(struct thread *t)
monotime(&start);
ospf6->ts_spf = start;
- if (ospf6_is_router_abr(ospf6))
+ if (ospf6_check_and_set_router_abr(ospf6))
ospf6_abr_range_reset_cost(ospf6);
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
@@ -645,7 +641,7 @@ static int ospf6_spf_calculation_thread(struct thread *t)
/* External LSA calculation */
ospf6_ase_calculate_timer_add(ospf6);
- if (ospf6_is_router_abr(ospf6))
+ if (ospf6_check_and_set_router_abr(ospf6))
ospf6_abr_defaults_to_stub(ospf6);
monotime(&end);
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 33b5dd1960..7e4604e987 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -232,6 +232,8 @@ void ospf6_vrf_init(void)
{
vrf_init(ospf6_vrf_new, ospf6_vrf_enable, ospf6_vrf_disable,
ospf6_vrf_delete, ospf6_vrf_enable);
+
+ vrf_cmd_init(NULL, &ospf6d_privs);
}
static void ospf6_top_lsdb_hook_add(struct ospf6_lsa *lsa)
@@ -268,6 +270,13 @@ static void ospf6_top_route_hook_add(struct ospf6_route *route)
else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
oa = (struct ospf6_area *)route->table->scope;
ospf6 = oa->ospf6;
+ } else {
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)
+ || IS_OSPF6_DEBUG_BROUTER)
+ zlog_debug(
+ "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX",
+ __func__, &route->prefix);
+ return;
}
ospf6_abr_originate_summary(route, ospf6);
@@ -284,6 +293,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
oa = (struct ospf6_area *)route->table->scope;
ospf6 = oa->ospf6;
+ } else {
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)
+ || IS_OSPF6_DEBUG_BROUTER)
+ zlog_debug(
+ "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX",
+ __func__, &route->prefix);
+ return;
}
route->flag |= OSPF6_ROUTE_REMOVE;
@@ -410,6 +426,8 @@ static struct ospf6 *ospf6_create(const char *name)
struct ospf6 *ospf6_instance_create(const char *name)
{
struct ospf6 *ospf6;
+ struct vrf *vrf;
+ struct interface *ifp;
ospf6 = ospf6_create(name);
if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
@@ -417,6 +435,13 @@ struct ospf6 *ospf6_instance_create(const char *name)
if (ospf6->router_id == 0)
ospf6_router_id_update(ospf6);
ospf6_add(ospf6);
+ if (ospf6->vrf_id != VRF_UNKNOWN) {
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (ifp->info)
+ ospf6_interface_start(ifp->info);
+ }
+ }
if (ospf6->fd < 0)
return ospf6;
@@ -867,7 +892,7 @@ DEFUN (no_ospf6_distance_ospf6,
return CMD_SUCCESS;
}
-DEFUN (ospf6_interface_area,
+DEFUN_HIDDEN (ospf6_interface_area,
ospf6_interface_area_cmd,
"interface IFNAME area <A.B.C.D|(0-4294967295)>",
"Enable routing on an IPv6 interface\n"
@@ -885,6 +910,13 @@ DEFUN (ospf6_interface_area,
struct interface *ifp;
vrf_id_t vrf_id = VRF_DEFAULT;
int ipv6_count = 0;
+ uint32_t area_id;
+ int format;
+
+ vty_out(vty,
+ "This command is deprecated, because it is not VRF-aware.\n");
+ vty_out(vty,
+ "Please, use \"ipv6 ospf6 area\" on an interface instead.\n");
if (ospf6->vrf_id != VRF_UNKNOWN)
vrf_id = ospf6->vrf_id;
@@ -917,8 +949,17 @@ DEFUN (ospf6_interface_area,
return CMD_WARNING_CONFIG_FAILED;
}
- /* parse Area-ID */
- OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa, ospf6);
+ if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
+ vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ oi->area_id = area_id;
+ oi->area_id_format = format;
+
+ oa = ospf6_area_lookup(area_id, ospf6);
+ if (oa == NULL)
+ oa = ospf6_area_create(area_id, ospf6, format);
/* attach interface to area */
listnode_add(oa->if_list, oi); /* sort ?? */
@@ -934,7 +975,7 @@ DEFUN (ospf6_interface_area,
ospf6_interface_enable(oi);
/* If the router is ABR, originate summary routes */
- if (ospf6_is_router_abr(ospf6)) {
+ if (ospf6_check_and_set_router_abr(ospf6)) {
ospf6_abr_enable_area(oa);
ospf6_schedule_abr_task(oa->ospf6);
}
@@ -942,7 +983,7 @@ DEFUN (ospf6_interface_area,
return CMD_SUCCESS;
}
-DEFUN (no_ospf6_interface_area,
+DEFUN_HIDDEN (no_ospf6_interface_area,
no_ospf6_interface_area_cmd,
"no interface IFNAME area <A.B.C.D|(0-4294967295)>",
NO_STR
@@ -962,6 +1003,11 @@ DEFUN (no_ospf6_interface_area,
uint32_t area_id;
vrf_id_t vrf_id = VRF_DEFAULT;
+ vty_out(vty,
+ "This command is deprecated, because it is not VRF-aware.\n");
+ vty_out(vty,
+ "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n");
+
if (ospf6->vrf_id != VRF_UNKNOWN)
vrf_id = ospf6->vrf_id;
@@ -1008,6 +1054,9 @@ DEFUN (no_ospf6_interface_area,
ospf6_abr_disable_area(oa);
}
+ oi->area_id = 0;
+ oi->area_id_format = OSPF6_AREA_FMT_UNSET;
+
return CMD_SUCCESS;
}
@@ -1585,9 +1634,6 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6)
/* OSPF configuration write function. */
static int config_write_ospf6(struct vty *vty)
{
- struct listnode *j, *k;
- struct ospf6_area *oa;
- struct ospf6_interface *oi;
struct ospf6 *ospf6;
struct listnode *node, *nnode;
@@ -1638,11 +1684,6 @@ static int config_write_ospf6(struct vty *vty)
ospf6_distance_config_write(vty, ospf6);
ospf6_distribute_config_write(vty, ospf6);
- for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, j, oa)) {
- for (ALL_LIST_ELEMENTS_RO(oa->if_list, k, oi))
- vty_out(vty, " interface %s area %s\n",
- oi->interface->name, oa->name);
- }
vty_out(vty, "!\n");
}
return 0;
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index bda00e0c9e..2fd195bb6d 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -508,7 +508,6 @@ static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn)
rn->info = NULL;
route_unlock_node(rn);
- route_unlock_node(rn);
}
struct ospf_external_aggr_rt *
@@ -1160,6 +1159,7 @@ int ospf_asbr_external_aggregator_unset(struct ospf *ospf,
rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
if (!rn)
return OSPF_INVALID;
+ route_unlock_node(rn);
aggr = rn->info;
@@ -1217,6 +1217,7 @@ int ospf_asbr_external_rt_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
if (!rn)
return OSPF_INVALID;
+ route_unlock_node(rn);
aggr = rn->info;
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 49829d86f1..c850df55bb 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2084,6 +2084,8 @@ void ospf_external_lsa_rid_change(struct ospf *ospf)
{
struct external_info *ei;
struct ospf_external_aggr_rt *aggr;
+ struct ospf_lsa *lsa = NULL;
+ int force;
int type;
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
@@ -2112,24 +2114,48 @@ void ospf_external_lsa_rid_change(struct ospf *ospf)
continue;
if (is_prefix_default(
- (struct prefix_ipv4 *)&ei->p))
+ (struct prefix_ipv4 *)&ei->p))
continue;
- if (!ospf_redistribute_check(ospf, ei, NULL))
- continue;
+ lsa = ospf_external_info_find_lsa(ospf, &ei->p);
aggr = ospf_external_aggr_match(ospf, &ei->p);
if (aggr) {
+
+ if (!ospf_redistribute_check(ospf, ei,
+ NULL))
+ continue;
+
if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
zlog_debug(
"Originate Summary LSA after reset/router-ID change");
+
/* Here the LSA is originated as new */
ospf_originate_summary_lsa(ospf, aggr,
ei);
- } else if (!ospf_external_lsa_originate(ospf,
- ei))
- flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
- "LSA: AS-external-LSA was not originated.");
+ } else if (lsa) {
+ /* LSA needs to be refreshed even if
+ * there is no change in the route
+ * params if the LSA is in maxage.
+ */
+ if (IS_LSA_MAXAGE(lsa))
+ force = LSA_REFRESH_FORCE;
+ else
+ force = LSA_REFRESH_IF_CHANGED;
+
+ ospf_external_lsa_refresh(ospf, lsa,
+ ei, force, 0);
+ } else {
+ if (!ospf_redistribute_check(ospf, ei,
+ NULL))
+ continue;
+
+ if (!ospf_external_lsa_originate(ospf,
+ NULL))
+ flog_warn(
+ EC_OSPF_LSA_INSTALL_FAILURE,
+ "LSA: AS-external-LSA was not originated.");
+ }
}
}
}
diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c
index a1b35b2fcd..8725497f2d 100644
--- a/ospfd/ospf_neighbor.c
+++ b/ospfd/ospf_neighbor.c
@@ -407,6 +407,9 @@ void ospf_renegotiate_optional_capabilities(struct ospf *top)
}
}
+ /* Refresh/Re-originate external LSAs (Type-7 and Type-5).*/
+ ospf_external_lsa_rid_change(top);
+
return;
}
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index d3b114840e..2525c1cf3a 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -71,19 +71,14 @@ static void ospf_route_map_update(const char *name)
/* Keep old route-map. */
struct route_map *old = ROUTEMAP(red);
- if (!old) {
- /* Route-map creation */
- /* Update route-map. */
- ROUTEMAP(red) =
- route_map_lookup_by_name(
- ROUTEMAP_NAME(red));
-
- route_map_counter_increment(
- ROUTEMAP(red));
- } else {
- /* Route-map deletion */
- ROUTEMAP(red) = NULL;
- }
+ ROUTEMAP(red) =
+ route_map_lookup_by_name(
+ ROUTEMAP_NAME(red));
+
+ if (!old)
+ route_map_counter_increment(
+ ROUTEMAP(red));
+
/* No update for this distribute type.
*/
if (old == NULL
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index cb64187d72..54ce248d89 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -12959,6 +12959,8 @@ void ospf_vty_init(void)
install_element(OSPF_NODE, &ospf_max_multipath_cmd);
install_element(OSPF_NODE, &no_ospf_max_multipath_cmd);
+ vrf_cmd_init(NULL, &ospfd_privs);
+
/* Init interface related vty commands. */
ospf_vty_if_init();
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index 1badaf95bd..7861559034 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -119,6 +119,7 @@ struct quagga_signal_t pbr_signals[] = {
static const struct frr_yang_module_info *const pbrd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
+ &frr_vrf_info,
};
FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT,
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 216834fe0c..3d56fc3daa 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -1143,10 +1143,14 @@ static const struct cmd_variable_handler pbr_map_name[] = {
}
};
+extern struct zebra_privs_t pbr_privs;
+
void pbr_vty_init(void)
{
cmd_variable_handler_register(pbr_map_name);
+ vrf_cmd_init(NULL, &pbr_privs);
+
install_node(&interface_node);
if_cmd_init();
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index f6072b1771..b3d4444652 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -3853,6 +3853,54 @@ static const char *pim_cli_get_vrf_name(struct vty *vty)
return yang_dnode_get_string(vrf_node, "./name");
}
+/**
+ * Compatibility function to keep the legacy mesh group CLI behavior:
+ * Delete group when there are no more configurations in it.
+ *
+ * NOTE:
+ * Don't forget to call `nb_cli_apply_changes` after this.
+ */
+static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
+ const char *gname)
+{
+ const char *vrfname;
+ char xpath_value[XPATH_MAXLEN];
+ char xpath_member_value[XPATH_MAXLEN];
+ const struct lyd_node *member_dnode;
+
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return;
+
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ /* Group must exists, otherwise just quit. */
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+ return;
+
+ /* Group members check: */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/members", sizeof(xpath_member_value));
+ if (yang_dnode_exists(vty->candidate_config->dnode,
+ xpath_member_value)) {
+ member_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ xpath_member_value);
+ if (!yang_is_last_list_dnode(member_dnode))
+ return;
+ }
+
+ /* Source address check: */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/source", sizeof(xpath_member_value));
+ if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value))
+ return;
+
+ /* No configurations found: delete it. */
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+}
+
DEFUN (clear_ip_interfaces,
clear_ip_interfaces_cmd,
"clear ip interfaces [vrf NAME]",
@@ -9685,305 +9733,199 @@ DEFUN (no_ip_msdp_peer,
return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (ip_msdp_mesh_group_member,
- ip_msdp_mesh_group_member_cmd,
- "ip msdp mesh-group WORD member A.B.C.D",
- IP_STR
- CFG_MSDP_STR
- "Configure MSDP mesh-group\n"
- "mesh group name\n"
- "mesh group member\n"
- "peer ip address\n")
+DEFPY(ip_msdp_mesh_group_member,
+ ip_msdp_mesh_group_member_cmd,
+ "ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "Mesh group name\n"
+ "Mesh group member\n"
+ "Peer IP address\n")
{
const char *vrfname;
- char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
- char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
+ char xpath_value[XPATH_MAXLEN];
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
- snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
- sizeof(msdp_mesh_group_name_xpath));
- snprintf(msdp_mesh_group_member_xpath,
- sizeof(msdp_mesh_group_member_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip",
- sizeof(msdp_mesh_group_member_xpath));
+ /* Create mesh group. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
- nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
- argv[3]->arg);
- nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE,
- argv[5]->arg);
+ /* Create mesh group member. */
+ strlcat(xpath_value, "/members[address='", sizeof(xpath_value));
+ strlcat(xpath_value, maddr_str, sizeof(xpath_value));
+ strlcat(xpath_value, "']", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_ip_msdp_mesh_group_member,
- no_ip_msdp_mesh_group_member_cmd,
- "no ip msdp mesh-group WORD member A.B.C.D",
- NO_STR
- IP_STR
- CFG_MSDP_STR
- "Delete MSDP mesh-group member\n"
- "mesh group name\n"
- "mesh group member\n"
- "peer ip address\n")
+DEFPY(no_ip_msdp_mesh_group_member,
+ no_ip_msdp_mesh_group_member_cmd,
+ "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group member\n"
+ "Mesh group name\n"
+ "Mesh group member\n"
+ "Peer IP address\n")
{
const char *vrfname;
- char pim_af_xpath[XPATH_MAXLEN];
- char mesh_group_xpath[XPATH_MAXLEN + 32];
- char group_member_list_xpath[XPATH_MAXLEN + 64];
- char group_member_xpath[XPATH_MAXLEN + 128];
- char source_xpath[XPATH_MAXLEN + 64];
- char mesh_group_name_xpath[XPATH_MAXLEN + 64];
- const char *mesh_group_name;
- const struct lyd_node *member_dnode;
+ char xpath_value[XPATH_MAXLEN];
+ char xpath_member_value[XPATH_MAXLEN];
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
- snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
- snprintf(mesh_group_xpath, sizeof(mesh_group_xpath),
- "%s/msdp-mesh-group", pim_af_xpath);
-
- snprintf(group_member_list_xpath, sizeof(group_member_list_xpath),
- "%s/msdp-mesh-group/member-ip", pim_af_xpath);
-
- snprintf(group_member_xpath, sizeof(group_member_xpath), "%s[.='%s']",
- group_member_list_xpath, argv[6]->arg);
-
- snprintf(source_xpath, sizeof(source_xpath),
- "%s/msdp-mesh-group/source-ip", pim_af_xpath);
-
- snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
- "%s/msdp-mesh-group/mesh-group-name", pim_af_xpath);
-
- if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
- == true) {
- mesh_group_name = yang_dnode_get_string(running_config->dnode,
- mesh_group_name_xpath);
- if (strcmp(mesh_group_name, argv[4]->arg)) {
- vty_out(vty, "%% mesh-group does not exist\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) {
+ vty_out(vty, "%% mesh-group does not exist\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- if (yang_dnode_exists(vty->candidate_config->dnode,
- group_member_xpath)) {
- if (!yang_dnode_exists(vty->candidate_config->dnode,
- source_xpath)) {
- member_dnode = yang_dnode_get(
- vty->candidate_config->dnode,
- group_member_xpath);
- if (yang_is_last_list_dnode(member_dnode)) {
- nb_cli_enqueue_change(vty, mesh_group_xpath,
- NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
- nb_cli_enqueue_change(vty, group_member_list_xpath,
- NB_OP_DESTROY, argv[6]->arg);
- return nb_cli_apply_changes(vty, NULL);
- }
- nb_cli_enqueue_change(vty, group_member_list_xpath,
- NB_OP_DESTROY, argv[6]->arg);
- return nb_cli_apply_changes(vty, NULL);
+ /* Remove mesh group member. */
+ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "/members[address='",
+ sizeof(xpath_member_value));
+ strlcat(xpath_member_value, maddr_str, sizeof(xpath_member_value));
+ strlcat(xpath_member_value, "']", sizeof(xpath_member_value));
+ if (!yang_dnode_exists(vty->candidate_config->dnode,
+ xpath_member_value)) {
+ vty_out(vty, "%% mesh-group member does not exist\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- vty_out(vty, "%% mesh-group member does not exist\n");
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
- return CMD_SUCCESS;
+ /*
+ * If this is the last member, then we must remove the group altogether
+ * to not break legacy CLI behaviour.
+ */
+ pim_cli_legacy_mesh_group_behavior(vty, gname);
+
+ return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (ip_msdp_mesh_group_source,
- ip_msdp_mesh_group_source_cmd,
- "ip msdp mesh-group WORD source A.B.C.D",
- IP_STR
- CFG_MSDP_STR
- "Configure MSDP mesh-group\n"
- "mesh group name\n"
- "mesh group local address\n"
- "source ip address for the TCP connection\n")
+DEFPY(ip_msdp_mesh_group_source,
+ ip_msdp_mesh_group_source_cmd,
+ "ip msdp mesh-group WORD$gname source A.B.C.D$saddr",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "Mesh group name\n"
+ "Mesh group local address\n"
+ "Source IP address for the TCP connection\n")
{
const char *vrfname;
- char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
- char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
+ char xpath_value[XPATH_MAXLEN];
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
- snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
- sizeof(msdp_mesh_group_name_xpath));
-
- snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip",
- sizeof(msdp_mesh_source_ip_xpath));
+ /* Create mesh group. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
- nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
- argv[3]->arg);
- nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY,
- argv[5]->arg);
+ /* Create mesh group member. */
+ strlcat(xpath_value, "/source", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_ip_msdp_mesh_group_source,
- no_ip_msdp_mesh_group_source_cmd,
- "no ip msdp mesh-group WORD source [A.B.C.D]",
- NO_STR
- IP_STR
- CFG_MSDP_STR
- "Delete MSDP mesh-group source\n"
- "mesh group name\n"
- "mesh group source\n"
- "mesh group local address\n")
+DEFPY(no_ip_msdp_mesh_group_source,
+ no_ip_msdp_mesh_group_source_cmd,
+ "no ip msdp mesh-group WORD$gname source [A.B.C.D]",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group source\n"
+ "Mesh group name\n"
+ "Mesh group source\n"
+ "Mesh group local address\n")
{
const char *vrfname;
- char msdp_mesh_xpath[XPATH_MAXLEN];
- char source_xpath[XPATH_MAXLEN];
- char group_member_xpath[XPATH_MAXLEN];
- char mesh_group_name_xpath[XPATH_MAXLEN];
- const char *mesh_group_name;
+ char xpath_value[XPATH_MAXLEN];
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
- snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
- snprintf(source_xpath, sizeof(source_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(source_xpath, "/msdp-mesh-group/source-ip",
- sizeof(source_xpath));
+ /* Create mesh group member. */
+ strlcat(xpath_value, "/source", sizeof(xpath_value));
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
- snprintf(group_member_xpath,
- sizeof(group_member_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(group_member_xpath, "/msdp-mesh-group/member-ip",
- sizeof(group_member_xpath));
+ /*
+ * If this is the last member, then we must remove the group altogether
+ * to not break legacy CLI behaviour.
+ */
+ pim_cli_legacy_mesh_group_behavior(vty, gname);
- snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
- sizeof(mesh_group_name_xpath));
-
- if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
- == true) {
- mesh_group_name = yang_dnode_get_string(running_config->dnode,
- mesh_group_name_xpath);
- if (strcmp(mesh_group_name, argv[4]->arg)) {
- vty_out(vty, "%% mesh-group does not exist\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
-
- if (!yang_dnode_exists(vty->candidate_config->dnode,
- group_member_xpath)) {
- nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY,
- NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
- nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
-DEFUN (no_ip_msdp_mesh_group,
- no_ip_msdp_mesh_group_cmd,
- "no ip msdp mesh-group [WORD]",
- NO_STR
- IP_STR
- CFG_MSDP_STR
- "Delete MSDP mesh-group\n"
- "mesh group name")
+DEFPY(no_ip_msdp_mesh_group,
+ no_ip_msdp_mesh_group_cmd,
+ "no ip msdp mesh-group WORD$gname",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group\n"
+ "Mesh group name")
{
const char *vrfname;
- const char *mesh_group_name;
- char xpath[XPATH_MAXLEN];
- char msdp_mesh_xpath[XPATH_MAXLEN];
+ char xpath_value[XPATH_MAXLEN];
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
- if (argc == 5) {
- snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
- "pim", vrfname, "frr-routing:ipv4");
- strlcat(xpath, "/msdp-mesh-group/mesh-group-name",
- sizeof(xpath));
-
- if (yang_dnode_exists(running_config->dnode, xpath) == true) {
- mesh_group_name =
- yang_dnode_get_string(running_config->dnode,
- xpath);
-
- if (strcmp(mesh_group_name, argv[4]->arg)) {
- vty_out(vty, "%% mesh-group does not exist\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
- }
-
- snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
- FRR_PIM_AF_XPATH,
- "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
- strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+ /* Get mesh group base XPath. */
+ snprintf(xpath_value, sizeof(xpath_value),
+ FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+ "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+ return CMD_SUCCESS;
- nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
-static void print_empty_json_obj(struct vty *vty)
-{
- json_object *json;
- json = json_object_new_object();
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
-}
-
-static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
- bool uj)
+static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg,
+ struct json_object *json)
{
struct listnode *mbrnode;
struct pim_msdp_mg_mbr *mbr;
- struct pim_msdp_mg *mg = pim->msdp.mg;
char mbr_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
char state_str[PIM_MSDP_STATE_STRLEN];
enum pim_msdp_peer_state state;
- json_object *json = NULL;
json_object *json_mg_row = NULL;
json_object *json_members = NULL;
json_object *json_row = NULL;
- if (!mg) {
- if (uj)
- print_empty_json_obj(vty);
- return;
- }
-
pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
- if (uj) {
- json = json_object_new_object();
+ if (json) {
/* currently there is only one mesh group but we should still
* make
* it a dict with mg-name as key */
@@ -10005,7 +9947,7 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
state = PIM_MSDP_DISABLED;
}
pim_msdp_state_dump(state, state_str, sizeof(state_str));
- if (uj) {
+ if (json) {
json_row = json_object_new_object();
json_object_string_add(json_row, "member", mbr_str);
json_object_string_add(json_row, "state", state_str);
@@ -10020,12 +9962,8 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
}
}
- if (uj) {
+ if (json)
json_object_object_add(json, mg->mesh_group_name, json_mg_row);
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
- }
}
DEFUN (show_ip_msdp_mesh_group,
@@ -10040,12 +9978,34 @@ DEFUN (show_ip_msdp_mesh_group,
{
bool uj = use_json(argc, argv);
int idx = 2;
+ struct pim_msdp_mg *mg;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct pim_instance *pim = vrf->info;
+ struct json_object *json = NULL;
if (!vrf)
return CMD_WARNING;
- ip_msdp_show_mesh_group(vrf->info, vty, uj);
+ /* Quick case: list is empty. */
+ if (SLIST_EMPTY(&pim->msdp.mglist)) {
+ if (uj)
+ vty_out(vty, "{}\n");
+
+ return CMD_SUCCESS;
+ }
+
+ if (uj)
+ json = json_object_new_object();
+
+ SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+ ip_msdp_show_mesh_group(vty, mg, json);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
return CMD_SUCCESS;
}
@@ -10061,23 +10021,32 @@ DEFUN (show_ip_msdp_mesh_group_vrf_all,
JSON_STR)
{
bool uj = use_json(argc, argv);
+ struct json_object *json = NULL, *vrf_json = NULL;
+ struct pim_instance *pim;
+ struct pim_msdp_mg *mg;
struct vrf *vrf;
- bool first = true;
if (uj)
- vty_out(vty, "{ ");
+ json = json_object_new_object();
+
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (uj) {
- if (!first)
- vty_out(vty, ", ");
- vty_out(vty, " \"%s\": ", vrf->name);
- first = false;
+ vrf_json = json_object_new_object();
+ json_object_object_add(json, vrf->name, vrf_json);
} else
vty_out(vty, "VRF: %s\n", vrf->name);
- ip_msdp_show_mesh_group(vrf->info, vty, uj);
+
+ pim = vrf->info;
+ SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+ ip_msdp_show_mesh_group(vty, mg, vrf_json);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
}
- if (uj)
- vty_out(vty, "}\n");
return CMD_SUCCESS;
}
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 9cf73c38c3..095c6de549 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -58,8 +58,6 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
enum pim_msdp_sa_flags flags);
static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2);
static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr);
-static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
- struct pim_msdp_mg_mbr *mbr);
/************************ SA cache management ******************************/
static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa,
@@ -1252,27 +1250,33 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2)
}
/************************** Mesh group management **************************/
-static void pim_msdp_mg_free(struct pim_instance *pim)
+void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp)
{
- struct pim_msdp_mg *mg = pim->msdp.mg;
+ struct pim_msdp_mg_mbr *mbr;
+ struct listnode *n, *nn;
- /* If the mesh-group has valid member or src_ip don't delete it */
- if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) {
+ if (*mgp == NULL)
return;
- }
+
+ /* SIP is being removed - tear down all active peer sessions */
+ for (ALL_LIST_ELEMENTS((*mgp)->mbr_list, n, nn, mbr))
+ pim_msdp_mg_mbr_del((*mgp), mbr);
if (PIM_DEBUG_MSDP_EVENTS) {
- zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name);
+ zlog_debug("MSDP mesh-group %s deleted",
+ (*mgp)->mesh_group_name);
}
- XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
- if (mg->mbr_list)
- list_delete(&mg->mbr_list);
+ XFREE(MTYPE_PIM_MSDP_MG_NAME, (*mgp)->mesh_group_name);
+
+ if ((*mgp)->mbr_list)
+ list_delete(&(*mgp)->mbr_list);
- XFREE(MTYPE_PIM_MSDP_MG, pim->msdp.mg);
+ XFREE(MTYPE_PIM_MSDP_MG, (*mgp));
}
-static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
+struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
+ const char *mesh_group_name)
{
struct pim_msdp_mg *mg;
@@ -1286,52 +1290,10 @@ static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
if (PIM_DEBUG_MSDP_EVENTS) {
zlog_debug("MSDP mesh-group %s created", mg->mesh_group_name);
}
- return mg;
-}
-
-enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
- const char *mesh_group_name)
-{
- struct pim_msdp_mg *mg = pim->msdp.mg;
- struct pim_msdp_mg_mbr *mbr;
-
- if (!mg
- || (mesh_group_name
- && strcmp(mg->mesh_group_name, mesh_group_name))) {
- return PIM_MSDP_ERR_NO_MG;
- }
-
- /* delete all the mesh-group members */
- while (!list_isempty(mg->mbr_list)) {
- mbr = listnode_head(mg->mbr_list);
- pim_msdp_mg_mbr_do_del(mg, mbr);
- }
-
- /* clear src ip */
- mg->src_ip.s_addr = INADDR_ANY;
-
- /* free up the mesh-group */
- pim_msdp_mg_free(pim);
- return PIM_MSDP_ERR_NONE;
-}
-
-static enum pim_msdp_err pim_msdp_mg_add(struct pim_instance *pim,
- const char *mesh_group_name)
-{
- if (pim->msdp.mg) {
- if (!strcmp(pim->msdp.mg->mesh_group_name, mesh_group_name)) {
- return PIM_MSDP_ERR_NONE;
- }
- /* currently only one mesh-group can exist at a time */
- return PIM_MSDP_ERR_MAX_MESH_GROUPS;
- }
- pim->msdp.mg = pim_msdp_mg_new(mesh_group_name);
- if (!pim->msdp.mg) {
- return PIM_MSDP_ERR_OOM;
- }
+ SLIST_INSERT_HEAD(&pim->msdp.mglist, mg, mg_entry);
- return PIM_MSDP_ERR_NONE;
+ return mg;
}
static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2)
@@ -1353,66 +1315,7 @@ static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr)
XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr);
}
-static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct pim_instance *pim,
- struct in_addr mbr_ip)
-{
- struct pim_msdp_mg_mbr *mbr;
- struct listnode *mbr_node;
-
- if (!pim->msdp.mg) {
- return NULL;
- }
- /* we can move this to a hash but considering that number of peers in
- * a mesh-group that seems like bit of an overkill */
- for (ALL_LIST_ELEMENTS_RO(pim->msdp.mg->mbr_list, mbr_node, mbr)) {
- if (mbr->mbr_ip.s_addr == mbr_ip.s_addr) {
- return mbr;
- }
- }
- return mbr;
-}
-
-enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr mbr_ip)
-{
- int rc;
- struct pim_msdp_mg_mbr *mbr;
- struct pim_msdp_mg *mg;
-
- rc = pim_msdp_mg_add(pim, mesh_group_name);
- if (rc != PIM_MSDP_ERR_NONE) {
- return rc;
- }
-
- mg = pim->msdp.mg;
- mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
- if (mbr) {
- return PIM_MSDP_ERR_MG_MBR_EXISTS;
- }
-
- mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
- mbr->mbr_ip = mbr_ip;
- listnode_add_sort(mg->mbr_list, mbr);
-
- /* if valid SIP has been configured add peer session */
- if (mg->src_ip.s_addr != INADDR_ANY) {
- pim_msdp_peer_add(pim, mbr_ip, mg->src_ip, mesh_group_name,
- &mbr->mp);
- }
-
- if (PIM_DEBUG_MSDP_EVENTS) {
- char ip_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<mbr?>", mbr->mbr_ip, ip_str, sizeof(ip_str));
- zlog_debug("MSDP mesh-group %s mbr %s created",
- mg->mesh_group_name, ip_str);
- }
- ++mg->mbr_cnt;
- return PIM_MSDP_ERR_NONE;
-}
-
-static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
- struct pim_msdp_mg_mbr *mbr)
+void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr)
{
/* Delete active peer session if any */
if (mbr->mp) {
@@ -1432,34 +1335,10 @@ static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
}
}
-enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr mbr_ip)
-{
- struct pim_msdp_mg_mbr *mbr;
- struct pim_msdp_mg *mg = pim->msdp.mg;
-
- if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
- return PIM_MSDP_ERR_NO_MG;
- }
-
- mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
- if (!mbr) {
- return PIM_MSDP_ERR_NO_MG_MBR;
- }
-
- pim_msdp_mg_mbr_do_del(mg, mbr);
- /* if there are no references to the mg free it */
- pim_msdp_mg_free(pim);
-
- return PIM_MSDP_ERR_NONE;
-}
-
-static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
+static void pim_msdp_src_del(struct pim_msdp_mg *mg)
{
struct pim_msdp_mg_mbr *mbr;
struct listnode *mbr_node;
- struct pim_msdp_mg *mg = pim->msdp.mg;
/* SIP is being removed - tear down all active peer sessions */
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
@@ -1474,91 +1353,38 @@ static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
}
}
-enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
- const char *mesh_group_name)
-{
- struct pim_msdp_mg *mg = pim->msdp.mg;
-
- if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
- return PIM_MSDP_ERR_NO_MG;
- }
-
- if (mg->src_ip.s_addr != INADDR_ANY) {
- mg->src_ip.s_addr = INADDR_ANY;
- pim_msdp_mg_src_do_del(pim);
- /* if there are no references to the mg free it */
- pim_msdp_mg_free(pim);
- }
- return PIM_MSDP_ERR_NONE;
-}
-
-enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr src_ip)
-{
- int rc;
- struct pim_msdp_mg_mbr *mbr;
- struct listnode *mbr_node;
- struct pim_msdp_mg *mg;
-
- if (src_ip.s_addr == INADDR_ANY) {
- pim_msdp_mg_src_del(pim, mesh_group_name);
- return PIM_MSDP_ERR_NONE;
- }
-
- rc = pim_msdp_mg_add(pim, mesh_group_name);
- if (rc != PIM_MSDP_ERR_NONE) {
- return rc;
- }
-
- mg = pim->msdp.mg;
- if (mg->src_ip.s_addr != INADDR_ANY) {
- pim_msdp_mg_src_do_del(pim);
- }
- mg->src_ip = src_ip;
-
- for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
- pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip, mesh_group_name,
- &mbr->mp);
- }
-
- if (PIM_DEBUG_MSDP_EVENTS) {
- char ip_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<src?>", mg->src_ip, ip_str, sizeof(ip_str));
- zlog_debug("MSDP mesh-group %s src %s set", mg->mesh_group_name,
- ip_str);
- }
- return PIM_MSDP_ERR_NONE;
-}
-
/*********************** MSDP feature APIs *********************************/
int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty,
const char *spaces)
{
+ struct pim_msdp_mg *mg;
struct listnode *mbrnode;
struct pim_msdp_mg_mbr *mbr;
- struct pim_msdp_mg *mg = pim->msdp.mg;
char mbr_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
int count = 0;
- if (!mg) {
+ if (SLIST_EMPTY(&pim->msdp.mglist))
return count;
- }
- if (mg->src_ip.s_addr != INADDR_ANY) {
- pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str));
- vty_out(vty, "%sip msdp mesh-group %s source %s\n", spaces,
- mg->mesh_group_name, src_str);
- ++count;
- }
+ SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry) {
+ if (mg->src_ip.s_addr != INADDR_ANY) {
+ pim_inet4_dump("<src?>", mg->src_ip, src_str,
+ sizeof(src_str));
+ vty_out(vty, "%sip msdp mesh-group %s source %s\n",
+ spaces, mg->mesh_group_name, src_str);
+ ++count;
+ }
- for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
- pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
- vty_out(vty, "%sip msdp mesh-group %s member %s\n", spaces,
- mg->mesh_group_name, mbr_str);
- ++count;
+ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
+ pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str,
+ sizeof(mbr_str));
+ vty_out(vty, "%sip msdp mesh-group %s member %s\n",
+ spaces, mg->mesh_group_name, mbr_str);
+ ++count;
+ }
}
+
return count;
}
@@ -1623,11 +1449,13 @@ void pim_msdp_init(struct pim_instance *pim, struct thread_master *master)
/* counterpart to MSDP init; XXX: unused currently */
void pim_msdp_exit(struct pim_instance *pim)
{
- pim_msdp_sa_adv_timer_setup(pim, false);
+ struct pim_msdp_mg *mg;
- /* XXX: stop listener and delete all peer sessions */
+ pim_msdp_sa_adv_timer_setup(pim, false);
- pim_msdp_mg_free(pim);
+ /* Stop listener and delete all peer sessions */
+ while ((mg = SLIST_FIRST(&pim->msdp.mglist)) != NULL)
+ pim_msdp_mg_free(pim, &mg);
if (pim->msdp.peer_hash) {
hash_clean(pim->msdp.peer_hash, NULL);
@@ -1653,3 +1481,57 @@ void pim_msdp_exit(struct pim_instance *pim)
stream_free(pim->msdp.work_obuf);
pim->msdp.work_obuf = NULL;
}
+
+void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
+ struct in_addr *ai)
+{
+ struct pim_msdp_mg_mbr *mbr;
+ struct listnode *mbr_node;
+
+ /* Stop all connections and remove data structures. */
+ pim_msdp_src_del(mg);
+
+ /* Set new address. */
+ mg->src_ip = *ai;
+
+ /* No new address, disable everyone. */
+ if (ai->s_addr == INADDR_ANY) {
+ if (PIM_DEBUG_MSDP_EVENTS)
+ zlog_debug("MSDP mesh-group %s src unset",
+ mg->mesh_group_name);
+ return;
+ }
+
+ /* Create data structures and start TCP connection. */
+ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr))
+ pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
+ mg->mesh_group_name, &mbr->mp);
+
+ if (PIM_DEBUG_MSDP_EVENTS)
+ zlog_debug("MSDP mesh-group %s src %pI4 set",
+ mg->mesh_group_name, &mg->src_ip);
+}
+
+struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
+ struct pim_msdp_mg *mg,
+ struct in_addr *ia)
+{
+ struct pim_msdp_mg_mbr *mbr;
+
+ mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
+ mbr->mbr_ip = *ia;
+ listnode_add_sort(mg->mbr_list, mbr);
+
+ /* if valid SIP has been configured add peer session */
+ if (mg->src_ip.s_addr != INADDR_ANY)
+ pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
+ mg->mesh_group_name, &mbr->mp);
+
+ if (PIM_DEBUG_MSDP_EVENTS)
+ zlog_debug("MSDP mesh-group %s mbr %pI4 created",
+ mg->mesh_group_name, &mbr->mbr_ip);
+
+ ++mg->mbr_cnt;
+
+ return mbr;
+}
diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h
index 4d01880fbf..bb7ee01ad8 100644
--- a/pimd/pim_msdp.h
+++ b/pimd/pim_msdp.h
@@ -19,6 +19,8 @@
#ifndef PIM_MSDP_H
#define PIM_MSDP_H
+#include "lib/openbsd-queue.h"
+
enum pim_msdp_peer_state {
PIM_MSDP_DISABLED,
PIM_MSDP_INACTIVE,
@@ -160,8 +162,13 @@ struct pim_msdp_mg {
struct in_addr src_ip;
uint32_t mbr_cnt;
struct list *mbr_list;
+
+ /** Belongs to PIM instance list. */
+ SLIST_ENTRY(pim_msdp_mg) mg_entry;
};
+SLIST_HEAD(pim_mesh_group_list, pim_msdp_mg);
+
enum pim_msdp_flags {
PIM_MSDPF_NONE = 0,
PIM_MSDPF_ENABLE = (1 << 0),
@@ -196,8 +203,8 @@ struct pim_msdp {
struct in_addr originator_id;
- /* currently only one mesh-group is supported - so just stash it here */
- struct pim_msdp_mg *mg;
+ /** List of mesh groups. */
+ struct pim_mesh_group_list mglist;
};
#define PIM_MSDP_PEER_READ_ON(mp) \
@@ -246,17 +253,39 @@ bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
void pim_msdp_up_join_state_changed(struct pim_instance *pim,
struct pim_upstream *xg_up);
void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg);
-enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
- const char *mesh_group_name);
-enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
- const char *mesh_group_name,
- struct in_addr src_ip);
enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
const char *mesh_group_name);
+
+/**
+ * Allocates a new mesh group data structure under PIM instance.
+ */
+struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
+ const char *mesh_group_name);
+/**
+ * Deallocates mesh group data structure under PIM instance.
+ */
+void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp);
+
+/**
+ * Change the source address of a mesh group peers. It will do the following:
+ * - Close all peers TCP connections
+ * - Recreate peers data structure
+ * - Start TCP connections with new local address.
+ */
+void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
+ struct in_addr *ai);
+
+/**
+ * Add new peer to mesh group and starts the connection if source address is
+ * configured.
+ */
+struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
+ struct pim_msdp_mg *mg,
+ struct in_addr *ia);
+
+/**
+ * Stops the connection and removes the peer data structures.
+ */
+void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr);
+
#endif
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index 37c539883d..ea53f1ef12 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -118,31 +118,24 @@ const struct frr_yang_module_info frr_pim_info = {
}
},
{
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group",
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups",
.cbs = {
- .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create,
- .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy,
+ .create = pim_msdp_mesh_group_create,
+ .destroy = pim_msdp_mesh_group_destroy,
}
},
{
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name",
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source",
.cbs = {
- .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify,
- .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy,
+ .modify = pim_msdp_mesh_group_source_modify,
+ .destroy = pim_msdp_mesh_group_source_destroy,
}
},
{
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip",
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members",
.cbs = {
- .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create,
- .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy,
- }
- },
- {
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip",
- .cbs = {
- .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify,
- .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy,
+ .create = pim_msdp_mesh_group_members_create,
+ .destroy = pim_msdp_mesh_group_members_destroy,
}
},
{
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index 440384e45c..1959b403ff 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -60,22 +60,12 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
- struct nb_cb_create_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
- struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
- struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
- struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
- struct nb_cb_create_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
- struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
- struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
- struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_create(struct nb_cb_create_args *args);
+int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args);
+int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args);
+int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 11e8da3b87..b70656ea7b 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -243,147 +243,6 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
return ret;
}
-static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
- const char *mg,
- char *errmsg, size_t errmsg_len)
-{
- enum pim_msdp_err result;
-
- result = pim_msdp_mg_del(pim, mg);
-
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_NO_MG:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group does not exist");
- break;
- default:
- snprintf(errmsg, errmsg_len,
- "mesh-group source del failed");
- }
-
- return result ? NB_ERR : NB_OK;
-}
-
-static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
- const char *mg,
- struct in_addr mbr_ip,
- char *errmsg, size_t errmsg_len)
-{
- enum pim_msdp_err result;
- int ret = NB_OK;
-
- result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
-
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_OOM:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% Out of memory");
- break;
- case PIM_MSDP_ERR_MG_MBR_EXISTS:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% mesh-group member exists");
- break;
- case PIM_MSDP_ERR_MAX_MESH_GROUPS:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% Only one mesh-group allowed currently");
- break;
- default:
- ret = NB_ERR;
- snprintf(errmsg, errmsg_len,
- "%% member add failed");
- }
-
- return ret;
-}
-
-static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
- const char *mg,
- struct in_addr mbr_ip,
- char *errmsg,
- size_t errmsg_len)
-{
- enum pim_msdp_err result;
-
- result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
-
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_NO_MG:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group does not exist");
- break;
- case PIM_MSDP_ERR_NO_MG_MBR:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group member does not exist");
- break;
- default:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group member del failed");
- }
-
- return result ? NB_ERR : NB_OK;
-}
-
-static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
- const char *mg,
- struct in_addr src_ip,
- char *errmsg, size_t errmsg_len)
-{
- enum pim_msdp_err result;
-
- result = pim_msdp_mg_src_add(pim, mg, src_ip);
-
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_OOM:
- snprintf(errmsg, errmsg_len,
- "%% Out of memory");
- break;
- case PIM_MSDP_ERR_MAX_MESH_GROUPS:
- snprintf(errmsg, errmsg_len,
- "%% Only one mesh-group allowed currently");
- break;
- default:
- snprintf(errmsg, errmsg_len,
- "%% source add failed");
- }
-
- return result ? NB_ERR : NB_OK;
-}
-
-static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
- const char *mg,
- char *errmsg,
- size_t errmsg_len)
-{
- enum pim_msdp_err result;
-
- result = pim_msdp_mg_src_del(pim, mg);
-
- switch (result) {
- case PIM_MSDP_ERR_NONE:
- break;
- case PIM_MSDP_ERR_NO_MG:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group does not exist");
- break;
- default:
- snprintf(errmsg, errmsg_len,
- "%% mesh-group source del failed");
- }
-
- return result ? NB_ERR : NB_OK;
-}
-
static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
struct in_addr peer_addr,
struct in_addr local_addr,
@@ -1146,29 +1005,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
}
/*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups
*/
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
- struct nb_cb_create_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- case NB_EV_APPLY:
- break;
- }
-
- return NB_OK;
-}
-
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
- struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_create(struct nb_cb_create_args *args)
{
+ struct pim_msdp_mg *mg;
struct vrf *vrf;
- struct pim_instance *pim;
- const char *mesh_group_name;
- int result;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1177,67 +1020,29 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- mesh_group_name = yang_dnode_get_string(args->dnode, "mesh-group-name");
-
- result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name,
- args->errmsg,
- args->errmsg_len);
-
- if (result != PIM_MSDP_ERR_NONE)
- return NB_ERR_INCONSISTENCY;
-
+ mg = pim_msdp_mg_new(vrf->info, yang_dnode_get_string(
+ args->dnode, "./name"));
+ nb_running_set_entry(args->dnode, mg);
break;
}
return NB_OK;
}
-/*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name
- */
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
- struct nb_cb_modify_args *args)
+int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args)
{
- const char *mesh_group_name;
- const char *mesh_group_name_old;
- char xpath[XPATH_MAXLEN];
+ struct pim_msdp_mg *mg;
+ struct vrf *vrf;
switch (args->event) {
case NB_EV_VALIDATE:
- mesh_group_name = yang_dnode_get_string(args->dnode, ".");
- yang_dnode_get_path(args->dnode, xpath, sizeof(xpath));
-
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- break;
-
- mesh_group_name_old = yang_dnode_get_string(
- running_config->dnode,
- xpath);
- if (strcmp(mesh_group_name, mesh_group_name_old)) {
- /* currently only one mesh-group can exist at a time */
- snprintf(args->errmsg, args->errmsg_len,
- "Only one mesh-group allowed currently");
- return NB_ERR_VALIDATION;
- }
- break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
- case NB_EV_APPLY:
break;
- }
-
- return NB_OK;
-}
-
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
- struct nb_cb_destroy_args *args)
-{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
case NB_EV_APPLY:
+ mg = nb_running_unset_entry(args->dnode);
+ vrf = nb_running_get_entry(args->dnode, NULL, true);
+ pim_msdp_mg_free(vrf->info, &mg);
break;
}
@@ -1245,16 +1050,15 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
}
/*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source
*/
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
- struct nb_cb_create_args *args)
+int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args)
{
+ const struct lyd_node *vrf_dnode;
+ struct pim_msdp_mg *mg;
struct vrf *vrf;
- struct pim_instance *pim;
- const char *mesh_group_name;
- struct ipaddr mbr_ip;
- enum pim_msdp_err result;
+ struct ipaddr ip;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1262,33 +1066,24 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- mesh_group_name = yang_dnode_get_string(args->dnode,
- "../mesh-group-name");
- yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
-
- result = ip_msdp_mesh_group_member_cmd_worker(
- pim, mesh_group_name, mbr_ip.ip._v4_addr,
- args->errmsg, args->errmsg_len);
-
- if (result != PIM_MSDP_ERR_NONE)
- return NB_ERR_INCONSISTENCY;
+ mg = nb_running_get_entry(args->dnode, NULL, true);
+ vrf_dnode =
+ yang_dnode_get_parent(args->dnode, "address-family");
+ vrf = nb_running_get_entry(vrf_dnode, "../../", true);
+ yang_dnode_get_ip(&ip, args->dnode, NULL);
+ pim_msdp_mg_src_add(vrf->info, mg, &ip.ip._v4_addr);
break;
}
-
return NB_OK;
}
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
- struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args)
{
+ const struct lyd_node *vrf_dnode;
+ struct pim_msdp_mg *mg;
struct vrf *vrf;
- struct pim_instance *pim;
- const char *mesh_group_name;
- struct ipaddr mbr_ip;
- enum pim_msdp_err result;
+ struct in_addr addr;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1296,36 +1091,30 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- mesh_group_name = yang_dnode_get_string(args->dnode,
- "../mesh-group-name");
- yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
-
- result = ip_no_msdp_mesh_group_member_cmd_worker(
- pim, mesh_group_name, mbr_ip.ip._v4_addr,
- args->errmsg, args->errmsg_len);
-
- if (result != PIM_MSDP_ERR_NONE)
- return NB_ERR_INCONSISTENCY;
+ mg = nb_running_get_entry(args->dnode, NULL, true);
+ vrf_dnode =
+ yang_dnode_get_parent(args->dnode, "address-family");
+ vrf = nb_running_get_entry(vrf_dnode, "../../", true);
+ addr.s_addr = INADDR_ANY;
+ pim_msdp_mg_src_add(vrf->info, mg, &addr);
break;
}
-
return NB_OK;
}
+
/*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members
*/
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
- struct nb_cb_modify_args *args)
+int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args)
{
+ const struct lyd_node *vrf_dnode;
+ struct pim_msdp_mg_mbr *mbr;
+ struct pim_msdp_mg *mg;
struct vrf *vrf;
- struct pim_instance *pim;
- const char *mesh_group_name;
- struct ipaddr src_ip;
- enum pim_msdp_err result;
+ struct ipaddr ip;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1333,31 +1122,24 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- mesh_group_name = yang_dnode_get_string(args->dnode,
- "../mesh-group-name");
- yang_dnode_get_ip(&src_ip, args->dnode, NULL);
-
- result = ip_msdp_mesh_group_source_cmd_worker(
- pim, mesh_group_name, src_ip.ip._v4_addr,
- args->errmsg, args->errmsg_len);
-
- if (result != PIM_MSDP_ERR_NONE)
- return NB_ERR_INCONSISTENCY;
+ mg = nb_running_get_entry(args->dnode, NULL, true);
+ vrf_dnode =
+ yang_dnode_get_parent(args->dnode, "address-family");
+ vrf = nb_running_get_entry(vrf_dnode, "../../", true);
+ yang_dnode_get_ip(&ip, args->dnode, "address");
+ mbr = pim_msdp_mg_mbr_add(vrf->info, mg, &ip.ip._v4_addr);
+ nb_running_set_entry(args->dnode, mbr);
break;
}
+
return NB_OK;
}
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
- struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
{
- struct vrf *vrf;
- struct pim_instance *pim;
- const char *mesh_group_name;
- enum pim_msdp_err result;
+ struct pim_msdp_mg_mbr *mbr;
+ struct pim_msdp_mg *mg;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1365,20 +1147,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- mesh_group_name = yang_dnode_get_string(args->dnode,
- "../mesh-group-name");
-
- result = ip_no_msdp_mesh_group_source_cmd_worker(
- pim, mesh_group_name, args->errmsg,
- args->errmsg_len);
-
- if (result != PIM_MSDP_ERR_NONE)
- return NB_ERR_INCONSISTENCY;
+ mbr = nb_running_get_entry(args->dnode, NULL, true);
+ mg = nb_running_get_entry(args->dnode, "../", true);
+ pim_msdp_mg_mbr_del(mg, mbr);
break;
}
+
return NB_OK;
}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index c6c82fb65a..7d940efd9c 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3690,6 +3690,8 @@ void rip_vrf_init(void)
{
vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
rip_vrf_enable);
+
+ vrf_cmd_init(NULL, &ripd_privs);
}
void rip_vrf_terminate(void)
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 3b8d2076f3..a0ea18f3e9 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2691,6 +2691,8 @@ void ripng_vrf_init(void)
{
vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
ripng_vrf_delete, ripng_vrf_enable);
+
+ vrf_cmd_init(NULL, &ripngd_privs);
}
void ripng_vrf_terminate(void)
diff --git a/tests/isisd/test_common.c b/tests/isisd/test_common.c
index 5b2028ffd4..ade3573535 100644
--- a/tests/isisd/test_common.c
+++ b/tests/isisd/test_common.c
@@ -309,7 +309,8 @@ static int topology_load_node(const struct isis_topology *topology,
{
int ret;
- isis_dynhn_insert(tnode->sysid, tnode->hostname, tnode->level);
+ isis_dynhn_insert(area->isis, tnode->sysid, tnode->hostname,
+ tnode->level);
for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
if ((tnode->level & level) == 0)
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index b89a5a008e..a30f33ccad 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -269,7 +269,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
if (sysid2buff(fail_id, fail_sysid_str) == 0) {
struct isis_dynhn *dynhn;
- dynhn = dynhn_find_by_name(fail_sysid_str);
+ dynhn = dynhn_find_by_name(area->isis, fail_sysid_str);
if (dynhn == NULL) {
vty_out(vty, "Invalid system id %s\n",
fail_sysid_str);
@@ -339,9 +339,6 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
/* Cleanup IS-IS area. */
isis_area_destroy(area);
- /* Cleanup hostnames. */
- dyn_cache_cleanup_all();
-
return CMD_SUCCESS;
}
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
index 597e230696..2d75428f1a 100644
--- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -906,17 +906,25 @@ def test_bgp_summary():
# Read expected result from file
expected_original = open(refTableFile).read().rstrip()
- for filter in ["", "remote-as internal", "remote-as external",
+ for arguments in ["", "remote-as internal", "remote-as external",
"remote-as 100", "remote-as 123",
"neighbor 192.168.7.10", "neighbor 192.168.7.10",
"neighbor fc00:0:0:8::1000",
- "neighbor 10.0.0.1"]:
+ "neighbor 10.0.0.1",
+ "terse",
+ "remote-as internal terse",
+ "remote-as external terse",
+ "remote-as 100 terse", "remote-as 123 terse",
+ "neighbor 192.168.7.10 terse", "neighbor 192.168.7.10 terse",
+ "neighbor fc00:0:0:8::1000 terse",
+ "neighbor 10.0.0.1 terse"]:
# Actual output from router
actual = (
net["r%s" % i]
- .cmd('vtysh -c "show ip bgp summary ' + filter + '" 2> /dev/null')
+ .cmd('vtysh -c "show ip bgp summary ' + arguments + '" 2> /dev/null')
.rstrip()
)
+
# Mask out "using XXiXX bytes" portion. They are random...
actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
# Mask out "using XiXXX KiB" portion. They are random...
@@ -928,48 +936,55 @@ def test_bgp_summary():
actual = re.sub(r"Total number.*", "", actual)
actual = re.sub(r"Displayed.*", "", actual)
# Remove IPv4 Unicast Summary (Title only)
- actual = re.sub(r"IPv4 Unicast Summary:", "", actual)
+ actual = re.sub(r"IPv4 Unicast Summary \(VRF default\):", "", actual)
# Remove IPv4 Multicast Summary (all of it)
- actual = re.sub(r"IPv4 Multicast Summary:", "", actual)
+ actual = re.sub(r"IPv4 Multicast Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
# Remove IPv4 VPN Summary (all of it)
- actual = re.sub(r"IPv4 VPN Summary:", "", actual)
+ actual = re.sub(r"IPv4 VPN Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
# Remove IPv4 Encap Summary (all of it)
- actual = re.sub(r"IPv4 Encap Summary:", "", actual)
+ actual = re.sub(r"IPv4 Encap Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
# Remove Unknown Summary (all of it)
- actual = re.sub(r"Unknown Summary:", "", actual)
+ actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
actual = re.sub(r"No Unknown neighbor is configured", "", actual)
- actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual)
+ actual = re.sub(r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual)
actual = re.sub(
r"No IPv4 labeled-unicast neighbor is configured", "", actual
)
expected = expected_original
- # apply filters on expected output
- if "internal" in filter or "remote-as 100" in filter:
+ # apply argumentss on expected output
+ if "internal" in arguments or "remote-as 100" in arguments:
expected = re.sub(r".+\s+200\s+.+", "", expected)
- elif "external" in filter:
+ elif "external" in arguments:
expected = re.sub(r".+\s+100\s+.+Active.+", "", expected)
- elif "remote-as 123" in filter:
+ elif "remote-as 123" in arguments:
expected = re.sub(
r"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
"", expected
)
- elif "192.168.7.10" in filter:
+ expected = re.sub(r"\nNeighbor.+Desc", "", expected)
+ expected = expected + "% No matching neighbor\n"
+ elif "192.168.7.10" in arguments:
expected = re.sub(
r"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+",
"", expected
)
- elif "fc00:0:0:8::1000" in filter:
+ elif "fc00:0:0:8::1000" in arguments:
expected = re.sub(
r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+",
"", expected
)
- elif "10.0.0.1" in filter:
- expected = "No such neighbor in this view/vrf"
+ elif "10.0.0.1" in arguments:
+ expected = "No such neighbor in VRF default"
+
+ if "terse" in arguments:
+ expected = re.sub(r"BGP table version .+", "", expected)
+ expected = re.sub(r"RIB entries .+", "", expected)
+ expected = re.sub(r"Peers [0-9]+, using .+", "", expected)
# Strip empty lines
actual = actual.lstrip().rstrip()
@@ -978,13 +993,17 @@ def test_bgp_summary():
expected = re.sub(r"\n+", "\n", expected)
# reapply initial formatting
- actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
- expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
+ if "terse" in arguments:
+ actual = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", actual)
+ expected = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", expected)
+ else:
+ actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
+ expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
# realign expected neighbor columns if needed
try:
- idx_actual = re.search(r"\n(Neighbor\s+V\s+)", actual).group(1).find("V")
- idx_expected = re.search(r"\n(Neighbor\s+V\s+)", expected).group(1).find("V")
+ idx_actual = re.search(r"(Neighbor\s+V\s+)", actual).group(1).find("V")
+ idx_expected = re.search(r"(Neighbor\s+V\s+)", expected).group(1).find("V")
idx_diff = idx_expected - idx_actual
if idx_diff > 0:
# Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
@@ -1002,8 +1021,8 @@ def test_bgp_summary():
diff = topotest.get_textdiff(
actual,
expected,
- title1="actual SHOW IP BGP SUMMARY " + filter.upper() ,
- title2="expected SHOW IP BGP SUMMARY " + filter.upper(),
+ title1="actual SHOW IP BGP SUMMARY " + arguments.upper() ,
+ title2="expected SHOW IP BGP SUMMARY " + arguments.upper(),
)
# Empty string if it matches, otherwise diff contains unified diff
@@ -1020,13 +1039,6 @@ def test_bgp_summary():
diff,
)
- # Actual output from router
- actual = (
- net["r%s" % i]
- .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
- .rstrip()
- )
-
# Make sure that all daemons are running
for i in range(1, 2):
fatal_error = net["r%s" % i].checkRouterRunning()
@@ -1074,22 +1086,22 @@ def test_bgp_ipv6_summary():
actual = re.sub(r"Total number.*", "", actual)
actual = re.sub(r"Displayed.*", "", actual)
# Remove IPv4 Unicast Summary (Title only)
- actual = re.sub(r"IPv6 Unicast Summary:", "", actual)
+ actual = re.sub(r"IPv6 Unicast Summary \(VRF default\):", "", actual)
# Remove IPv4 Multicast Summary (all of it)
- actual = re.sub(r"IPv6 Multicast Summary:", "", actual)
+ actual = re.sub(r"IPv6 Multicast Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv6 Multicast neighbor is configured", "", actual)
# Remove IPv4 VPN Summary (all of it)
- actual = re.sub(r"IPv6 VPN Summary:", "", actual)
+ actual = re.sub(r"IPv6 VPN Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv6 VPN neighbor is configured", "", actual)
# Remove IPv4 Encap Summary (all of it)
- actual = re.sub(r"IPv6 Encap Summary:", "", actual)
+ actual = re.sub(r"IPv6 Encap Summary \(VRF default\):", "", actual)
actual = re.sub(r"No IPv6 Encap neighbor is configured", "", actual)
# Remove Unknown Summary (all of it)
- actual = re.sub(r"Unknown Summary:", "", actual)
+ actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
actual = re.sub(r"No Unknown neighbor is configured", "", actual)
# Remove Labeled Unicast Summary (all of it)
- actual = re.sub(r"IPv6 labeled-unicast Summary:", "", actual)
+ actual = re.sub(r"IPv6 labeled-unicast Summary \(VRF default\):", "", actual)
actual = re.sub(
r"No IPv6 labeled-unicast neighbor is configured", "", actual
)
diff --git a/tests/topotests/bfd_topo2/r4/ipv6_routes.json b/tests/topotests/bfd_topo2/r4/ipv6_routes.json
index c828575c84..eb571d5d1c 100644
--- a/tests/topotests/bfd_topo2/r4/ipv6_routes.json
+++ b/tests/topotests/bfd_topo2/r4/ipv6_routes.json
@@ -35,7 +35,7 @@
{
"distance": 110,
"protocol": "ospf6",
- "metric": 10,
+ "metric": 20,
"selected": true,
"installed": true,
"prefix": "2001:db8:1::/64",
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index de5c584e91..e57db7471c 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -2,8 +2,10 @@
Topotest conftest.py file.
"""
+import glob
import os
import pdb
+import re
import pytest
from lib.topogen import get_topogen, diagnose_env
@@ -11,6 +13,12 @@ from lib.topotest import json_cmp_result
from lib.topotest import g_extra_config as topotest_extra_config
from lib.topolog import logger
+try:
+ from _pytest._code.code import ExceptionInfo
+ leak_check_ok = True
+except ImportError:
+ leak_check_ok = False
+
def pytest_addoption(parser):
"""
@@ -67,6 +75,18 @@ def pytest_addoption(parser):
)
parser.addoption(
+ "--valgrind-extra",
+ action="store_true",
+ help="Generate suppression file, and enable more precise (slower) valgrind checks",
+ )
+
+ parser.addoption(
+ "--valgrind-memleaks",
+ action="store_true",
+ help="Run all daemons under valgrind for memleak detection",
+ )
+
+ parser.addoption(
"--vtysh",
metavar="ROUTER[,ROUTER...]",
help="Comma-separated list of routers to spawn vtysh on, or 'all'",
@@ -79,6 +99,37 @@ def pytest_addoption(parser):
)
+def check_for_memleaks():
+ if not topotest_extra_config["valgrind_memleaks"]:
+ return
+
+ leaks = []
+ tgen = get_topogen()
+ latest = []
+ existing = []
+ if tgen is not None:
+ logdir = "/tmp/topotests/{}".format(tgen.modname)
+ if hasattr(tgen, "valgrind_existing_files"):
+ existing = tgen.valgrind_existing_files
+ latest = glob.glob(os.path.join(logdir, "*.valgrind.*"))
+
+ for vfile in latest:
+ if vfile in existing:
+ continue
+ with open(vfile) as vf:
+ vfcontent = vf.read()
+ match = re.search(r"ERROR SUMMARY: (\d+) errors", vfcontent)
+ if match and match.group(1) != "0":
+ emsg = '{} in {}'.format(match.group(1), vfile)
+ leaks.append(emsg)
+
+ if leaks:
+ if leak_check_ok:
+ pytest.fail("Memleaks found:\n\t" + "\n\t".join(leaks))
+ else:
+ logger.error("Memleaks found:\n\t" + "\n\t".join(leaks))
+
+
def pytest_runtest_call():
"""
This function must be run after setup_module(), it does standarized post
@@ -139,6 +190,9 @@ def pytest_configure(config):
shell_on_error = config.getoption("--shell-on-error")
topotest_extra_config["shell_on_error"] = shell_on_error
+ topotest_extra_config["valgrind_extra"] = config.getoption("--valgrind-extra")
+ topotest_extra_config["valgrind_memleaks"] = config.getoption("--valgrind-memleaks")
+
vtysh = config.getoption("--vtysh")
topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else []
@@ -159,6 +213,12 @@ def pytest_runtest_makereport(item, call):
else:
pause = False
+ if call.excinfo is None and call.when == "call":
+ try:
+ check_for_memleaks()
+ except:
+ call.excinfo = ExceptionInfo()
+
if call.excinfo is None:
error = False
else:
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 50cb586acd..db7b3586f1 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -990,7 +990,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
# Verification APIs
#############################################
@retry(attempts=4, wait=2, return_is_str=True)
-def verify_router_id(tgen, topo, input_dict):
+def verify_router_id(tgen, topo, input_dict, expected=True):
"""
Running command "show ip bgp json" for DUT and reading router-id
from input_dict and verifying with command output.
@@ -1006,6 +1006,8 @@ def verify_router_id(tgen, topo, input_dict):
* `topo`: input json file data
* `input_dict`: input dictionary, have details of Device Under Test, for
which user wants to test the data
+ * `expected` : expected results from API, by-default True
+
Usage
-----
# Verify if router-id for r1 is 12.12.12.12
@@ -1060,7 +1062,7 @@ def verify_router_id(tgen, topo, input_dict):
@retry(attempts=50, wait=3, return_is_str=True)
-def verify_bgp_convergence(tgen, topo, dut=None):
+def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
"""
API will verify if BGP is converged with in the given time frame.
Running "show bgp summary json" command and verify bgp neighbor
@@ -1070,6 +1072,8 @@ def verify_bgp_convergence(tgen, topo, dut=None):
* `tgen`: topogen object
* `topo`: input json file data
* `dut`: device under test
+ * `expected` : expected results from API, by-default True
+
Usage
-----
# To veriry is BGP is converged for all the routers used in
@@ -1264,7 +1268,7 @@ def verify_bgp_convergence(tgen, topo, dut=None):
@retry(attempts=4, wait=4, return_is_str=True)
def verify_bgp_community(
- tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False
+ tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False, expected=True
):
"""
API to veiryf BGP large community is attached in route for any given
@@ -1280,6 +1284,7 @@ def verify_bgp_community(
values needs to be verified
* `vrf`: VRF name
* `bestpath`: To check best path cli
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1423,7 +1428,7 @@ def modify_as_number(tgen, topo, input_dict):
@retry(attempts=4, wait=2, return_is_str=True)
-def verify_as_numbers(tgen, topo, input_dict):
+def verify_as_numbers(tgen, topo, input_dict, expected=True):
"""
This API is to verify AS numbers for given DUT by running
"show ip bgp neighbor json" command. Local AS and Remote AS
@@ -1435,6 +1440,7 @@ def verify_as_numbers(tgen, topo, input_dict):
* `topo`: input json file data
* `addr_type` : ip type, ipv4/ipv6
* `input_dict`: defines - for which router, AS numbers needs to be verified
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1522,7 +1528,7 @@ def verify_as_numbers(tgen, topo, input_dict):
@retry(attempts=50, wait=3, return_is_str=True)
-def verify_bgp_convergence_from_running_config(tgen, dut=None):
+def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True):
"""
API to verify BGP convergence b/w loopback and physical interface.
This API would be used when routers have BGP neighborship is loopback
@@ -1532,6 +1538,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None):
----------
* `tgen`: topogen object
* `dut`: device under test
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2086,6 +2093,7 @@ def verify_bgp_attributes(
input_dict=None,
seq_id=None,
nexthop=None,
+ expected=True
):
"""
API will verify BGP attributes set by Route-map for given prefix and
@@ -2101,6 +2109,7 @@ def verify_bgp_attributes(
* `rmap_name`: route map name for which set criteria needs to be verified
* `input_dict`: defines for which router, AS numbers needs
* `seq_id`: sequence number of rmap, default is None
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2216,7 +2225,7 @@ def verify_bgp_attributes(
@retry(attempts=4, wait=2, return_is_str=True)
def verify_best_path_as_per_bgp_attribute(
- tgen, addr_type, router, input_dict, attribute
+ tgen, addr_type, router, input_dict, attribute, expected=True
):
"""
API is to verify best path according to BGP attributes for given routes.
@@ -2231,6 +2240,8 @@ def verify_best_path_as_per_bgp_attribute(
* `attribute` : calculate best path using this attribute
* `input_dict`: defines different routes to calculate for which route
best path is selected
+ * `expected` : expected results from API, by-default True
+
Usage
-----
# To verify best path for routes 200.50.2.0/32 and 200.60.2.0/32 from
@@ -2420,7 +2431,7 @@ def verify_best_path_as_per_bgp_attribute(
@retry(attempts=5, wait=2, return_is_str=True)
def verify_best_path_as_per_admin_distance(
- tgen, addr_type, router, input_dict, attribute
+ tgen, addr_type, router, input_dict, attribute, expected=True
):
"""
API is to verify best path according to admin distance for given
@@ -2435,6 +2446,8 @@ def verify_best_path_as_per_admin_distance(
* `attribute` : calculate best path using admin distance
* `input_dict`: defines different routes with different admin distance
to calculate for which route best path is selected
+ * `expected` : expected results from API, by-default True
+
Usage
-----
# To verify best path for route 200.50.2.0/32 from router r2 to
@@ -2532,7 +2545,7 @@ def verify_best_path_as_per_admin_distance(
@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
def verify_bgp_rib(
- tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None
+ tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None, expected=True
):
"""
This API is to verify whether bgp rib has any
@@ -2547,6 +2560,7 @@ def verify_bgp_rib(
* `next_hop`[optional]: next_hop which needs to be verified,
default = static
* 'aspath'[optional]: aspath which needs to be verified
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2833,7 +2847,7 @@ def verify_bgp_rib(
@retry(attempts=5, wait=2, return_is_str=True)
-def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify verify_graceful_restart configuration of DUT and
cross verify the same from the peer bgp routerrouter.
@@ -2847,6 +2861,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
which user wants to test the data
* `dut`: input dut router name
* `peer`: input peer router name
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -3082,7 +3097,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
@retry(attempts=5, wait=2, return_is_str=True)
-def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify r_bit in the BGP gr capability advertised
by the neighbor router
@@ -3096,6 +3111,8 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
which user wants to test the data
* `dut`: input dut router name
* `peer`: peer name
+ * `expected` : expected results from API, by-default True
+
Usage
-----
input_dict = {
@@ -3200,7 +3217,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
@retry(attempts=5, wait=2, return_is_str=True)
-def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify EOR
@@ -3363,7 +3380,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
@retry(attempts=4, wait=2, return_is_str=True)
-def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify f_bit in the BGP gr capability advertised
by the neighbor router
@@ -3377,6 +3394,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
which user wants to test the data
* `dut`: input dut router name
* `peer`: peer name
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -3516,6 +3534,8 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
for which user wants to test the data
* `dut`: input dut router name
* `peer`: peer name
+ * `expected` : expected results from API, by-default True
+
Usage
-----
# Configure graceful-restart
@@ -3629,7 +3649,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
@retry(attempts=4, wait=2, return_is_str=True)
-def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
+def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=True):
"""
This API is to verify gr_address_family in the BGP gr capability advertised
by the neighbor router
@@ -3641,6 +3661,7 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
* `addr_type` : ip type ipv4/ipv6
* `addr_type` : ip type IPV4 Unicast/IPV6 Unicast
* `dut`: input dut router name
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -3730,6 +3751,7 @@ def verify_attributes_for_evpn_routes(
ipLen=None,
rd_peer=None,
rt_peer=None,
+ expected=True
):
"""
API to verify rd and rt value using "sh bgp l2vpn evpn 10.1.1.1"
@@ -3747,6 +3769,8 @@ def verify_attributes_for_evpn_routes(
* `ipLen` : IP prefix length
* `rd_peer` : Peer name from which RD will be auto-generated
* `rt_peer` : Peer name from which RT will be auto-generated
+ * `expected` : expected results from API, by-default True
+
Usage
-----
input_dict_1 = {
@@ -4117,7 +4141,7 @@ def verify_attributes_for_evpn_routes(
@retry(attempts=5, wait=2, return_is_str=True)
def verify_evpn_routes(
- tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None
+ tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None, expected=True
):
"""
API to verify evpn routes using "sh bgp l2vpn evpn"
@@ -4132,6 +4156,8 @@ def verify_evpn_routes(
* `route_type` : Route type 5 is supported as of now
* `EthTag` : Ethernet tag, by-default is 0
* `next_hop` : Prefered nexthop for the evpn routes
+ * `expected` : expected results from API, by-default True
+
Usage
-----
input_dict_1 = {
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index ee7cd6a7af..3f78f020bc 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -123,6 +123,17 @@ DEBUG_LOGS = {
"debug ospf te",
"debug ospf zebra",
],
+ "ospf6": [
+ "debug ospf6 event",
+ "debug ospf6 ism",
+ "debug ospf6 lsa",
+ "debug ospf6 nsm",
+ "debug ospf6 nssa",
+ "debug ospf6 packet all",
+ "debug ospf6 sr",
+ "debug ospf6 te",
+ "debug ospf6 zebra",
+ ],
}
if config.has_option("topogen", "verbosity"):
@@ -422,7 +433,10 @@ def check_router_status(tgen):
daemons.append("zebra")
if "pimd" in result:
daemons.append("pimd")
-
+ if "ospfd" in result:
+ daemons.append("ospfd")
+ if "ospf6d" in result:
+ daemons.append("ospf6d")
rnode.startDaemons(daemons)
except Exception as e:
@@ -890,6 +904,10 @@ def topo_daemons(tgen, topo):
for val in topo["routers"][rtr]["links"].values():
if "pim" in val and "pimd" not in daemon_list:
daemon_list.append("pimd")
+ if "ospf" in val and "ospfd" not in daemon_list:
+ daemon_list.append("ospfd")
+ if "ospf6" in val and "ospf6d" not in daemon_list:
+ daemon_list.append("ospf6d")
break
return daemon_list
diff --git a/tests/topotests/lib/mcast-tester.py b/tests/topotests/lib/mcast-tester.py
new file mode 100755
index 0000000000..07e4ab8773
--- /dev/null
+++ b/tests/topotests/lib/mcast-tester.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+
+"""
+Subscribe to a multicast group so that the kernel sends an IGMP JOIN
+for the multicast group we subscribed to.
+"""
+
+import argparse
+import os
+import json
+import socket
+import subprocess
+import struct
+import sys
+import time
+
+#
+# Functions
+#
+def interface_name_to_index(name):
+ "Gets the interface index using its name. Returns None on failure."
+ interfaces = json.loads(
+ subprocess.check_output('ip -j link show', shell=True))
+
+ for interface in interfaces:
+ if interface['ifname'] == name:
+ return interface['ifindex']
+
+ return None
+
+
+def multicast_join(sock, ifindex, group, port):
+ "Joins a multicast group."
+ mreq = struct.pack(
+ "=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex
+ )
+
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind((group, port))
+ sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+
+
+#
+# Main code.
+#
+parser = argparse.ArgumentParser(description="Multicast RX utility")
+parser.add_argument('socket', help='Point to topotest UNIX socket')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('interface', help='Interface name')
+parser.add_argument(
+ '--send',
+ help='Transmit instead of join with interval (defaults to 0.7 sec)',
+ type=float, default=0)
+args = parser.parse_args()
+
+ttl = 16
+port = 1000
+
+# Get interface index/validate.
+ifindex = interface_name_to_index(args.interface)
+if ifindex is None:
+ sys.stderr.write('Interface {} does not exists\n'.format(args.interface))
+ sys.exit(1)
+
+# We need root privileges to set up multicast.
+if os.geteuid() != 0:
+ sys.stderr.write("ERROR: You must have root privileges\n")
+ sys.exit(1)
+
+# Wait for topotest to synchronize with us.
+toposock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+while True:
+ try:
+ toposock.connect(args.socket)
+ break
+ except ConnectionRefusedError:
+ time.sleep(1)
+ continue
+
+msock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+if args.send > 0:
+ # Prepare multicast bit in that interface.
+ msock.setsockopt(
+ socket.SOL_SOCKET, 25,
+ struct.pack("%ds" % len(args.interface),
+ args.interface.encode('utf-8')))
+ # Set packets TTL.
+ msock.setsockopt(
+ socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", ttl))
+ # Block to ensure packet send.
+ msock.setblocking(True)
+ # Set topotest socket non blocking so we can multiplex the main loop.
+ toposock.setblocking(False)
+else:
+ multicast_join(msock, ifindex, args.group, port)
+
+counter = 0
+while True:
+ if args.send > 0:
+ msock.sendto(b"test %d" % counter, (args.group, port))
+ counter += 1
+ time.sleep(args.send)
+
+ try:
+ data = toposock.recv(1)
+ if data == b'':
+ print(' -> Connection closed')
+ break
+ except BlockingIOError:
+ continue
+
+msock.close()
+
+sys.exit(0)
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 7ad64de4a1..3f39b93d8c 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -18,13 +18,16 @@
# OF THIS SOFTWARE.
#
-from copy import deepcopy
import traceback
+import ipaddr
+import ipaddress
+import sys
+
+from copy import deepcopy
from time import sleep
from lib.topolog import logger
-import ipaddr
from lib.topotest import frr_unicode
-
+from ipaddress import IPv6Address
# Import common_config to use commomnly used APIs
from lib.common_config import (
create_common_configuration,
@@ -86,10 +89,21 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru
logger.debug("Router %s: 'ospf' not present in input_dict", router)
continue
- result = __create_ospf_global(tgen, input_dict, router, build, load_config)
+ result = __create_ospf_global(
+ tgen, input_dict, router, build, load_config)
if result is True:
ospf_data = input_dict[router]["ospf"]
+ for router in input_dict.keys():
+ if "ospf6" not in input_dict[router]:
+ logger.debug("Router %s: 'ospf6' not present in input_dict", router)
+ continue
+
+ result = __create_ospf_global(
+ tgen, input_dict, router, build, load_config, ospf='ospf6')
+ if result is True:
+ ospf_data = input_dict[router]["ospf6"]
+
logger.debug("Exiting lib API: create_router_ospf()")
return result
@@ -158,6 +172,7 @@ def __create_ospf_global(
config_data.append(cmd)
+
# router id
router_id = ospf_data.setdefault("router_id", None)
del_router_id = ospf_data.setdefault("del_router_id", False)
@@ -166,6 +181,33 @@ def __create_ospf_global(
if router_id:
config_data.append("{} router-id {}".format(ospf, router_id))
+ # log-adjacency-changes
+ log_adj_changes = ospf_data.setdefault("log_adj_changes", None)
+ del_log_adj_changes = ospf_data.setdefault("del_log_adj_changes", False)
+ if del_log_adj_changes:
+ config_data.append("no log-adjacency-changes detail")
+ if log_adj_changes:
+ config_data.append("log-adjacency-changes {}".format(
+ log_adj_changes))
+
+ # aggregation timer
+ aggr_timer = ospf_data.setdefault("aggr_timer", None)
+ del_aggr_timer = ospf_data.setdefault("del_aggr_timer", False)
+ if del_aggr_timer:
+ config_data.append("no aggregation timer")
+ if aggr_timer:
+ config_data.append("aggregation timer {}".format(
+ aggr_timer))
+
+ # maximum path information
+ ecmp_data = ospf_data.setdefault("maximum-paths", {})
+ if ecmp_data:
+ cmd = "maximum-paths {}".format(ecmp_data)
+ del_action = ospf_data.setdefault("del_max_path", False)
+ if del_action:
+ cmd = "no maximum-paths"
+ config_data.append(cmd)
+
# redistribute command
redistribute_data = ospf_data.setdefault("redistribute", {})
if redistribute_data:
@@ -203,6 +245,34 @@ def __create_ospf_global(
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ #def route information
+ def_rte_data = ospf_data.setdefault("default-information", {})
+ if def_rte_data:
+ if "originate" not in def_rte_data:
+ logger.debug("Router %s: 'originate key' not present in "
+ "input_dict", router)
+ else:
+ cmd = "default-information originate"
+
+ if "always" in def_rte_data:
+ cmd = cmd + " always"
+
+ if "metric" in def_rte_data:
+ cmd = cmd + " metric {}".format(def_rte_data["metric"])
+
+ if "metric-type" in def_rte_data:
+ cmd = cmd + " metric-type {}".format(def_rte_data[
+ "metric-type"])
+
+ if "route-map" in def_rte_data:
+ cmd = cmd + " route-map {}".format(def_rte_data[
+ "route-map"])
+
+ del_action = def_rte_data.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
# area interface information for ospf6d only
if ospf == "ospf6":
area_iface = ospf_data.setdefault("neighbors", {})
@@ -217,6 +287,21 @@ def __create_ospf_global(
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ try:
+ if "area" in input_dict[router]['links'][neighbor][
+ 'ospf6']:
+ iface = input_dict[router]["links"][neighbor]["interface"]
+ cmd = "interface {} area {}".format(
+ iface, input_dict[router]['links'][neighbor][
+ 'ospf6']['area'])
+ if input_dict[router]['links'][neighbor].setdefault(
+ "delete", False):
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ except KeyError:
+ pass
+
+
# summary information
summary_data = ospf_data.setdefault("summary-address", {})
if summary_data:
@@ -427,11 +512,11 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
result = create_common_configuration(
tgen, router, config_data, "interface_config", build=build
)
- logger.debug("Exiting lib API: create_igmp_config()")
+ logger.debug("Exiting lib API: config_ospf_interface()")
return result
-def clear_ospf(tgen, router):
+def clear_ospf(tgen, router, ospf=None):
"""
This API is to clear ospf neighborship by running
clear ip ospf interface * command,
@@ -451,11 +536,16 @@ def clear_ospf(tgen, router):
return False
rnode = tgen.routers()[router]
-
# Clearing OSPF
- logger.info("Clearing ospf process for router %s..", router)
+ if ospf:
+ version = "ipv6"
+ else:
+ version = "ip"
- run_frr_cmd(rnode, "clear ip ospf interface ")
+ cmd = "clear {} ospf interface".format(version)
+ logger.info(
+ "Clearing ospf process on router %s.. using command '%s'", router, cmd)
+ run_frr_cmd(rnode, cmd)
logger.debug("Exiting lib API: clear_ospf()")
@@ -490,7 +580,7 @@ def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
# Verification procs
################################
@retry(attempts=40, wait=2, return_is_str=True)
-def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
+def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False, expected=True):
"""
This API is to verify ospf neighborship by running
show ip ospf neighbour command,
@@ -502,6 +592,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
* `dut`: device under test
* `input_dict` : Input dict data, required when configuring from testcase
* `lan` : verify neighbors in lan topology
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -683,70 +774,194 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
################################
# Verification procs
################################
-@retry(attempts=40, wait=2, return_is_str=True)
-def verify_ospf6_neighbor(tgen, topo):
+@retry(attempts=10, wait=2, return_is_str=True)
+def verify_ospf6_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
"""
This API is to verify ospf neighborship by running
- show ip ospf neighbour command,
+ show ipv6 ospf neighbour command,
Parameters
----------
* `tgen` : Topogen object
* `topo` : json file data
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `lan` : verify neighbors in lan topology
Usage
-----
- Check FULL neighbors.
- verify_ospf_neighbor(tgen, topo)
+ 1. To check FULL neighbors.
+ verify_ospf_neighbor(tgen, topo, dut=dut)
- result = verify_ospf_neighbor(tgen, topo)
+ 2. To check neighbors with their roles.
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "neighbors": {
+ "r1": {
+ "state": "Full",
+ "role": "DR"
+ },
+ "r2": {
+ "state": "Full",
+ "role": "DROther"
+ },
+ "r3": {
+ "state": "Full",
+ "role": "DROther"
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf6_neighbor(tgen, topo, dut, input_dict, lan=True)
Returns
-------
True or False (Error Message)
"""
-
- logger.debug("Entering lib API: verify_ospf6_neighbor()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
result = False
- for router, rnode in tgen.routers().items():
- if "ospf6" not in topo["routers"][router]:
- continue
- logger.info("Verifying OSPF6 neighborship on router %s:", router)
- show_ospf_json = run_frr_cmd(
- rnode, "show ipv6 ospf6 neighbor json", isjson=True
- )
+ if input_dict:
+ for router, rnode in tgen.routers().items():
+ if 'ospf6' not in topo['routers'][router]:
+ continue
- if not show_ospf_json:
- return "OSPF6 is not running"
-
- ospf_nbr_list = topo["routers"][router]["ospf6"]["neighbors"]
- no_of_peer = 0
- for ospf_nbr in ospf_nbr_list:
- ospf_nbr_rid = topo["routers"][ospf_nbr]["ospf6"]["router_id"]
- for neighbor in show_ospf_json["neighbors"]:
- if neighbor["neighborId"] == ospf_nbr_rid:
- nh_state = neighbor["state"]
- break
- else:
- return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid)
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF neighborship on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode,
+ "show ipv6 ospf neighbor json", isjson=True)
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF6 is not running"
+ return errormsg
+
+ ospf_data_list = input_dict[router]["ospf6"]
+ ospf_nbr_list = ospf_data_list['neighbors']
+
+ for ospf_nbr, nbr_data in ospf_nbr_list.items():
+ data_ip = data_rid = topo['routers'][ospf_nbr]['ospf6']['router_id']
+ if ospf_nbr in data_ip:
+ nbr_details = nbr_data[ospf_nbr]
+ elif lan:
+ for switch in topo['switches']:
+ if 'ospf6' in topo['switches'][switch]['links'][router]:
+ neighbor_ip = data_ip
+ else:
+ continue
+ else:
+ neighbor_ip = data_ip[router]['ipv6'].split("/")[0]
- if nh_state == "Full":
- no_of_peer += 1
+ nh_state = None
+ neighbor_ip = neighbor_ip.lower()
+ nbr_rid = data_rid
+ get_index_val = dict((d['neighborId'], dict( \
+ d, index=index)) for (index, d) in enumerate( \
+ show_ospf_json['neighbors']))
+ try:
+ nh_state = get_index_val.get(neighbor_ip)['state']
+ intf_state = get_index_val.get(neighbor_ip)['ifState']
+ except TypeError:
+ errormsg = "[DUT: {}] OSPF peer {} missing,from "\
+ "{} ".format(router,
+ nbr_rid, ospf_nbr)
+ return errormsg
- if no_of_peer == len(ospf_nbr_list):
- logger.info("[DUT: {}] OSPF6 is Converged".format(router))
- result = True
- else:
- return "[DUT: {}] OSPF6 is not Converged".format(router)
+ nbr_state = nbr_data.setdefault("state",None)
+ nbr_role = nbr_data.setdefault("role",None)
- logger.debug("Exiting API: verify_ospf6_neighbor()")
+ if nbr_state:
+ if nbr_state == nh_state:
+ logger.info("[DUT: {}] OSPF6 Nbr is {}:{} State {}".format
+ (router, ospf_nbr, nbr_rid, nh_state))
+ result = True
+ else:
+ errormsg = ("[DUT: {}] OSPF6 is not Converged, neighbor"
+ " state is {} , Expected state is {}".format(router,
+ nh_state, nbr_state))
+ return errormsg
+ if nbr_role:
+ if nbr_role == intf_state:
+ logger.info("[DUT: {}] OSPF6 Nbr is {}: {} Role {}".format(
+ router, ospf_nbr, nbr_rid, nbr_role))
+ else:
+ errormsg = ("[DUT: {}] OSPF6 is not Converged with rid"
+ "{}, role is {}, Expected role is {}".format(router,
+ nbr_rid, intf_state, nbr_role))
+ return errormsg
+ continue
+ else:
+
+ for router, rnode in tgen.routers().items():
+ if 'ospf6' not in topo['routers'][router]:
+ continue
+
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF6 neighborship on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode,
+ "show ipv6 ospf neighbor json", isjson=True)
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF6 is not running"
+ return errormsg
+
+ ospf_data_list = topo["routers"][router]["ospf6"]
+ ospf_neighbors = ospf_data_list['neighbors']
+ total_peer = 0
+ total_peer = len(ospf_neighbors.keys())
+ no_of_ospf_nbr = 0
+ ospf_nbr_list = ospf_data_list['neighbors']
+ no_of_peer = 0
+ for ospf_nbr, nbr_data in ospf_nbr_list.items():
+ data_ip = data_rid = topo['routers'][ospf_nbr]['ospf6']['router_id']
+ if ospf_nbr in data_ip:
+ nbr_details = nbr_data[ospf_nbr]
+ elif lan:
+ for switch in topo['switches']:
+ if 'ospf6' in topo['switches'][switch]['links'][router]:
+ neighbor_ip = data_ip
+ else:
+ continue
+ else:
+ neighbor_ip = data_ip
+
+ nh_state = None
+ neighbor_ip = neighbor_ip.lower()
+ nbr_rid = data_rid
+ get_index_val = dict((d['neighborId'], dict( \
+ d, index=index)) for (index, d) in enumerate( \
+ show_ospf_json['neighbors']))
+ try:
+ nh_state = get_index_val.get(neighbor_ip)['state']
+ intf_state = get_index_val.get(neighbor_ip)['ifState']
+ except TypeError:
+ errormsg = "[DUT: {}] OSPF peer {} missing,from "\
+ "{} ".format(router,
+ nbr_rid, ospf_nbr)
+ return errormsg
+
+ if nh_state == 'Full':
+ no_of_peer += 1
+
+ if no_of_peer == total_peer:
+ logger.info("[DUT: {}] OSPF6 is Converged".format(router))
+ result = True
+ else:
+ errormsg = ("[DUT: {}] OSPF6 is not Converged".format(router))
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
@retry(attempts=21, wait=2, return_is_str=True)
def verify_ospf_rib(
- tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None
+ tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None, expected=True
):
"""
This API is to verify ospf routes by running
@@ -761,6 +976,7 @@ def verify_ospf_rib(
* `tag` : tag to be verified
* `metric` : metric to be verified
* `fib` : True if the route is installed in FIB.
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1021,7 +1237,7 @@ def verify_ospf_rib(
@retry(attempts=10, wait=2, return_is_str=True)
-def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
+def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None, expected=True):
"""
This API is to verify ospf routes by running
show ip ospf interface command.
@@ -1033,6 +1249,7 @@ def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
* `dut`: device under test
* `lan`: if set to true this interface belongs to LAN.
* `input_dict` : Input dict data, required when configuring from testcase
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1110,7 +1327,7 @@ def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
@retry(attempts=11, wait=2, return_is_str=True)
-def verify_ospf_database(tgen, topo, dut, input_dict):
+def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
"""
This API is to verify ospf lsa's by running
show ip ospf database command.
@@ -1121,6 +1338,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict):
* `dut`: device under test
* `input_dict` : Input dict data, required when configuring from testcase
* `topo` : next to be verified
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1273,7 +1491,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict):
@retry(attempts=10, wait=2, return_is_str=True)
-def verify_ospf_summary(tgen, topo, dut, input_dict):
+def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
"""
This API is to verify ospf routes by running
show ip ospf interface command.
@@ -1284,6 +1502,7 @@ def verify_ospf_summary(tgen, topo, dut, input_dict):
* `topo` : topology descriptions
* `dut`: device under test
* `input_dict` : Input dict data, required when configuring from testcase
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1349,3 +1568,667 @@ def verify_ospf_summary(tgen, topo, dut, input_dict):
logger.debug("Exiting API: verify_ospf_summary()")
return result
+
+
+
+@retry(attempts=10, wait=3, return_is_str=True)
+def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
+ tag=None, metric=None, fib=None):
+ """
+ This API is to verify ospf routes by running
+ show ip ospf route command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `next_hop` : next to be verified
+ * `tag` : tag to be verified
+ * `metric` : metric to be verified
+ * `fib` : True if the route is installed in FIB.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": ip_net,
+ "no_of_ip": 1,
+ "routeType": "N"
+ }
+ ]
+ }
+ }
+
+ result = verify_ospf6_rib(tgen, dut, input_dict,next_hop=nh)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+ router_list = tgen.routers()
+ additional_nexthops_in_required_nhs = []
+ found_hops = []
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s RIB:", router)
+
+ # Verifying RIB routes
+ command = "show ipv6 ospf route"
+
+ found_routes = []
+ missing_routes = []
+
+ if "static_routes" in input_dict[routerInput] or \
+ "prefix" in input_dict[routerInput]:
+ if "prefix" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["prefix"]
+ else:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+
+ for static_route in static_routes:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ ospf_rib_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Fix for PR 2644182
+ try:
+ ospf_rib_json = ospf_rib_json['routes']
+ except KeyError:
+ pass
+
+ # Verifying output dictionary ospf_rib_json is not empty
+ if bool(ospf_rib_json) is False:
+ errormsg = "[DUT: {}] No routes found in OSPF6 route " \
+ "table".format(router)
+ return errormsg
+
+ network = static_route["network"]
+ no_of_ip = static_route.setdefault("no_of_ip", 1)
+ _tag = static_route.setdefault("tag", None)
+ _rtype = static_route.setdefault("routeType", None)
+
+
+ # Generating IPs for verification
+ ip_list = generate_ips(network, no_of_ip)
+ st_found = False
+ nh_found = False
+ for st_rt in ip_list:
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != 'ipv6':
+ continue
+
+ if st_rt in ospf_rib_json:
+
+ st_found = True
+ found_routes.append(st_rt)
+
+ if fib and next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ for mnh in range(0, len(ospf_rib_json[st_rt])):
+ if 'fib' in ospf_rib_json[st_rt][
+ mnh]["nextHops"][0]:
+ found_hops.append([rib_r[
+ "ip"] for rib_r in ospf_rib_json[
+ st_rt][mnh]["nextHops"]])
+
+ if found_hops[0]:
+ missing_list_of_nexthops = \
+ set(found_hops[0]).difference(next_hop)
+ additional_nexthops_in_required_nhs = \
+ set(next_hop).difference(found_hops[0])
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Nexthop "
+ "%s is not active for route %s in "
+ "RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt, dut)
+ errormsg = (
+ "Nexthop {} is not active"
+ " for route {} in RIB of router"
+ " {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt, dut))
+ return errormsg
+ else:
+ nh_found = True
+
+ elif next_hop and fib is None:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+ found_hops = [rib_r['nextHop'] for rib_r in
+ ospf_rib_json[st_rt][
+ "nextHops"]]
+
+ if found_hops:
+ missing_list_of_nexthops = \
+ set(found_hops).difference(next_hop)
+ additional_nexthops_in_required_nhs = \
+ set(next_hop).difference(found_hops)
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Missing nexthop %s for route"\
+ " %s in RIB of router %s\n", \
+ additional_nexthops_in_required_nhs, \
+ st_rt, dut)
+ errormsg=("Nexthop {} is Missing for "\
+ "route {} in RIB of router {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt, dut))
+ return errormsg
+ else:
+ nh_found = True
+ if _rtype:
+ if "destinationType" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: destinationType missing"
+ "for route {} in OSPF RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+ elif _rtype != ospf_rib_json[st_rt][
+ "destinationType"]:
+ errormsg = ("[DUT: {}]: destinationType mismatch"
+ "for route {} in OSPF RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+ else:
+ logger.info("DUT: {}]: Found destinationType {}"
+ "for route {}".\
+ format(dut, _rtype, st_rt))
+ if tag:
+ if "tag" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: tag is not"
+ " present for"
+ " route {} in RIB \n".\
+ format(dut, st_rt
+ ))
+ return errormsg
+
+ if _tag != ospf_rib_json[
+ st_rt]["tag"]:
+ errormsg = ("[DUT: {}]: tag value {}"
+ " is not matched for"
+ " route {} in RIB \n".\
+ format(dut, _tag, st_rt,
+ ))
+ return errormsg
+
+ if metric is not None:
+ if "type2cost" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: metric is"
+ " not present for"
+ " route {} in RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+
+ if metric != ospf_rib_json[
+ st_rt]["type2cost"]:
+ errormsg = ("[DUT: {}]: metric value "
+ "{} is not matched for "
+ "route {} in RIB \n".\
+ format(dut, metric, st_rt,
+ ))
+ return errormsg
+
+ else:
+ missing_routes.append(st_rt)
+
+ if nh_found:
+ logger.info("[DUT: {}]: Found next_hop {} for all OSPF"
+ " routes in RIB".format(router, next_hop))
+
+ if len(missing_routes) > 0:
+ errormsg = ("[DUT: {}]: Missing route in RIB, "
+ "routes: {}".\
+ format(dut, missing_routes))
+ return errormsg
+
+ if found_routes:
+ logger.info("[DUT: %s]: Verified routes in RIB, found"
+ " routes are: %s\n", dut, found_routes)
+ result = True
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
+
+
+@retry(attempts=3, wait=2, return_is_str=True)
+def verify_ospf6_interface(tgen, topo, dut=None,lan=False, input_dict=None):
+ """
+ This API is to verify ospf routes by running
+ show ip ospf interface command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : topology descriptions
+ * `dut`: device under test
+ * `lan`: if set to true this interface belongs to LAN.
+ * `input_dict` : Input dict data, required when configuring from testcase
+
+ Usage
+ -----
+ input_dict= {
+ 'r0': {
+ 'links':{
+ 's1': {
+ 'ospf6':{
+ 'priority':98,
+ 'timerDeadSecs': 4,
+ 'area': '0.0.0.3',
+ 'mcastMemberOspfDesignatedRouters': True,
+ 'mcastMemberOspfAllRouters': True,
+ 'ospfEnabled': True,
+
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+
+ for router, rnode in tgen.routers().iteritems():
+ if 'ospf6' not in topo['routers'][router]:
+ continue
+
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF interface on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode, "show ipv6 ospf interface json",
+ isjson=True)
+
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF6 is not running"
+ return errormsg
+
+ # To find neighbor ip type
+ ospf_intf_data = input_dict[router]["links"]
+ for ospf_intf, intf_data in ospf_intf_data.items():
+ intf = topo['routers'][router]['links'][ospf_intf]['interface']
+ if intf in show_ospf_json:
+ for intf_attribute in intf_data['ospf6']:
+ if intf_data['ospf6'][intf_attribute] is not list:
+ if intf_data['ospf6'][intf_attribute] == show_ospf_json[
+ intf][intf_attribute]:
+ logger.info("[DUT: %s] OSPF6 interface %s: %s is %s",
+ router, intf, intf_attribute, intf_data['ospf6'][
+ intf_attribute])
+ elif intf_data['ospf6'][intf_attribute] is list:
+ for addr_list in len(show_ospf_json[intf][intf_attribute]):
+ if show_ospf_json[intf][intf_attribute][addr_list][
+ 'address'].split('/')[0] == intf_data['ospf6'][
+ 'internetAddress'][0]['address']:
+ break
+ else:
+ errormsg= "[DUT: {}] OSPF6 interface {}: {} is {}, \
+ Expected is {}".format(router, intf, intf_attribute,
+ intf_data['ospf6'][intf_attribute], intf_data['ospf6'][
+ intf_attribute])
+ return errormsg
+ else:
+ errormsg= "[DUT: {}] OSPF6 interface {}: {} is {}, \
+ Expected is {}".format(router, intf, intf_attribute,
+ intf_data['ospf6'][intf_attribute], intf_data['ospf6'][
+ intf_attribute])
+ return errormsg
+ result = True
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
+
+
+@retry(attempts=11, wait=2, return_is_str=True)
+def verify_ospf6_database(tgen, topo, dut, input_dict):
+ """
+ This API is to verify 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
+
+ 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 = verify_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))
+
+ 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)
+ show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json",
+ 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 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']:
+ if lsa['lsaId'] == rtrlsa['lsaId'] and \
+ lsa['advertisedRouter'] == rtrlsa[
+ 'advertisedRouter']:
+ 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 {}".format(router, ospf_area, lsa)
+ 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
+
+
+
+def config_ospf6_interface (tgen, topo, input_dict=None, build=False,
+ load_config=True):
+ """
+ API to configure ospf on router.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `build` : Only for initial setup phase this is set as True.
+ * `load_config` : Loading the config to router this is set as True.
+
+ Usage
+ -----
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": 'message-digest',
+ "authentication-key": "ospf",
+ "message-digest-key": "10"
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf6_interface(tgen, topo, r1_ospf_auth)
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ input_dict = deepcopy(input_dict)
+ for router in input_dict.keys():
+ config_data = []
+ for lnk in input_dict[router]['links'].keys():
+ if "ospf6" not in input_dict[router]['links'][lnk]:
+ logger.debug("Router %s: ospf6 configs is not present in"
+ "input_dict, passed input_dict", router,
+ input_dict)
+ continue
+ ospf_data = input_dict[router]['links'][lnk]['ospf6']
+ data_ospf_area = ospf_data.setdefault("area", None)
+ data_ospf_auth = ospf_data.setdefault("authentication", None)
+ data_ospf_dr_priority = ospf_data.setdefault("priority", None)
+ data_ospf_cost = ospf_data.setdefault("cost", None)
+ data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None)
+
+ try:
+ intf = topo['routers'][router]['links'][lnk]['interface']
+ except KeyError:
+ intf = topo['switches'][router]['links'][lnk]['interface']
+
+ # interface
+ cmd = "interface {}".format(intf)
+
+ config_data.append(cmd)
+ # interface area config
+ if data_ospf_area:
+ cmd = "ipv6 ospf area {}".format(data_ospf_area)
+ config_data.append(cmd)
+
+ # interface ospf dr priority
+ if data_ospf_dr_priority:
+ cmd = "ipv6 ospf priority {}".format(
+ ospf_data["priority"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ # interface ospf cost
+ if data_ospf_cost:
+ cmd = "ipv6 ospf cost {}".format(
+ ospf_data["cost"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ # interface ospf mtu
+ if data_ospf_mtu:
+ cmd = "ipv6 ospf mtu-ignore"
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if build:
+ return config_data
+ else:
+ result = create_common_configuration(tgen, router, config_data,
+ "interface_config",
+ build=build)
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index 61a5705a5d..ce90717fa4 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -496,7 +496,7 @@ def configure_pim_force_expire(tgen, topo, input_dict, build=False):
# Verification APIs
#############################################
@retry(attempts=6, wait=2, return_is_str=True)
-def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
+def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
"""
Verify all PIM neighbors are up and running, config is verified
using "show ip pim neighbor" cli
@@ -508,6 +508,7 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
* `dut` : dut info
* `iface` : link for which PIM nbr need to check
* `nbr_ip` : neighbor ip of interface
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -619,7 +620,7 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
@retry(attempts=21, wait=2, return_is_str=True)
-def verify_igmp_groups(tgen, dut, interface, group_addresses):
+def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
"""
Verify IGMP groups are received from an intended interface
by running "show ip igmp groups" command
@@ -630,6 +631,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses):
* `dut`: device under test
* `interface`: interface, from which IGMP groups would be received
* `group_addresses`: IGMP group address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -693,7 +695,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses):
@retry(attempts=31, wait=2, return_is_str=True)
def verify_upstream_iif(
- tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1
+ tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1, expected=True
):
"""
Verify upstream inbound interface is updated correctly
@@ -708,6 +710,7 @@ def verify_upstream_iif(
* `group_addresses`: IGMP group address
* `joinState`: upstream join state
* `refCount`: refCount value
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -845,7 +848,7 @@ def verify_upstream_iif(
@retry(attempts=6, wait=2, return_is_str=True)
-def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
+def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses, expected=True):
"""
Verify join state is updated correctly and join timer is
running with the help of "show ip pim upstream" cli
@@ -857,6 +860,7 @@ def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
* `iif`: inbound interface
* `src_address`: source address
* `group_addresses`: IGMP group address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -964,7 +968,7 @@ def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
@retry(attempts=41, wait=2, return_is_dict=True)
def verify_ip_mroutes(
- tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0
+ tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0, expected=True
):
"""
Verify ip mroutes and make sure (*, G)/(S, G) is present in mroutes
@@ -980,7 +984,7 @@ def verify_ip_mroutes(
* `oil`: Outgoing interface
* `return_uptime`: If True, return uptime dict, default is False
* `mwait`: Wait time, default is 0
-
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1161,7 +1165,7 @@ def verify_ip_mroutes(
@retry(attempts=31, wait=2, return_is_str=True)
def verify_pim_rp_info(
- tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None
+ tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None, expected=True
):
"""
Verify pim rp info by running "show ip pim rp-info" cli
@@ -1176,6 +1180,7 @@ def verify_pim_rp_info(
* `rp`: RP address
* `source`: Source of RP
* `iamrp`: User defined RP
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1317,7 +1322,7 @@ def verify_pim_rp_info(
@retry(attempts=31, wait=2, return_is_str=True)
def verify_pim_state(
- tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None
+ tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None, expected=True
):
"""
Verify pim state by running "show ip pim state" cli
@@ -1331,6 +1336,7 @@ def verify_pim_state(
* `group_addresses`: IGMP group address
* `src_address`: source address, default = None
* installed_fl` : Installed flag
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1485,7 +1491,7 @@ def verify_pim_interface_traffic(tgen, input_dict):
@retry(attempts=21, wait=2, return_is_str=True)
-def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
+def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None, expected=True):
"""
Verify all PIM interface are up and running, config is verified
using "show ip pim interface" cli
@@ -1497,6 +1503,7 @@ def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
* `dut` : device under test
* `interface` : interface name
* `interface_ip` : interface ip address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -1791,7 +1798,7 @@ def clear_ip_igmp_interfaces(tgen, dut):
@retry(attempts=10, wait=2, return_is_str=True)
-def clear_ip_mroute_verify(tgen, dut):
+def clear_ip_mroute_verify(tgen, dut, expected=True):
"""
Clear ip mroute by running "clear ip mroute" cli and verify
mroutes are up again after mroute clear
@@ -1800,6 +1807,8 @@ def clear_ip_mroute_verify(tgen, dut):
----------
* `tgen`: topogen object
* `dut`: Device Under Test
+ * `expected` : expected results from API, by-default True
+
Usage
-----
@@ -2165,7 +2174,7 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
@retry(attempts=6, wait=2, return_is_str=True)
-def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
+def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None, expected=True):
"""
Verify pim rp info by running "show ip pim rp-info" cli
@@ -2177,6 +2186,7 @@ def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
* `grp_addr`: IGMP group address
* 'rp_source': source from which rp installed
* 'rpadd': rp address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2267,7 +2277,7 @@ def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
@retry(attempts=31, wait=2, return_is_str=True)
-def verify_pim_bsr(tgen, topo, dut, bsr_ip):
+def verify_pim_bsr(tgen, topo, dut, bsr_ip, expected=True):
"""
Verify all PIM interface are up and running, config is verified
using "show ip pim interface" cli
@@ -2278,6 +2288,7 @@ def verify_pim_bsr(tgen, topo, dut, bsr_ip):
* `topo` : json file data
* `dut` : device under test
* 'bsr' : bsr ip to be verified
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2322,7 +2333,7 @@ def verify_pim_bsr(tgen, topo, dut, bsr_ip):
@retry(attempts=31, wait=2, return_is_str=True)
-def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None):
+def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None, expected=True):
"""
Verify IP PIM upstream rpf, config is verified
using "show ip pim neighbor" cli
@@ -2336,6 +2347,7 @@ def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=N
* `group_addresses` : list of group address for which upstream info
needs to be checked
* `rp` : RP address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2519,7 +2531,7 @@ def enable_disable_pim_bsm(tgen, router, intf, enable=True):
@retry(attempts=31, wait=2, return_is_str=True)
-def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None):
+def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None, expected=True):
"""
Verify ip pim join by running "show ip pim join" cli
@@ -2531,6 +2543,7 @@ def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=
* `interface`: interface name, from which PIM join would come
* `group_addresses`: IGMP group address
* `src_address`: Source address
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2609,7 +2622,7 @@ def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=
@retry(attempts=31, wait=2, return_is_dict=True)
-def verify_igmp_config(tgen, input_dict, stats_return=False):
+def verify_igmp_config(tgen, input_dict, stats_return=False, expected=True):
"""
Verify igmp interface details, verifying following configs:
timerQueryInterval
@@ -2623,6 +2636,7 @@ def verify_igmp_config(tgen, input_dict, stats_return=False):
* `input_dict` : Input dict data, required to verify
timer
* `stats_return`: If user wants API to return statistics
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -2898,7 +2912,7 @@ def verify_igmp_config(tgen, input_dict, stats_return=False):
@retry(attempts=31, wait=2, return_is_str=True)
-def verify_pim_config(tgen, input_dict):
+def verify_pim_config(tgen, input_dict, expected=True):
"""
Verify pim interface details, verifying following configs:
drPriority
@@ -2912,6 +2926,7 @@ def verify_pim_config(tgen, input_dict):
* `tgen`: topogen object
* `input_dict` : Input dict data, required to verify
timer
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -3023,7 +3038,7 @@ def verify_pim_config(tgen, input_dict):
@retry(attempts=21, wait=2, return_is_dict=True)
-def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
+def verify_multicast_traffic(tgen, input_dict, return_traffic=False, expected=True):
"""
Verify multicast traffic by running
"show multicast traffic count json" cli
@@ -3034,6 +3049,8 @@ def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
* `input_dict(dict)`: defines DUT, what and for which interfaces
traffic needs to be verified
* `return_traffic`: returns traffic stats
+ * `expected` : expected results from API, by-default True
+
Usage
-----
input_dict = {
@@ -3264,7 +3281,7 @@ def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
@retry(attempts=21, wait=2, return_is_str=True)
-def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
+def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag, expected=True):
"""
Verify flag state for mroutes and make sure (*, G)/(S, G) are having
coorect flags by running "show ip mroute" cli
@@ -3276,6 +3293,7 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
* `src_address`: source address
* `group_addresses`: IGMP group address
* `flag`: flag state, needs to be verified
+ * `expected` : expected results from API, by-default True
Usage
-----
@@ -3358,7 +3376,7 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
@retry(attempts=21, wait=2, return_is_str=True)
-def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
+def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip, expected=True):
"""
Verify all IGMP interface are up and running, config is verified
using "show ip igmp interface" cli
@@ -3370,6 +3388,7 @@ def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
* `dut` : device under test
* `igmp_iface` : interface name
* `interface_ip` : interface ip address
+ * `expected` : expected results from API, by-default True
Usage
-----
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 553f2bc6cf..ade5933504 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -222,6 +222,22 @@ class Topogen(object):
self.peern += 1
return self.gears[name]
+ def add_host(self, name, ip, defaultRoute):
+ """
+ Adds a new host to the topology. This function has the following
+ parameters:
+ * `ip`: the peer address (e.g. '1.2.3.4/24')
+ * `defaultRoute`: the peer default route (e.g. 'via 1.2.3.1')
+ """
+ if name is None:
+ name = "host{}".format(self.peern)
+ if name in self.gears:
+ raise KeyError("host already exists")
+
+ self.gears[name] = TopoHost(self, name, ip=ip, defaultRoute=defaultRoute)
+ self.peern += 1
+ return self.gears[name]
+
def add_link(self, node1, node2, ifname1=None, ifname2=None):
"""
Creates a connection between node1 and node2. The nodes can be the
@@ -641,6 +657,8 @@ class TopoRouter(TopoGear):
# Try to find relevant old logfiles in /tmp and delete them
map(os.remove, glob.glob("{}/{}/*.log".format(self.logdir, self.name)))
+ # Remove old valgrind files
+ map(os.remove, glob.glob("{}/{}.valgrind.*".format(self.logdir, self.name)))
# Remove old core files
map(os.remove, glob.glob("{}/{}/*.dmp".format(self.logdir, self.name)))
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 2a5bd17361..d1f60bfe0d 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1454,6 +1454,8 @@ class Router(Node):
gdb_breakpoints = g_extra_config["gdb_breakpoints"]
gdb_daemons = g_extra_config["gdb_daemons"]
gdb_routers = g_extra_config["gdb_routers"]
+ valgrind_extra = g_extra_config["valgrind_extra"]
+ valgrind_memleaks = g_extra_config["valgrind_memleaks"]
bundle_data = ""
@@ -1503,7 +1505,14 @@ class Router(Node):
) + "/var/run/{}/snmpd.pid -x /etc/frr/agentx".format(self.routertype)
else:
binary = os.path.join(self.daemondir, daemon)
+
cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon)
+ if valgrind_memleaks:
+ this_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+ supp_file = os.path.abspath(os.path.join(this_dir, "../../../tools/valgrind.supp"))
+ cmdenv += " /usr/bin/valgrind --num-callers=50 --log-file={1}/{2}.valgrind.{0}.%p --leak-check=full --suppressions={3}".format(daemon, self.logdir, self.name, supp_file)
+ if valgrind_extra:
+ cmdenv += "--gen-suppressions=all --expensive-definedness-checks=yes"
cmdopt = "{} --log file:{}.log --log-level debug".format(
daemon_opts, daemon
)
diff --git a/tests/topotests/msdp_mesh_topo1/__init__.py b/tests/topotests/msdp_mesh_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/__init__.py
diff --git a/tests/topotests/msdp_mesh_topo1/r1/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r1/bgpd.conf
new file mode 100644
index 0000000000..953d90aa03
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r1/bgpd.conf
@@ -0,0 +1,7 @@
+router bgp 65000
+ neighbor 10.254.254.2 remote-as 65000
+ neighbor 10.254.254.2 update-source 10.254.254.1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r1/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r1/ospfd.conf
new file mode 100644
index 0000000000..c1adbd5440
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r1/ospfd.conf
@@ -0,0 +1,8 @@
+interface r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r1/pimd.conf b/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
new file mode 100644
index 0000000000..49341efa57
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
@@ -0,0 +1,15 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.1
+!
+interface r1-eth0
+ ip pim
+!
+interface r1-eth1
+ ip pim
+ ip igmp
+!
+ip pim rp 10.254.254.1
+ip msdp mesh-group mg-1 source 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.2
+ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r1/zebra.conf b/tests/topotests/msdp_mesh_topo1/r1/zebra.conf
new file mode 100644
index 0000000000..42c850f00f
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r1/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.2/24
+!
+interface r1-eth1
+ ip address 192.168.10.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r2/bgpd.conf
new file mode 100644
index 0000000000..f442efc60f
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r2/bgpd.conf
@@ -0,0 +1,10 @@
+router bgp 65000
+ neighbor pg-1 peer-group
+ neighbor pg-1 update-source 10.254.254.1
+ neighbor pg-1 remote-as 65000
+ neighbor 10.254.254.1 peer-group pg-1
+ neighbor 10.254.254.3 peer-group pg-1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r2/ospfd.conf
new file mode 100644
index 0000000000..9e9ac5fb2e
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r2/ospfd.conf
@@ -0,0 +1,13 @@
+interface r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+interface r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ network 192.168.2.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/pimd.conf b/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
new file mode 100644
index 0000000000..9005263ed7
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
@@ -0,0 +1,14 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.2
+!
+interface r2-eth0
+ ip pim
+!
+interface r2-eth1
+ ip pim
+!
+ip pim rp 10.254.254.2
+ip msdp mesh-group mg-1 source 10.254.254.2
+ip msdp mesh-group mg-1 member 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r2/zebra.conf b/tests/topotests/msdp_mesh_topo1/r2/zebra.conf
new file mode 100644
index 0000000000..6b26194218
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r2/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ip address 192.168.1.1/24
+!
+interface r2-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r3/bgpd.conf
new file mode 100644
index 0000000000..6c3f89ad97
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r3/bgpd.conf
@@ -0,0 +1,7 @@
+router bgp 65000
+ neighbor 192.168.2.1 remote-as 65000
+ neighbor 192.168.2.1 update-source 10.254.254.3
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r3/ospfd.conf
new file mode 100644
index 0000000000..7b7b1abe62
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r3/ospfd.conf
@@ -0,0 +1,8 @@
+interface r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.2.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/pimd.conf b/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
new file mode 100644
index 0000000000..30e1148561
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
@@ -0,0 +1,15 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.3
+!
+interface r3-eth0
+ ip pim
+!
+interface r3-eth1
+ ip pim
+ ip igmp
+!
+ip pim rp 10.254.254.3
+ip msdp mesh-group mg-1 source 10.254.254.3
+ip msdp mesh-group mg-1 member 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.2
diff --git a/tests/topotests/msdp_mesh_topo1/r3/zebra.conf b/tests/topotests/msdp_mesh_topo1/r3/zebra.conf
new file mode 100644
index 0000000000..a8a15f3c0f
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/r3/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.2/24
+!
+interface r3-eth1
+ ip address 192.168.30.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot
new file mode 100644
index 0000000000..8792e2c7bb
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot
@@ -0,0 +1,88 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="msdp_mesh_topo1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ h1 [
+ shape=doubleoctagon
+ label="h1",
+ fillcolor="#4f4f4f",
+ style=filled,
+ ];
+ h2 [
+ shape=doubleoctagon
+ label="h2",
+ fillcolor="#4f4f4f",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="sw1\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="sw2\n192.168.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s3 [
+ shape=oval,
+ label="sw3\n192.168.10.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s4 [
+ shape=oval,
+ label="sw3\n192.168.30.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- s1 [label="eth0\n.2"];
+ r2 -- s1 [label="eth0\n.1"];
+
+ r2 -- s2 [label="eth1\n.1"];
+ r3 -- s2 [label="eth0\n.2"];
+
+ r1 -- s3 [label="eth1\n.1"];
+ h1 -- s3 [label="eth0\n.2"];
+
+ r3 -- s4 [label="eth1\n.1"];
+ h2 -- s4 [label="eth0\n.2"];
+}
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png
new file mode 100644
index 0000000000..9a15b8b088
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png
Binary files differ
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
new file mode 100644
index 0000000000..719ead091c
--- /dev/null
+++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
@@ -0,0 +1,296 @@
+#!/usr/bin/env python
+
+#
+# test_msdp_mesh_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (C) 2021 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.
+#
+
+"""
+test_msdp_mesh_topo1.py: Test the FRR PIM MSDP mesh groups.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import socket
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.pimd]
+
+#
+# Test global variables:
+# They are used to handle communicating with external application.
+#
+APP_SOCK_PATH = '/tmp/topotests/apps.sock'
+HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
+app_listener = None
+app_clients = {}
+
+def listen_to_applications():
+ "Start listening socket to connect with applications."
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+ sock.bind(APP_SOCK_PATH)
+ sock.listen(10)
+ global app_listener
+ app_listener = sock
+
+def accept_host(host):
+ "Accept connection from application running in hosts."
+ global app_listener, app_clients
+ conn = app_listener.accept()
+ app_clients[host] = {
+ 'fd': conn[0],
+ 'address': conn[1]
+ }
+
+def close_applications():
+ "Signal applications to stop and close all sockets."
+ global app_listener, app_clients
+
+ # Close listening socket.
+ app_listener.close()
+
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ # Close all host connections.
+ for host in ["h1", "h2"]:
+ if app_clients.get(host) is None:
+ continue
+ app_clients["h1"]["fd"].close()
+
+
+class MSDPMeshTopo1(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 3 routers
+ for routern in range(1, 4):
+ 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["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ # Create stub networks for multicast traffic.
+ tgen.add_host("h1", "192.168.10.2/24", "192.168.10.1")
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["h1"])
+
+ tgen.add_host("h2", "192.168.30.2/24", "192.168.30.1")
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["h2"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(MSDPMeshTopo1, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BGP, daemon_file)
+
+ daemon_file = "{}/{}/ospfd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_OSPF, daemon_file)
+
+ daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_PIM, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Start applications socket.
+ listen_to_applications()
+
+
+def test_wait_ospf_convergence():
+ "Wait for OSPF to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_loopback_route(router, iptype, route, proto):
+ "Wait until route is present on RIB for protocol."
+ logger.info("waiting route {} in {}".format(route, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show {} route json".format(iptype),
+ {route: [{"protocol": proto}]}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=1)
+ assertmsg = '"{}" OSPF convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ # Wait for R1 <-> R2 convergence.
+ expect_loopback_route("r1", "ip", "10.254.254.2/32", "ospf")
+ # Wait for R1 <-> R3 convergence.
+ expect_loopback_route("r1", "ip", "10.254.254.3/32", "ospf")
+
+ # Wait for R2 <-> R1 convergence.
+ expect_loopback_route("r2", "ip", "10.254.254.1/32", "ospf")
+ # Wait for R2 <-> R3 convergence.
+ expect_loopback_route("r2", "ip", "10.254.254.3/32", "ospf")
+
+ # Wait for R3 <-> R1 convergence.
+ expect_loopback_route("r3", "ip", "10.254.254.1/32", "ospf")
+ # Wait for R3 <-> R2 convergence.
+ expect_loopback_route("r3", "ip", "10.254.254.2/32", "ospf")
+
+
+def test_wait_msdp_convergence():
+ "Wait for MSDP to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("test MSDP convergence")
+
+ tgen.gears["h1"].run("{} --send='0.7' '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h1-eth0'))
+ accept_host("h1")
+
+ tgen.gears["h2"].run("{} '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h2-eth0'))
+ accept_host("h2")
+
+ def expect_msdp_peer(router, peer, sa_count=0):
+ "Expect MSDP peer connection to be established with SA amount."
+ logger.info("waiting MSDP connection from peer {} on router {}".format(peer, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ip msdp peer json",
+ {peer: {"state": "established", "saCount": sa_count}}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" MSDP connection failure'.format(router)
+ assert result is None, assertmsg
+
+ # R1 peers.
+ expect_msdp_peer("r1", "10.254.254.2")
+ expect_msdp_peer("r1", "10.254.254.3")
+
+ # R2 peers.
+ expect_msdp_peer("r2", "10.254.254.1", 1)
+ expect_msdp_peer("r2", "10.254.254.3")
+
+ # R3 peers.
+ expect_msdp_peer("r3", "10.254.254.1", 1)
+ expect_msdp_peer("r3", "10.254.254.2")
+
+
+def test_msdp_sa_configuration():
+ "Expect the multicast traffic SA to be created"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("test MSDP SA")
+
+ def expect_msdp_sa(router, source, group, local, rp, spt_setup):
+ "Expect MSDP SA."
+ logger.info("waiting MSDP SA on router {}".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ip msdp sa json",
+ {group: {source: {"local": local, "rp": rp, "sptSetup": spt_setup}}}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" MSDP SA failure'.format(router)
+ assert result is None, assertmsg
+
+ source = "192.168.10.2"
+ group = "229.0.1.10"
+ rp = "10.254.254.1"
+
+ # R1 SA.
+ expect_msdp_sa("r1", source, group, "yes", "-", "-")
+
+ # R2 SA.
+ expect_msdp_sa("r2", source, group, "no", rp, "no")
+
+ # R3 peers.
+ expect_msdp_sa("r3", source, group, "no", rp, "yes")
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ close_applications()
+ tgen.stop_topology()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref b/tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref
index a2ddf7c5ae..96489b0756 100644
--- a/tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref
+++ b/tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref b/tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref
index 1f642b1b22..78c1ad8830 100644
--- a/tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref
+++ b/tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref
@@ -4,7 +4,7 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref b/tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref
index 8e3afa583a..dc0acbe0c5 100644
--- a/tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref
+++ b/tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref
@@ -4,7 +4,7 @@ O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:
O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref b/tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref
index 0df652ffb3..730fd9f2d5 100644
--- a/tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref
+++ b/tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref
@@ -6,4 +6,4 @@ O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX
O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1_vrf/README.md b/tests/topotests/ospf6_topo1_vrf/README.md
index 3ed0b8fbe2..18bca5c54f 100644
--- a/tests/topotests/ospf6_topo1_vrf/README.md
+++ b/tests/topotests/ospf6_topo1_vrf/README.md
@@ -54,10 +54,12 @@ Simplified `R1` config (R1 is similar)
hostname r1
!
interface r1-stubnet vrf r1-cust1
+ ipv6 ospf6 area 0.0.0.0
ipv6 address fc00:1:1:1::1/64
ipv6 ospf6 network broadcast
!
interface r1-sw5 vrf r1-cust1
+ ipv6 ospf6 area 0.0.0.0
ipv6 address fc00:a:a:a::1/64
ipv6 ospf6 network broadcast
!
@@ -65,8 +67,6 @@ Simplified `R1` config (R1 is similar)
router-id 10.0.0.1
log-adjacency-changes detail
redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
!
ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 vrf r1-cust1
@@ -75,14 +75,17 @@ Simplified `R3` config
hostname r3
!
interface r3-stubnet vrf r3-cust1
+ ipv6 ospf6 area 0.0.0.0
ipv6 address fc00:3:3:3::3/64
ipv6 ospf6 network broadcast
!
interface r3-sw5 vrf r3-cust1
+ ipv6 ospf6 area 0.0.0.0
ipv6 address fc00:a:a:a::3/64
ipv6 ospf6 network broadcast
!
interface r3-sw6 vrf r3-cust1
+ ipv6 ospf6 area 0.0.0.1
ipv6 address fc00:b:b:b::3/64
ipv6 ospf6 network broadcast
!
@@ -90,9 +93,6 @@ Simplified `R3` config
router-id 10.0.0.3
log-adjacency-changes detail
redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
!
ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 vrf r3-cust1
diff --git a/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf
index ed480354e4..83bdfb7c81 100644
--- a/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf
+++ b/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf
@@ -9,12 +9,14 @@ debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
-interface r1-stubnet vrf r1-cust1
+interface r1-stubnet
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 10
!
-interface r1-sw5 vrf r1-cust1
+interface r1-sw5
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 10
@@ -23,8 +25,6 @@ router ospf6 vrf r1-cust1
ospf6 router-id 10.0.0.1
log-adjacency-changes detail
redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
!
line vty
exec-timeout 0 0
diff --git a/tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref b/tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref
index a2ddf7c5ae..96489b0756 100644
--- a/tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref
+++ b/tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf
index 485771e7d5..7fd01aa0cc 100644
--- a/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf
+++ b/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf
@@ -9,12 +9,14 @@ debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
-interface r2-stubnet vrf r2-cust1
+interface r2-stubnet
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 dead-interval 10
ipv6 ospf6 hello-interval 2
!
-interface r2-sw5 vrf r2-cust1
+interface r2-sw5
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 dead-interval 10
ipv6 ospf6 hello-interval 2
@@ -23,8 +25,6 @@ router ospf6 vrf r2-cust1
ospf6 router-id 10.0.0.2
log-adjacency-changes detail
redistribute static
- interface r2-stubnet area 0.0.0.0
- interface r2-sw5 area 0.0.0.0
!
line vty
exec-timeout 0 0
diff --git a/tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref b/tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref
index 3289619414..4c390f7cd6 100644
--- a/tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref
+++ b/tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf
index f5837bf6fd..df5aed3a6a 100644
--- a/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf
+++ b/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf
@@ -9,17 +9,20 @@ debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
-interface r3-stubnet vrf r3-cust1
+interface r3-stubnet
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 dead-interval 10
ipv6 ospf6 hello-interval 2
!
-interface r3-sw5 vrf r3-cust1
+interface r3-sw5
+ ipv6 ospf6 area 0.0.0.0
ipv6 ospf6 network broadcast
ipv6 ospf6 dead-interval 10
ipv6 ospf6 hello-interval 2
!
-interface r3-sw6 vrf r3-cust1
+interface r3-sw6
+ ipv6 ospf6 area 0.0.0.1
ipv6 ospf6 network broadcast
ipv6 ospf6 dead-interval 10
ipv6 ospf6 hello-interval 2
@@ -28,9 +31,6 @@ router ospf6 vrf r3-cust1
ospf6 router-id 10.0.0.3
log-adjacency-changes detail
redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
!
line vty
exec-timeout 0 0
diff --git a/tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref b/tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref
index ac713190ff..989213f963 100644
--- a/tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref
+++ b/tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref
@@ -4,6 +4,6 @@ O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:
O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf
index ab67d06ff4..465defb40f 100644
--- a/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf
+++ b/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf
@@ -9,12 +9,14 @@ debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
-interface r4-stubnet vrf r4-cust1
+interface r4-stubnet
+ ipv6 ospf6 area 0.0.0.1
ipv6 ospf6 network broadcast
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 10
!
-interface r4-sw6 vrf r4-cust1
+interface r4-sw6
+ ipv6 ospf6 area 0.0.0.1
ipv6 ospf6 network broadcast
ipv6 ospf6 hello-interval 2
ipv6 ospf6 dead-interval 10
@@ -23,8 +25,6 @@ router ospf6 vrf r4-cust1
ospf6 router-id 10.0.0.4
log-adjacency-changes detail
redistribute static
- interface r4-stubnet area 0.0.0.1
- interface r4-sw6 area 0.0.0.1
!
line vty
exec-timeout 0 0
diff --git a/tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref b/tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref
index 0df652ffb3..730fd9f2d5 100644
--- a/tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref
+++ b/tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref
@@ -6,4 +6,4 @@ O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX
O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_topo1/r1/ospf6route.txt b/tests/topotests/ospf_topo1/r1/ospf6route.txt
index 1bfd6942ea..d01511c0ee 100644
--- a/tests/topotests/ospf_topo1/r1/ospf6route.txt
+++ b/tests/topotests/ospf_topo1/r1/ospf6route.txt
@@ -1,13 +1,13 @@
*N IA 2001:db8:1::/64 :: r1-eth0 00:02:11
*N IA 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
- N E1 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
+ N E2 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
*N IA 2001:db8:3::/64 :: r1-eth1 00:02:11
- N E1 2001:db8:3::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:3::/64 fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
+ N E2 2001:db8:3::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:3::/64 fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
*N IA 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
*N IE 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
+ N E2 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
*N IE 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
- N E1 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
+ N E2 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
diff --git a/tests/topotests/ospf_topo1/r1/ospf6route_down.txt b/tests/topotests/ospf_topo1/r1/ospf6route_down.txt
index 1ce96c86c0..57113d049f 100644
--- a/tests/topotests/ospf_topo1/r1/ospf6route_down.txt
+++ b/tests/topotests/ospf_topo1/r1/ospf6route_down.txt
@@ -1,5 +1,5 @@
*N IA 2001:db8:1::/64 :: r1-eth0 00:01:51
*N IA 2001:db8:2::/64 fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
- N E1 2001:db8:2::/64 fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
+ N E2 2001:db8:2::/64 fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
*N IA 2001:db8:3::/64 :: r1-eth1 00:00:52
- N E1 2001:db8:3::/64 fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
+ N E2 2001:db8:3::/64 fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
diff --git a/tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt b/tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt
index 4df6e5ec00..48e9209a04 100644
--- a/tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt
+++ b/tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt
@@ -1,13 +1,13 @@
*N IA 2001:db8:1::/64 :: r1-eth0 00:06:13
*N IA 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
- N E1 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
+ N E2 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
*N IA 2001:db8:3::/64 :: r1-eth1 00:06:13
- N E1 2001:db8:3::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
+ N E2 2001:db8:3::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
fe80::e8bb:62ff:fee8:7022 r1-eth1
*N IA 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
- N E1 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
+ N E2 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
*N IE 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
- N E1 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
- N E1 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:07
+ N E2 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:08
+ N E2 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:07
*N IE 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:07
- N E1 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:07
+ N E2 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r1-eth1 00:06:07
diff --git a/tests/topotests/ospf_topo1/r2/ospf6route.txt b/tests/topotests/ospf_topo1/r2/ospf6route.txt
index 7d3ce5b207..71c84d2ebd 100644
--- a/tests/topotests/ospf_topo1/r2/ospf6route.txt
+++ b/tests/topotests/ospf_topo1/r2/ospf6route.txt
@@ -1,13 +1,13 @@
*N IA 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
- N E1 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
+ N E2 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
*N IA 2001:db8:2::/64 :: r2-eth0 00:03:39
*N IA 2001:db8:3::/64 :: r2-eth1 00:03:34
- N E1 2001:db8:3::/64 fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
- N E1 2001:db8:3::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:3::/64 fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
+ N E2 2001:db8:3::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
*N IA 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:100::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
*N IE 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
+ N E2 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:200::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
*N IE 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
- N E1 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
+ N E2 2001:db8:300::/64 fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
diff --git a/tests/topotests/ospf_topo1/r2/ospf6route_down.txt b/tests/topotests/ospf_topo1/r2/ospf6route_down.txt
index acfffc9f1c..a1f041218b 100644
--- a/tests/topotests/ospf_topo1/r2/ospf6route_down.txt
+++ b/tests/topotests/ospf_topo1/r2/ospf6route_down.txt
@@ -1,5 +1,5 @@
*N IA 2001:db8:1::/64 fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
- N E1 2001:db8:1::/64 fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
+ N E2 2001:db8:1::/64 fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
*N IA 2001:db8:2::/64 :: r2-eth0 00:07:17
*N IA 2001:db8:3::/64 :: r2-eth1 00:06:27
- N E1 2001:db8:3::/64 fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
+ N E2 2001:db8:3::/64 fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
diff --git a/tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt b/tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt
index f58b501e31..0c06d234cf 100644
--- a/tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt
+++ b/tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt
@@ -1,13 +1,13 @@
*N IA 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
- N E1 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
+ N E2 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
*N IA 2001:db8:2::/64 :: r2-eth0 00:07:09
*N IA 2001:db8:3::/64 :: r2-eth1 00:07:04
- N E1 2001:db8:3::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
+ N E2 2001:db8:3::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
fe80::98cd:28ff:fe5e:3d93 r2-eth1
*N IA 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
- N E1 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
+ N E2 2001:db8:100::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
*N IE 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
- N E1 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
- N E1 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:03
+ N E2 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:04
+ N E2 2001:db8:200::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:03
*N IE 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:03
- N E1 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:03
+ N E2 2001:db8:300::/64 fe80::400f:dff:fe35:a1e7 r2-eth1 00:07:03
diff --git a/tests/topotests/ospf_topo1/r3/ospf6route.txt b/tests/topotests/ospf_topo1/r3/ospf6route.txt
index b123c42650..69c99b4fd1 100644
--- a/tests/topotests/ospf_topo1/r3/ospf6route.txt
+++ b/tests/topotests/ospf_topo1/r3/ospf6route.txt
@@ -1,12 +1,12 @@
*N IA 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
- N E1 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
+ N E2 2001:db8:1::/64 fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
*N IA 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
- N E1 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
+ N E2 2001:db8:2::/64 fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
*N IA 2001:db8:3::/64 :: r3-eth0 00:04:08
- N E1 2001:db8:3::/64 fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
- N E1 2001:db8:3::/64 fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
+ N E2 2001:db8:3::/64 fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
+ N E2 2001:db8:3::/64 fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
*N IA 2001:db8:100::/64 :: r3-eth1 00:04:08
*N IA 2001:db8:200::/64 :: r3-eth2 00:04:05
- N E1 2001:db8:200::/64 fe80::78e0:deff:feb1:ec0 r3-eth2 00:04:00
+ N E2 2001:db8:200::/64 fe80::78e0:deff:feb1:ec0 r3-eth2 00:04:00
*N IA 2001:db8:300::/64 fe80::78e0:deff:feb1:ec0 r3-eth2 00:04:00
- N E1 2001:db8:300::/64 fe80::78e0:deff:feb1:ec0 r3-eth2 00:04:00
+ N E2 2001:db8:300::/64 fe80::78e0:deff:feb1:ec0 r3-eth2 00:04:00
diff --git a/tests/topotests/ospf_topo1/r3/ospf6route_down.txt b/tests/topotests/ospf_topo1/r3/ospf6route_down.txt
index ed69a8376b..645ee0bfc4 100644
--- a/tests/topotests/ospf_topo1/r3/ospf6route_down.txt
+++ b/tests/topotests/ospf_topo1/r3/ospf6route_down.txt
@@ -1,5 +1,5 @@
*N IA 2001:db8:100::/64 :: r3-eth1 00:08:06
*N IA 2001:db8:200::/64 :: r3-eth2 00:08:04
- N E1 2001:db8:200::/64 fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
+ N E2 2001:db8:200::/64 fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
*N IA 2001:db8:300::/64 fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
- N E1 2001:db8:300::/64 fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
+ N E2 2001:db8:300::/64 fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
diff --git a/tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt b/tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt
index 54e575adcb..ecd51be4ef 100644
--- a/tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt
+++ b/tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt
@@ -1,12 +1,12 @@
*N IA 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
- N E1 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
+ N E2 2001:db8:1::/64 fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
*N IA 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
- N E1 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
+ N E2 2001:db8:2::/64 fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
*N IA 2001:db8:3::/64 :: r3-eth0 00:09:03
- N E1 2001:db8:3::/64 fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
+ N E2 2001:db8:3::/64 fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
fe80::e8bb:62ff:fee8:7022 r3-eth0
*N IA 2001:db8:100::/64 :: r3-eth1 00:09:03
*N IA 2001:db8:200::/64 :: r3-eth2 00:09:02
- N E1 2001:db8:200::/64 fe80::d0dc:aff:fec5:5973 r3-eth2 00:08:57
+ N E2 2001:db8:200::/64 fe80::d0dc:aff:fec5:5973 r3-eth2 00:08:57
*N IA 2001:db8:300::/64 fe80::d0dc:aff:fec5:5973 r3-eth2 00:08:57
- N E1 2001:db8:300::/64 fe80::d0dc:aff:fec5:5973 r3-eth2 00:08:57
+ N E2 2001:db8:300::/64 fe80::d0dc:aff:fec5:5973 r3-eth2 00:08:57
diff --git a/tests/topotests/ospf_topo1/r4/ospf6route.txt b/tests/topotests/ospf_topo1/r4/ospf6route.txt
index ceeee2cac8..3a4f5efdf0 100644
--- a/tests/topotests/ospf_topo1/r4/ospf6route.txt
+++ b/tests/topotests/ospf_topo1/r4/ospf6route.txt
@@ -1,13 +1,13 @@
*N IE 2001:db8:1::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:1::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:1::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
*N IE 2001:db8:2::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:2::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:2::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
*N IE 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
*N IE 2001:db8:100::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:100::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:100::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
*N IA 2001:db8:200::/64 :: r4-eth0 00:04:30
- N E1 2001:db8:200::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:200::/64 fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
*N IA 2001:db8:300::/64 :: r4-eth1 00:04:30
diff --git a/tests/topotests/ospf_topo1/r4/ospf6route_down.txt b/tests/topotests/ospf_topo1/r4/ospf6route_down.txt
index 4ad636dd98..165f8dbdf8 100644
--- a/tests/topotests/ospf_topo1/r4/ospf6route_down.txt
+++ b/tests/topotests/ospf_topo1/r4/ospf6route_down.txt
@@ -1,5 +1,5 @@
*N IE 2001:db8:100::/64 fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
- N E1 2001:db8:100::/64 fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
+ N E2 2001:db8:100::/64 fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
*N IA 2001:db8:200::/64 :: r4-eth0 00:01:50
- N E1 2001:db8:200::/64 fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
+ N E2 2001:db8:200::/64 fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
*N IA 2001:db8:300::/64 :: r4-eth1 00:01:50
diff --git a/tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt b/tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt
index b5cb10b72b..d0d72a876f 100644
--- a/tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt
+++ b/tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt
@@ -1,12 +1,12 @@
*N IE 2001:db8:1::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:1::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:1::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
*N IE 2001:db8:2::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:2::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:2::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
*N IE 2001:db8:3::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:3::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:3::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:3::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:3::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
*N IE 2001:db8:100::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:100::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:100::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
*N IA 2001:db8:200::/64 :: r4-eth0 00:09:17
- N E1 2001:db8:200::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:200::/64 fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
*N IA 2001:db8:300::/64 :: r4-eth1 00:09:18
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
new file mode 100644
index 0000000000..3669b3a554
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
@@ -0,0 +1,173 @@
+{
+ "feature": [
+ "bgp"
+ ],
+ "address_types": [
+ "ipv6"
+ ],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json
new file mode 100644
index 0000000000..d93eb1f217
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json
@@ -0,0 +1,190 @@
+{
+ "address_types": [
+ "ipv6"
+ ],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR1",
+ "ospf6": {
+ "area": "0.0.0.0"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "1.0.4.17",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
new file mode 100644
index 0000000000..4aa71bfb16
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
@@ -0,0 +1,374 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2021 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
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+from lib.topotest import frr_unicode
+
+# 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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+from lib.bgp import verify_bgp_convergence, create_router_bgp
+
+# 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,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons,
+ get_frr_ipv6_linklocal,
+)
+
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+ verify_ospf6_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf6_rib,
+ create_router_ospf,
+ verify_ospf6_interface,
+ verify_ospf6_database,
+ config_ospf6_interface,
+)
+
+from ipaddress import IPv6Address
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospfv3_rte_calc.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+ "ipv6": [
+ "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",
+ ],
+ "ipv6": ["2::1/128", "2::2/128", "2::3/128", "2::4/128", "2::5/128"],
+}
+TOPOOLOGY = """
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+"""
+
+TESTCASES = """
+1. OSPF Cost - verifying ospf interface cost functionality
+"""
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+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...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # 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)
+
+ ospf_covergence = verify_ospf6_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 get_llip(onrouter, intf):
+ """
+ API to get the link local ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `fromnode`: Source node
+ * `tonode` : interface for which link local ip needs to be returned.
+
+ Usage
+ -----
+ result = get_llip('r1', 'r2-link0')
+
+ Returns
+ -------
+ 1) link local ipv6 address from the interface.
+ 2) errormsg - when link local ip not found.
+ """
+ tgen = get_topogen()
+ intf = topo["routers"][onrouter]["links"][intf]["interface"]
+ llip = get_frr_ipv6_linklocal(tgen, onrouter, intf)
+ if llip:
+ logger.info("llip ipv6 address to be set as NH is %s", llip)
+ return llip
+ return None
+
+
+def get_glipv6(onrouter, intf):
+ """
+ API to get the global ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `onrouter`: Source node
+ * `intf` : interface for which link local ip needs to be returned.
+
+ Usage
+ -----
+ result = get_glipv6('r1', 'r2-link0')
+
+ Returns
+ -------
+ 1) global ipv6 address from the interface.
+ 2) errormsg - when link local ip not found.
+ """
+ glipv6 = (topo["routers"][onrouter]["links"][intf]["ipv6"]).split("/")[0]
+ if glipv6:
+ logger.info("Global ipv6 address to be set as NH is %s", glipv6)
+ return glipv6
+ return None
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {
+ "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)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {
+ "redistribute": [{"redist_type": "connected", "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_ospfv3_cost_tc52_p0(request):
+ """OSPF Cost - verifying ospf interface cost functionality"""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure ospf cost as 20 on interface between R0 and R1. "
+ "Configure ospf cost as 30 between interface between R0 and R2."
+ )
+
+ r0_ospf_cost = {
+ "r0": {"links": {"r1": {"ospf6": {"cost": 20}}, "r2": {"ospf6": {"cost": 30}}}}
+ }
+ result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that cost is updated in the ospf interface between"
+ " r0 and r1 as 30 and r0 and r2 as 20"
+ )
+ dut = "r0"
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Swap the costs between interfaces on r0, between r0 and r1 to 30"
+ ", r0 and r2 to 20"
+ )
+
+ r0_ospf_cost = {
+ "r0": {"links": {"r1": {"ospf6": {"cost": 30}}, "r2": {"ospf6": {"cost": 20}}}}
+ }
+ result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that cost is updated in the ospf interface between r0 "
+ "and r1 as 30 and r0 and r2 as 20."
+ )
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" Un configure cost from the interface r0 - r1.")
+
+ r0_ospf_cost = {
+ "r0": {"links": {"r1": {"ospf6": {"cost": 30, "del_action": True}}}}
+ }
+ result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {"links": {"r1": {"ospf6": {"cost": 10}}, "r2": {"ospf6": {"cost": 20}}}}
+ }
+ step(
+ "Verify that cost is updated in the ospf interface between r0"
+ " and r1 as 10 and r0 and r2 as 20."
+ )
+
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" Un configure cost from the interface r0 - r2.")
+
+ r0_ospf_cost = {
+ "r0": {"links": {"r2": {"ospf6": {"cost": 20, "del_action": True}}}}
+ }
+ result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that cost is updated in the ospf interface between r0"
+ "and r1 as 10 and r0 and r2 as 10"
+ )
+
+ input_dict = {
+ "r0": {"links": {"r1": {"ospf6": {"cost": 10}}, "r2": {"ospf6": {"cost": 10}}}}
+ }
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ 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/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
new file mode 100644
index 0000000000..a84f1a1eb6
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
@@ -0,0 +1,417 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2021 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
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+from lib.topotest import frr_unicode
+
+# 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 mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+
+# 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,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+ verify_ospf6_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf6_rib,
+ create_router_ospf,
+ verify_ospf6_interface,
+ verify_ospf6_database,
+ config_ospf6_interface,
+)
+
+from ipaddress import IPv6Address
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospfv3_single_area.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. OSPF IFSM -Verify state change events on p2p network.
+2. OSPF Timers - Verify OSPF interface timer hello interval functionality
+3. OSPF Timers - Verify OSPF interface timer dead interval functionality
+4. Verify ospf show commands with json output.
+5. Verify NFSM events when ospf nbr changes with different MTU values.
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+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...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # 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)
+
+ ospf_covergence = verify_ospf6_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)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospfv3_p2p_tc3_p0(request):
+ """OSPF IFSM -Verify state change events on p2p network."""
+ 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():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ step(
+ "Verify that OSPF is subscribed to multi cast services "
+ "(All SPF, all DR Routers)."
+ )
+ step("Verify that interface is enabled in ospf.")
+ step("Verify that config is successful.")
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv6": topo["routers"]["r0"]["links"]["r3"]["ipv6"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"] = str(
+ IPv6Address(frr_unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ospf6": {
+ "internetAddress": [
+ {
+ "type": "inet6",
+ "address": topo_modify_change_ip["routers"]["r0"][
+ "links"
+ ]["r3"]["ipv6"].split("/")[0],
+ }
+ ],
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Modify the mask on the R0 interface")
+ ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"]
+ mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"]
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv6": ip_addr,
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"] = str(
+ IPv6Address(frr_unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ospf6": {
+ "internetAddress": [
+ {
+ "type": "inet6",
+ "address": topo_modify_change_ip["routers"]["r0"][
+ "links"
+ ]["r3"]["ipv6"].split("/")[0],
+ }
+ ],
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv6": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "ipv6"
+ ],
+ "interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "interface"
+ ],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ build_config_from_json(tgen, topo, save_bkup=False)
+
+ step("Change the area id on the interface")
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf6": {"area": "0.0.0.0"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf6": {"area": "0.0.0.1"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf6": {"area": "0.0.0.1"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf6": {"area": "0.0.0.0"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify the all neighbors are up after clearing the process.")
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr, ospf="ospf6")
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+ 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/tools/frr-reload.py b/tools/frr-reload.py
index 448ab79ead..7cb8a2e729 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -595,10 +595,12 @@ end
"ip ",
"ipv6 ",
"log ",
+ "mac access-list ",
"mpls lsp",
"mpls label",
"no ",
"password ",
+ "pbr ",
"ptm-enable",
"router-id ",
"service ",
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 6c3863132d..7af9148a8e 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -771,6 +771,7 @@ void vrrp_vty_init(void)
install_node(&debug_node);
install_node(&interface_node);
install_node(&vrrp_node);
+ vrf_cmd_init(NULL, &vrrp_privs);
if_cmd_init();
install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 87f1f67443..71f672554b 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -56,7 +56,7 @@ DECLARE_MGROUP(MVTYSH);
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
-#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD
+#define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD
#define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD
/* Daemons who can process nexthop-group configs */
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang
index 70adb37b26..4c4819ac25 100644
--- a/yang/frr-pim.yang
+++ b/yang/frr-pim.yang
@@ -174,26 +174,36 @@ module frr-pim {
"Enable ssmpingd operation.";
}
- container msdp-mesh-group {
- presence
- "Configure MSDP mesh-group.";
+ list msdp-mesh-groups {
+ key "name";
+ description
+ "RFC 3618 Section 10.2. MSDP mesh-group semantics
- leaf mesh-group-name {
- type string;
+ Groups multiple MSDP peers to reduce SA flooding typically used
+ in intra-domain settings.";
+
+ leaf name {
+ type string {
+ length 1..64;
+ }
description
- "MSDP mesh group name.";
+ "The mesh group name.";
}
- leaf-list member-ip {
+ leaf source {
type inet:ip-address;
description
- "Peer ip address.";
+ "Source IP address for the TCP connections.";
}
- leaf source-ip {
- type inet:ip-address;
- description
- "Source ip address for the TCP connection.";
+ list members {
+ key "address";
+
+ leaf address {
+ type inet:ip-address;
+ description
+ "Peer member IP address.";
+ }
}
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 06aaa706dc..d5969ab9bb 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2848,7 +2848,7 @@ stream_failure:
static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
{
- /* to avoid sending other messages like ZERBA_INTERFACE_UP */
+ /* to avoid sending other messages like ZEBRA_INTERFACE_UP */
if (hdr->command == ZEBRA_TABLE_MANAGER_CONNECT)
zread_table_manager_connect(client, msg, zvrf_id(zvrf));
else {
@@ -2856,7 +2856,7 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
if (!client->proto) {
flog_err(
EC_ZEBRA_TM_ALIENS,
- "Got table request from an unidentified client");
+ "Got SRv6 request from an unidentified client");
return;
}
if (hdr->command == ZEBRA_GET_TABLE_CHUNK)
diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c
index 3b0c75151b..40a2c94e2a 100644
--- a/zebra/zebra_mlag.c
+++ b/zebra/zebra_mlag.c
@@ -111,7 +111,7 @@ void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len)
struct stream *s = NULL;
int msg_type = 0;
- s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ s = stream_new(ZEBRA_MLAG_BUF_LIMIT);
/*
* Place holder we need the message type first
*/
@@ -1081,7 +1081,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: {
ZebraMlagMrouteAddBulk *Bulk_msg = NULL;
ZebraMlagMrouteAdd *msg = NULL;
- size_t i;
+ size_t i, length_spot;
Bulk_msg = zebra_mlag_mroute_add_bulk__unpack(
NULL, hdr->data.len, hdr->data.data);
@@ -1093,10 +1093,17 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
stream_putw(s, (Bulk_msg->n_mroute_add
* sizeof(struct mlag_mroute_add)));
/* No. of msgs in Batch */
- stream_putw(s, Bulk_msg->n_mroute_add);
+ length_spot = stream_putw(s, Bulk_msg->n_mroute_add);
/* Actual Data */
for (i = 0; i < Bulk_msg->n_mroute_add; i++) {
+ if (STREAM_SIZE(s)
+ < VRF_NAMSIZ + 22 + INTERFACE_NAMSIZ) {
+ zlog_warn(
+ "We have received more messages than we can parse at this point in time: %zu",
+ Bulk_msg->n_mroute_add);
+ break;
+ }
msg = Bulk_msg->mroute_add[i];
@@ -1116,13 +1123,16 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
else
stream_put(s, NULL, INTERFACE_NAMSIZ);
}
+
+ stream_putw_at(s, length_spot, i + 1);
+
zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg,
NULL);
} break;
case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: {
ZebraMlagMrouteDelBulk *Bulk_msg = NULL;
ZebraMlagMrouteDel *msg = NULL;
- size_t i;
+ size_t i, length_spot;
Bulk_msg = zebra_mlag_mroute_del_bulk__unpack(
NULL, hdr->data.len, hdr->data.data);
@@ -1134,10 +1144,16 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
stream_putw(s, (Bulk_msg->n_mroute_del
* sizeof(struct mlag_mroute_del)));
/* No. of msgs in Batch */
- stream_putw(s, Bulk_msg->n_mroute_del);
+ length_spot = stream_putw(s, Bulk_msg->n_mroute_del);
/* Actual Data */
for (i = 0; i < Bulk_msg->n_mroute_del; i++) {
+ if (STREAM_SIZE(s)
+ < VRF_NAMSIZ + 16 + INTERFACE_NAMSIZ) {
+ zlog_warn(
+ "We have received more messages than we can parse at this time");
+ break;
+ }
msg = Bulk_msg->mroute_del[i];
@@ -1154,6 +1170,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
else
stream_put(s, NULL, INTERFACE_NAMSIZ);
}
+
+ stream_putw_at(s, length_spot, i + 1);
+
zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg,
NULL);
} break;
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index a4382441c8..41d55c2e6c 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1367,7 +1367,6 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
stream_putw_at(s, 0, stream_get_endp(s));
client->nh_last_upd_time = monotime(NULL);
- client->last_write_cmd = cmd;
return zserv_send_message(client, s);
failure:
diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c
index 98158ecc12..6dd60af9fb 100644
--- a/zebra/zebra_srte.c
+++ b/zebra/zebra_srte.c
@@ -161,7 +161,6 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
stream_putw_at(s, 0, stream_get_endp(s));
client->nh_last_upd_time = monotime(NULL);
- client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
return zserv_send_message(client, s);
failure:
diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index 5664a29682..b11331a180 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -181,13 +181,13 @@ assign_srv6_locator_chunk(uint8_t proto,
loc->status_up = false;
chunk = srv6_locator_chunk_alloc();
- chunk->proto = 0;
+ chunk->proto = NO_PROTO;
listnode_add(loc->chunks, chunk);
zebra_srv6_locator_add(loc);
}
for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
- if (chunk->proto != 0 && chunk->proto != proto)
+ if (chunk->proto != NO_PROTO && chunk->proto != proto)
continue;
chunk_found = true;
break;
@@ -199,6 +199,8 @@ assign_srv6_locator_chunk(uint8_t proto,
}
chunk->proto = proto;
+ chunk->instance = instance;
+ chunk->session_id = session_id;
return loc;
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 0bf4d8ece2..1d94fcae6b 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1070,8 +1070,14 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
0, client->redist_v4_del_cnt);
vty_out(vty, "Redist:v6 %-12u%-12u%-12u\n", client->redist_v6_add_cnt,
0, client->redist_v6_del_cnt);
+ vty_out(vty, "VRF %-12u%-12u%-12u\n", client->vrfadd_cnt, 0,
+ client->vrfdel_cnt);
vty_out(vty, "Connected %-12u%-12u%-12u\n", client->ifadd_cnt, 0,
client->ifdel_cnt);
+ vty_out(vty, "Interface %-12u%-12u%-12u\n", client->ifup_cnt, 0,
+ client->ifdown_cnt);
+ vty_out(vty, "Intf Addr %-12u%-12u%-12u\n",
+ client->connected_rt_add_cnt, 0, client->connected_rt_del_cnt);
vty_out(vty, "BFD peer %-12u%-12u%-12u\n", client->bfd_peer_add_cnt,
client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
vty_out(vty, "NHT v4 %-12u%-12u%-12u\n",
@@ -1080,20 +1086,17 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
vty_out(vty, "VxLAN SG %-12u%-12u%-12u\n", client->vxlan_sg_add_cnt,
0, client->vxlan_sg_del_cnt);
- vty_out(vty, "Interface Up Notifications: %u\n", client->ifup_cnt);
- vty_out(vty, "Interface Down Notifications: %u\n", client->ifdown_cnt);
- vty_out(vty, "VNI add notifications: %u\n", client->vniadd_cnt);
- vty_out(vty, "VNI delete notifications: %u\n", client->vnidel_cnt);
- vty_out(vty, "L3-VNI add notifications: %u\n", client->l3vniadd_cnt);
- vty_out(vty, "L3-VNI delete notifications: %u\n", client->l3vnidel_cnt);
- vty_out(vty, "MAC-IP add notifications: %u\n", client->macipadd_cnt);
- vty_out(vty, "MAC-IP delete notifications: %u\n", client->macipdel_cnt);
- vty_out(vty, "ES add notifications: %u\n", client->local_es_add_cnt);
- vty_out(vty, "ES delete notifications: %u\n", client->local_es_del_cnt);
- vty_out(vty, "ES-EVI add notifications: %u\n",
- client->local_es_evi_add_cnt);
- vty_out(vty, "ES-EVI delete notifications: %u\n",
- client->local_es_evi_del_cnt);
+ vty_out(vty, "VNI %-12u%-12u%-12u\n", client->vniadd_cnt, 0,
+ client->vnidel_cnt);
+ vty_out(vty, "L3-VNI %-12u%-12u%-12u\n", client->l3vniadd_cnt, 0,
+ client->l3vnidel_cnt);
+ vty_out(vty, "MAC-IP %-12u%-12u%-12u\n", client->macipadd_cnt, 0,
+ client->macipdel_cnt);
+ vty_out(vty, "ES %-12u%-12u%-12u\n", client->local_es_add_cnt,
+ 0, client->local_es_del_cnt);
+ vty_out(vty, "ES-EVI %-12u%-12u%-12u\n",
+ client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt);
+ vty_out(vty, "Errors: %u\n", client->error_cnt);
TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));