diff options
28 files changed, 7891 insertions, 717 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a88f39f46b..6735c1a952 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -11304,8 +11304,13 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,  					   vty,  					   use_json,  					   json_paths); -		if (use_json && display) -			json_object_object_add(json, "paths", json_paths); +		if (use_json) { +			if (display) +				json_object_object_add(json, "paths", +						       json_paths); +			else +				json_object_free(json_paths); +		}  	} else {  		if ((dest = bgp_node_match(rib, &match)) != NULL) {  			const struct prefix *dest_p = bgp_dest_get_prefix(dest); @@ -12784,6 +12789,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,  				"No such neighbor or address family");  			vty_out(vty, "%s\n", json_object_to_json_string(json));  			json_object_free(json); +			json_object_free(json_loop);  		} else  			vty_out(vty, "%% No such neighbor or address family\n"); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 6bcde16269..3dc2cfbd5c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3531,8 +3531,9 @@ static void bgp_route_map_process_peer(const char *rmap_name,  				       PEER_FLAG_SOFT_RECONFIG)) {  				if (bgp_debug_update(peer, NULL, NULL, 1))  					zlog_debug( -						"Processing route_map %s update on peer %s (inbound, soft-reconfig)", -						rmap_name, peer->host); +						"Processing route_map %s(%s:%s) update on peer %s (inbound, soft-reconfig)", +						rmap_name, afi2str(afi), +						safi2str(safi), peer->host);  				bgp_soft_reconfig_in(peer, afi, safi);  			} else if (CHECK_FLAG(peer->cap, @@ -3541,8 +3542,9 @@ static void bgp_route_map_process_peer(const char *rmap_name,  						 PEER_CAP_REFRESH_NEW_RCV)) {  				if (bgp_debug_update(peer, NULL, NULL, 1))  					zlog_debug( -						"Processing route_map %s update on peer %s (inbound, route-refresh)", -						rmap_name, peer->host); +						"Processing route_map %s(%s:%s) update on peer %s (inbound, route-refresh)", +						rmap_name, afi2str(afi), +						safi2str(safi), peer->host);  				bgp_route_refresh_send(  					peer, afi, safi, 0, 0, 0,  					BGP_ROUTE_REFRESH_NORMAL); @@ -3681,8 +3683,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,  			if (BGP_DEBUG(zebra, ZEBRA))  				zlog_debug( -					"Processing route_map %s update on table map", -					rmap_name); +					"Processing route_map %s(%s:%s) update on table map", +					rmap_name, afi2str(afi), +					safi2str(safi));  			if (route_update)  				bgp_zebra_announce_table(bgp, afi, safi);  		} @@ -3709,8 +3712,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,  				if (bgp_debug_zebra(bn_p))  					zlog_debug( -						"Processing route_map %s update on static route %s", -						rmap_name, +						"Processing route_map %s(%s:%s) update on static route %s", +						rmap_name, afi2str(afi), +						safi2str(safi),  						inet_ntop(bn_p->family,  							  &bn_p->u.prefix, buf,  							  INET6_ADDRSTRLEN)); @@ -3760,8 +3764,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,  				if (bgp_debug_zebra(bn_p))  					zlog_debug( -						"Processing route_map %s update on aggregate-address route %s", -						rmap_name, +						"Processing route_map %s(%s:%s) update on aggregate-address route %s", +						rmap_name, afi2str(afi), +						safi2str(safi),  						inet_ntop(bn_p->family,  							  &bn_p->u.prefix, buf,  							  INET6_ADDRSTRLEN)); @@ -3796,8 +3801,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,  				if (BGP_DEBUG(zebra, ZEBRA))  					zlog_debug( -						"Processing route_map %s update on redistributed routes", -						rmap_name); +						"Processing route_map %s(%s:%s) update on redistributed routes", +						rmap_name, afi2str(afi), +						safi2str(safi));  				bgp_redistribute_resend(bgp, afi, i,  							red->instance); @@ -3816,8 +3822,8 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,  		if (BGP_DEBUG(zebra, ZEBRA))  			zlog_debug( -				"Processing route_map %s update on advertise type5 route command", -				rmap_name); +				"Processing route_map %s(%s:%s) update on advertise type5 route command", +				rmap_name, afi2str(afi), safi2str(safi));  		if (route_update && advertise_type5_routes(bgp, afi)) {  			bgp_evpn_withdraw_type5_routes(bgp, afi, safi); diff --git a/doc/developer/topotests-markers.rst b/doc/developer/topotests-markers.rst new file mode 100644 index 0000000000..02ffe3f777 --- /dev/null +++ b/doc/developer/topotests-markers.rst @@ -0,0 +1,115 @@ +.. _topotests-markers: + +Markers +-------- + +To allow for automated selective testing on large scale continuous integration +systems, all tests must be marked with at least one of the following markers: + +* babeld +* bfdd +* bgpd +* eigrpd +* isisd +* ldpd +* nhrpd +* ospf6d +* ospfd +* pathd +* pbrd +* pimd +* ripd +* ripngd +* sharpd +* staticd +* vrrpd + +The markers corespond to the daemon subdirectories in FRR's source code and have +to be added to tests on a module level depending on which daemons are used +during the test. + +The goal is to have continuous integration systems scan code submissions, detect +changes to files in a daemons subdirectory and select only tests using that +daemon to run to shorten developers waiting times for test results and save test +infrastructure resources. + +Newly written modules and code changes on tests, which do not contain any or +incorrect markers will be rejected by reviewers. + + +Registering markers +^^^^^^^^^^^^^^^^^^^ +The Registration of new markers takes place in the file +``tests/topotests/pytest.ini`` and should be discussed with members of the TSC +beforehand. + +.. code:: python3 + +    # tests/topotests/pytest.ini +    [pytest] +    ... +    markers = +        babeld: Tests that run against BABELD +        bfdd: Tests that run against BFDD +        ... +        vrrpd: Tests that run against VRRPD + + +Adding markers to tests +^^^^^^^^^^^^^^^^^^^^^^^ +Markers are added to a test by placing a global variable in the test module. + +Adding a single marker: + +.. code:: python3 + +    import pytest +     +    ... +     +    pytestmark = pytest.mark.bfdd +     +    ... +     +    def test_using_bfdd(): + + +Adding multiple markers: + +.. code:: python3 + +    import pytest +     +    ... +     +    pytestmark = [ +        pytest.mark.bgpd, +        pytest.mark.ospfd, +        pytest.mark.ospf6d +    ] +     +    ... +     +    def test_using_bgpd_ospfd_ospf6d(): + + +Selecting marked modules fort testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Selecting by a single marker: + +.. code:: bash + +    pytest -v -m isisd + +Selecting by multiple markers: + +.. code:: bash + +    pytest -v -m "isisd or ldpd or nhrpd" + + +Further Information +^^^^^^^^^^^^^^^^^^^ +The `online pytest documentation <https://docs.pytest.org/en/stable/example/markers.html>`_ +provides further information and usage examples for pytest markers. + diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 688f73c991..3e8987f126 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -792,6 +792,8 @@ Requirements:    conforms with this, run it without the :option:`-s` parameter.  - Use `black <https://github.com/psf/black>`_ code formatter before creating    a pull request. This ensures we have a unified code style. +- Mark test modules with pytest markers depending on the daemons used during the +  tests (s. Markers)  Tips: @@ -950,6 +952,8 @@ does what you need. If nothing is similar, then you may create a new topology,  preferably, using the newest template  (:file:`tests/topotests/example-test/test_template.py`). +.. include:: topotests-markers.rst +  .. include:: topotests-snippets.rst  License diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index d5b41b3d21..173daa9b22 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -435,10 +435,12 @@ Require policy on EBGP  .. clicmd:: [no] bgp ebgp-requires-policy     This command requires incoming and outgoing filters to be applied -   for eBGP sessions. Without the incoming filter, no routes will be -   accepted. Without the outgoing filter, no routes will be announced. +   for eBGP sessions as part of RFC-8212 compliance. Without the incoming +   filter, no routes will be accepted. Without the outgoing filter, no +   routes will be announced. -   This is enabled by default. +   This is enabled by default for the traditional configuration and +   turned off by default for datacenter configuration.     When the incoming or outgoing filter is missing you will see     "(Policy)" sign under ``show bgp summary``: @@ -457,6 +459,22 @@ Require policy on EBGP        192.168.0.2     4      65002         8        10        0    0    0 00:03:09            5 (Policy)        fe80:1::2222    4      65002         9        11        0    0    0 00:03:09     (Policy) (Policy) +   Additionally a `show bgp neighbor` command would indicate in the `For address family:` +   block that: + +   .. code-block:: frr + +      exit1# show bgp neighbor +      ... +      For address family: IPv4 Unicast +       Update group 1, subgroup 1 +       Packet Queue length 0 +       Inbound soft reconfiguration allowed +       Community attribute sent to this neighbor(all) +       Inbound updates discarded due to missing policy +       Outbound updates discarded due to missing policy +       0 accepted prefixes +  Reject routes with AS_SET or AS_CONFED_SET types  ------------------------------------------------ diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 4f0ff90943..b00bdb3ab8 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -170,10 +170,34 @@ Showing OSPF6 information     instance ID, simply type "show ipv6 ospf6 <cr>". JSON output can be     obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 database -.. clicmd:: show ipv6 ospf6 database +.. index:: show ipv6 ospf6 database [<detail|dump|internal>] [json] +.. clicmd:: show ipv6 ospf6 database [<detail|dump|internal>] [json] -   This command shows LSA database summary. You can specify the type of LSA. +   This command shows LSAs present in the LSDB. There are three view options. +   These options helps in viewing all the parameters of the LSAs. JSON output +   can be obtained by appending 'json' to the end of command. JSON option is +   not applicable with 'dump' option. + +.. index:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] +.. clicmd:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] + +   These options filters out the LSA based on its type. The three views options +   works here as well. JSON output can be obtained by appending 'json' to the +   end of command. + +.. index:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] +.. clicmd:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] + +   The LSAs additinally can also be filtered with the linkstate-id and +   advertising-router fields. We can use the LSA type filter and views with +   this command as well and visa-versa. JSON output can be obtained by +   appending 'json' to the end of command. + +.. index:: show ipv6 ospf6 database self-originated [json] +.. clicmd:: show ipv6 ospf6 database self-originated [json] + +   This command is used to filter the LSAs which are originated by the present +   router. All the other filters are applicable here as well.  .. index:: show ipv6 ospf6 interface [json]  .. clicmd:: show ipv6 ospf6 interface [json] diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 8cfdf2642c..eee98275ec 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1296,7 +1296,9 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,  }  static int ospf6_inter_area_prefix_lsa_show(struct vty *vty, -					    struct ospf6_lsa *lsa) +					    struct ospf6_lsa *lsa, +					    json_object *json_obj, +					    bool use_json)  {  	struct ospf6_inter_prefix_lsa *prefix_lsa;  	char buf[INET6_ADDRSTRLEN]; @@ -1304,16 +1306,29 @@ static int ospf6_inter_area_prefix_lsa_show(struct vty *vty,  	prefix_lsa = (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(  		lsa->header); -	vty_out(vty, "     Metric: %lu\n", -		(unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa)); +	if (use_json) { +		json_object_int_add( +			json_obj, "metric", +			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa)); +		ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options, +					      buf, sizeof(buf)); +		json_object_string_add(json_obj, "prefixOptions", buf); +		json_object_string_add( +			json_obj, "prefix", +			ospf6_inter_area_prefix_lsa_get_prefix_str( +				lsa, buf, sizeof(buf), 0)); +	} else { +		vty_out(vty, "     Metric: %lu\n", +			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa)); -	ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options, buf, -				      sizeof(buf)); -	vty_out(vty, "     Prefix Options: %s\n", buf); +		ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options, +					      buf, sizeof(buf)); +		vty_out(vty, "     Prefix Options: %s\n", buf); -	vty_out(vty, "     Prefix: %s\n", -		ospf6_inter_area_prefix_lsa_get_prefix_str(lsa, buf, -							   sizeof(buf), 0)); +		vty_out(vty, "     Prefix: %s\n", +			ospf6_inter_area_prefix_lsa_get_prefix_str( +				lsa, buf, sizeof(buf), 0)); +	}  	return 0;  } @@ -1338,7 +1353,9 @@ static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa,  }  static int ospf6_inter_area_router_lsa_show(struct vty *vty, -					    struct ospf6_lsa *lsa) +					    struct ospf6_lsa *lsa, +					    json_object *json_obj, +					    bool use_json)  {  	struct ospf6_inter_router_lsa *router_lsa;  	char buf[64]; @@ -1347,12 +1364,22 @@ static int ospf6_inter_area_router_lsa_show(struct vty *vty,  		lsa->header);  	ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf)); -	vty_out(vty, "     Options: %s\n", buf); -	vty_out(vty, "     Metric: %lu\n", -		(unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa)); +	if (use_json) { +		json_object_string_add(json_obj, "options", buf); +		json_object_int_add( +			json_obj, "metric", +			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa)); +	} else { +		vty_out(vty, "     Options: %s\n", buf); +		vty_out(vty, "     Metric: %lu\n", +			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa)); +	}  	inet_ntop(AF_INET, &router_lsa->router_id, buf, sizeof(buf)); -	vty_out(vty, "     Destination Router ID: %s\n", buf); +	if (use_json) +		json_object_string_add(json_obj, "destinationRouterId", buf); +	else +		vty_out(vty, "     Destination Router ID: %s\n", buf);  	return 0;  } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 0e419cbff6..af99bc0c88 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1890,7 +1890,8 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,  	return (buf);  } -static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +				      json_object *json_obj, bool use_json)  {  	struct ospf6_as_external_lsa *external;  	char buf[64]; @@ -1908,31 +1909,65 @@ static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  		 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'  								      : '-')); -	vty_out(vty, "     Bits: %s\n", buf); -	vty_out(vty, "     Metric: %5lu\n", -		(unsigned long)OSPF6_ASBR_METRIC(external)); - -	ospf6_prefix_options_printbuf(external->prefix.prefix_options, buf, -				      sizeof(buf)); -	vty_out(vty, "     Prefix Options: %s\n", buf); +	if (use_json) { +		json_object_string_add(json_obj, "bits", buf); +		json_object_int_add(json_obj, "metric", +				    (unsigned long)OSPF6_ASBR_METRIC(external)); +		ospf6_prefix_options_printbuf(external->prefix.prefix_options, +					      buf, sizeof(buf)); +		json_object_string_add(json_obj, "prefixOptions", buf); +		json_object_int_add( +			json_obj, "referenceLsType", +			ntohs(external->prefix.prefix_refer_lstype)); +		json_object_string_add(json_obj, "prefix", +				       ospf6_as_external_lsa_get_prefix_str( +					       lsa, buf, sizeof(buf), 0)); + +		/* Forwarding-Address */ +		json_object_boolean_add( +			json_obj, "forwardingAddressPresent", +			CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)); +		if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) +			json_object_string_add( +				json_obj, "forwardingAddress", +				ospf6_as_external_lsa_get_prefix_str( +					lsa, buf, sizeof(buf), 1)); + +		/* Tag */ +		json_object_boolean_add( +			json_obj, "tagPresent", +			CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)); +		if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) +			json_object_int_add(json_obj, "tag", +					    ospf6_as_external_lsa_get_tag(lsa)); +	} else { +		vty_out(vty, "     Bits: %s\n", buf); +		vty_out(vty, "     Metric: %5lu\n", +			(unsigned long)OSPF6_ASBR_METRIC(external)); -	vty_out(vty, "     Referenced LSType: %d\n", -		ntohs(external->prefix.prefix_refer_lstype)); +		ospf6_prefix_options_printbuf(external->prefix.prefix_options, +					      buf, sizeof(buf)); +		vty_out(vty, "     Prefix Options: %s\n", buf); -	vty_out(vty, "     Prefix: %s\n", -		ospf6_as_external_lsa_get_prefix_str(lsa, buf, sizeof(buf), 0)); +		vty_out(vty, "     Referenced LSType: %d\n", +			ntohs(external->prefix.prefix_refer_lstype)); -	/* Forwarding-Address */ -	if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) { -		vty_out(vty, "     Forwarding-Address: %s\n", +		vty_out(vty, "     Prefix: %s\n",  			ospf6_as_external_lsa_get_prefix_str(lsa, buf, -							     sizeof(buf), 1)); -	} +							     sizeof(buf), 0)); + +		/* Forwarding-Address */ +		if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) { +			vty_out(vty, "     Forwarding-Address: %s\n", +				ospf6_as_external_lsa_get_prefix_str( +					lsa, buf, sizeof(buf), 1)); +		} -	/* Tag */ -	if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) { -		vty_out(vty, "     Tag: %" ROUTE_TAG_PRI "\n", -			ospf6_as_external_lsa_get_tag(lsa)); +		/* Tag */ +		if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) { +			vty_out(vty, "     Tag: %" ROUTE_TAG_PRI "\n", +				ospf6_as_external_lsa_get_tag(lsa)); +		}  	}  	return 0; diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 17538c466a..01e4b31c4e 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -92,12 +92,15 @@ static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf,  	return buf;  } -static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +				 json_object *json_obj, bool use_json)  {  	char *start, *end, *current;  	char buf[32], name[32], bits[16], options[32];  	struct ospf6_router_lsa *router_lsa;  	struct ospf6_router_lsdesc *lsdesc; +	json_object *json_arr; +	json_object *json_loop;  	router_lsa =  		(struct ospf6_router_lsa *)((char *)lsa->header @@ -105,7 +108,12 @@ static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	ospf6_capability_printbuf(router_lsa->bits, bits, sizeof(bits));  	ospf6_options_printbuf(router_lsa->options, options, sizeof(options)); -	vty_out(vty, "    Bits: %s Options: %s\n", bits, options); +	if (use_json) { +		json_object_string_add(json_obj, "bits", bits); +		json_object_string_add(json_obj, "options", options); +		json_arr = json_object_new_array(); +	} else +		vty_out(vty, "    Bits: %s Options: %s\n", bits, options);  	start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);  	end = (char *)lsa->header + ntohs(lsa->header->length); @@ -126,18 +134,43 @@ static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  			snprintf(name, sizeof(name), "Unknown (%#x)",  				 lsdesc->type); -		vty_out(vty, "    Type: %s Metric: %d\n", name, -			ntohs(lsdesc->metric)); -		vty_out(vty, "    Interface ID: %s\n", -			inet_ntop(AF_INET, &lsdesc->interface_id, buf, -				  sizeof(buf))); -		vty_out(vty, "    Neighbor Interface ID: %s\n", -			inet_ntop(AF_INET, &lsdesc->neighbor_interface_id, buf, -				  sizeof(buf))); -		vty_out(vty, "    Neighbor Router ID: %s\n", -			inet_ntop(AF_INET, &lsdesc->neighbor_router_id, buf, -				  sizeof(buf))); +		if (use_json) { +			json_loop = json_object_new_object(); +			json_object_string_add(json_loop, "type", name); +			json_object_int_add(json_loop, "metric", +					    ntohs(lsdesc->metric)); +			json_object_string_add(json_loop, "interfaceId", +					       inet_ntop(AF_INET, +							 &lsdesc->interface_id, +							 buf, sizeof(buf))); +			json_object_string_add( +				json_loop, "neighborInterfaceId", +				inet_ntop(AF_INET, +					  &lsdesc->neighbor_interface_id, buf, +					  sizeof(buf))); +			json_object_string_add( +				json_loop, "neighborRouterId", +				inet_ntop(AF_INET, &lsdesc->neighbor_router_id, +					  buf, sizeof(buf))); +			json_object_array_add(json_arr, json_loop); +		} else { +			vty_out(vty, "    Type: %s Metric: %d\n", name, +				ntohs(lsdesc->metric)); +			vty_out(vty, "    Interface ID: %s\n", +				inet_ntop(AF_INET, &lsdesc->interface_id, buf, +					  sizeof(buf))); +			vty_out(vty, "    Neighbor Interface ID: %s\n", +				inet_ntop(AF_INET, +					  &lsdesc->neighbor_interface_id, buf, +					  sizeof(buf))); +			vty_out(vty, "    Neighbor Router ID: %s\n", +				inet_ntop(AF_INET, &lsdesc->neighbor_router_id, +					  buf, sizeof(buf))); +		}  	} +	if (use_json) +		json_object_object_add(json_obj, "lsaDescription", json_arr); +  	return 0;  } @@ -421,29 +454,44 @@ static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf,  	return (buf);  } -static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +				  json_object *json_obj, bool use_json)  {  	char *start, *end, *current;  	struct ospf6_network_lsa *network_lsa;  	struct ospf6_network_lsdesc *lsdesc;  	char buf[128], options[32]; +	json_object *json_arr;  	network_lsa =  		(struct ospf6_network_lsa *)((caddr_t)lsa->header  					     + sizeof(struct ospf6_lsa_header));  	ospf6_options_printbuf(network_lsa->options, options, sizeof(options)); -	vty_out(vty, "     Options: %s\n", options); +	if (use_json) +		json_object_string_add(json_obj, "options", options); +	else +		vty_out(vty, "     Options: %s\n", options);  	start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);  	end = (char *)lsa->header + ntohs(lsa->header->length); +	if (use_json) +		json_arr = json_object_new_array(); +  	for (current = start;  	     current + sizeof(struct ospf6_network_lsdesc) <= end;  	     current += sizeof(struct ospf6_network_lsdesc)) {  		lsdesc = (struct ospf6_network_lsdesc *)current;  		inet_ntop(AF_INET, &lsdesc->router_id, buf, sizeof(buf)); -		vty_out(vty, "     Attached Router: %s\n", buf); +		if (use_json) +			json_object_array_add(json_arr, +					      json_object_new_string(buf)); +		else +			vty_out(vty, "     Attached Router: %s\n", buf);  	} +	if (use_json) +		json_object_object_add(json_obj, "attachedRouter", json_arr); +  	return 0;  } @@ -625,7 +673,8 @@ static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,  	return NULL;  } -static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +			       json_object *json_obj, bool use_json)  {  	char *start, *end, *current;  	struct ospf6_link_lsa *link_lsa; @@ -634,6 +683,10 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	struct ospf6_prefix *prefix;  	const char *p, *mc, *la, *nu;  	struct in6_addr in6; +	json_object *json_loop; +	json_object *json_arr = NULL; +	char str[15]; +	char prefix_string[133];  	link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header  					     + sizeof(struct ospf6_lsa_header)); @@ -642,10 +695,18 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf));  	prefixnum = ntohl(link_lsa->prefix_num); -	vty_out(vty, "     Priority: %d Options: %s\n", link_lsa->priority, -		options); -	vty_out(vty, "     LinkLocal Address: %s\n", buf); -	vty_out(vty, "     Number of Prefix: %d\n", prefixnum); +	if (use_json) { +		json_arr = json_object_new_array(); +		json_object_int_add(json_obj, "priority", link_lsa->priority); +		json_object_string_add(json_obj, "options", options); +		json_object_string_add(json_obj, "linkLocalAddress", buf); +		json_object_int_add(json_obj, "numberOfPrefix", prefixnum); +	} else { +		vty_out(vty, "     Priority: %d Options: %s\n", +			link_lsa->priority, options); +		vty_out(vty, "     LinkLocal Address: %s\n", buf); +		vty_out(vty, "     Number of Prefix: %d\n", prefixnum); +	}  	start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);  	end = (char *)lsa->header + ntohs(lsa->header->length); @@ -668,16 +729,31 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  		nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU)  			      ? "NU"  			      : "--"); -		vty_out(vty, "     Prefix Options: %s|%s|%s|%s\n", p, mc, la, -			nu); +		if (use_json) { +			json_loop = json_object_new_object(); +			snprintf(str, sizeof(str), "%s|%s|%s|%s", p, mc, la, +				 nu); +			json_object_string_add(json_loop, "prefixOption", str); +		} else +			vty_out(vty, "     Prefix Options: %s|%s|%s|%s\n", p, +				mc, la, nu);  		memset(&in6, 0, sizeof(in6));  		memcpy(&in6, OSPF6_PREFIX_BODY(prefix),  		       OSPF6_PREFIX_SPACE(prefix->prefix_length));  		inet_ntop(AF_INET6, &in6, buf, sizeof(buf)); -		vty_out(vty, "     Prefix: %s/%d\n", buf, -			prefix->prefix_length); +		if (use_json) { +			snprintf(prefix_string, sizeof(prefix_string), "%s/%d", +				 buf, prefix->prefix_length); +			json_object_string_add(json_loop, "prefix", +					       prefix_string); +			json_object_array_add(json_arr, json_loop); +		} else +			vty_out(vty, "     Prefix: %s/%d\n", buf, +				prefix->prefix_length);  	} +	if (use_json) +		json_object_object_add(json_obj, "prefix", json_arr);  	return 0;  } @@ -828,7 +904,8 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,  	return (buf);  } -static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +				       json_object *json_obj, bool use_json)  {  	char *start, *end, *current;  	struct ospf6_intra_prefix_lsa *intra_prefix_lsa; @@ -838,6 +915,10 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	char id[16], adv_router[16];  	const char *p, *mc, *la, *nu;  	struct in6_addr in6; +	json_object *json_loop; +	json_object *json_arr = NULL; +	char str[15]; +	char prefix_string[133];  	intra_prefix_lsa = (struct ospf6_intra_prefix_lsa  				    *)((caddr_t)lsa->header @@ -845,13 +926,25 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	prefixnum = ntohs(intra_prefix_lsa->prefix_num); -	vty_out(vty, "     Number of Prefix: %d\n", prefixnum); +	if (use_json) { +		json_arr = json_object_new_array(); +		json_object_int_add(json_obj, "numberOfPrefix", prefixnum); +	} else +		vty_out(vty, "     Number of Prefix: %d\n", prefixnum);  	inet_ntop(AF_INET, &intra_prefix_lsa->ref_id, id, sizeof(id));  	inet_ntop(AF_INET, &intra_prefix_lsa->ref_adv_router, adv_router,  		  sizeof(adv_router)); -	vty_out(vty, "     Reference: %s Id: %s Adv: %s\n", -		ospf6_lstype_name(intra_prefix_lsa->ref_type), id, adv_router); +	if (use_json) { +		json_object_string_add( +			json_obj, "reference", +			ospf6_lstype_name(intra_prefix_lsa->ref_type)); +		json_object_string_add(json_obj, "referenceId", id); +		json_object_string_add(json_obj, "referenceAdv", adv_router); +	} else +		vty_out(vty, "     Reference: %s Id: %s Adv: %s\n", +			ospf6_lstype_name(intra_prefix_lsa->ref_type), id, +			adv_router);  	start = (char *)intra_prefix_lsa  		+ sizeof(struct ospf6_intra_prefix_lsa); @@ -875,16 +968,31 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  		nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU)  			      ? "NU"  			      : "--"); -		vty_out(vty, "     Prefix Options: %s|%s|%s|%s\n", p, mc, la, -			nu); +		if (use_json) { +			json_loop = json_object_new_object(); +			snprintf(str, sizeof(str), "%s|%s|%s|%s", p, mc, la, +				 nu); +			json_object_string_add(json_loop, "prefixOption", str); +		} else +			vty_out(vty, "     Prefix Options: %s|%s|%s|%s\n", p, +				mc, la, nu);  		memset(&in6, 0, sizeof(in6));  		memcpy(&in6, OSPF6_PREFIX_BODY(prefix),  		       OSPF6_PREFIX_SPACE(prefix->prefix_length));  		inet_ntop(AF_INET6, &in6, buf, sizeof(buf)); -		vty_out(vty, "     Prefix: %s/%d\n", buf, -			prefix->prefix_length); +		if (use_json) { +			snprintf(prefix_string, sizeof(prefix_string), "%s/%d", +				 buf, prefix->prefix_length); +			json_object_string_add(json_loop, "prefix", +					       prefix_string); +			json_object_array_add(json_arr, json_loop); +		} else +			vty_out(vty, "     Prefix: %s/%d\n", buf, +				prefix->prefix_length);  	} +	if (use_json) +		json_object_object_add(json_obj, "prefix", json_arr);  	return 0;  } diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 29141ee7f8..f1b04c9bec 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -66,7 +66,8 @@ struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa)  	return ospf6;  } -static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +				  json_object *json_obj, bool use_json)  {  	uint8_t *start, *end, *current;  	char byte[4]; @@ -74,18 +75,22 @@ static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	start = (uint8_t *)lsa->header + sizeof(struct ospf6_lsa_header);  	end = (uint8_t *)lsa->header + ntohs(lsa->header->length); -	vty_out(vty, "        Unknown contents:\n"); -	for (current = start; current < end; current++) { -		if ((current - start) % 16 == 0) -			vty_out(vty, "\n        "); -		else if ((current - start) % 4 == 0) -			vty_out(vty, " "); +	if (use_json) +		json_object_string_add(json_obj, "LsaType", "unknown"); +	else { +		vty_out(vty, "        Unknown contents:\n"); +		for (current = start; current < end; current++) { +			if ((current - start) % 16 == 0) +				vty_out(vty, "\n        "); +			else if ((current - start) % 4 == 0) +				vty_out(vty, " "); + +			snprintf(byte, sizeof(byte), "%02x", *current); +			vty_out(vty, "%s", byte); +		} -		snprintf(byte, sizeof(byte), "%02x", *current); -		vty_out(vty, "%s", byte); +		vty_out(vty, "\n\n");  	} - -	vty_out(vty, "\n\n");  	return 0;  } @@ -392,13 +397,15 @@ void ospf6_lsa_show_summary_header(struct vty *vty)  		"AdvRouter", "Age", "SeqNum", "Payload");  } -void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa) +void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, +			    json_object *json_array, bool use_json)  {  	char adv_router[16], id[16];  	int type;  	const struct ospf6_lsa_handler *handler; -	char buf[64], tmpbuf[80]; +	char buf[64];  	int cnt = 0; +	json_object *json_obj = NULL;  	assert(lsa);  	assert(lsa->header); @@ -409,34 +416,95 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa)  	type = ntohs(lsa->header->type);  	handler = ospf6_get_lsa_handler(lsa->header->type); + +	if (use_json) +		json_obj = json_object_new_object(); +  	if ((type == OSPF6_LSTYPE_INTER_PREFIX)  	    || (type == OSPF6_LSTYPE_INTER_ROUTER)  	    || (type == OSPF6_LSTYPE_AS_EXTERNAL)) { -		vty_out(vty, "%-4s %-15s%-15s%4hu %8lx %30s\n", -			ospf6_lstype_short_name(lsa->header->type), id, -			adv_router, ospf6_lsa_age_current(lsa), -			(unsigned long)ntohl(lsa->header->seqnum), -			handler->lh_get_prefix_str(lsa, buf, sizeof(buf), 0)); +		if (use_json) { +			json_object_string_add( +				json_obj, "type", +				ospf6_lstype_short_name(lsa->header->type)); +			json_object_string_add(json_obj, "lsId", id); +			json_object_string_add(json_obj, "advRouter", +					       adv_router); +			json_object_int_add(json_obj, "age", +					    ospf6_lsa_age_current(lsa)); +			json_object_int_add( +				json_obj, "seqNum", +				(unsigned long)ntohl(lsa->header->seqnum)); +			json_object_string_add( +				json_obj, "payload", +				handler->lh_get_prefix_str(lsa, buf, +							   sizeof(buf), 0)); +			json_object_array_add(json_array, json_obj); +		} else +			vty_out(vty, "%-4s %-15s%-15s%4hu %8lx %30s\n", +				ospf6_lstype_short_name(lsa->header->type), id, +				adv_router, ospf6_lsa_age_current(lsa), +				(unsigned long)ntohl(lsa->header->seqnum), +				handler->lh_get_prefix_str(lsa, buf, +							   sizeof(buf), 0));  	} else if (type != OSPF6_LSTYPE_UNKNOWN) { -		snprintf(tmpbuf, sizeof(tmpbuf), "%-4s %-15s%-15s%4hu %8lx", -			 ospf6_lstype_short_name(lsa->header->type), id, -			 adv_router, ospf6_lsa_age_current(lsa), -			 (unsigned long)ntohl(lsa->header->seqnum)); -  		while (handler->lh_get_prefix_str(lsa, buf, sizeof(buf), cnt)  		       != NULL) { -			vty_out(vty, "%s %30s\n", tmpbuf, buf); +			if (use_json) { +				json_object_string_add( +					json_obj, "type", +					ospf6_lstype_short_name( +						lsa->header->type)); +				json_object_string_add(json_obj, "lsId", id); +				json_object_string_add(json_obj, "advRouter", +						       adv_router); +				json_object_int_add(json_obj, "age", +						    ospf6_lsa_age_current(lsa)); +				json_object_int_add( +					json_obj, "seqNum", +					(unsigned long)ntohl( +						lsa->header->seqnum)); +				json_object_string_add(json_obj, "payload", +						       buf); +				json_object_array_add(json_array, json_obj); +				json_obj = json_object_new_object(); +			} else +				vty_out(vty, "%-4s %-15s%-15s%4hu %8lx %30s\n", +					ospf6_lstype_short_name( +						lsa->header->type), +					id, adv_router, +					ospf6_lsa_age_current(lsa), +					(unsigned long)ntohl( +						lsa->header->seqnum), +					buf);  			cnt++;  		} +		if (use_json) +			json_object_free(json_obj);  	} else { -		vty_out(vty, "%-4s %-15s%-15s%4hu %8lx\n", -			ospf6_lstype_short_name(lsa->header->type), id, -			adv_router, ospf6_lsa_age_current(lsa), -			(unsigned long)ntohl(lsa->header->seqnum)); +		if (use_json) { +			json_object_string_add( +				json_obj, "type", +				ospf6_lstype_short_name(lsa->header->type)); +			json_object_string_add(json_obj, "lsId", id); +			json_object_string_add(json_obj, "advRouter", +					       adv_router); +			json_object_int_add(json_obj, "age", +					    ospf6_lsa_age_current(lsa)); +			json_object_int_add( +				json_obj, "seqNum", +				(unsigned long)ntohl(lsa->header->seqnum)); +			json_object_array_add(json_array, json_obj); +		} else +			vty_out(vty, "%-4s %-15s%-15s%4hu %8lx\n", +				ospf6_lstype_short_name(lsa->header->type), id, +				adv_router, ospf6_lsa_age_current(lsa), +				(unsigned long)ntohl(lsa->header->seqnum));  	}  } -void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa) +void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa, +			 json_object *json_array, bool use_json)  {  	uint8_t *start, *end, *current;  	char byte[4]; @@ -444,6 +512,9 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa)  	start = (uint8_t *)lsa->header;  	end = (uint8_t *)lsa->header + ntohs(lsa->header->length); +	if (use_json) +		return; +  	vty_out(vty, "\n");  	vty_out(vty, "%s:\n", lsa->name); @@ -458,12 +529,15 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa)  	}  	vty_out(vty, "\n\n"); +  	return;  } -void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa) +void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa, +			     json_object *json_array, bool use_json)  {  	char adv_router[64], id[64]; +	json_object *json_obj;  	assert(lsa && lsa->header); @@ -471,30 +545,56 @@ void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa)  	inet_ntop(AF_INET, &lsa->header->adv_router, adv_router,  		  sizeof(adv_router)); -	vty_out(vty, "\n"); -	vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa), -		ospf6_lstype_name(lsa->header->type)); -	vty_out(vty, "Link State ID: %s\n", id); -	vty_out(vty, "Advertising Router: %s\n", adv_router); -	vty_out(vty, "LS Sequence Number: %#010lx\n", -		(unsigned long)ntohl(lsa->header->seqnum)); -	vty_out(vty, "CheckSum: %#06hx Length: %hu\n", -		ntohs(lsa->header->checksum), ntohs(lsa->header->length)); -	vty_out(vty, "Flag: %x \n", lsa->flag); -	vty_out(vty, "Lock: %d \n", lsa->lock); -	vty_out(vty, "ReTx Count: %d\n", lsa->retrans_count); -	vty_out(vty, "Threads: Expire: 0x%p, Refresh: 0x%p \n", -		(void *)lsa->expire, (void *)lsa->refresh); -	vty_out(vty, "\n"); +	if (use_json) { +		json_obj = json_object_new_object(); +		json_object_int_add(json_obj, "age", +				    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", +				    (unsigned long)ntohl(lsa->header->seqnum)); +		json_object_int_add(json_obj, "checksum", +				    ntohs(lsa->header->checksum)); +		json_object_int_add(json_obj, "length", +				    ntohs(lsa->header->length)); +		json_object_int_add(json_obj, "flag", lsa->flag); +		json_object_int_add(json_obj, "lock", lsa->lock); +		json_object_int_add(json_obj, "reTxCount", lsa->retrans_count); + +		/* Threads Data not added */ +		json_object_array_add(json_array, json_obj); +	} else { +		vty_out(vty, "\n"); +		vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa), +			ospf6_lstype_name(lsa->header->type)); +		vty_out(vty, "Link State ID: %s\n", id); +		vty_out(vty, "Advertising Router: %s\n", adv_router); +		vty_out(vty, "LS Sequence Number: %#010lx\n", +			(unsigned long)ntohl(lsa->header->seqnum)); +		vty_out(vty, "CheckSum: %#06hx Length: %hu\n", +			ntohs(lsa->header->checksum), +			ntohs(lsa->header->length)); +		vty_out(vty, "Flag: %x \n", lsa->flag); +		vty_out(vty, "Lock: %d \n", lsa->lock); +		vty_out(vty, "ReTx Count: %d\n", lsa->retrans_count); +		vty_out(vty, "Threads: Expire: 0x%p, Refresh: 0x%p \n", +			(void *)lsa->expire, (void *)lsa->refresh); +		vty_out(vty, "\n"); +	}  	return;  } -void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa) +void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +		    json_object *json_array, bool use_json)  {  	char adv_router[64], id[64];  	const struct ospf6_lsa_handler *handler;  	struct timeval now, res;  	char duration[64]; +	json_object *json_obj = NULL;  	assert(lsa && lsa->header); @@ -505,27 +605,47 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa)  	monotime(&now);  	timersub(&now, &lsa->installed, &res);  	timerstring(&res, duration, sizeof(duration)); - -	vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa), -		ospf6_lstype_name(lsa->header->type)); -	vty_out(vty, "Link State ID: %s\n", id); -	vty_out(vty, "Advertising Router: %s\n", adv_router); -	vty_out(vty, "LS Sequence Number: %#010lx\n", -		(unsigned long)ntohl(lsa->header->seqnum)); -	vty_out(vty, "CheckSum: %#06hx Length: %hu\n", -		ntohs(lsa->header->checksum), ntohs(lsa->header->length)); -	vty_out(vty, "Duration: %s\n", duration); +	if (use_json) { +		json_obj = json_object_new_object(); +		json_object_int_add(json_obj, "age", +				    ospf6_lsa_age_current(lsa)); +		json_object_string_add(json_obj, "type", +				       ospf6_lstype_name(lsa->header->type)); +		json_object_string_add(json_obj, "advertisingRouter", +				       adv_router); +		json_object_int_add(json_obj, "lsSequenceNumber", +				    (unsigned long)ntohl(lsa->header->seqnum)); +		json_object_int_add(json_obj, "checkSum", +				    ntohs(lsa->header->checksum)); +		json_object_int_add(json_obj, "length", +				    ntohs(lsa->header->length)); +		json_object_string_add(json_obj, "duration", duration); +	} else { +		vty_out(vty, "Age: %4hu Type: %s\n", ospf6_lsa_age_current(lsa), +			ospf6_lstype_name(lsa->header->type)); +		vty_out(vty, "Link State ID: %s\n", id); +		vty_out(vty, "Advertising Router: %s\n", adv_router); +		vty_out(vty, "LS Sequence Number: %#010lx\n", +			(unsigned long)ntohl(lsa->header->seqnum)); +		vty_out(vty, "CheckSum: %#06hx Length: %hu\n", +			ntohs(lsa->header->checksum), +			ntohs(lsa->header->length)); +		vty_out(vty, "Duration: %s\n", duration); +	}  	handler = ospf6_get_lsa_handler(lsa->header->type);  	if (handler->lh_show != NULL) -		handler->lh_show(vty, lsa); +		handler->lh_show(vty, lsa, json_obj, use_json);  	else {  		assert(unknown_handler.lh_show != NULL); -		unknown_handler.lh_show(vty, lsa); +		unknown_handler.lh_show(vty, lsa, json_obj, use_json);  	} -	vty_out(vty, "\n"); +	if (use_json) +		json_object_array_add(json_array, json_obj); +	else +		vty_out(vty, "\n");  }  /* OSPFv3 LSA creation/deletion function */ diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 814e276796..7fa9c5fe40 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -21,6 +21,7 @@  #ifndef OSPF6_LSA_H  #define OSPF6_LSA_H  #include "ospf6_top.h" +#include "lib/json.h"  /* Debug option */  #define OSPF6_LSA_DEBUG           0x01 @@ -141,9 +142,10 @@ struct ospf6_lsa_handler {  	uint16_t lh_type; /* host byte order */  	const char *lh_name;  	const char *lh_short_name; -	int (*lh_show)(struct vty *, struct ospf6_lsa *); -	char *(*lh_get_prefix_str)(struct ospf6_lsa *, char *buf, -				   int buflen, int pos); +	int (*lh_show)(struct vty *, struct ospf6_lsa *, json_object *json_obj, +		       bool use_json); +	char *(*lh_get_prefix_str)(struct ospf6_lsa *, char *buf, int buflen, +				   int pos);  	uint8_t lh_debug;  }; @@ -206,10 +208,14 @@ extern char *ospf6_lsa_printbuf(struct ospf6_lsa *lsa, char *buf, int size);  extern void ospf6_lsa_header_print_raw(struct ospf6_lsa_header *header);  extern void ospf6_lsa_header_print(struct ospf6_lsa *lsa);  extern void ospf6_lsa_show_summary_header(struct vty *vty); -extern void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa); -extern void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa); -extern void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa); -extern void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa); +extern void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, +				   json_object *json, bool use_json); +extern void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa, +				json_object *json, bool use_json); +extern void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa, +				    json_object *json, bool use_json); +extern void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, +			   json_object *json, bool use_json);  extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header);  extern struct ospf6_lsa * diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index c136c558cb..9636e1a230 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -346,55 +346,6 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)  	return (reschedule);  } -void ospf6_lsdb_show(struct vty *vty, enum ospf_lsdb_show_level level, -		     uint16_t *type, uint32_t *id, uint32_t *adv_router, -		     struct ospf6_lsdb *lsdb) -{ -	struct ospf6_lsa *lsa; -	const struct route_node *end = NULL; -	void (*showfunc)(struct vty *, struct ospf6_lsa *) = NULL; - -	switch (level) { -	case OSPF6_LSDB_SHOW_LEVEL_DETAIL: -		showfunc = ospf6_lsa_show; -		break; -	case OSPF6_LSDB_SHOW_LEVEL_INTERNAL: -		showfunc = ospf6_lsa_show_internal; -		break; -	case OSPF6_LSDB_SHOW_LEVEL_DUMP: -		showfunc = ospf6_lsa_show_dump; -		break; -	case OSPF6_LSDB_SHOW_LEVEL_NORMAL: -	default: -		showfunc = ospf6_lsa_show_summary; -	} - -	if (type && id && adv_router) { -		lsa = ospf6_lsdb_lookup(*type, *id, *adv_router, lsdb); -		if (lsa) { -			if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) -				ospf6_lsa_show(vty, lsa); -			else -				(*showfunc)(vty, lsa); -		} -		return; -	} - -	if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) -		ospf6_lsa_show_summary_header(vty); - -	end = ospf6_lsdb_head(lsdb, !!type + !!(type && adv_router), -			      type ? *type : 0, adv_router ? *adv_router : 0, -			      &lsa); -	while (lsa) { -		if ((!adv_router || lsa->header->adv_router == *adv_router) -		    && (!id || lsa->header->id == *id)) -			(*showfunc)(vty, lsa); - -		lsa = ospf6_lsdb_next(end, lsa); -	} -} -  uint32_t ospf6_new_ls_id(uint16_t type, uint32_t adv_router,  			 struct ospf6_lsdb *lsdb)  { diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 457e3dc4e4..7a62c46b02 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -92,7 +92,8 @@ enum ospf_lsdb_show_level {  extern void ospf6_lsdb_show(struct vty *vty, enum ospf_lsdb_show_level level,  			    uint16_t *type, uint32_t *id, uint32_t *adv_router, -			    struct ospf6_lsdb *lsdb); +			    struct ospf6_lsdb *lsdb, json_object *json, +			    bool use_json);  extern uint32_t ospf6_new_ls_id(uint16_t type, uint32_t adv_router,  				struct ospf6_lsdb *lsdb); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 4b958e550f..02eb4baf8d 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -44,6 +44,7 @@  #include "ospf6_flood.h"  #include "ospf6d.h"  #include "ospf6_bfd.h" +#include "lib/json.h"  struct route_node *route_prev(struct route_node *node)  { @@ -154,53 +155,264 @@ static uint16_t parse_type_spec(int idx_lsa, int argc, struct cmd_token **argv)  	return type;  } +void ospf6_lsdb_show(struct vty *vty, enum ospf_lsdb_show_level level, +		     uint16_t *type, uint32_t *id, uint32_t *adv_router, +		     struct ospf6_lsdb *lsdb, json_object *json_obj, +		     bool use_json) +{ +	struct ospf6_lsa *lsa; +	const struct route_node *end = NULL; +	void (*showfunc)(struct vty *, struct ospf6_lsa *, json_object *, +			 bool) = NULL; +	json_object *json_array = NULL; + +	switch (level) { +	case OSPF6_LSDB_SHOW_LEVEL_DETAIL: +		showfunc = ospf6_lsa_show; +		break; +	case OSPF6_LSDB_SHOW_LEVEL_INTERNAL: +		showfunc = ospf6_lsa_show_internal; +		break; +	case OSPF6_LSDB_SHOW_LEVEL_DUMP: +		showfunc = ospf6_lsa_show_dump; +		break; +	case OSPF6_LSDB_SHOW_LEVEL_NORMAL: +	default: +		showfunc = ospf6_lsa_show_summary; +	} + +	if (use_json) +		json_array = json_object_new_array(); + +	if (type && id && adv_router) { +		lsa = ospf6_lsdb_lookup(*type, *id, *adv_router, lsdb); +		if (lsa) { +			if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) +				ospf6_lsa_show(vty, lsa, json_array, use_json); +			else +				(*showfunc)(vty, lsa, json_array, use_json); +		} + +		if (use_json) +			json_object_object_add(json_obj, "lsa", json_array); +		return; +	} + +	if ((level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) && !use_json) +		ospf6_lsa_show_summary_header(vty); + +	end = ospf6_lsdb_head(lsdb, !!type + !!(type && adv_router), +			      type ? *type : 0, adv_router ? *adv_router : 0, +			      &lsa); +	while (lsa) { +		if ((!adv_router || lsa->header->adv_router == *adv_router) +		    && (!id || lsa->header->id == *id)) +			(*showfunc)(vty, lsa, json_array, use_json); +		lsa = ospf6_lsdb_next(end, lsa); +	} + +	if (use_json) +		json_object_object_add(json_obj, "lsa", json_array); +} + +static void ospf6_lsdb_show_wrapper(struct vty *vty, +				    enum ospf_lsdb_show_level level, +				    uint16_t *type, uint32_t *id, +				    uint32_t *adv_router, bool uj, +				    struct ospf6 *ospf6) +{ +	struct listnode *i, *j; +	struct ospf6 *o = ospf6; +	struct ospf6_area *oa; +	struct ospf6_interface *oi; +	json_object *json = NULL; +	json_object *json_array = NULL; +	json_object *json_obj = NULL; + +	if (uj) { +		json = json_object_new_object(); +		json_array = json_object_new_array(); +	} +	for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { +		if (uj) { +			json_obj = json_object_new_object(); +			json_object_string_add(json_obj, "areaId", oa->name); +		} else +			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); +		ospf6_lsdb_show(vty, level, type, id, adv_router, oa->lsdb, +				json_obj, uj); +		if (uj) +			json_object_array_add(json_array, json_obj); +	} +	if (uj) +		json_object_object_add(json, "areaScopedLinkStateDb", +				       json_array); + +	if (uj) +		json_array = json_object_new_array(); +	for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { +		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { +			if (uj) { +				json_obj = json_object_new_object(); +				json_object_string_add(json_obj, "areaId", +						       oa->name); +				json_object_string_add(json_obj, "interface", +						       oi->interface->name); +			} else +				vty_out(vty, IF_LSDB_TITLE_FORMAT, +					oi->interface->name, oa->name); +			ospf6_lsdb_show(vty, level, type, id, adv_router, +					oi->lsdb, json_obj, uj); +			if (uj) +				json_object_array_add(json_array, json_obj); +		} +	} +	if (uj) +		json_object_object_add(json, "interfaceScopedLinkStateDb", +				       json_array); +	if (uj) { +		json_array = json_object_new_array(); +		json_obj = json_object_new_object(); +	} else +		vty_out(vty, AS_LSDB_TITLE_FORMAT); + +	ospf6_lsdb_show(vty, level, type, id, adv_router, o->lsdb, json_obj, +			uj); + +	if (uj) { +		json_object_array_add(json_array, json_obj); +		json_object_object_add(json, "asScopedLinkStateDb", json_array); + +		vty_out(vty, "%s\n", +			json_object_to_json_string_ext( +				json, JSON_C_TO_STRING_PRETTY)); +		json_object_free(json); +	} else +		vty_out(vty, "\n"); +} + +static void ospf6_lsdb_type_show_wrapper(struct vty *vty, +					 enum ospf_lsdb_show_level level, +					 uint16_t *type, uint32_t *id, +					 uint32_t *adv_router, bool uj, +					 struct ospf6 *ospf6) +{ +	struct listnode *i, *j; +	struct ospf6 *o = ospf6; +	struct ospf6_area *oa; +	struct ospf6_interface *oi; +	json_object *json = NULL; +	json_object *json_array = NULL; +	json_object *json_obj = NULL; + +	if (uj) { +		json = json_object_new_object(); +		json_array = json_object_new_array(); +	} + +	switch (OSPF6_LSA_SCOPE(*type)) { +	case OSPF6_SCOPE_AREA: +		for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { +			if (uj) { +				json_obj = json_object_new_object(); +				json_object_string_add(json_obj, "areaId", +						       oa->name); +			} else +				vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); + +			ospf6_lsdb_show(vty, level, type, id, adv_router, +					oa->lsdb, json_obj, uj); +			if (uj) +				json_object_array_add(json_array, json_obj); +		} +		if (uj) +			json_object_object_add(json, "areaScopedLinkStateDb", +					       json_array); +		break; + +	case OSPF6_SCOPE_LINKLOCAL: +		for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { +			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { +				if (uj) { +					json_obj = json_object_new_object(); +					json_object_string_add( +						json_obj, "areaId", oa->name); +					json_object_string_add( +						json_obj, "interface", +						oi->interface->name); +				} else +					vty_out(vty, IF_LSDB_TITLE_FORMAT, +						oi->interface->name, oa->name); + +				ospf6_lsdb_show(vty, level, type, id, +						adv_router, oi->lsdb, json_obj, +						uj); + +				if (uj) +					json_object_array_add(json_array, +							      json_obj); +			} +		} +		if (uj) +			json_object_object_add( +				json, "interfaceScopedLinkStateDb", json_array); +		break; + +	case OSPF6_SCOPE_AS: +		if (uj) +			json_obj = json_object_new_object(); +		else +			vty_out(vty, AS_LSDB_TITLE_FORMAT); + +		ospf6_lsdb_show(vty, level, type, id, adv_router, o->lsdb, +				json_obj, uj); +		if (uj) { +			json_object_array_add(json_array, json_obj); +			json_object_object_add(json, "asScopedLinkStateDb", +					       json_array); +		} +		break; + +	default: +		assert(0); +		break; +	} +	if (uj) { +		vty_out(vty, "%s\n", +			json_object_to_json_string_ext( +				json, JSON_C_TO_STRING_PRETTY)); +		json_object_free(json); +	} else +		vty_out(vty, "\n"); +} +  DEFUN (show_ipv6_ospf6_database,         show_ipv6_ospf6_database_cmd, -       "show ipv6 ospf6 database [<detail|dump|internal>]", +       "show ipv6 ospf6 database [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR         "Display Link state database\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +        JSON_STR)  {  	int idx_level = 4;  	int level; -	struct listnode *i, *j; +	bool uj = use_json(argc, argv);  	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi; -  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6);  	level = parse_show_level(idx_level, argc, argv); - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, NULL, NULL, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, NULL, NULL, oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, NULL, NULL, ospf6->lsdb); - -	vty_out(vty, "\n"); +	ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, NULL, uj, ospf6);  	return CMD_SUCCESS;  } -DEFUN (show_ipv6_ospf6_database_type, -       show_ipv6_ospf6_database_type_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [<detail|dump|internal>]", +DEFUN (show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd, +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -217,16 +429,14 @@ DEFUN (show_ipv6_ospf6_database_type,         "Display details of LSAs\n"         "Dump LSAs\n"         "Display LSA's internal information\n" -      ) +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_level = 5;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -235,43 +445,13 @@ DEFUN (show_ipv6_ospf6_database_type,  	type = parse_type_spec(idx_lsa, argc, argv);  	level = parse_show_level(idx_level, argc, argv); -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, NULL, NULL, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, NULL, NULL, -						oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, NULL, NULL, ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, NULL, uj, ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_id,         show_ipv6_ospf6_database_id_cmd, -       "show ipv6 ospf6 database <*|linkstate-id> A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database <*|linkstate-id> A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -281,16 +461,15 @@ DEFUN (show_ipv6_ospf6_database_id,         "Specify Link state ID as IPv4 address notation\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_ipv4 = 5;  	int idx_level = 6;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint32_t id = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -300,30 +479,14 @@ DEFUN (show_ipv6_ospf6_database_id,  		inet_pton(AF_INET, argv[idx_ipv4]->arg, &id);  	level = parse_show_level(idx_level, argc, argv); +	ospf6_lsdb_show_wrapper(vty, level, NULL, &id, NULL, uj, ospf6); -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, &id, NULL, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, &id, NULL, oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, &id, NULL, ospf6->lsdb); - -	vty_out(vty, "\n");  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_router,         show_ipv6_ospf6_database_router_cmd, -       "show ipv6 ospf6 database <*|adv-router> * A.B.C.D <detail|dump|internal>", +       "show ipv6 ospf6 database <*|adv-router> * A.B.C.D <detail|dump|internal> [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -334,16 +497,15 @@ DEFUN (show_ipv6_ospf6_database_router,         "Specify Advertising Router as IPv4 address notation\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_ipv4 = 6;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -351,24 +513,7 @@ DEFUN (show_ipv6_ospf6_database_router,  	inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);  	level = parse_show_level(idx_level, argc, argv); -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, -					oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, ospf6->lsdb); - -	vty_out(vty, "\n"); +	ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, &adv_router, uj, ospf6);  	return CMD_SUCCESS;  } @@ -408,7 +553,7 @@ DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router,  			return CMD_SUCCESS;  		}  		ospf6_lsdb_show(vty, level, &type, NULL, NULL, -				oa->temp_router_lsa_lsdb); +				oa->temp_router_lsa_lsdb, NULL, false);  		/* Remove the temp cache */  		ospf6_remove_temp_router_lsa(oa);  	} @@ -420,7 +565,7 @@ DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router,  DEFUN (show_ipv6_ospf6_database_type_id,         show_ipv6_ospf6_database_type_id_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -439,18 +584,16 @@ DEFUN (show_ipv6_ospf6_database_type_id,         "Display details of LSAs\n"         "Dump LSAs\n"         "Display LSA's internal information\n" -      ) +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_ipv4 = 6;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t id = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -460,42 +603,13 @@ DEFUN (show_ipv6_ospf6_database_type_id,  	inet_pton(AF_INET, argv[idx_ipv4]->arg, &id);  	level = parse_show_level(idx_level, argc, argv); -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, &id, NULL, oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, &id, NULL, -						oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, &id, NULL, ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, NULL, uj, ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_router,         show_ipv6_ospf6_database_type_router_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> <*|adv-router> A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> <*|adv-router> A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -515,18 +629,16 @@ DEFUN (show_ipv6_ospf6_database_type_router,         "Display details of LSAs\n"         "Dump LSAs\n"         "Display LSA's internal information\n" -      ) +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_ipv4 = 6;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -535,45 +647,15 @@ DEFUN (show_ipv6_ospf6_database_type_router,  	inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);  	level = parse_show_level(idx_level, argc, argv); -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, NULL, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, NULL, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, NULL, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_id_router,         show_ipv6_ospf6_database_id_router_cmd, -       "show ipv6 ospf6 database * A.B.C.D A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database * A.B.C.D A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -584,18 +666,16 @@ DEFUN (show_ipv6_ospf6_database_id_router,         "Display details of LSAs\n"         "Dump LSAs\n"         "Display LSA's internal information\n" -      ) +       JSON_STR)  {  	int idx_ls_id = 5;  	int idx_adv_rtr = 6;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint32_t id = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -603,31 +683,14 @@ DEFUN (show_ipv6_ospf6_database_id_router,  	inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);  	level = parse_show_level(idx_level, argc, argv); -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, -					oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, ospf6->lsdb); - -	vty_out(vty, "\n"); +	ospf6_lsdb_show_wrapper(vty, level, NULL, &id, &adv_router, uj, ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id,         show_ipv6_ospf6_database_adv_router_linkstate_id_cmd, -       "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -638,18 +701,17 @@ DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id,         "Specify Link state ID as IPv4 address notation\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_adv_rtr = 5;  	int idx_ls_id = 7;  	int idx_level = 8;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint32_t id = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -658,30 +720,13 @@ DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id,  	inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);  	level = parse_show_level(idx_level, argc, argv); -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, -					oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, &id, &adv_router, ospf6->lsdb); - -	vty_out(vty, "\n"); +	ospf6_lsdb_show_wrapper(vty, level, NULL, &id, &adv_router, uj, ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_id_router,         show_ipv6_ospf6_database_type_id_router_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D A.B.C.D [<dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D A.B.C.D [<dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -698,20 +743,19 @@ DEFUN (show_ipv6_ospf6_database_type_id_router,         "Specify Link state ID as IPv4 address notation\n"         "Specify Advertising Router as IPv4 address notation\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_ls_id = 5;  	int idx_adv_rtr = 6;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t id = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -722,45 +766,15 @@ DEFUN (show_ipv6_ospf6_database_type_id_router,  	inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);  	level = parse_show_level(idx_level, argc, argv); -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, &id, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id,         show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> adv-router A.B.C.D linkstate-id A.B.C.D [<dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> adv-router A.B.C.D linkstate-id A.B.C.D [<dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -779,20 +793,19 @@ DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id,         "Search by Link state ID\n"         "Specify Link state ID as IPv4 address notation\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_adv_rtr = 6;  	int idx_ls_id = 8;  	int idx_level = 9;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t id = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); @@ -803,44 +816,14 @@ DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id,  	inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);  	level = parse_show_level(idx_level, argc, argv); -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, &id, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_self_originated,         show_ipv6_ospf6_database_self_originated_cmd, -       "show ipv6 ospf6 database self-originated [<detail|dump|internal>]", +       "show ipv6 ospf6 database self-originated [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -848,46 +831,28 @@ DEFUN (show_ipv6_ospf6_database_self_originated,         "Display Self-originated LSAs\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_level = 5;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6);  	level = parse_show_level(idx_level, argc, argv);  	adv_router = ospf6->router_id; -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -		ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, oa->lsdb); -	} - -	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -			vty_out(vty, IF_LSDB_TITLE_FORMAT, oi->interface->name, -				oa->name); -			ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, -					oi->lsdb); -		} -	} - -	vty_out(vty, AS_LSDB_TITLE_FORMAT); -	ospf6_lsdb_show(vty, level, NULL, NULL, &adv_router, ospf6->lsdb); - -	vty_out(vty, "\n"); +	ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, &adv_router, uj, ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_self_originated,         show_ipv6_ospf6_database_type_self_originated_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated [<detail|dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -904,17 +869,16 @@ DEFUN (show_ipv6_ospf6_database_type_self_originated,         "Display Self-originated LSAs\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_level = 6;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t adv_router = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -923,44 +887,14 @@ DEFUN (show_ipv6_ospf6_database_type_self_originated,  	adv_router = ospf6->router_id; -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, NULL, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, NULL, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, NULL, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id,         show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated linkstate-id A.B.C.D [<detail|dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated linkstate-id A.B.C.D [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -979,19 +913,18 @@ DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id,         "Specify Link state ID as IPv4 address notation\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_ls_id = 7;  	int idx_level = 8;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t adv_router = 0;  	uint32_t id = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -1000,44 +933,14 @@ DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id,  	level = parse_show_level(idx_level, argc, argv);  	adv_router = ospf6->router_id; -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, &id, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  }  DEFUN (show_ipv6_ospf6_database_type_id_self_originated,         show_ipv6_ospf6_database_type_id_self_originated_cmd, -       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D self-originated [<detail|dump|internal>]", +       "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D self-originated [<detail|dump|internal>] [json]",         SHOW_STR         IPV6_STR         OSPF6_STR @@ -1055,19 +958,18 @@ DEFUN (show_ipv6_ospf6_database_type_id_self_originated,         "Display Self-originated LSAs\n"         "Display details of LSAs\n"         "Dump LSAs\n" -       "Display LSA's internal information\n") +       "Display LSA's internal information\n" +       JSON_STR)  {  	int idx_lsa = 4;  	int idx_ls_id = 5;  	int idx_level = 7;  	int level; -	struct listnode *i, *j; -	struct ospf6 *ospf6; -	struct ospf6_area *oa; -	struct ospf6_interface *oi;  	uint16_t type = 0;  	uint32_t adv_router = 0;  	uint32_t id = 0; +	bool uj = use_json(argc, argv); +	struct ospf6 *ospf6;  	ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);  	OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -1076,38 +978,8 @@ DEFUN (show_ipv6_ospf6_database_type_id_self_originated,  	level = parse_show_level(idx_level, argc, argv);  	adv_router = ospf6->router_id; -	switch (OSPF6_LSA_SCOPE(type)) { -	case OSPF6_SCOPE_AREA: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			vty_out(vty, AREA_LSDB_TITLE_FORMAT, oa->name); -			ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -					oa->lsdb); -		} -		break; - -	case OSPF6_SCOPE_LINKLOCAL: -		for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) { -			for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { -				vty_out(vty, IF_LSDB_TITLE_FORMAT, -					oi->interface->name, oa->name); -				ospf6_lsdb_show(vty, level, &type, &id, -						&adv_router, oi->lsdb); -			} -		} -		break; - -	case OSPF6_SCOPE_AS: -		vty_out(vty, AS_LSDB_TITLE_FORMAT); -		ospf6_lsdb_show(vty, level, &type, &id, &adv_router, -				ospf6->lsdb); -		break; - -	default: -		assert(0); -		break; -	} - -	vty_out(vty, "\n"); +	ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj, +				     ospf6);  	return CMD_SUCCESS;  } diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py index 4305e0199f..973303b830 100644 --- a/tests/topotests/example-test/test_template.py +++ b/tests/topotests/example-test/test_template.py @@ -44,6 +44,18 @@ from lib.topolog import logger  from mininet.topo import Topo +#TODO: select markers based on daemons used during test +# pytest module level markers +""" +pytestmark = pytest.mark.bfdd # single marker +pytestmark = [ +	pytest.mark.bgpd, +	pytest.mark.ospfd, +	pytest.mark.ospf6d +] # multiple markers +""" + +  class TemplateTopo(Topo):      "Test topology builder" diff --git a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py index f24f463b8a..cd48716905 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py +++ b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py @@ -53,6 +53,19 @@ from lib.topolog import logger  from lib.bgp import verify_bgp_convergence  from lib.topojson import build_topo_from_json, build_config_from_json + +#TODO: select markers based on daemons used during test +# pytest module level markers +""" +pytestmark = pytest.mark.bfdd # single marker +pytestmark = [ +	pytest.mark.bgpd, +	pytest.mark.ospfd, +	pytest.mark.ospf6d +] # multiple markers +""" + +  # Reading the data from JSON File for topology and configuration creation  jsonFile = "{}/example_topojson_multiple_links.json".format(CWD)  try: diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py index 3ae3c9f4fe..0c72e30044 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py +++ b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py @@ -52,6 +52,19 @@ from lib.topolog import logger  from lib.bgp import verify_bgp_convergence  from lib.topojson import build_topo_from_json, build_config_from_json + +#TODO: select markers based on daemons used during test +# pytest module level markers +""" +pytestmark = pytest.mark.bfdd # single marker +pytestmark = [ +	pytest.mark.bgpd, +	pytest.mark.ospfd, +	pytest.mark.ospf6d +] # multiple markers +""" + +  # Reading the data from JSON File for topology and configuration creation  jsonFile = "{}/example_topojson.json".format(CWD) diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py index 06fa2f4626..d05ad6db21 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py +++ b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py @@ -54,6 +54,19 @@ from lib.topolog import logger  from lib.bgp import verify_bgp_convergence  from lib.topojson import build_topo_from_json, build_config_from_json + +#TODO: select markers based on daemons used during test +# pytest module level markers +""" +pytestmark = pytest.mark.bfdd # single marker +pytestmark = [ +	pytest.mark.bgpd, +	pytest.mark.ospfd, +	pytest.mark.ospf6d +] # multiple markers +""" + +  # Reading the data from JSON File for topology and configuration creation  jsonFile = "{}/example_topojson.json".format(CWD) diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index 6bb1326519..294f60bf68 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -539,7 +539,8 @@ def configure_pim_force_expire(tgen, topo, input_dict, build=False):  #############################################  # Verification APIs  ############################################# -def verify_pim_neighbors(tgen, topo, dut=None, iface=None): +@retry(attempts=6, wait=2, return_is_str=True) +def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):      """      Verify all PIM neighbors are up and running, config is verified      using "show ip pim neighbor" cli @@ -550,10 +551,11 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None):      * `topo` : json file data      * `dut` : dut info      * `iface` : link for which PIM nbr need to check +    * `nbr_ip` : neighbor ip of interface      Usage      ----- -    result = verify_pim_neighbors(tgen, topo, dut, link) +    result = verify_pim_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)      Returns      ------- @@ -1530,8 +1532,8 @@ def verify_pim_interface_traffic(tgen, input_dict):      return output_dict -@retry(attempts=31, wait=2, return_is_str=True) -def verify_pim_interface(tgen, topo, dut): +@retry(attempts=21, wait=2, return_is_str=True) +def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):      """      Verify all PIM interface are up and running, config is verified      using "show ip pim interface" cli @@ -1541,10 +1543,12 @@ def verify_pim_interface(tgen, topo, dut):      * `tgen`: topogen object      * `topo` : json file data      * `dut` : device under test +    * `interface` : interface name +    * `interface_ip` : interface ip address      Usage      ----- -    result = verify_pim_interfacetgen, topo, dut) +    result = verify_pim_interfacetgen, topo, dut, interface=ens192, interface_ip=20.1.1.1)      Returns      ------- @@ -1560,56 +1564,55 @@ def verify_pim_interface(tgen, topo, dut):          logger.info("[DUT: %s]: Verifying PIM interface status:", dut)          rnode = tgen.routers()[dut] -        show_ip_pim_interface_json = run_frr_cmd( -            rnode, "show ip pim interface json", isjson=True -        ) - -        for destLink, data in topo["routers"][dut]["links"].items(): -            if "type" in data and data["type"] == "loopback": -                continue +        show_ip_pim_interface_json = rnode.\ +            vtysh_cmd("show ip pim interface json", isjson=True) + +        logger.info("show_ip_pim_interface_json: \n %s", +                    show_ip_pim_interface_json) + +        if interface_ip: +            if interface in show_ip_pim_interface_json: +                pim_intf_json = show_ip_pim_interface_json[interface] +                if pim_intf_json["address"] != interface_ip: +                    errormsg = ("[DUT %s]: PIM interface " +                            "ip is not correct " +                            "[FAILED]!! Expected : %s, Found : %s" +                            %(dut, pim_intf_json["address"],interface_ip)) +                    return errormsg +                else: +                    logger.info("[DUT %s]: PIM interface " +                            "ip is correct " +                            "[Passed]!! Expected : %s, Found : %s" +                            %(dut, pim_intf_json["address"],interface_ip)) +                    return True +        else: +            for destLink, data in topo["routers"][dut]["links"].items(): +                if "type" in data and data["type"] == "loopback": +                    continue -            if "pim" in data and data["pim"] == "enable": -                pim_interface = data["interface"] -                pim_intf_ip = data["ipv4"].split("/")[0] +                if "pim" in data and data["pim"] == "enable": +                    pim_interface = data["interface"] +                    pim_intf_ip = data["ipv4"].split("/")[0] -                if pim_interface in show_ip_pim_interface_json: -                    pim_intf_json = show_ip_pim_interface_json[pim_interface] +                    if pim_interface in show_ip_pim_interface_json: +                        pim_intf_json = show_ip_pim_interface_json\ +                            [pim_interface]                      # Verifying PIM interface -                    if ( -                        pim_intf_json["address"] != pim_intf_ip -                        and pim_intf_json["state"] != "up" -                    ): -                        errormsg = ( -                            "[DUT %s]: PIM interface: %s " -                            "PIM interface ip: %s, status check " -                            "[FAILED]!! Expected : %s, Found : %s" -                            % ( -                                dut, -                                pim_interface, -                                pim_intf_ip, -                                pim_interface, -                                pim_intf_json["state"], -                            ) -                        ) +                    if pim_intf_json["address"] != pim_intf_ip and \ +                        pim_intf_json["state"] != "up": +                        errormsg = ("[DUT %s]: PIM interface: %s " +                                    "PIM interface ip: %s, status check " +                                    "[FAILED]!! Expected : %s, Found : %s" +                                    %(dut, pim_interface, pim_intf_ip, +                                    pim_interface, pim_intf_json["state"]))                          return errormsg -                    logger.info( -                        "[DUT %s]: PIM interface: %s, " -                        "interface ip: %s, status: %s" -                        " [PASSED]!!", -                        dut, -                        pim_interface, -                        pim_intf_ip, -                        pim_intf_json["state"], -                    ) -                else: -                    errormsg = ( -                        "[DUT %s]: PIM interface: %s " -                        "PIM interface ip: %s, is not present " -                        % (dut, pim_interface, pim_intf_ip,) -                    ) -                    return errormsg +                    logger.info("[DUT %s]: PIM interface: %s, " +                                "interface ip: %s, status: %s" +                                " [PASSED]!!", +                                dut, pim_interface, pim_intf_ip, +                                pim_intf_json["state"])      logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))      return True @@ -1846,7 +1849,6 @@ def clear_ip_mroute_verify(tgen, dut):      rnode = tgen.routers()[dut] -    # sleep(60)      logger.info("[DUT: %s]: IP mroutes uptime before clear", dut)      mroute_json_1 = run_frr_cmd(rnode, "show ip mroute json", isjson=True) @@ -3387,3 +3389,62 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):      logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))      return True + + +@retry(attempts=21, wait=2, return_is_str=True) +def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip): +    """ +    Verify all IGMP interface are up and running, config is verified +    using "show ip igmp interface" cli + +    Parameters +    ---------- +    * `tgen`: topogen object +    * `topo` : json file data +    * `dut` : device under test +    * `igmp_iface` : interface name +    * `interface_ip` : interface ip address + +    Usage +    ----- +    result = verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip) + +    Returns +    ------- +    errormsg(str) or True +    """ + +    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + +    for router in tgen.routers(): +        if router != dut: +            continue + +        logger.info("[DUT: %s]: Verifying PIM interface status:", +                    dut) + +        rnode = tgen.routers()[dut] +        show_ip_igmp_interface_json = \ +            run_frr_cmd(rnode, "show ip igmp interface json", isjson=True) + +        if  igmp_iface in show_ip_igmp_interface_json: +            igmp_intf_json = show_ip_igmp_interface_json[igmp_iface] +            # Verifying igmp interface +            if  igmp_intf_json["address"] != interface_ip: +                errormsg = ("[DUT %s]: igmp interface ip is not correct " +                            "[FAILED]!! Expected : %s, Found : %s" +                            %(dut, igmp_intf_json["address"], interface_ip)) +                return errormsg + +            logger.info("[DUT %s]: igmp interface: %s, " +                        "interface ip: %s" +                        " [PASSED]!!", +                        dut, igmp_iface, interface_ip) +        else: +            errormsg = ("[DUT %s]: igmp interface: %s " +                        "igmp interface ip: %s, is not present " +                        %(dut, igmp_iface, interface_ip)) +            return errormsg + +    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) +    return True diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py index ba5835dcf7..910e901ade 100644 --- a/tests/topotests/lib/snmptest.py +++ b/tests/topotests/lib/snmptest.py @@ -80,11 +80,14 @@ class SnmpTester(object):      def _parse_multiline(self, snmp_output):          results = snmp_output.strip().split("\r\n") -        out_dict = {} +        out_dict = {} +        out_list = []          for response in results:              out_dict[self._get_snmp_oid(response)] = self._get_snmp_value(response) -        return out_dict +            out_list.append(self._get_snmp_value(response)) + +        return out_dict, out_list      def get(self, oid):          cmd = "snmpget {0} {1}".format(self._snmp_config(), oid) @@ -114,7 +117,7 @@ class SnmpTester(object):          return self.get_next(oid) == value      def test_oid_walk(self, oid, values, oids=None): -        results_dict = self.walk(oid) +        results_dict, results_list = self.walk(oid)          print("res {}".format(results_dict))          if oids is not None:              index = 0 @@ -124,4 +127,4 @@ class SnmpTester(object):                  index += 1              return True -        return results_dict.values() == values +        return results_list == values diff --git a/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json new file mode 100644 index 0000000000..f582f4929d --- /dev/null +++ b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo3.json @@ -0,0 +1,140 @@ +{ +    "ipv4base": "10.0.0.0", +    "ipv4mask": 24, +    "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"}, +    "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, +    "routers": { +        "l1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "i1": {"ipv4": "auto", "pim": "enable"}, +                "i6": {"ipv4": "auto", "pim": "enable"}, +                "i7": {"ipv4": "auto", "pim": "enable"}, +                "r2": {"ipv4": "auto", "pim": "enable"}, +                "c1": {"ipv4": "auto", "pim": "enable"} +            }, +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1" :{ +                        "igmp":{ +                            "version":  "2" +                        } +                    } +                } +            }, +            "static_routes": [{ +                "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.9.0/24", "1.0.3.5/32"], +                "next_hop": "10.0.12.2" +            }, +            { +                "network": ["1.0.1.2/32", "1.0.3.5/32", "10.0.1.0/24", "1.0.2.2/32", "10.0.4.0/24"], +                "next_hop": "10.0.2.1" +            }] +        }, +        "r2": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "l1": {"ipv4": "auto", "pim": "enable"}, +                "f1": {"ipv4": "auto", "pim": "enable"}, +                "i3": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "1.0.3.5/32"], +                "next_hop": "10.0.7.1" +            }, +            { +                "network": ["1.0.1.2/32", "10.0.8.0/24", "10.0.10.0/24", "10.0.4.0/24", "10.0.11.0/24", "10.0.1.0/24"], +                "next_hop": "10.0.12.1" +            }] +        }, +        "f1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "r2": {"ipv4": "auto", "pim": "enable"}, +                "c2": {"ipv4": "auto", "pim": "enable"}, +                "i2": {"ipv4": "auto", "pim": "enable"}, +                "i8": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"], +                "next_hop": "10.0.7.2" +	        }, +            { +                "network": ["1.0.2.2/32", "10.0.1.0/24", "10.0.4.0/24", "1.0.1.2/32"], +                "next_hop": "10.0.3.1" +            }] +        }, +        "c1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "c2": {"ipv4": "auto", "pim": "enable"}, +                "l1": {"ipv4": "auto", "pim": "enable"}, +                "i4": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"], +                "next_hop": "10.0.2.2" +	        }, +            { +                "network": ["10.0.5.0/24", "10.0.7.0/24", "1.0.3.5/32", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "10.0.4.0/24"], +                "next_hop": "10.0.0.2" +            }] +        }, +        "c2": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "c1": {"ipv4": "auto", "pim": "enable"}, +                "f1": {"ipv4": "auto", "pim": "enable"}, +                "i5": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"], +                "next_hop": "10.0.3.2" +            }, +            { +                "network": ["1.0.1.2/32", "10.0.4.0/24"], +                "next_hop": "10.0.0.1" +            }] +        }, +        "i1": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i2": { +            "links": { +                "f1": {"ipv4": "auto"} +            } +        }, +        "i3": { +            "links": { +                "r2": {"ipv4": "auto"} +            } +        }, +        "i4": { +            "links": { +                "c1": {"ipv4": "auto"} +            } +        }, +        "i5": { +            "links": { +                "c2": {"ipv4": "auto"} +            } +        }, +        "i6": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i7": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i8": { +            "links": { +                "f1": {"ipv4": "auto"} +            } +        } +    } +} diff --git a/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json new file mode 100644 index 0000000000..4635dac7d2 --- /dev/null +++ b/tests/topotests/multicast-pim-sm-topo3/multicast_pim_sm_topo4.json @@ -0,0 +1,137 @@ +{ +    "ipv4base": "10.0.0.0", +    "ipv4mask": 24, +    "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"}, +    "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, +    "routers": { +        "l1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "i1": {"ipv4": "auto", "pim": "enable"}, +                "i6": {"ipv4": "auto", "pim": "enable"}, +                "i7": {"ipv4": "auto", "pim": "enable"}, +                "r2": {"ipv4": "auto", "pim": "enable"}, +                "c1": {"ipv4": "auto", "pim": "enable"} +            }, +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1" :{ +                        "igmp":{ +                            "version":  "2" +                        } +                    } +                } +            }, +            "static_routes": [{ +                "network": ["10.0.4.0/24", "10.0.3.1/24"], +                "next_hop": "10.0.12.2" +            }, +            { +                "network": ["10.0.1.2/24"], +                "next_hop":  "10.0.2.1" +            }] + +        }, + +        "r2": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "l1": {"ipv4": "auto", "pim": "enable"}, +                "f1": {"ipv4": "auto", "pim": "enable"}, +                "i3": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["10.0.4.0/24","10.0.3.1/24"], +                "next_hop": "10.0.7.1" +            }, +            { +                "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"], +                "next_hop": "10.0.12.1" +            }] +        }, +        "f1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "r2": {"ipv4": "auto", "pim": "enable"}, +                "c2": {"ipv4": "auto", "pim": "enable"}, +                "i2": {"ipv4": "auto", "pim": "enable"}, +                "i8": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["10.0.4.0/24","10.0.3.1/24"], +                "next_hop": "10.0.3.1" +	        }, +            { +                "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"], +                "next_hop": "10.0.7.2" +            }] +        }, +        "c1": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "c2": {"ipv4": "auto", "pim": "enable"}, +                "l1": {"ipv4": "auto", "pim": "enable"}, +                "i4": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [{ +                "network": ["1.0.4.11/32","10.0.4.2/24", "10.0.3.1/24"], +                "next_hop": "10.0.2.2" +	        }] + + +        }, +        "c2": { +            "links": { +                "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, +                "c1": {"ipv4": "auto", "pim": "enable"}, +                "f1": {"ipv4": "auto", "pim": "enable"}, +                "i5": {"ipv4": "auto", "pim": "enable"} +            }, +            "static_routes": [ +            { +                "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"], +                "next_hop": "10.0.3.2" +            }] +        }, +        "i1": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i2": { +            "links": { +                "f1": {"ipv4": "auto"} +            } +        }, +        "i3": { +            "links": { +                "r2": {"ipv4": "auto"} +            } +        }, +        "i4": { +            "links": { +                "c1": {"ipv4": "auto"} +            } +        }, +        "i5": { +            "links": { +                "c2": {"ipv4": "auto"} +            } +        }, +        "i6": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i7": { +            "links": { +                "l1": {"ipv4": "auto"} +            } +        }, +        "i8": { +            "links": { +                "f1": {"ipv4": "auto"} +            } +        } +    } +} diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py new file mode 100755 index 0000000000..d31d7ace92 --- /dev/null +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py @@ -0,0 +1,4607 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test multicast pim sm: + +Test steps +- Create topology (setup module) +- Bring up topology + +Following tests are covered: + +1.  verify oil when join prune sent scenario_1 p0 +2.  verify oil when join prune sent scenario_2 p0 +3.  shut noshut source interface when upstream cleared from LHR p0( +4.  shut noshut receiver interface when upstream cleared from LHR p0( +5.  verify igmp clis p0 +6.  verify igmp cli generate query once p0 +7.  verify remove add igmp config to receiver interface p0 +8.  verify remove add igmp commands when pim configured p0 +9.  verify remove add pim commands when igmp configured p0 +10. pim dr priority p0 +11. pim hello timer p0 +12. Verify mroute after removing RP sending IGMP prune p2 +13. Verify prune is sent to LHR and FHR when PIM nbr went down +14. Verify mroute flag in LHR and FHR node +15. Verify IGMP prune processed correctly when same join received from IGMP and PIM +16. Verify multicast traffic flowing fine, when LHR connected to RP +17. Verify multicast traffic is flowing fine when FHR is connected to RP +""" + +import os +import re +import sys +import json +import time +import datetime +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +from lib.common_config import ( +    start_topology, +    write_test_header, +    write_test_footer, +    step, +    iperfSendIGMPJoin, +    addKernelRoute, +    reset_config_on_routers, +    iperfSendTraffic, +    kill_iperf, +    shutdown_bringup_interface, +    kill_router_daemons, +    start_router, +    start_router_daemons, +    stop_router, +    apply_raw_config, +    add_interfaces_to_vlan, +    tcpdump_capture_start, +    tcpdump_capture_stop, +    LOGDIR, +    check_router_status, +    required_linux_kernel_version, +    topo_daemons, +) +from lib.pim import ( +    create_pim_config, +    create_igmp_config, +    verify_igmp_groups, +    verify_ip_mroutes, +    clear_ip_mroute_verify, +    clear_ip_mroute, +    clear_ip_pim_interface_traffic, +    verify_igmp_config, +    verify_pim_neighbors, +    verify_pim_config, +    verify_pim_interface, +    verify_upstream_iif, +    verify_multicast_traffic, +    verify_pim_rp_info, +    get_refCount_for_mroute, +    verify_multicast_flag_state, +) +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/multicast_pim_sm_topo3.json".format(CWD) +try: +    with open(jsonFile, "r") as topoJson: +        topo = json.load(topoJson) +except IOError: +    assert False, "Could not read file {}".format(jsonFile) + +TOPOLOGY = """ + +    i4-----c1-------------c2---i5 +            |              | +            |              | +    i1-----l1------r2-----f1---i2 +       |    |      |       | +       |    |      |       | +      i7    i6     i3     i8 + +    Description: +    i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP +                                     join and traffic +    l1 - LHR +    f1 - FHR +    r2 - FRR router +    c1 - FRR router +    c2 - FRR router +""" + +# Global variables +VLAN_1 = 2501 +GROUP_RANGE = "225.0.0.0/8" +IGMP_GROUP = "225.1.1.1/32" +IGMP_JOIN = "225.1.1.1" +VLAN_INTF_ADRESS_1 = "10.0.8.3/24" +GROUP_RANGE_1 = [ +    "225.1.1.1/32", +    "225.1.1.2/32", +    "225.1.1.3/32", +    "225.1.1.4/32", +    "225.1.1.5/32", +] +IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"] +GROUP_RANGE_2 = [ +    "226.1.1.1/32", +    "226.1.1.2/32", +    "226.1.1.3/32", +    "226.1.1.4/32", +    "226.1.1.5/32", +] +IGMP_JOIN_RANGE_2 = ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"] +GROUP_RANGE_3 = [ +    "227.1.1.1/32", +    "227.1.1.2/32", +    "227.1.1.3/32", +    "227.1.1.4/32", +    "227.1.1.5/32", +] +IGMP_JOIN_RANGE_3 = ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"] + +SAME_VLAN_IP_1 = {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"} +SAME_VLAN_IP_2 = {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"} +SAME_VLAN_IP_3 = {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"} +SAME_VLAN_IP_4 = {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"} +TCPDUMP_FILE = "{}/{}".format(LOGDIR, "v2query.txt") + + +class CreateTopo(Topo): +    """ +    Test BasicTopo - topology 1 + +    * `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 +    """ + +    # Required linux kernel version for this suite to run. +    result = required_linux_kernel_version("4.19") +    if result is not True: +        pytest.skip("Kernel requirements are not met") + +    testsuite_run_time = time.asctime(time.localtime(time.time())) +    logger.info("Testsuite start time: {}".format(testsuite_run_time)) +    logger.info("=" * 40) +    logger.info("Master Topology: \n {}".format(TOPOLOGY)) + +    logger.info("Running setup_module to create topology") + +    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) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    # Creating configuration from JSON +    build_config_from_json(tgen, topo) + +    logger.info("Running setup_module() done") + + +def teardown_module(): +    """Teardown the pytest environment""" + +    logger.info("Running teardown_module to delete topology") + +    tgen = get_topogen() + +    # Stop toplogy and Remove tmp files +    tgen.stop_topology() + +    logger.info( +        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) +    ) +    logger.info("=" * 40) + + +##################################################### +# +#   Testcases +# +##################################################### + + +def config_to_send_igmp_join_and_traffic( +    tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False +): +    """ +    API to do pre-configuration to send IGMP join and multicast +    traffic + +    parameters: +    ----------- +    * `tgen`: topogen object +    * `topo`: input json data +    * `tc_name`: caller test case name +    * `iperf`: router running iperf +    * `iperf_intf`: interface name router running iperf +    * `GROUP_RANGE`: group range +    * `join`: IGMP join, default False +    * `traffic`: multicast traffic, default False +    """ + +    if join: +        # Add route to kernal +        result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    if traffic: +        # Add route to kernal +        result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        router_list = tgen.routers() +        for router in router_list.keys(): +            if router == iperf: +                continue + +            rnode = router_list[router] +            rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter") + +        for router in topo["routers"].keys(): +            if "static_routes" in topo["routers"][router]: +                static_routes = topo["routers"][router]["static_routes"] +                for static_route in static_routes: +                    network = static_route["network"] +                    next_hop = static_route["next_hop"] +                    if type(network) is not list: +                        network = [network] +                    for net in network: +                        addKernelRoute(tgen, router, iperf_intf, net, next_hop) +    return True + + +def verify_mroute_repopulated(uptime_before, uptime_after): +    """ +    API to compare uptime for mroutes + +    Parameters +    ---------- +    * `uptime_before` : Uptime dictionary for any particular instance +    * `uptime_after` : Uptime dictionary for any particular instance +    """ + +    for group in uptime_before.keys(): +        for source in uptime_before[group].keys(): +            if set(uptime_before[group]) != set(uptime_after[group]): +                errormsg = ( +                    "mroute (%s, %s) has not come" +                    " up after mroute clear [FAILED!!]" % (source, group) +                ) +                return errormsg + +            d1 = datetime.datetime.strptime(uptime_before[group][source], "%H:%M:%S") +            d2 = datetime.datetime.strptime(uptime_after[group][source], "%H:%M:%S") +            if d2 >= d1: +                errormsg = "mroute (%s, %s) is not " "repopulated [FAILED!!]" % ( +                    source, +                    group, +                ) +                return errormsg + +            logger.info("mroute (%s, %s) is " "repopulated [PASSED!!]", source, group) + +    return True + + +def verify_state_incremented(state_before, state_after): +    """ +    API to compare interface traffic state incrementing + +    Parameters +    ---------- +    * `state_before` : State dictionary for any particular instance +    * `state_after` : State dictionary for any particular instance +    """ + +    for router, state_data in state_before.items(): +        for state, value in state_data.items(): +            if state_before[router][state] >= state_after[router][state]: +                errormsg = ( +                    "[DUT: %s]: state %s value has not" +                    " incremented, Initial value: %s, " +                    "Current value: %s [FAILED!!]" +                    % ( +                        router, +                        state, +                        state_before[router][state], +                        state_after[router][state], +                    ) +                ) +                return errormsg + +            logger.info( +                "[DUT: %s]: State %s value is " +                "incremented, Initial value: %s, Current value: %s" +                " [PASSED!!]", +                router, +                state, +                state_before[router][state], +                state_after[router][state], +            ) + +    return True + + +def find_v2_query_msg_in_tcpdump(tgen, router, message, count, cap_file): +    """ +    Find v2 query messages in tcpdump file + +    Parameters +    ---------- +    * `tgen` : Topology handler +    * `router` : Device under test +    * `cap_file` : tcp dump file name + +    """ + +    filepath = os.path.join(LOGDIR, tgen.modname, router, cap_file) +    with open(filepath) as f: +        if len(re.findall("{}".format(message), f.read())) < count: +            errormsg = "[DUT: %s]: Verify Message: %s in tcpdump" " [FAILED!!]" % ( +                router, +                message, +            ) +            return errormsg + +        logger.info( +            "[DUT: %s]: Found message: %s in tcpdump " " count: %s [PASSED!!]", +            router, +            message, +            count, +        ) +    return True + + +def find_tos_in_tcpdump(tgen, router, message, cap_file): +    """ +    Find v2 query messages in tcpdump file + +    Parameters +    ---------- +    * `tgen` : Topology handler +    * `router` : Device under test +    * `cap_file` : tcp dump file name + +    """ + +    filepath = os.path.join(LOGDIR, tgen.modname, router, cap_file) +    with open(filepath) as f: + +        if len(re.findall(message, f.read())) < 1: +            errormsg = "[DUT: %s]: Verify Message: %s in tcpdump" " [FAILED!!]" % ( +                router, +                message, +            ) +            return errormsg + +        logger.info( +            "[DUT: %s]: Found message: %s in tcpdump " "[PASSED!!]", router, message +        ) +    return True + + +def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): +    """ +    TC_21_1: +    Verify OIL detail updated in (S,G) and (*,G) mroute when IGMP +    join/prune is sent +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (226.1.1.1-5)" +    ) +    step( +        "Enable IGMP of FRR3 interface and send IGMP joins " +        " from FRR3 node for group range (226.1.1.1-5)" +    ) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_dict = { +        "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = { +        "i1": topo["routers"]["i1"]["links"]["l1"]["interface"], +        "i8": topo["routers"]["i8"]["links"]["f1"]["interface"], +    } + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (226.1.1.1-5) in R2") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Configure one source on FRR3 for all the groups and send" " multicast traffic" +    ) + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i2, +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR1 node") + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False) + +    step( +        "After receiving the IGMP prune from FRR1 , verify traffic " +        "immediately stopped for this receiver 'show ip multicast'" +    ) + +    input_traffic = {"l1": {"traffic_sent": [intf_l1_i1]}} +    result = verify_multicast_traffic(tgen, input_traffic, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        " Traffic is not stopped yet \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step( +        "IGMP groups are remove from FRR1 node 'show ip igmp groups'" +        " FRR3 IGMP still present" +    ) + +    dut = "l1" +    result = verify_igmp_groups( +        tgen, dut, intf_l1_i1, IGMP_JOIN_RANGE_1, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "IGMP groups are not deleted \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    dut = "f1" +    result = verify_igmp_groups(tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "(*,G) and (S,G) OIL got removed immediately after receiving" +        " prune 'show ip pim state' and 'show ip mroute' on FRR1 node," +        " no impact on FRR3 receiver" +    ) + +    input_dict_l1 = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroutes are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "upstream entries are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    input_dict_f1 = [ +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_f1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_f1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " " FRR3 node") + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    shutdown_bringup_interface(tgen, "f1", intf_f1_i8, False) + +    step( +        "After receiving the IGMP prune from FRR3s , verify traffic " +        "immediately stopped for this receiver 'show ip multicast'" +    ) + +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    result = verify_multicast_traffic(tgen, input_traffic, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        " Traffic is not stopped yet \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step( +        "IGMP groups are remove from FRR1 node 'show ip igmp groups'" +        " FRR3 IGMP still present" +    ) + +    dut = "f1" +    result = verify_igmp_groups( +        tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "IGMP groups are not deleted \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step( +        "(*,G) and (S,G) OIL got prune state (none) from all the nodes" +        "FRR1, FRR3 verify using 'show ip mroute'" +    ) + +    input_dict_l1 = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroutes are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "upstream entries are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    shutdown_bringup_interface(tgen, "f1", intf_f1_i8, True) +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True) + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_verify_oil_when_join_prune_sent_scenario_2_p1(request): +    """ +    TC_21_2: Verify OIL detail updated in (S,G) and (*,G) mroute when IGMP +    join/prune is sent +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Removing FRR3 to simulate topo " "FHR(FRR1)---LHR(FRR2)") + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_r2, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (226.1.1.1-5)" +    ) +    step( +        "Enable IGMP of FRR3 interface and send IGMP joins " +        " from FRR3 node for group range (226.1.1.1-5)" +    ) + +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    input_dict = { +        "r2": {"igmp": {"interfaces": {intf_r2_i3: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = { +        "i1": topo["routers"]["i1"]["links"]["l1"]["interface"], +        "i3": topo["routers"]["i3"]["links"]["r2"]["interface"], +    } + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (226.1.1.1-5) in R2") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR3(r2) node") + +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False) + +    step( +        "After sending IGMP prune from FRR3(r2) node verify (*,G) OIL " +        "immediately removed for local receiver mroute should have " +        " PIM protocol , IGMP should be removed verify using " +        "'show ip mroute' no impact seen on FRR1(l1) (*,G)" +    ) + +    input_dict_r2 = [ +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        } +    ] + +    for data in input_dict_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroutes are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    input_dict_l1_r2 = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_l1_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send the IGMP prune from ixia to (226.1.1.1-5) receiver on " "FRR1(l1) node") + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False) + +    step( +        "After sending IGMP prune from FRR1 node verify (*,G) OIL" +        "got removed immediately from FRR1 node" +    ) + +    input_dict_l1 = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        } +    ] + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroutes are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    step("After prune is sent verify upstream got removed in FRR1 node") + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "upstream entries are still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    write_test_footer(tc_name) + + +def test_shut_noshut_source_interface_when_upstream_cleared_from_LHR_p1(request): +    """ +    TC_26: Verify shut/no shut of source interface after upstream got cleared +    from LHR +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP on R2 (loopback interface) for " "the group range 225.0.0.0/8") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE_1, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver") + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "'show ip mroute' showing correct RPF and OIF interface for (*,G)" +        " and (S,G) entries on all the nodes" +    ) + +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i2, +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    step( +        "'show ip pim upstream' and 'show ip pim upstream-rpf' showing" +        " correct OIL and IIF on all the nodes" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the source interface from FRR3") +    intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"] +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False) + +    step( +        "After shut of source interface verify (S,G) mroutes are cleared" +        " from all the nodes" +    ) + +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    result = verify_ip_mroutes( +        tgen, "f1", source_i2, IGMP_JOIN_RANGE_1, intf_f1_i2, intf_f1_r2, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n mroutes are" +        " still present \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behavior: {}".format(result)) + +    step( +        "After waiting for (S,G) timeout from FRR1 for same" +        " source verify that (S,G) is flushed from FRR1 node" +        " 'show ip pim upstream' 'show ip mroute' " +    ) + +    done_flag = False +    for retry in range(1, 11): +        result = verify_upstream_iif( +            tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False +        ) +        if result is not True: +            done_flag = True +        else: +            continue +        if done_flag: +            logger.info("Expected Behavior: {}".format(result)) +            break + +    assert done_flag is True, ( +        "Testcase {} : Failed Error: \n " +        "mroutes are still present, after waiting for 10 mins".format(tc_name) +    ) + +    step("No shut the Source interface just after the upstream is expired" " from FRR1") +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True) + +    step( +        "After no shut of source interface , verify all the (S,G) is " +        " populated again on 'show ip mroute' 'show ip pim upstream' " +        " with proper OIL and IIF detail" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("shut and no shut the source interface immediately") +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True) + +    step( +        "All the mroutes got updated with proper OIL after no shut of" +        "interface verify using 'show ip mroute'" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_shut_noshut_receiver_interface_when_upstream_cleared_from_LHR_p1(request): +    """ +    TC_27: Verify shut/no shut of receiver interface after upstream got +    cleared from LHR +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP on R2 (loopback interface) for " "the group range 225.0.0.0/8") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE_1, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver") + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "'show ip mroute' showing correct RPF and OIF interface for (*,G)" +        " and (S,G) entries on all the nodes" +    ) + +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i2, +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "'show ip pim upstream' and 'show ip pim upstream-rpf' showing" +        " correct OIL and IIF on all the nodes" +    ) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the source interface FRR1") +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"] +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False) + +    step( +        "After waiting for (S,G) timeout from FRR1 for same" +        " source verify that (S,G) is flushed from FRR1 node" +        " 'show ip pim upstream' 'show ip mroute' " +    ) + +    done_flag = False +    for retry in range(1, 11): +        result = verify_upstream_iif( +            tgen, "l1", "Unknown", source_i2, IGMP_JOIN_RANGE_1, expected=False +        ) +        if result is not True: +            done_flag = True +        else: +            continue +        if done_flag: +            logger.info("Expected Behavior: {}".format(result)) +            break + +    assert done_flag is True, ( +        "Testcase {} : Failed Error: \n " +        "mroutes are still present, after waiting for 10 mins".format(tc_name) +    ) + +    step("No shut the Source interface just after the upstream is expired" " from FRR1") +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True) + +    step( +        "After no shut of source interface , verify all the (S,G) is " +        " populated again on 'show ip mroute' 'show ip pim upstream' " +        " with proper OIL and IIF detail" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("shut and no shut the source interface immediately") +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_i2, True) + +    step( +        "After no shut of receiver interface , verify all the (S,G) is " +        "populated again on 'show ip mroute' 'show ip pim upstream' " +        "with proper OIL and IIF detail" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): +    """ +    TC_33: Verify removing and adding IGMP config from the receiver interface +    """ +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Enable PIM on all routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure source on FRR3 and start the traffic for" " (225.1.1.1-225.1.1.10)") + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure source on FRR1 and start the traffic for" " (225.1.1.1-225.1.1.10)") + +    input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i6 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i6, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from" +        " receiver interface of FRR1" +    ) + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    input_dict_2 = { +        "l1": { +            "igmp": { +                "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("IGMP join removed from FRR1 , verify using " "'show ip igmp groups json'") + +    dut = "l1" +    interface = topo["routers"]["l1"]["links"]["i1"]["interface"] +    result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n Groups are not" +        " present \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    intf_f1_i2 = topo["routers"]["f1"]["links"]["i2"]["interface"] +    input_traffic = { +        "l1": {"traffic_received": [intf_l1_r2], "traffic_sent": [intf_l1_i1]}, +        "f1": {"traffic_sent": [intf_f1_r2], "traffic_received": [intf_f1_i2]}, +    } +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "Configure igmp 'ip igmp' and 'ip igmp version 2' from " +        "receiver interface of FRR1" +    ) + +    input_dict_2 = { +        "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "After adding IGMP on receiver interface verify (S,G) and (*,G)" +        " entries got populated and traffic is resumed on FRR1 and FRR3 node" +    ) + +    step( +        "Verify OIL/IIF and drJoinDesired using 'show ip mroute , and traffic" +        " using show ip pim upstream and show ip multicast'" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from" +        " receiver interface of FRR1" +    ) + +    input_dict_2 = { +        "l1": { +            "igmp": { +                "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} +            } +        } +    } + +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("IGMP join removed from FRR1 , verify using " "'show ip igmp groups json'") + +    dut = "l1" +    interface = topo["routers"]["l1"]["links"]["i1"]["interface"] +    result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n Groups are not" +        " present \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "Configure igmp 'ip igmp' and 'ip igmp version 2' from " +        "receiver interface of FRR1" +    ) + +    input_dict_2 = { +        "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "After adding IGMP on receiver interface verify (S,G) and (*,G)" +        " entries got populated and traffic is resumed on FRR1 and FRR3 node" +    ) + +    step( +        "Verify OIL/IIF and drJoinDesired using 'show ip mroute , and traffic" +        " using show ip pim upstream and show ip multicast'" +    ) + +    input_dict_l1_f1 = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i6, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_l1_f1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_l1_f1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Remove ip igmp and send igmp prune from FRR1 interface") + +    input_dict_2 = { +        "l1": { +            "igmp": { +                "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) +    step( +        "Verification: After removing igmp 'no ip igmp' and " +        " sending prune verify mroute and upstream got removed" +        " from FRR1 verify using 'show ip mroute' and " +        "'show ip pim upstream'" +    ) + +    dut = "l1" +    iif = topo["routers"]["l1"]["links"]["i6"]["interface"] +    oil = topo["routers"]["l1"]["links"]["i1"]["interface"] +    source = source_i6 +    result = verify_ip_mroutes( +        tgen, dut, source, IGMP_JOIN_RANGE_1, iif, oil, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n routes are still" +        " present \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    write_test_footer(tc_name) + + +def test_verify_remove_add_igmp_commands_when_pim_configured_p0(request): +    """ +    TC_34: Verify removing and adding IGMP commands when PIM is already +    configured +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Enable PIM on all routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure source on FRR3 and start the traffic for" " (225.1.1.1-225.1.1.10)") + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure source on FRR1 and start the traffic for" " (225.1.1.1-225.1.1.10)") + +    input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i6 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i6, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After configuring IGMP related config , " +        "verify config is present in the interface " +        "'show ip igmp interface ensxx json'" +    ) + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    input_dict_1 = { +        "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}} +    } + +    result = verify_igmp_config(tgen, input_dict_1) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Remove igmp 'no ip igmp' and 'no ip igmp version 2' from" +        " receiver interface of FRR1" +    ) + +    input_dict_2 = { +        "l1": { +            "igmp": { +                "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} +            } +        } +    } + +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After removing the config CLI got removed " +        "'show ip igmp interface ensxx json'" +    ) + +    result = verify_igmp_config(tgen, input_dict_1, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "IGMP interface is not removed \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip igmp last-member-query-count 10' on FRR1" " receiver interface") + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": {"igmp": {"query": {"last-member-query-count": 5}}} +                } +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    result = verify_igmp_config(tgen, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Remove 'ip igmp last-member-query-count 10' on FRR1" " receiver interface") + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": { +                        "igmp": { +                            "query": {"last-member-query-count": "", "delete": True} +                        } +                    } +                } +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": {"igmp": {"query": {"last-member-query-count": 2}}} +                } +            } +        } +    } +    result = verify_igmp_config(tgen, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step( +        "Configure 'ip igmp last-member-query-interval 20' on FRR1" +        " receiver interface" +    ) + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": { +                        "igmp": {"query": {"last-member-query-interval": 20}} +                    } +                } +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    result = verify_igmp_config(tgen, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Remove 'ip igmp last-member-query-count 10' on FRR1" " receiver interface") + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": { +                        "igmp": { +                            "query": {"last-member-query-interval": "", "delete": True} +                        } +                    } +                } +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_dict_3 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": { +                        "igmp": {"query": {"last-member-query-interval": 10}} +                    } +                } +            } +        } +    } +    result = verify_igmp_config(tgen, input_dict_3) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_verify_remove_add_pim_commands_when_igmp_configured_p1(request): +    """ +    TC_35: Verify removing and adding PIM commands when IGMP is already +    configured +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Configure 'ip pim' on receiver interface on FRR1") +    step("Enable PIM on all routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim' on receiver interface on FRR1") + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    input_dict_1 = {"l1": {"pim": {"disable": intf_l1_i1}}} +    result = create_pim_config(tgen, topo, input_dict_1) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim bsm' on receiver interface on FRR1") + +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim bsm"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim bsm' on receiver interface on FRR1") + +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim bsm"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim drpriority' on receiver interface on FRR1") + +    raw_config = { +        "l1": { +            "raw_config": ["interface {}".format(intf_l1_i1), "ip pim drpriority 10"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After configuring PIM related config, " +        "verify config is present in the interface " +        "'show ip pim interface ensxx json'" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"drPriority": 10}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim drpriority' on receiver interface on FRR1") + +    raw_config = { +        "l1": { +            "raw_config": ["interface {}".format(intf_l1_i1), "no ip pim drpriority 10"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After removing the config CLI got removed " +        "'show ip pim interface ensxx json'" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"drPriority": 1}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim hello' on receiver interface on FRR1") + +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim hello 50"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After configuring PIM related config, " +        "verify config is present in the interface " +        "'show ip pim interface ensxx json'" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"helloPeriod": 50}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim hello' on receiver interface on FRR1") + +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim hello"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Verification: After removing the config CLI got removed " +        "'show ip pim interface ensxx json'" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_i1: {"helloPeriod": 30}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim unicast-bsm' on receiver interface on FRR1") + +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "ip pim unicast-bsm"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim hello' on receiver interface on FRR1") + +    raw_config = { +        "l1": { +            "raw_config": ["interface {}".format(intf_l1_i1), "no ip pim unicast-bsm"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_pim_dr_priority_p0(request): +    """ +    TC_36: Verify highest DR priority become the PIM DR +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Configure 'ip pim' on receiver interface on FRR1") +    step("Enable PIM on all routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    input_src = {"i2": topo["routers"]["i2"]["links"]["f1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim drpriority 10' on receiver interface on FRR1(LHR)") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    raw_config = { +        "l1": { +            "raw_config": ["interface {}".format(intf_l1_r2), "ip pim drpriority 10"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "DR config is successful on FRR1 node , verify using " +        " 'show ip pim interface json'" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_r2: {"drPriority": 10}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure 'ip pim drpriority 20' on receiver interface on FRR3(FHR)") + +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    raw_config = { +        "f1": { +            "raw_config": ["interface {}".format(intf_f1_r2), "ip pim drpriority 20"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "DR config is successful on FRR3 node , verify using " +        " 'show ip pim interface json'" +    ) + +    input_dict_dr = {"f1": {"pim": {"interfaces": {intf_f1_r2: {"drPriority": 20}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "PIM is enable on FRR1, FRR2 interface and neighbor is up, " +        " verify using 'show ip pim interface'" +    ) + +    result = verify_pim_interface(tgen, topo, "l1") +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    result = verify_pim_interface(tgen, topo, "f1") +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Highet IP become PIM DR , verify using " +        "'show ip pim interface json' and 'show ip pim neighbor'" +    ) +    step("Highest priority become PIM DR") + +    dr_address = topo["routers"]["l1"]["links"]["r2"]["ipv4"].split("/")[0] +    input_dict_dr = { +        "l1": {"pim": {"interfaces": {intf_l1_r2: {"drAddress": dr_address}}}} +    } +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    dr_address = topo["routers"]["f1"]["links"]["r2"]["ipv4"].split("/")[0] +    input_dict_dr = { +        "f1": {"pim": {"interfaces": {intf_f1_r2: {"drAddress": dr_address}}}} +    } +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim drpriority' on receiver interface on FRR1") + +    raw_config = { +        "l1": { +            "raw_config": ["interface {}".format(intf_l1_r2), "no ip pim drpriority 10"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove 'no ip pim drpriority' on receiver interface on FRR3") + +    raw_config = { +        "f1": { +            "raw_config": ["interface {}".format(intf_f1_r2), "no ip pim drpriority 20"] +        } +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "After removing drpriority , config got removed from both the " +        "nodes and highest IP become PIM DR" +    ) + +    input_dict_dr = {"l1": {"pim": {"interfaces": {intf_l1_r2: {"drPriority": 1}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    input_dict_dr = {"f1": {"pim": {"interfaces": {intf_f1_r2: {"drPriority": 1}}}}} +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    dr_address = topo["routers"]["r2"]["links"]["l1"]["ipv4"].split("/")[0] +    input_dict_dr = { +        "l1": {"pim": {"interfaces": {intf_l1_r2: {"drAddress": dr_address}}}} +    } +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    dr_address = topo["routers"]["r2"]["links"]["f1"]["ipv4"].split("/")[0] +    input_dict_dr = { +        "f1": {"pim": {"interfaces": {intf_f1_r2: {"drAddress": dr_address}}}} +    } +    result = verify_pim_config(tgen, input_dict_dr) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_pim_hello_timer_p1(request): +    """ +    TC_37: Verify PIM hello is sent on configured timer +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step("Configure 'ip pim' on receiver interface on FRR1") +    step("Enable PIM on all routers") +    step("Enable IGMP on FRR1 interface and send IGMP join " "(225.1.1.1-225.1.1.10)") + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in cisco-1(f1)") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Configure PIM hello interval timer 100 on FRR1 node (FRR1-FRR2 link)") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 100"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "PIM hello interval is configured on interface verify using " +        "'show ip pim interface'" +    ) + +    input_dict_hello = { +        "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 100}}}} +    } +    result = verify_pim_config(tgen, input_dict_hello) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Modify hello timer to 180 and then 50sec") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 180"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "PIM hello interval is configured on interface verify using " +        "'show ip pim interface'" +    ) + +    input_dict_hello = { +        "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 180}}}} +    } +    result = verify_pim_config(tgen, input_dict_hello) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    raw_config = { +        "l1": {"raw_config": ["interface {}".format(intf_l1_r2), "ip pim hello 50"]} +    } +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "PIM hello interval is configured on interface verify using " +        "'show ip pim interface'" +    ) + +    input_dict_hello = { +        "l1": {"pim": {"interfaces": {intf_l1_r2: {"helloPeriod": 50}}}} +    } +    result = verify_pim_config(tgen, input_dict_hello) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify that no core is observed") +    if tgen.routers_have_failure(): +        assert False, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_mroute_after_removing_RP_sending_IGMP_prune_p2(request): +    """ +    TC_39 Verify mroute after removing the RP and sending IGMP prune +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove cisco connected link to simulate topo " +        "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))" +    ) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_dict = { +        "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send" +        " multicast traffic" +    ) + +    input_src = {"i6": topo["routers"]["i6"]["links"]["l1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] + +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Remove the RP config for both the range from all the nodes") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                        "delete": True, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    input_dict_starg = [ +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        } +    ] + +    input_dict_sg = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroute still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send prune from receiver-1 (using ctrl+c) on iperf interface") +    kill_iperf(tgen) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    traffic_before = verify_multicast_traffic( +        tgen, input_traffic, return_traffic=True, expected=False +    ) +    assert isinstance(traffic_before, dict), ( +        "Testcase {} : Failed \n traffic_before is not dictionary \n " +        "Error: {}".format(tc_name, result) +    ) + +    step("IGMP groups are remove from FRR1 node 'show ip igmp groups'") + +    dut = "f1" +    result = verify_igmp_groups( +        tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "IGMP groups still present  still present \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step( +        "After receiving the IGMP prune from FRR1 , verify traffic " +        "immediately stopped for this receiver 'show ip multicast'" +    ) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    traffic_after = verify_multicast_traffic( +        tgen, input_traffic, return_traffic=True, expected=False +    ) +    assert isinstance(traffic_after, dict), ( +        "Testcase {} : Failed \n traffic_after is not dictionary \n " +        "Error: {}".format(tc_name, result) +    ) + +    result = verify_state_incremented(traffic_before, traffic_after) +    assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) +    logger.info("Expected Behaviour: {}".format(result)) + +    step("Configure static RP for (225.1.1.1-5) as R2 loopback interface") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send IGMP joins again from LHR,check IGMP joins and starg received") + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send traffic from FHR and verify mroute upstream") + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): +    """ +    TC_38 Verify prune is sent to LHR and FHR when PIM nbr went down +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove cisco connected link to simulate topo " +        "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))" +    ) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_dict = { +        "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send" +        " multicast traffic" +    ) + +    input_src = { +        "i6": topo["routers"]["i6"]["links"]["l1"]["interface"], +        "i2": topo["routers"]["i2"]["links"]["f1"]["interface"], +    } + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] +    source_i1 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] + +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i1, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) +    step("Verify mcast traffic received") +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the link from LHR to RP from RP node") + +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False) + +    step("Verify RP info after Shut the link from LHR to RP from RP node") +    dut = "f1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE +    ) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    input_dict_starg = [ +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        } +    ] + +    input_dict_sg_i2 = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    input_dict_sg_i1 = [ +        { +            "dut": "f1", +            "src_address": source_i1, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        } +    ] + +    input_dict_sg_i2_l1 = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        } +    ] + +    step("Verify mroute after Shut the link from LHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "mroute still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify upstream after Shut the link from LHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n " +            "upstream still present \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("No shut the link from LHR to RP from RP node") + +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_f1, True) + +    step("Verify RP info after No shut the link from LHR to RP from RP node") +    dut = "f1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "RP iif is not updated \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step("Verify mroute  after No shut the link from LHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify upstrem after No shut the link from LHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify mcast traffic received after noshut LHR to RP from RP node") + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the link from FHR to RP from RP node") + +    intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_l1, False) + +    kill_iperf(tgen, dut="i2", action="remove_traffic") + +    step("Verify RP info after Shut the link from FHR to RP from RP node") +    dut = "l1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE +    ) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step("Verify mroute after Shut the link from FHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify upstream after Shut the link from FHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2_l1: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +    step(" No shut the link from FHR to RP from RP node") + +    intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_l1, True) + +    step("Verify RP info after Noshut the link from FHR to RP from RP node") + +    dut = "l1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "RP iif is not updated \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step("Verify mroute after Noshut the link from FHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify mroute after Noshut the link from FHR to RP from RP node") + +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify mcast traffic received after noshut FHR to RP from RP node") +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the link from FHR to RP from FHR node") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_r2, False) + +    step("Verify PIM Nbrs after Shut the link from FHR to RP from FHR node") + +    kill_iperf(tgen, dut="i6", action="remove_traffic") + +    step("Verify RP info after Shut the link from FHR to RP from FHR node") +    dut = "l1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE +    ) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step("Verify mroute after Shut the link from FHR to RP from FHR node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify upstream after Shut the link from FHR to RP from FHR node") +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2_l1: +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +    step(" No shut the link from FHR to RP from FHR node") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_r2, True) + +    step("Verify RP info after No Shut the link from FHR to RP from FHR node") +    dut = "l1" +    rp_address = "1.0.5.17" +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n " +        "RP iif is not updated \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    step("Verify mroute after No Shut the link from FHR to RP from FHR node") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify upstream after No Shut the link from FHR to RP from FHR node") + +    for data in input_dict_starg: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_sg_i2: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify mcast traffic received after noshut FHR to RP from FHR node") +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_mroute_flags_p1(request): +    """ +    TC_47 Verify mroute flag in LHR and FHR node +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove cisco connected link to simulate topo " +        "LHR(FRR1(f1))----RP(cisco(f1)---FHR(FRR3(l1))" +    ) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_f1_i8 = topo["routers"]["f1"]["links"]["i8"]["interface"] +    input_dict = { +        "f1": {"igmp": {"interfaces": {intf_f1_i8: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i8": topo["routers"]["i8"]["links"]["f1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "r2": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Send traffic from FHR to all the groups ( 225.1.1.1 to 225.1.1.5) and send" +        " multicast traffic" +    ) + +    input_src = { +        "i6": topo["routers"]["i6"]["links"]["l1"]["interface"], +        "i2": topo["routers"]["i2"]["links"]["f1"]["interface"], +    } + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i2 = topo["routers"]["i6"]["links"]["l1"]["ipv4"].split("/")[0] +    source_i1 = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0] + +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": source_i2, +            "iif": topo["routers"]["l1"]["links"]["i6"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i1, +            "iif": topo["routers"]["f1"]["links"]["i2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": source_i2, +            "iif": topo["routers"]["f1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["f1"]["links"]["i8"]["interface"], +        }, +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    dut = "f1" +    step("verify flag for (*,G) on f1") +    src_address = "*" +    flag = "SC" +    result = verify_multicast_flag_state( +        tgen, dut, src_address, IGMP_JOIN_RANGE_1, flag +    ) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("verify flag for (S,G) on f1 for Remote spurce ") +    src_address = source_i2 +    flag = "ST" +    result = verify_multicast_flag_state( +        tgen, dut, src_address, IGMP_JOIN_RANGE_1, flag +    ) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request): +    """ +    TC_11: Verify multicast traffic flowing fine, when LHR connected to RP +    Topology used: +    FHR(FRR3(l1))---LHR(FRR1(r2)----RP(FRR2(f1)) +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step( +        "Remove FRR3 to cisco connected link to simulate topo " +        "FHR(FRR3(l1))---LHR(FRR1(r2)----RP(FRR2(f1))" +    ) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) + +    step("Disable IGMP config from l1") +    input_dict_2 = { +        "l1": { +            "igmp": { +                "interfaces": { +                    "l1-i1-eth1": {"igmp": {"version": "2", "delete": True,}} +                } +            } +        } +    } +    result = create_igmp_config(tgen, topo, input_dict_2) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers") +    step( +        "Enable IGMP on FRR1(r2) interface and send IGMP join (226.1.1.1-5)" +        " and (232.1.1.1-5)" +    ) + +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    input_dict = { +        "r2": {"igmp": {"interfaces": {intf_r2_i3: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3 +    _IGMP_JOIN_RANGE = IGMP_JOIN_RANGE_2 + IGMP_JOIN_RANGE_3 + +    input_join = {"i3": topo["routers"]["i3"]["links"]["r2"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, _GROUP_RANGE, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, _IGMP_JOIN_RANGE, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (226.1.1.1-5) and (232.1.1.1-5) in (f1)") + +    input_dict = { +        "f1": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["f1"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": _GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send multicast traffic from FRR3 to 225.1.1.1-225.1.1.10" " receiver") + +    input_src = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, _GROUP_RANGE, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, _IGMP_JOIN_RANGE, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "'show ip mroute' showing correct RPF and OIF interface for (*,G)" +        " and (S,G) entries on all the nodes" +    ) + +    source_i1 = topo["routers"]["i1"]["links"]["l1"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": source_i1, +            "iif": topo["routers"]["l1"]["links"]["i1"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i1, +            "iif": topo["routers"]["r2"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Multicast traffic is flowing for all the groups verify" +        "using 'show ip multicast'" +    ) + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"] +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"] +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    input_traffic = { +        "l1": {"traffic_received": [intf_l1_i1]}, +        "r2": {"traffic_received": [intf_r2_l1], "traffic_sent": [intf_r2_i3]}, +    } +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut and No shut the receiver port") + +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False) + +    step( +        "Verification: After Shut of receiver port, Verify (*,G) and " +        "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'" +    ) + +    input_dict_r2 = [ +        { +            "dut": "r2", +            "src_address": "*", +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i1, +            "iif": topo["routers"]["r2"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +    ] + +    for data in input_dict_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            " Expected Behaviour: mroutes are cleared \n Error: {}".format( +                tc_name, result +            ) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    shutdown_bringup_interface(tgen, "r2", intf_r2_i3, True) + +    step( +        "Verification: After No shut of receiver port , Verify (*,G)" +        " and (S,G) got populated on LHR node (FRR1) using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_r2: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Multicast traffic is resumed for all the groups verify " +        "using 'show ip multicast'" +    ) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut and No shut the source port") + +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False) + +    step( +        "Verification: After Shut of source port, Verify (*,G) and " +        "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'" +    ) + +    input_dict_l1 = [ +        { +            "dut": "l1", +            "src_address": source_i1, +            "iif": topo["routers"]["l1"]["links"]["i1"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["r2"]["interface"], +        } +    ] + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            "mroutes are cleared \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True) + +    step( +        "Verification: After No shut of source port , Verify (*,G)" +        " and (S,G) got populated on LHR node (FRR1) using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Multicast traffic is resumed for all the groups verify " +        "using 'show ip multicast'" +    ) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut and No shut of LHR to cisco port from LHR side") + +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False) + +    step( +        "Verification: After Shut of source port, Verify (S,G) got " +        "removed from LHR and FHR using 'show ip mroute'" +    ) + +    input_dict_r2_f1 = [ +        { +            "dut": "r2", +            "src_address": "*", +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["i3"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_r2_f1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            " mroutes are cleared \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    shutdown_bringup_interface(tgen, "r2", intf_r2_f1, True) + +    step( +        "Verification: After No shut of source port , Verify (*,G)" +        " and (S,G) got populated on LHR node (FRR1) using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Multicast traffic is resumed for all the groups verify " +        "using 'show ip multicast'" +    ) + +    input_traffic_r2 = { +        "r2": {"traffic_received": [intf_r2_l1], "traffic_sent": [intf_r2_i3]} +    } +    result = verify_multicast_traffic(tgen, input_traffic_r2) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut and no shut of FHR to LHR port from FHR side") + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_r2, False) + +    step( +        "Verification: After Shut of LHR to FHR port, Verify (S,G)" +        "got removed from LHR 'show ip mroute'" +    ) + +    dut = "r2" +    src_address = "*" +    iif = topo["routers"]["r2"]["links"]["f1"]["interface"] +    oil = topo["routers"]["r2"]["links"]["i3"]["interface"] + +    result = verify_ip_mroutes(tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    src_address = source_i1 +    iif = topo["routers"]["r2"]["links"]["l1"]["interface"] +    oil = topo["routers"]["r2"]["links"]["i3"]["interface"] + +    result = verify_ip_mroutes( +        tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil, expected=False +    ) +    assert result is not True, ( +        "Testcase {} : Failed \n" +        " mroutes are cleared \n Error: {}".format(tc_name, result) +    ) +    logger.info("Expected Behaviour: {}".format(result)) + +    shutdown_bringup_interface(tgen, "l1", intf_l1_r2, True) + +    step( +        "Verification: After No shut of source port , Verify (*,G)" +        " and (S,G) got populated on LHR node (FRR1) using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "Multicast traffic is resumed for all the groups verify " +        "using 'show ip multicast'" +    ) + +    result = verify_multicast_traffic(tgen, input_traffic_r2) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request): +    """ +    TC_12: Verify multicast traffic is flowing fine when FHR is connected to RP +    Topology used: +    LHR(FRR1)---FHR(FRR3)----RP(FRR2) +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) +    check_router_status(tgen) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    step( +        "Remove FRR3 to FRR2 connected link to simulate topo " +        "FHR(FRR3)---LHR(FRR1)----RP(FFR2)" +    ) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["interface"] +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) +    shutdown_bringup_interface(tgen, "f1", intf_f1_c2, False) + +    step("Enable the PIM on all the interfaces of FRR1, R2 and FRR3" " routers") +    step("Enable IGMP on FRR1(l1) interface and send IGMP join " " and (225.1.1.1-5)") + +    _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3 +    _IGMP_JOIN_RANGE = IGMP_JOIN_RANGE_2 + IGMP_JOIN_RANGE_3 + +    input_join = {"i1": topo["routers"]["i1"]["links"]["l1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, _GROUP_RANGE, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, _IGMP_JOIN_RANGE, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure RP for (225.1.1.1-5) in (f1)") + +    input_dict = { +        "f1": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["f1"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": _GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send multicast traffic from FRR3(r2) to 225.1.1.1-225.1.1.10" " receiver") + +    input_src = {"i3": topo["routers"]["i3"]["links"]["r2"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, _GROUP_RANGE, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, _IGMP_JOIN_RANGE, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step( +        "'show ip mroute' showing correct RPF and OIF interface for (*,G)" +        " and (S,G) entries on all the nodes" +    ) + +    source_i3 = topo["routers"]["i3"]["links"]["r2"]["ipv4"].split("/")[0] +    input_dict_all = [ +        { +            "dut": "l1", +            "src_address": "*", +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "l1", +            "src_address": source_i3, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": "*", +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "r2", +            "src_address": source_i3, +            "iif": topo["routers"]["r2"]["links"]["i3"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +    ] + +    for data in input_dict_all: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_all: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["interface"] +    intf_f1_r2 = topo["routers"]["f1"]["links"]["r2"]["interface"] +    intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] +    input_traffic = { +        "l1": {"traffic_received": [intf_l1_r2], "traffic_sent": [intf_l1_i1]} +    } +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the receiver(l1) port in 1 min interval") + +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, False) + +    step( +        "Verification: After Shut of receiver port, Verify (*,G) and " +        "(S,G) got removed from LHR node (FRR1) using 'show ip mroute'" +    ) + +    input_dict_l1 = [ +        { +            "dut": "l1", +            "src_address": source_i3, +            "iif": topo["routers"]["l1"]["links"]["r2"]["interface"], +            "oil": topo["routers"]["l1"]["links"]["i1"]["interface"], +        } +    ] + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            " mroutes are cleared \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    step("No shut the receiver(l1) port in 1 min interval") + +    shutdown_bringup_interface(tgen, "l1", intf_l1_i1, True) + +    step( +        "Verification: After No shut of receiver port , Verify (*,G)" +        " and (S,G) got populated on LHR node (FRR1) using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_l1: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_l1: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut the source(r2) port in 1 min interval") + +    intf_r2_i3 = topo["routers"]["r2"]["links"]["i3"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_i3, False) + +    step( +        "Verification: After Shut of source port, Verify (S,G) got " +        "removed from FHR using 'show ip mroute'" +    ) + +    input_dict_r2 = [ +        { +            "dut": "r2", +            "src_address": source_i3, +            "iif": topo["routers"]["r2"]["links"]["i3"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        } +    ] + +    for data in input_dict_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            " mroutes are cleared \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    step("No shut the source(r2) port in 1 min interval") + +    shutdown_bringup_interface(tgen, "r2", intf_r2_i3, True) + +    step( +        "Verification: After No shut of source port , Verify (*,G)" +        " and (S,G) got populated on LHR and FHR using " +        "'show ip mroute' 'show ip pim upstream'" +    ) + +    for data in input_dict_r2: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_r2: +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], _IGMP_JOIN_RANGE +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    result = verify_multicast_traffic(tgen, input_traffic) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Shut FHR to RP port from FHR side") + +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["interface"] +    shutdown_bringup_interface(tgen, "r2", intf_r2_f1, False) + +    step( +        "Verification: After Shut of FHR to cisco port, Verify (*,G) " +        "got removed from FHR and cisco node using 'show ip mroute'" +    ) + +    input_dict_all_star = [ +        { +            "dut": "r2", +            "src_address": "*", +            "iif": topo["routers"]["r2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["r2"]["links"]["l1"]["interface"], +        }, +        { +            "dut": "f1", +            "src_address": "*", +            "iif": "lo", +            "oil": topo["routers"]["f1"]["links"]["r2"]["interface"], +        }, +    ] + +    for data in input_dict_all_star: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            _IGMP_JOIN_RANGE, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, ( +            "Testcase {} : Failed \n" +            " mroutes are cleared \n Error: {}".format(tc_name, result) +        ) +        logger.info("Expected Behaviour: {}".format(result)) + +    write_test_footer(tc_name) + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py new file mode 100755 index 0000000000..33c57f209a --- /dev/null +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py @@ -0,0 +1,1120 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test multicast pim sm: + +Test steps +- Create topology (setup module) +- Bring up topology + +Following tests are covered: + +1. TC:48 Verify mroute after configuring black-hole route for RP and source +2. TC:49 Verify mroute when RP is reachable using default route +3. TC:50 Verify mroute when LHR,FHR,RP and transit routers reachable +    using default routes +4. TC:52 Verify PIM nbr after changing interface ip +5. TC:53 Verify IGMP interface updated with correct detail after changing interface config +6. TC:54 Verify received and transmit hello stats are getting cleared after PIM nbr reset + + +""" + +import os +import re +import sys +import json +import time +import datetime +from time import sleep +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +from lib.common_config import ( +    start_topology, +    write_test_header, +    write_test_footer, +    step, +    iperfSendIGMPJoin, +    addKernelRoute, +    reset_config_on_routers, +    iperfSendTraffic, +    kill_iperf, +    shutdown_bringup_interface, +    start_router, +    stop_router, +    apply_raw_config, +    create_static_routes, +    required_linux_kernel_version, +    topo_daemons, +) +from lib.pim import ( +    create_pim_config, +    create_igmp_config, +    verify_igmp_groups, +    verify_ip_mroutes, +    clear_ip_pim_interface_traffic, +    verify_igmp_config, +    verify_pim_neighbors, +    verify_pim_config, +    verify_pim_interface, +    verify_upstream_iif, +    clear_ip_mroute, +    verify_multicast_traffic, +    verify_pim_rp_info, +    verify_pim_interface_traffic, +    verify_igmp_interface, +) +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/multicast_pim_sm_topo4.json".format(CWD) +try: +    with open(jsonFile, "r") as topoJson: +        topo = json.load(topoJson) +except IOError: +    assert False, "Could not read file {}".format(jsonFile) + +TOPOLOGY = """ + + +    i4-----c1-------------c2---i5 +            |              | +            |              | +    i1-----l1------r2-----f1---i2 +       |    |      |       | +       |    |      |       | +      i7    i6     i3     i8 + +    Description: +    i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP +                                     join and traffic +    l1 - LHR +    f1 - FHR +    r2 - FRR router +    c1 - FRR router +    c2 - FRR router +""" + +# Global variables + +GROUP_RANGE = "224.0.0.0/4" +IGMP_GROUP = "225.1.1.1/32" +IGMP_JOIN = "225.1.1.1" +GROUP_RANGE_1 = [ +    "225.1.1.1/32", +    "225.1.1.2/32", +    "225.1.1.3/32", +    "225.1.1.4/32", +    "225.1.1.5/32", +] +IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"] +NEW_ADDRESS_1 = "192.168.20.1" +NEW_ADDRESS_2 = "192.168.20.2" +NEW_ADDRESS_1_SUBNET = "192.168.20.1/24" +NEW_ADDRESS_2_SUBNET = "192.168.20.2/24" + + +class CreateTopo(Topo): +    """ +    Test BasicTopo - topology 1 + +    * `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 +    """ + +    # Required linux kernel version for this suite to run. +    result = required_linux_kernel_version("4.19") +    if result is not True: +        pytest.skip("Kernel requirements are not met") + +    testsuite_run_time = time.asctime(time.localtime(time.time())) +    logger.info("Testsuite start time: {}".format(testsuite_run_time)) +    logger.info("=" * 40) +    logger.info("Master Topology: \n {}".format(TOPOLOGY)) + +    logger.info("Running setup_module to create topology") + +    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) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    # Creating configuration from JSON +    build_config_from_json(tgen, topo) + +    logger.info("Running setup_module() done") + + +def teardown_module(): +    """Teardown the pytest environment""" + +    logger.info("Running teardown_module to delete topology") + +    tgen = get_topogen() + +    # Stop toplogy and Remove tmp files +    tgen.stop_topology() + +    logger.info( +        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) +    ) +    logger.info("=" * 40) + + +##################################################### +# +#   Testcases +# +##################################################### + + +def config_to_send_igmp_join_and_traffic( +    tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False +): +    """ +    API to do pre-configuration to send IGMP join and multicast +    traffic + +    parameters: +    ----------- +    * `tgen`: topogen object +    * `topo`: input json data +    * `tc_name`: caller test case name +    * `iperf`: router running iperf +    * `iperf_intf`: interface name router running iperf +    * `GROUP_RANGE`: group range +    * `join`: IGMP join, default False +    * `traffic`: multicast traffic, default False +    """ + +    if join: +        # Add route to kernal +        result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    if traffic: +        # Add route to kernal +        result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        router_list = tgen.routers() +        for router in router_list.keys(): +            if router == iperf: +                continue + +            rnode = router_list[router] +            rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter") + +        for router in topo["routers"].keys(): +            if "static_routes" in topo["routers"][router]: +                static_routes = topo["routers"][router]["static_routes"] +                for static_route in static_routes: +                    network = static_route["network"] +                    next_hop = static_route["next_hop"] +                    if type(network) is not list: +                        network = [network] + +    return True + + +def verify_state_incremented(state_before, state_after): +    """ +    API to compare interface traffic state incrementing + +    Parameters +    ---------- +    * `state_before` : State dictionary for any particular instance +    * `state_after` : State dictionary for any particular instance +    """ + +    for router, state_data in state_before.items(): +        for state, value in state_data.items(): +            if state_before[router][state] >= state_after[router][state]: +                errormsg = ( +                    "[DUT: %s]: state %s value has not" +                    " incremented, Initial value: %s, " +                    "Current value: %s [FAILED!!]" +                    % ( +                        router, +                        state, +                        state_before[router][state], +                        state_after[router][state], +                    ) +                ) +                return errormsg + +            logger.info( +                "[DUT: %s]: State %s value is " +                "incremented, Initial value: %s, Current value: %s" +                " [PASSED!!]", +                router, +                state, +                state_before[router][state], +                state_after[router][state], +            ) + +    return True + + +def test_mroute_when_RP_reachable_default_route_p2(request): +    """ +    TC_49 Verify mroute when and source RP is reachable using default route +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove c1-c2 connected link to simulate topo " +        "c1(FHR)---l1(RP)----r2---f1-----c2(LHR)" +    ) + +    intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"] +    intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"] +    shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False) +    shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_c2_i5 = topo["routers"]["c2"]["links"]["i5"]["interface"] +    input_dict = { +        "c2": {"igmp": {"interfaces": {intf_c2_i5: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "l1": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send traffic from C1 to all the groups ( 225.1.1.1 to 225.1.1.5)") + +    input_src = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i4 = topo["routers"]["i4"]["links"]["c1"]["ipv4"].split("/")[0] + +    input_dict_starg = [ +        { +            "dut": "c2", +            "src_address": "*", +            "iif": topo["routers"]["c2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["c2"]["links"]["i5"]["interface"], +        } +    ] + +    input_dict_sg = [ +        { +            "dut": "c2", +            "src_address": source_i4, +            "iif": topo["routers"]["c2"]["links"]["f1"]["interface"], +            "oil": topo["routers"]["c2"]["links"]["i5"]["interface"], +        } +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Delete static routes on c2") +    input_dict = { +        "c2": { +            "static_routes": [ +                { +                    "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"], +                    "next_hop": "10.0.3.2", +                    "delete": True, +                } +            ] +        } +    } + +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + +    step("Verify RP info unknown after removing static route from c2 ") +    dut = "c2" +    rp_address = topo["routers"]["l1"]["links"]["lo"]["ipv4"].split("/")[0] +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE +    ) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step("Verify mroute not present after Delete of static routes on c1") + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +    step("Configure default routes on c2") + +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["ipv4"].split("/")[0] + +    input_dict = { +        "c2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_f1_c2}]} +    } +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + +    step("applying ip nht config  on c2") + +    raw_config = {"c2": {"raw_config": ["ip nht resolve-via-default"]}} + +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify RP info is NOT unknown after removing static route from c2 ") +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False +    ) +    assert result is not True, "Testcase {} :Failed \n Error: {}".format( +        tc_name, result +    ) + +    step("Verify (s,g) populated after adding default route ") + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify (*,g) populated after adding default route ") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_mroute_with_RP_default_route_all_nodes_p2(request): +    """ +    TC_50 Verify mroute when LHR,FHR,RP and transit routers reachable +    using default routes +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove c1-c2 connected link to simulate topo " +        "c1(LHR)---l1(RP)----r2---f1-----c2(FHR)" +    ) + +    intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"] +    intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"] +    shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False) +    shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_c1_i4 = topo["routers"]["c1"]["links"]["i4"]["interface"] +    input_dict = { +        "c1": {"igmp": {"interfaces": {intf_c1_i4: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "l1": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send traffic from C2 to all the groups ( 225.1.1.1 to 225.1.1.5)") + +    input_src = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0] + +    input_dict_starg = [ +        { +            "dut": "c1", +            "src_address": "*", +            "iif": topo["routers"]["c1"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"], +        } +    ] + +    input_dict_sg = [ +        { +            "dut": "c1", +            "src_address": source_i5, +            "iif": topo["routers"]["c1"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"], +        } +    ] + +    step("Verify mroutes and iff upstream") + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Delete static routes RP on all the nodes") +    input_dict = { +        "c2": { +            "static_routes": [ +                {"network": ["1.0.4.11/32"], "next_hop": "10.0.3.2", "delete": True} +            ] +        }, +        "c1": { +            "static_routes": [ +                {"network": ["1.0.4.11/32"], "next_hop": "10.0.2.2", "delete": True} +            ] +        }, +        "r2": { +            "static_routes": [ +                {"network": ["1.0.4.11/32"], "next_hop": "10.0.12.1", "delete": True} +            ] +        }, +        "f1": { +            "static_routes": [ +                {"network": ["1.0.4.11/32"], "next_hop": "10.0.7.2", "delete": True} +            ] +        }, +    } + +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + +    step("Verify RP info unknown after removing static route from c2 ") +    dut = "c2" +    rp_address = topo["routers"]["l1"]["links"]["lo"]["ipv4"].split("/")[0] +    SOURCE = "Static" +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE +    ) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +        result = verify_upstream_iif( +            tgen, +            data["dut"], +            data["iif"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            expected=False, +        ) +        assert result is not True, "Testcase {} : Failed Error: {}".format( +            tc_name, result +        ) + +    step("Configure default routes on all the nodes") + +    intf_f1_c2 = topo["routers"]["f1"]["links"]["c2"]["ipv4"].split("/")[0] +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["ipv4"].split("/")[0] +    intf_l1_r2 = topo["routers"]["l1"]["links"]["r2"]["ipv4"].split("/")[0] +    intf_r2_f1 = topo["routers"]["r2"]["links"]["f1"]["ipv4"].split("/")[0] + +    input_dict = { +        "c1": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_l1_c1}]}, +        "c2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_f1_c2}]}, +        "r2": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_l1_r2}]}, +        "f1": {"static_routes": [{"network": "0.0.0.0/0", "next_hop": intf_r2_f1}]}, +    } +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + +    step("applying ip nht config  on c2") + +    raw_config = { +        "c1": {"raw_config": ["ip nht resolve-via-default"]}, +        "c2": {"raw_config": ["ip nht resolve-via-default"]}, +        "r2": {"raw_config": ["ip nht resolve-via-default"]}, +        "f1": {"raw_config": ["ip nht resolve-via-default"]}, +        "l1": {"raw_config": ["ip nht resolve-via-default"]}, +    } + +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify RP info Not unknown after removing static route from c2 ") +    dut = "c2" +    step("Verify RP info is NOT unknown after removing static route from c2 ") +    result = verify_pim_rp_info( +        tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False +    ) +    assert result is not True, "Testcase {} :Failed \n Error: {}".format( +        tc_name, result +    ) + +    step("Verify (s,g) populated after adding default route ") + +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Verify (*,g) populated after adding default route ") + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +        result = verify_upstream_iif( +            tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_PIM_hello_tx_rx_p1(request): +    """ +    TC_54 Verify received and transmit hello stats +        are getting cleared after PIM nbr reset +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) + +    # Creating configuration from JSON +    kill_iperf(tgen) +    clear_ip_mroute(tgen) +    reset_config_on_routers(tgen) +    clear_ip_pim_interface_traffic(tgen, topo) + +    # Don"t run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) +    step( +        "Remove c1-c2 connected link to simulate topo " +        "c1(LHR)---l1(RP)----r2---f1-----c2(FHR)" +    ) + +    intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"] +    intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"] +    shutdown_bringup_interface(tgen, "c1", intf_c1_c2, False) +    shutdown_bringup_interface(tgen, "c2", intf_c2_c1, False) + +    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3") +    step( +        "Enable IGMP of FRR1 interface and send IGMP joins " +        " from FRR1 node for group range (225.1.1.1-5)" +    ) + +    intf_c1_i4 = topo["routers"]["c1"]["links"]["i4"]["interface"] +    input_dict = { +        "c1": {"igmp": {"interfaces": {intf_c1_i4: {"igmp": {"version": "2"}}}}} +    } +    result = create_igmp_config(tgen, topo, input_dict) +    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    input_join = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]} + +    for recvr, recvr_intf in input_join.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, recvr, recvr_intf, GROUP_RANGE_1, join=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendIGMPJoin(tgen, recvr, IGMP_JOIN_RANGE_1, join_interval=1) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +    step("Configure static RP for (225.1.1.1-5) as R2") + +    input_dict = { +        "l1": { +            "pim": { +                "rp": [ +                    { +                        "rp_addr": topo["routers"]["l1"]["links"]["lo"]["ipv4"].split( +                            "/" +                        )[0], +                        "group_addr_range": GROUP_RANGE, +                    } +                ] +            } +        } +    } + +    result = create_pim_config(tgen, topo, input_dict) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("Send Mcast traffic from C2 to all the groups ( 225.1.1.1 to 225.1.1.5)") + +    input_src = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]} + +    for src, src_intf in input_src.items(): +        result = config_to_send_igmp_join_and_traffic( +            tgen, topo, tc_name, src, src_intf, GROUP_RANGE_1, traffic=True +        ) +        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + +        result = iperfSendTraffic(tgen, src, IGMP_JOIN_RANGE_1, 32, 2500) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0] + +    input_dict_starg = [ +        { +            "dut": "c1", +            "src_address": "*", +            "iif": topo["routers"]["c1"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"], +        } +    ] + +    input_dict_sg = [ +        { +            "dut": "c1", +            "src_address": source_i5, +            "iif": topo["routers"]["c1"]["links"]["l1"]["interface"], +            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"], +        } +    ] + +    step("(*,G) and (S,G) created on f1 and node verify using 'show ip mroute'") +    for data in input_dict_sg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    for data in input_dict_starg: +        result = verify_ip_mroutes( +            tgen, +            data["dut"], +            data["src_address"], +            IGMP_JOIN_RANGE_1, +            data["iif"], +            data["oil"], +        ) +        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    intf_l1_c1 = topo["routers"]["l1"]["links"]["c1"]["interface"] +    intf_c1_l1 = topo["routers"]["c1"]["links"]["l1"]["interface"] + +    step("verify before stats on C1") +    state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}} + +    c1_state_before = verify_pim_interface_traffic(tgen, state_dict) +    assert isinstance( +        c1_state_before, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("Flap PIM nbr while doing interface c1-l1 interface shut from f1 side") +    shutdown_bringup_interface(tgen, "c1", intf_c1_l1, False) + +    step( +        "After shut of local interface from c1 , verify rx/tx hello counters are cleared on c1 side" +        "verify using 'show ip pim interface traffic'" +    ) +    shutdown_bringup_interface(tgen, "c1", intf_c1_l1, True) + +    step("verify stats after on c1") +    c1_state_after = verify_pim_interface_traffic(tgen, state_dict) +    assert isinstance( +        c1_state_after, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("verify stats not increamented on c1") +    result = verify_state_incremented(c1_state_before, c1_state_after) +    assert ( +        result is not True +    ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) + +    step("verify before stats on l1") +    l1_state_dict = {"l1": {intf_l1_c1: ["helloTx", "helloRx"],}} + +    l1_state_before = verify_pim_interface_traffic(tgen, l1_state_dict) +    assert isinstance( +        l1_state_before, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("Flap PIM nbr while doing interface r2-c1 shut from r2 side") +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, False) + +    step( +        "After shut the interface from r2 side , verify r2 side rx and tx of hello" +        "counters are resetted show ip pim interface traffic" +    ) +    shutdown_bringup_interface(tgen, "l1", intf_l1_c1, True) + +    step("verify stats after on l1") +    l1_state_after = verify_pim_interface_traffic(tgen, l1_state_dict) +    assert isinstance( +        l1_state_after, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("verify stats not increamented on l1") +    result = verify_state_incremented(l1_state_before, l1_state_after) +    assert ( +        result is not True +    ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) + +    step("Reinit the dict") +    c1_state_before = {} +    l1_state_before = {} +    c1_state_after = {} +    l1_state_after = {} + +    step("verify before stats on C1") +    state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}} + +    c1_state_before = verify_pim_interface_traffic(tgen, state_dict) +    assert isinstance( +        c1_state_before, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("Flap c1-r2 pim nbr while changing ip address from c1 side") +    c1_l1_ip_subnet = topo["routers"]["c1"]["links"]["l1"]["ipv4"] + +    raw_config = { +        "c1": { +            "raw_config": [ +                "interface {}".format(intf_c1_l1), +                "no ip address {}".format(c1_l1_ip_subnet), +                "ip address {}".format(NEW_ADDRESS_2_SUBNET), +            ] +        } +    } + +    result = apply_raw_config(tgen, raw_config) +    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + +    step("verify stats after on c1") +    c1_state_after = verify_pim_interface_traffic(tgen, state_dict) +    assert isinstance( +        c1_state_after, dict +    ), "Testcase{} : Failed \n state_before is not dictionary \n " +    "Error: {}".format(tc_name, result) + +    step("verify stats not increamented on c1") +    result = verify_state_incremented(c1_state_before, c1_state_after) +    assert ( +        result is not True +    ), "Testcase{} : Failed Error: {}" "stats incremented".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/ospf_basic_functionality/ospf_chaos.json b/tests/topotests/ospf_basic_functionality/ospf_chaos.json new file mode 100644 index 0000000000..ed199f181b --- /dev/null +++ b/tests/topotests/ospf_basic_functionality/ospf_chaos.json @@ -0,0 +1,166 @@ +{ + +    "ipv4base": "10.0.0.0", +    "ipv4mask": 24, +    "link_ip_start": { +        "ipv4": "10.0.0.0", +        "v4mask": 24 +    }, +    "lo_prefix": { +        "ipv4": "1.0.", +        "v4mask": 32 +    }, +    "routers": { +        "r0": { +            "links": { +                "r1": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r2": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r3": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                } +            }, +            "ospf": { +                "router_id": "100.1.1.0", +                "neighbors": { +                    "r1": {}, +                    "r2": {}, +                    "r3": {} +                }, +                "redistribute": [{ +                        "redist_type": "static" +                    }, +                    { +                        "redist_type": "connected" +                    } +                ] +            } +        }, +        "r1": { +            "links": { +                "r0": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r2": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r3": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                } +            }, +            "ospf": { +                "router_id": "100.1.1.1", +                "neighbors": { +                    "r0": {}, +                    "r2": {}, +                    "r3": {} +                } +            } +        }, +        "r2": { +            "links": { +                "r0": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r1": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r3": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                } +            }, +            "ospf": { +                "router_id": "100.1.1.2", +                "neighbors": { +                    "r1": {}, +                    "r0": {}, +                    "r3": {} +                } +            } +        }, +        "r3": { +            "links": { +                "r0": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r1": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                }, +                "r2": { +                    "ipv4": "auto", +                    "ospf": { +                        "area": "0.0.0.0", +                        "hello_interval": 1, +                        "dead_interval": 4 +                    } +                } +            }, +            "ospf": { +                "router_id": "100.1.1.3", +                "neighbors": { +                    "r0": {}, +                    "r1": {}, +                    "r2": {} +                } +            } +        } +    } +} diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py new file mode 100644 index 0000000000..37b7528490 --- /dev/null +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -0,0 +1,576 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. +# ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + + +"""OSPF Basic Functionality Automation.""" +import os +import sys +import time +import pytest +from copy import deepcopy +import json + +# 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 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, +    step, +    shutdown_bringup_interface, +    topo_daemons, +    verify_rib, +    stop_router, start_router, +    create_static_routes, +    start_router_daemons, +    kill_router_daemons +) + +from lib.ospf import ( +    verify_ospf_neighbor, verify_ospf_rib, +    create_router_ospf) + +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json +from ipaddress import IPv4Address + + + +# Global variables +topo = None + +NETWORK = { +    "ipv4": ["11.0.20.1/32", "11.0.20.2/32", "11.0.20.3/32", "11.0.20.4/32", +             "11.0.20.5/32"] +} +""" +Topology: +      Please view in a fixed-width font such as Courier. +      +---+  A1       +---+ +      +R1 +------------+R2 | +      +-+-+-           +--++ +        |  --        --  | +        |    -- A0 --    | +      A0|      ----      | +        |      ----      | A2 +        |    --    --    | +        |  --        --  | +      +-+-+-            +-+-+ +      +R0 +-------------+R3 | +      +---+     A3     +---+ + +TESTCASES = +1. Verify ospf functionality after restart ospfd. +2. Verify ospf functionality after restart FRR service. +3. Verify ospf functionality when staticd is restarted. + """ + +# Reading the data from JSON File for topology creation +jsonFile = "{}/ospf_chaos.json".format(CWD) +try: +    with open(jsonFile, "r") as topoJson: +        topo = json.load(topoJson) +except IOError: +    assert False, "Could not read file {}".format(jsonFile) + +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_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( +        ospf_covergence +    ) + +    logger.info("Running setup_module() done") + + +def teardown_module(mod): +    """ +    Teardown the pytest environment. + +    * `mod`: module name +    """ + +    logger.info("Running teardown_module to delete topology") + +    tgen = get_topogen() + +    # Stop toplogy and Remove tmp files +    tgen.stop_topology() + +    logger.info( +        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) +    ) +    logger.info("=" * 40) + + +# ################################## +# Test cases start here. +# ################################## +def test_ospf_chaos_tc31_p1(request): +    """Verify ospf functionality after restart ospfd.""" +    tc_name = request.node.name +    write_test_header(tc_name) +    tgen = get_topogen() +    global topo +    step("Bring up the base config as per the topology") +    reset_config_on_routers(tgen) + +    step( +        "Create static routes(10.0.20.1/32) in R1 and redistribute " +        "to OSPF using route map.") + +    # Create Static routes +    input_dict = { +        "r0": { +            "static_routes": [ +                { +                    "network": NETWORK['ipv4'][0], +                    "no_of_ip": 5, +                    "next_hop": 'Null0', +                } +            ] +        } +    } +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    ospf_red_r0 = { +        "r0": { +            "ospf": { +                "redistribute": [{ +                    "redist_type": "static" +                    }] +            } +        } +    } +    result = create_router_ospf(tgen, topo, ospf_red_r0) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Verify OSPF neighbors after base config is done.") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                      " {}".format(ospf_covergence)) + +    step("Verify that route is advertised to R1.") +    dut = 'r1' +    protocol = 'ospf' +    nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib( +        tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Kill OSPFd daemon on R0.") +    kill_router_daemons(tgen, "r0", ["ospfd"]) + +    step("Verify OSPF neighbors are down after killing ospfd in R0") +    dut = 'r0' +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, +        expected=False) +    assert ospf_covergence is not True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step("Verify that route advertised to R1 are deleted from RIB and FIB.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, expected=False) +    assert result is not True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +        expected=False) +    assert result is not True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Bring up OSPFd daemon on R0.") +    start_router_daemons(tgen, "r0", ["ospfd"]) + +    step("Verify OSPF neighbors are up after bringing back ospfd in R0") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Kill OSPFd daemon on R1.") +    kill_router_daemons(tgen, "r1", ["ospfd"]) + +    step("Verify OSPF neighbors are down after killing ospfd in R1") +    dut = 'r1' +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, +        expected=False) +    assert ospf_covergence is not True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step("Bring up OSPFd daemon on R1.") +    start_router_daemons(tgen, "r1", ["ospfd"]) + +    step("Verify OSPF neighbors are up after bringing back ospfd in R1") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                      " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") + +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    write_test_footer(tc_name) + + +def test_ospf_chaos_tc32_p1(request): +    """Verify ospf functionality after restart FRR service. """ +    tc_name = request.node.name +    write_test_header(tc_name) +    tgen = get_topogen() +    global topo +    step("Bring up the base config as per the topology") +    reset_config_on_routers(tgen) + +    step( +        "Create static routes(10.0.20.1/32) in R1 and redistribute " +        "to OSPF using route map.") + +    # Create Static routes +    input_dict = { +        "r0": { +            "static_routes": [ +                { +                    "network": NETWORK['ipv4'][0], +                    "no_of_ip": 5, +                    "next_hop": 'Null0', +                } +            ] +        } +    } +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    ospf_red_r0 = { +        "r0": { +            "ospf": { +                "redistribute": [{ +                    "redist_type": "static" +                    }] +            } +        } +    } +    result = create_router_ospf(tgen, topo, ospf_red_r0) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Verify OSPF neighbors after base config is done.") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step("Verify that route is advertised to R1.") +    dut = 'r1' +    protocol = 'ospf' + +    nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Restart frr on R0") +    stop_router(tgen, 'r0') +    start_router(tgen, 'r0') + +    step("Verify OSPF neighbors are up after restarting R0") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Restart frr on R1") +    stop_router(tgen, 'r1') +    start_router(tgen, 'r1') + +    step("Verify OSPF neighbors are up after restarting R1") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    write_test_footer(tc_name) + + +def test_ospf_chaos_tc34_p1(request): +    """ +    verify ospf functionality when staticd is restarted. + +    Verify ospf functionalitywhen staticroutes are +    redistributed & Staticd is restarted. +    """ +    tc_name = request.node.name +    write_test_header(tc_name) +    tgen = get_topogen() +    global topo +    step("Bring up the base config as per the topology") +    reset_config_on_routers(tgen) + +    step( +        "Create static routes(10.0.20.1/32) in R1 and redistribute " +        "to OSPF using route map.") + +    # Create Static routes +    input_dict = { +        "r0": { +            "static_routes": [ +                { +                    "network": NETWORK['ipv4'][0], +                    "no_of_ip": 5, +                    "next_hop": 'Null0', +                } +            ] +        } +    } +    result = create_static_routes(tgen, input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    ospf_red_r0 = { +        "r0": { +            "ospf": { +                "redistribute": [{ +                    "redist_type": "static" +                    }] +            } +        } +    } +    result = create_router_ospf(tgen, topo, ospf_red_r0) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Verify OSPF neighbors after base config is done.") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step("Verify that route is advertised to R1.") +    dut = 'r1' +    protocol = 'ospf' +    nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Kill staticd daemon on R0.") +    kill_router_daemons(tgen, "r0", ["staticd"]) + +    step("Verify that route advertised to R1 are deleted from RIB and FIB.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, expected=False) +    assert result is not True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +            expected=False) +    assert result is not True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Bring up staticd daemon on R0.") +    start_router_daemons(tgen, "r0", ["staticd"]) + +    step("Verify OSPF neighbors are up after bringing back ospfd in R0") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    step("Kill staticd daemon on R1.") +    kill_router_daemons(tgen, "r1", ["staticd"]) + +    step("Bring up staticd daemon on R1.") +    start_router_daemons(tgen, "r1", ["staticd"]) + +    step("Verify OSPF neighbors are up after bringing back ospfd in R1") +    # Api call verify whether OSPF is converged +    ospf_covergence = verify_ospf_neighbor(tgen, topo) +    assert ospf_covergence is True, ("setup_module :Failed \n Error:" +                                          " {}".format(ospf_covergence)) + +    step( +        "All the neighbours are up and routes are installed before the" +        " restart. Verify OSPF route table and ip route table.") + +    dut = 'r1' +    protocol = 'ospf' +    result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, +    next_hop=nh) +    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/pytest.ini b/tests/topotests/pytest.ini index d1b18a57bb..0c45a09445 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,16 +1,29 @@  # Skip pytests example directory  [pytest]  norecursedirs = .git example-test example-topojson-test lib docker + +# Markers +# +# Please consult the documentation and discuss with TSC members before applying +# any changes to this list.  markers = -	babel: Tests that run against BABEL -	bfd: Tests that run against BFDD -	eigrp: Tests that run against EIGRPD -	isis: Tests that run against ISISD -	ldp: Tests that run against LDPD -	ospf: Tests that run against OSPF( v2 and v3 ) -	pbr: Tests that run against PBRD -	pim: Tests that run against pim -	rip: Tests that run against RIP, both v4 and v6 +	babeld: Tests that run against BABELD +	bfdd: Tests that run against BFDD +	bgpd: Tests that run against BGPD +	eigrpd: Tests that run against EIGRPD +	isisd: Tests that run against ISISD +	ldpd: Tests that run against LDPD +	nhrpd: Tests that run against NHRPD +	ospf6d: Tests that run against OSPF6D +	ospfd: Tests that run against OSPFD +	pathd: Tests that run against PATHD +	pbrd: Tests that run against PBRD +	pimd: Tests that run against PIMD +	ripd: Tests that run against RIPD +	ripngd: Tests that run against RIPNGD +	sharpd: Tests that run against SHARPD +	staticd: Tests that run against STATICD +	vrrpd: Tests that run against VRRPD  [topogen]  # Default configuration values diff --git a/tests/topotests/simple-snmp-test/test_simple_snmp.py b/tests/topotests/simple-snmp-test/test_simple_snmp.py index 2b609ef14c..1e56252ea3 100755 --- a/tests/topotests/simple-snmp-test/test_simple_snmp.py +++ b/tests/topotests/simple-snmp-test/test_simple_snmp.py @@ -76,6 +76,11 @@ class TemplateTopo(Topo):  def setup_module(mod):      "Sets up the pytest environment" + +    # skip tests is SNMP not installed +    if not os.path.isfile("/usr/sbin/snmpd"): +        error_msg = "SNMP not installed - skipping" +        pytest.skip(error_msg)      # This function initiates the topology build with Topogen...      tgen = Topogen(TemplateTopo, mod.__name__)      # ... and here it calls Mininet initialization functions. @@ -120,11 +125,13 @@ def test_r1_bgp_version():      "Wait for protocol convergence"      tgen = get_topogen() -    #tgen.mininet_cli() +    # tgen.mininet_cli()      r1 = tgen.net.get("r1")      r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")      assert r1_snmp.test_oid("bgpVersin", None)      assert r1_snmp.test_oid("bgpVersion", "10") +    assert r1_snmp.test_oid_walk("bgpVersion", ["10"]) +    assert r1_snmp.test_oid_walk("bgpVersion", ["10"], ["0"])  if __name__ == "__main__":  | 
