From cc3d8343087d47393c5485280e0daa204b0eb99a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 7 Oct 2021 12:02:57 -0400 Subject: [PATCH 1/6] zebra: GR data was being printed 2 times for `show zebra client` When issuing the `show zebra client` command data about Graceful Restart state is being printed 2 times. Signed-off-by: Donald Sharp --- zebra/zserv.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index e4a48093f7..0c4515a695 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1007,7 +1007,6 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; uint32_t last_read_cmd, last_write_cmd; - struct client_gr_info *info = NULL; vty_out(vty, "Client: %s", zebra_route_string(client->proto)); if (client->instance) @@ -1100,22 +1099,6 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); - TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { - vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); - vty_out(vty, "Capabilities : "); - switch (info->capabilities) { - case ZEBRA_CLIENT_GR_CAPABILITIES: - vty_out(vty, "Graceful Restart\n"); - break; - case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: - case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: - case ZEBRA_CLIENT_GR_DISABLE: - case ZEBRA_CLIENT_RIB_STALE_TIME: - vty_out(vty, "None\n"); - break; - } - } - #if defined DEV_BUILD vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, From 76ab1a97021a7a6f00de9e87643d589c844a3421 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 7 Oct 2021 12:08:42 -0400 Subject: [PATCH 2/6] zebra: Display how long zebra is expected to wait for GR When a client sends to zebra that GR mode is being turned on. The client also passes down the time zebra should hold onto the routes. Display this time with the output of the `show zebra client` command as well. Signed-off-by: Donald Sharp --- zebra/zserv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index 0c4515a695..abb9c5ca5d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1134,7 +1134,8 @@ static void zebra_show_stale_client_detail(struct vty *vty, vty_out(vty, "Capabilities : "); switch (info->capabilities) { case ZEBRA_CLIENT_GR_CAPABILITIES: - vty_out(vty, "Graceful Restart\n"); + vty_out(vty, "Graceful Restart(%u seconds)\n", + info->stale_removal_time); break; case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: From 6255aad0bc78c1b110d72988f62427a057c1a80f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Oct 2021 07:37:15 -0400 Subject: [PATCH 3/6] tests: Fix ospf[6]_gr_topo1 tests to work better under load 2 things: a) Each test was setting up for graceful restart with calls to `graceful-restart prepare ip[v6] ospf`, then sleeping for 3 or 5 seconds. Then killing the ospf process. Under heavy load there is no guarantee that zebra has received/processed this signal. Write some code to ensure that this happens b) Tests are issuing commands in this order: 1) issue gr prepare command 2) kill router 3) 4) start router 5) Imagine that the system is under some load and there is a small amount of time before step 5 happens. In this case ospf could have come up and started neighbor relations and also started installing routes. If zebra receives a new route before step 5 is issued then the route could be in a state where it is not installed, because it is being sent to the kernel for installation. This would fail the test because it would only look 1 time. This is fixed by giving time on restart for the routes to be in the installed state. Signed-off-by: Donald Sharp --- .../ospf6_gr_topo1/test_ospf6_gr_topo1.py | 48 +++++++++++++++---- .../ospf_gr_topo1/test_ospf_gr_topo1.py | 47 ++++++++++++++---- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index ccbcadb8b1..d50223191d 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -175,10 +175,21 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in # all routers of the routing domain. + # If we are not on initial convergence *but* we are checking + # after a restart. Looking in the zebra rib for installed + # is a recipe for test failure. Why? because if we are restarting + # then ospf is in the process of establishing neighbors and passing + # new routes to zebra. Zebra will not mark the route as installed + # when it receives a replacement from ospf until it has finished + # processing it. Let's give it a few seconds to allow this to happen + # under load. if initial_convergence == True: tries = 240 else: - tries = 1 + if restarting != None: + tries = 40 + else: + tries = 1 router_compare_json_output( rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries ) @@ -212,6 +223,26 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): ) +def ensure_gr_is_in_zebra(rname): + retry = True + retry_times = 10 + tgen = get_topogen() + + while retry and retry_times > 0: + out = tgen.net[rname].cmd( + 'vtysh -c "show zebra client" | grep "Client: ospf6$" -A 40 | grep "Capabilities "' + ) + + if "Graceful Restart" not in out: + sleep(2) + retry_times -= 1 + else: + retry = False + + assertmsg = "%s does not appear to have Graceful Restart setup" % rname + assert not retry and retry_times > 0, assertmsg + + # # Test initial network convergence # @@ -238,10 +269,9 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospf6d"], save_config=False) check_routers(exiting="rt1") - start_router_daemons(tgen, "rt1", ["ospf6d"]) check_routers(restarting="rt1") @@ -258,7 +288,7 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospf6d"], save_config=False) check_routers(exiting="rt2") @@ -278,7 +308,7 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospf6d"], save_config=False) check_routers(exiting="rt3") @@ -298,7 +328,7 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospf6d"], save_config=False) check_routers(exiting="rt4") @@ -318,7 +348,7 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospf6d"], save_config=False) check_routers(exiting="rt5") @@ -338,7 +368,7 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospf6d"], save_config=False) check_routers(exiting="rt6") @@ -358,7 +388,7 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospf6d"], save_config=False) check_routers(exiting="rt7") diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 7d9cc68412..1432d53ffc 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -184,10 +184,21 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in # all routers of the routing domain. + # If we are not on initial convergence *but* we are checking + # after a restart. Looking in the zebra rib for installed + # is a recipe for test failure. Why? because if we are restarting + # then ospf is in the process of establishing neighbors and passing + # new routes to zebra. Zebra will not mark the route as installed + # when it receives a replacement from ospf until it has finished + # processing it. Let's give it a few seconds to allow this to happen + # under load. if initial_convergence == True: tries = 240 else: - tries = 1 + if restarting != None: + tries = 40 + else: + tries = 1 router_compare_json_output( rname, "show ip route ospf json", "show_ip_route.json", tries ) @@ -215,6 +226,26 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): ) +def ensure_gr_is_in_zebra(rname): + retry = True + retry_times = 10 + tgen = get_topogen() + + while retry and retry_times > 0: + out = tgen.net[rname].cmd( + 'vtysh -c "show zebra client" | grep "Client: ospf$" -A 40 | grep "Capabilities "' + ) + + if "Graceful Restart" not in out: + sleep(2) + retry_times -= 1 + else: + retry = False + + assertmsg = "%s does not appear to have Graceful Restart setup" % rname + assert not retry and retry_times > 0, assertmsg + + # # Test initial network convergence # @@ -241,7 +272,7 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospfd"], save_config=False) check_routers(exiting="rt1") @@ -261,7 +292,7 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospfd"], save_config=False) check_routers(exiting="rt2") @@ -281,7 +312,7 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospfd"], save_config=False) check_routers(exiting="rt3") @@ -301,7 +332,7 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospfd"], save_config=False) check_routers(exiting="rt4") @@ -321,7 +352,7 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospfd"], save_config=False) check_routers(exiting="rt5") @@ -341,7 +372,7 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospfd"], save_config=False) check_routers(exiting="rt6") @@ -361,7 +392,7 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospfd"], save_config=False) check_routers(exiting="rt7") From a792fa7b150831c1d2f70ddae580e6fc38a51ab0 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 7 Oct 2021 21:05:20 -0300 Subject: [PATCH 4/6] ospfd: display detailed information about opaque LSAs in JSON format Signed-off-by: Renato Westphal --- ospfd/ospf_opaque.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 9ec2ed0aa8..955d9168c4 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1182,6 +1182,16 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); + } else { + json_object_string_add( + json, "opaqueType", + ospf_opaque_type_name(opaque_type)); + json_object_int_add(json, "opaqueId", opaque_id); + json_object_int_add(json, "opaqueDataLength", + ntohs(lsah->length) + - OSPF_LSA_HEADER_SIZE); + json_object_boolean_add(json, "opaqueDataLengthValid", + VALID_OPAQUE_INFO_LEN(lsah)); } } else { zlog_debug(" Opaque-Type %u (%s)", opaque_type, From 3e63092b83c6710dd978b705537a2bb8c586ea8b Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 7 Oct 2021 21:06:01 -0300 Subject: [PATCH 5/6] ospfd: fix display of plain-text data on "show ... json" commands Add a 'json' parameter to the 'show_opaque_info' callback definition, and update all instances of that callback to not display plain-text data when the user requested JSON data. Signed-off-by: Renato Westphal --- ospfd/ospf_apiserver.c | 6 +++++- ospfd/ospf_apiserver.h | 3 ++- ospfd/ospf_ext.c | 18 ++++++++++++++---- ospfd/ospf_gr_helper.c | 9 +++++++-- ospfd/ospf_opaque.c | 8 +++++--- ospfd/ospf_opaque.h | 3 ++- ospfd/ospf_ri.c | 11 +++++++++-- ospfd/ospf_te.c | 9 +++++++-- 8 files changed, 51 insertions(+), 16 deletions(-) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index cbd03441ef..a33ca95777 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2059,7 +2059,8 @@ void ospf_apiserver_nsm_change(struct ospf_neighbor *nbr, int old_status) } } -void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) +void ospf_apiserver_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct opaque_lsa { struct lsa_header header; @@ -2070,6 +2071,9 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) struct opaque_lsa *olsa; int opaquelen; + if (json) + return; + olsa = (struct opaque_lsa *)lsa->data; if (VALID_OPAQUE_INFO_LEN(lsa->data)) diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 89a9474972..544a32a28c 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -182,7 +182,8 @@ extern void ospf_apiserver_nsm_change(struct ospf_neighbor *nbr, extern void ospf_apiserver_config_write_router(struct vty *vty); extern void ospf_apiserver_config_write_if(struct vty *vty, struct interface *ifp); -extern void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa); +extern void ospf_apiserver_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); extern int ospf_ospf_apiserver_lsa_originator(void *arg); extern struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa); extern void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv, diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 2d08eeece2..ea1506ea27 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -80,7 +80,8 @@ static struct ospf_ext_lp OspfEXT; */ /* Extended Prefix Opaque LSA related callback functions */ -static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_ext_pref_lsa_originate(void *arg); static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa); static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti, @@ -90,7 +91,8 @@ static int ospf_ext_link_new_if(struct interface *ifp); static int ospf_ext_link_del_if(struct interface *ifp); static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status); static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status); -static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_ext_link_lsa_originate(void *arg); static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa); static void ospf_ext_link_lsa_schedule(struct ext_itf *exti, @@ -1846,12 +1848,16 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, } /* Extended Link TLVs */ -static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -1932,12 +1938,16 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, } /* Extended Prefix TLVs */ -static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index b3eaf7bbdb..a58a120b6b 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -75,7 +75,8 @@ static const char * const ospf_rejected_reason_desc[] = { "Router is in the process of graceful restart", }; -static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa); +static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr); static unsigned int ospf_enable_rtr_hash_key(const void *data) @@ -1012,7 +1013,8 @@ void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf, * Returns: * Nothing. */ -static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) +static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = NULL; struct tlv_header *tlvh = NULL; @@ -1022,6 +1024,9 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t length = 0; int sum = 0; + if (json) + return; + lsah = (struct lsa_header *)lsa->data; if (lsa->size <= OSPF_LSA_HEADER_SIZE) { diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 955d9168c4..a89e90bf70 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -274,7 +274,8 @@ struct ospf_opaque_functab { void (*config_write_router)(struct vty *vty); void (*config_write_if)(struct vty *vty, struct interface *ifp); void (*config_write_debug)(struct vty *vty); - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa); + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); int (*lsa_originator)(void *arg); struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa); int (*new_lsa_hook)(struct ospf_lsa *lsa); @@ -373,7 +374,8 @@ int ospf_register_opaque_functab( void (*config_write_router)(struct vty *vty), void (*config_write_if)(struct vty *vty, struct interface *ifp), void (*config_write_debug)(struct vty *vty), - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa), + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa), int (*lsa_originator)(void *arg), struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa), int (*new_lsa_hook)(struct ospf_lsa *lsa), @@ -1207,7 +1209,7 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, /* Call individual output functions. */ if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL) if (functab->show_opaque_info != NULL) - (*functab->show_opaque_info)(vty, lsa); + (*functab->show_opaque_info)(vty, json, lsa); return; } diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 7d401c3dcc..bded32215b 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -136,7 +136,8 @@ extern int ospf_register_opaque_functab( void (*config_write_router)(struct vty *vty), void (*config_write_if)(struct vty *vty, struct interface *ifp), void (*config_write_debug)(struct vty *vty), - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa), + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa), int (*lsa_originator)(void *arg), struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa), int (*new_lsa_hook)(struct ospf_lsa *lsa), diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 602f98d141..0efa6ca4d5 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -73,7 +73,9 @@ static struct ospf_router_info OspfRI; static void ospf_router_info_ism_change(struct ospf_interface *oi, int old_status); static void ospf_router_info_config_write_router(struct vty *vty); -static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_router_info_show_info(struct vty *vty, + struct json_object *json, + struct ospf_lsa *lsa); static int ospf_router_info_lsa_originate(void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, @@ -1552,12 +1554,17 @@ static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh) return TLV_SIZE(tlvh); } -static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_router_info_show_info(struct vty *vty, + struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index d95e677f6f..03fa572859 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -87,7 +87,8 @@ static int ospf_mpls_te_del_if(struct interface *ifp); static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_status); static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router(struct vty *vty); -static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate_area(void *arg); static int ospf_mpls_te_lsa_inter_as_as(void *arg); static int ospf_mpls_te_lsa_inter_as_area(void *arg); @@ -3783,7 +3784,8 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, return sum; } -static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh, *next; @@ -3791,6 +3793,9 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, uint16_t subtotal, uint16_t total) = NULL; + if (json) + return; + sum = 0; total = lsa->size - OSPF_LSA_HEADER_SIZE; From 10396dc55af08178b96df9d200e288aa6139cc08 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 7 Oct 2021 21:00:06 -0300 Subject: [PATCH 6/6] tests: check for received Grace-LSAs on the OSPF GR topotests Ensure GR helpers have received a Grace-LSA before killing the ospfd/ospf6d process that is undergoing a graceful restart. Signed-off-by: Renato Westphal --- .../ospf6_gr_topo1/test_ospf6_gr_topo1.py | 47 +++++++++++++++++++ .../ospf_gr_topo1/test_ospf_gr_topo1.py | 47 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index d50223191d..e59333ebd2 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -171,6 +171,41 @@ def router_compare_json_output(rname, command, reference, tries): assert diff is None, assertmsg +def expect_grace_lsa(restarting, helper): + """ + Check if the given helper neighbor has already received a Grace-LSA from + the router performing a graceful restart. + """ + tgen = get_topogen() + + logger.info( + "'{}': checking if a Grace-LSA was received from '{}'".format( + helper, restarting + ) + ) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[helper], + "show ipv6 ospf6 database json", + { + "interfaceScopedLinkStateDb": [ + { + "lsa": [ + { + "type": "GR", + "advRouter": restarting, + } + ] + } + ] + }, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = '"{}" didn\'t receive a Grace-LSA from "{}"'.format(helper, restarting) + + assert result is None, assertmsg + + def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in @@ -269,6 +304,7 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="1.1.1.1", helper="rt2") ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospf6d"], save_config=False) check_routers(exiting="rt1") @@ -288,6 +324,8 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="2.2.2.2", helper="rt1") + expect_grace_lsa(restarting="2.2.2.2", helper="rt3") ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospf6d"], save_config=False) check_routers(exiting="rt2") @@ -308,6 +346,9 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="3.3.3.3", helper="rt2") + expect_grace_lsa(restarting="3.3.3.3", helper="rt4") + expect_grace_lsa(restarting="3.3.3.3", helper="rt6") ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospf6d"], save_config=False) check_routers(exiting="rt3") @@ -328,6 +369,8 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="4.4.4.4", helper="rt3") + expect_grace_lsa(restarting="4.4.4.4", helper="rt5") ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospf6d"], save_config=False) check_routers(exiting="rt4") @@ -348,6 +391,7 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="5.5.5.5", helper="rt4") ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospf6d"], save_config=False) check_routers(exiting="rt5") @@ -368,6 +412,8 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="6.6.6.6", helper="rt3") + expect_grace_lsa(restarting="6.6.6.6", helper="rt7") ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospf6d"], save_config=False) check_routers(exiting="rt6") @@ -388,6 +434,7 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') + expect_grace_lsa(restarting="6.6.6.6", helper="rt6") ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospf6d"], save_config=False) check_routers(exiting="rt7") diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 1432d53ffc..3e3bf5cb8c 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -180,6 +180,41 @@ def router_compare_json_output(rname, command, reference, tries): assert diff is None, assertmsg +def expect_grace_lsa(restarting, area, helper): + """ + Check if the given helper neighbor has already received a Grace-LSA from + the router performing a graceful restart. + """ + tgen = get_topogen() + + logger.info( + "'{}': checking if a Grace-LSA was received from '{}'".format( + helper, restarting + ) + ) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[helper], + "show ip ospf database opaque-link json", + { + "linkLocalOpaqueLsa": { + "areas": { + area: [ + { + "advertisingRouter": restarting, + "opaqueType": "Grace-LSA", + } + ] + } + } + }, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = '"{}" didn\'t receive a Grace-LSA from "{}"'.format(helper, restarting) + + assert result is None, assertmsg + + def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in @@ -272,6 +307,7 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="1.1.1.1", area="0.0.0.1", helper="rt2") ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospfd"], save_config=False) check_routers(exiting="rt1") @@ -292,6 +328,8 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="2.2.2.2", area="0.0.0.1", helper="rt1") + expect_grace_lsa(restarting="2.2.2.2", area="0.0.0.0", helper="rt3") ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospfd"], save_config=False) check_routers(exiting="rt2") @@ -312,6 +350,9 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt2") + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt4") + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt6") ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospfd"], save_config=False) check_routers(exiting="rt3") @@ -332,6 +373,8 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="4.4.4.4", area="0.0.0.0", helper="rt3") + expect_grace_lsa(restarting="4.4.4.4", area="0.0.0.2", helper="rt5") ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospfd"], save_config=False) check_routers(exiting="rt4") @@ -352,6 +395,7 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="5.5.5.5", area="0.0.0.2", helper="rt4") ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospfd"], save_config=False) check_routers(exiting="rt5") @@ -372,6 +416,8 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="6.6.6.6", area="0.0.0.0", helper="rt3") + expect_grace_lsa(restarting="6.6.6.6", area="0.0.0.3", helper="rt7") ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospfd"], save_config=False) check_routers(exiting="rt6") @@ -392,6 +438,7 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ip ospf"') + expect_grace_lsa(restarting="7.7.7.7", area="0.0.0.3", helper="rt6") ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospfd"], save_config=False) check_routers(exiting="rt7")