diff options
| -rw-r--r-- | doc/user/ospfd.rst | 14 | ||||
| -rw-r--r-- | lib/libospf.h | 1 | ||||
| -rw-r--r-- | ospfd/ospf_flood.c | 9 | ||||
| -rw-r--r-- | ospfd/ospf_gr.c | 11 | ||||
| -rw-r--r-- | ospfd/ospf_interface.c | 32 | ||||
| -rw-r--r-- | ospfd/ospf_interface.h | 3 | ||||
| -rw-r--r-- | ospfd/ospf_opaque.c | 6 | ||||
| -rw-r--r-- | ospfd/ospf_packet.c | 16 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 79 | ||||
| -rw-r--r-- | tests/topotests/ospfapi/test_ospf_clientapi.py | 439 |
10 files changed, 585 insertions, 25 deletions
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 3430d8a282..232b1c3934 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -912,7 +912,7 @@ Opaque LSA - *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for + *ospfd* supports Opaque LSA (:rfc:`5250`) as partial support for MPLS Traffic Engineering LSAs. The opaque-lsa capability must be enabled in the configuration. An alternate command could be "mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR @@ -920,6 +920,18 @@ Opaque LSA extensions that are used with MPLS-TE; it does not support a complete RSVP-TE solution. +.. clicmd:: ip ospf capability opaque [A.B.C.D] + + Enable or disable OSPF LSA database exchange and flooding on an interface. + The default is that opaque capability is enabled as long as the opaque + capability is enabled with the :clicmd:`capability opaque` command at the + OSPF instance level (using the command above). Note that disabling opaque + LSA support on an interface will impact the applications using opaque LSAs + if the opaque LSAs are not received on other flooding paths by all the + OSPF routers using those applications. For example, OSPF Graceful Restart + uses opaque-link LSAs and disabling support on an interface will disable + graceful restart signaling on that interface. + .. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) .. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID diff --git a/lib/libospf.h b/lib/libospf.h index 9eaca9a1a8..e3c1adb810 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -69,6 +69,7 @@ extern "C" { #define OSPF_MTU_IGNORE_DEFAULT 0 #define OSPF_FAST_HELLO_DEFAULT 0 #define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false +#define OSPF_OPAQUE_CAPABLE_DEFAULT true #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ #define OSPF_AREA_RANGE_COST_UNSPEC -1U diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 5ae15fd887..dd8c9268f1 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -568,6 +568,15 @@ int ospf_flood_through_interface(struct ospf_interface *oi, if (!ospf_if_is_enable(oi)) return 0; + if (IS_OPAQUE_LSA(lsa->data->type) && + !OSPF_IF_PARAM(oi, opaque_capable)) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug( + "%s: Skipping interface %s (%s) with opaque disabled.", + __func__, IF_NAME(oi), ospf_get_name(oi->ospf)); + return 0; + } + /* If flood reduction is configured, set the DC bit on the lsa. */ if (IS_LSA_SELF(lsa)) { if (OSPF_FR_CONFIG(oi->area->ospf, oi->area)) { diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index 2a346f2388..c23c42052f 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -773,8 +773,15 @@ static void ospf_gr_prepare(void) } /* Send a Grace-LSA to all neighbors. */ - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) - ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, false); + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) { + if (OSPF_IF_PARAM(oi, opaque_capable)) + ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, + false); + else + zlog_debug( + "GR: skipping grace LSA on interface %s (%s) with opaque capability disabled", + IF_NAME(oi), ospf_get_name(oi->ospf)); + } /* Record end of the grace period in non-volatile memory. */ ospf_gr_nvm_update(ospf, true); diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 840756c05c..72de198116 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -548,6 +548,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, auth_crypt); UNSET_IF_PARAM(oip, auth_type); UNSET_IF_PARAM(oip, if_area); + UNSET_IF_PARAM(oip, opaque_capable); oip->auth_crypt = list_new(); @@ -556,6 +557,7 @@ static struct ospf_if_params *ospf_new_if_params(void) oip->ptp_dmvpn = 0; oip->p2mp_delay_reflood = OSPF_P2MP_DELAY_REFLOOD_DEFAULT; + oip->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT; return oip; } @@ -585,19 +587,20 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) oip = rn->info; route_unlock_node(rn); - if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) - && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) - && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) - && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) - && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) - && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) - && !OSPF_IF_PARAM_CONFIGURED(oip, v_wait) - && !OSPF_IF_PARAM_CONFIGURED(oip, priority) - && !OSPF_IF_PARAM_CONFIGURED(oip, type) - && !OSPF_IF_PARAM_CONFIGURED(oip, auth_simple) - && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) - && !OSPF_IF_PARAM_CONFIGURED(oip, if_area) - && listcount(oip->auth_crypt) == 0) { + if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && + !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && + !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && + !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && + !OSPF_IF_PARAM_CONFIGURED(oip, v_wait) && + !OSPF_IF_PARAM_CONFIGURED(oip, priority) && + !OSPF_IF_PARAM_CONFIGURED(oip, type) && + !OSPF_IF_PARAM_CONFIGURED(oip, auth_simple) && + !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) && + !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && + !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) && + listcount(oip->auth_crypt) == 0) { ospf_del_if_params(ifp, oip); rn->info = NULL; route_unlock_node(rn); @@ -703,6 +706,9 @@ int ospf_if_new_hook(struct interface *ifp) SET_IF_PARAM(IF_DEF_PARAMS(ifp), auth_type); IF_DEF_PARAMS(ifp)->auth_type = OSPF_AUTH_NOTSET; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable); + IF_DEF_PARAMS(ifp)->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT; + rc = ospf_opaque_new_if(ifp); return rc; } diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index ec1afa1b8b..38ec45c757 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -112,6 +112,9 @@ struct ospf_if_params { /* point-to-multipoint delayed reflooding configuration */ bool p2mp_delay_reflood; + + /* Opaque LSA capability at interface level (see RFC5250) */ + DECLARE_IF_PARAM(bool, opaque_capable); }; enum { MEMBER_ALLROUTERS = 0, diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 6894c6a009..27f47a6d79 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1851,9 +1851,9 @@ static void ospf_opaque_type9_lsa_reoriginate_timer(struct event *t) return; } - if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) - || !ospf_if_is_enable(oi) - || ospf_nbr_count_opaque_capable(oi) == 0) { + if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) || + !OSPF_IF_PARAM(oi, opaque_capable) || !ospf_if_is_enable(oi) || + ospf_nbr_count_opaque_capable(oi) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 105c04c7a1..cfa0d5d574 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -953,8 +953,9 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) - && CHECK_FLAG(hello->options, OSPF_OPTION_O)) { + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable) && + CHECK_FLAG(hello->options, OSPF_OPTION_O)) { /* * This router does know the correct usage of O-bit * the bit should be set in DD packet only. @@ -1362,8 +1363,9 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, } #endif /* REJECT_IF_TBIT_ON */ - if (CHECK_FLAG(dd->options, OSPF_OPTION_O) - && !CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { + if (CHECK_FLAG(dd->options, OSPF_OPTION_O) && + (!CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) || + !OSPF_IF_PARAM(oi, opaque_capable))) { /* * This node is not configured to handle O-bit, for now. * Clear it to ignore unsupported capability proposed by @@ -1448,7 +1450,8 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, /* This is where the real Options are saved */ nbr->options = dd->options; - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( "Neighbor[%pI4] is %sOpaque-capable.", @@ -3435,7 +3438,8 @@ static int ospf_make_db_desc(struct ospf_interface *oi, /* Set Options. */ options = OPTIONS(oi); - if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) + if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) && + OSPF_IF_PARAM(oi, opaque_capable)) SET_FLAG(options, OSPF_OPTION_O); if (OSPF_FR_CONFIG(oi->ospf, oi->area)) SET_FLAG(options, OSPF_OPTION_DC); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 863055bf42..54fd60af23 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3811,6 +3811,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, lookup_msg(ospf_ism_state_msg, oi->state, NULL)); json_object_int_add(json_oi, "priority", PRIORITY(oi)); + json_object_boolean_add( + json_interface_sub, "opaqueCapable", + OSPF_IF_PARAM(oi, opaque_capable)); } else { vty_out(vty, " Area %s\n", ospf_area_desc_string(oi->area)); @@ -3830,6 +3833,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, OSPF_IF_PARAM(oi, transmit_delay), lookup_msg(ospf_ism_state_msg, oi->state, NULL), PRIORITY(oi)); + if (!OSPF_IF_PARAM(oi, opaque_capable)) + vty_out(vty, + " Opaque LSA capability disabled on interface\n"); } /* Show DR information. */ @@ -9803,6 +9809,61 @@ DEFUN (no_ip_ospf_mtu_ignore, return CMD_SUCCESS; } +DEFPY(ip_ospf_capability_opaque, ip_ospf_capability_opaque_addr_cmd, + "[no] ip ospf capability opaque [A.B.C.D]$ip_addr", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Disable OSPF capability on this interface\n" + "Disable OSPF opaque LSA capability on this interface\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct route_node *rn; + bool old_opaque_capable; + bool opaque_capable_change; + + struct ospf_if_params *params; + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + old_opaque_capable = params->opaque_capable; + params->opaque_capable = (no) ? false : true; + opaque_capable_change = (old_opaque_capable != params->opaque_capable); + if (params->opaque_capable != OSPF_OPAQUE_CAPABLE_DEFAULT) + SET_IF_PARAM(params, opaque_capable); + else { + UNSET_IF_PARAM(params, opaque_capable); + if (params != IF_DEF_PARAMS(ifp)) { + ospf_free_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + } + + /* + * If there is a change to the opaque capability, flap the interface + * to reset all the neighbor adjacencies. + */ + if (opaque_capable_change) { + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + struct ospf_interface *oi = rn->info; + + if (oi && (oi->state > ISM_Down) && + (ip_addr.s_addr == INADDR_ANY || + IPV4_ADDR_SAME(&oi->address->u.prefix4, + &ip_addr))) { + OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown); + OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceUp); + } + } + } + return CMD_SUCCESS; +} + DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, @@ -12167,6 +12228,21 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) if (params && params->ldp_sync_info) ospf_ldp_sync_if_write_config(vty, params); + /* Capability opaque print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, opaque_capable) && + params->opaque_capable != + OSPF_OPAQUE_CAPABLE_DEFAULT) { + if (params->opaque_capable == false) + vty_out(vty, + " no ip ospf capability opaque"); + else + vty_out(vty, + " ip ospf capability opaque"); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + while (1) { if (rn == NULL) rn = route_top(IF_OIFS_PARAMS(ifp)); @@ -12976,6 +13052,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &ip_ospf_passive_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_passive_cmd); + /* "ip ospf capability opaque" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_capability_opaque_addr_cmd); + /* These commands are compatibitliy for previous version. */ install_element(INTERFACE_NODE, &ospf_authentication_key_cmd); install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd); diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 39ebbcfb62..7a7ea85e2f 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -17,6 +17,7 @@ import subprocess import sys import time from datetime import datetime, timedelta +from functools import partial import pytest from lib.common_config import ( @@ -31,6 +32,12 @@ from lib.micronet import Timeout, comm_error from lib.topogen import Topogen, TopoRouter from lib.topotest import interface_set_status, json_cmp +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + pytestmark = [pytest.mark.ospfd] CWD = os.path.dirname(os.path.realpath(__file__)) @@ -1142,6 +1149,438 @@ def test_ospf_opaque_restart(tgen): _test_opaque_add_restart_add(tgen, apibin) +def _test_opaque_interface_disable(tgen, apibin): + "Test disabling opaque capability on an interface" + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + tc_name = "opaque_interface_disable" + + p = None + pread = None + # Log to our stdin, stderr + pout = open(os.path.join(r1.net.logdir, "r1/intf-disable.log"), "a+") + try: + # STEP 1 in test_ospf_opaque_interface_disable and STEP 56 in CI tests + step("Disable OSPF opaque LSA Copability on r1's interface to r2") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nno ip ospf capability opaque") + time.sleep(15) + + # STEP 2 in test_ospf_opaque_interface_disable and STEP 57 in CI tests + step("Verify the r1 configuration of 'no ip ospf capability opaque'") + no_capability_opaque_cfg = ( + tgen.net["r1"] + .cmd( + 'vtysh -c "show running ospfd" | grep "^ no ip ospf capability opaque"' + ) + .rstrip() + ) + assertmsg = ( + "'no ip ospf capability opaque' applied, but not present in configuration" + ) + assert no_capability_opaque_cfg == " no ip ospf capability opaque", assertmsg + + # STEP 3 in test_ospf_opaque_interface_disable and STEP 58 in CI tests + step("Verify the ospf opaque option is not applied to the r1 interface") + r1_interface_without_opaque = { + "interfaces": { + "r1-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.1", + "ospfIfType": "Broadcast", + "opaqueCapable": False, + } + } + } + r1_interface_with_opaque = { + "interfaces": { + "r1-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.1", + "ospfIfType": "Broadcast", + "opaqueCapable": True, + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + r1_neighbor_without_opaque = { + "neighbors": { + "2.0.0.0": [ + { + "optionsList": "*|-|-|-|-|-|E|-", + } + ] + } + } + r2_neighbor_without_opaque = { + "neighbors": { + "1.0.0.0": [ + { + "optionsList": "*|-|-|-|-|-|E|-", + } + ] + } + } + # STEP 4 in test_ospf_opaque_interface_disable and STEP 59 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 5 in test_ospf_opaque_interface_disable and STEP 60 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 6 in test_ospf_opaque_interface_disable and STEP 61 in CI tests + step( + "Verify no r2 configuration of 'no ip ospf capability opaque' in r2 configuration" + ) + rc, _, _ = tgen.net["r2"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r2 configuration" + assert rc, assertmsg + + # STEP 7 in test_ospf_opaque_interface_disable and STEP 62 in CI tests + step("Verify the ospf opaque option is applied to the r2 interface") + r2_interface_without_opaque = { + "interfaces": { + "r2-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.2", + "ospfIfType": "Broadcast", + "opaqueCapable": False, + } + } + } + r2_interface_with_opaque = { + "interfaces": { + "r2-eth0": { + "ifUp": True, + "ospfEnabled": True, + "ipAddress": "10.0.1.2", + "ospfIfType": "Broadcast", + "opaqueCapable": True, + } + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF interface has opaque capability disabled" + assert result is None, assertmsg + + # STEP 8 in test_ospf_opaque_interface_disable and STEP 63 in CI tests + step("Install opaque LSAs on r1") + pread = r2.popen( + ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"], + encoding=None, # don't buffer + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + p = r1.popen( + [ + apibin, + "-v", + "add,9,10.0.1.1,230,1,feedaceedeadbeef", + "add,10,1.2.3.4,231,1,feedaceecafebeef", + "add,11,232,1,feedaceebaddbeef", + "wait,20", + ] + ) + opaque_LSAs_in_database = { + "areas": { + "1.2.3.4": { + "linkLocalOpaqueLsa": [ + { + "lsId": "230.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "linkLocalOpaqueLsaCount": 1, + "areaLocalOpaqueLsa": [ + { + "lsId": "231.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "areaLocalOpaqueLsaCount": 1, + }, + }, + "asExternalOpaqueLsa": [ + { + "lsId": "232.0.0.1", + "advertisedRouter": "1.0.0.0", + "sequenceNumber": "80000001", + }, + ], + "asExternalOpaqueLsaCount": 1, + } + opaque_area_empty_database = { + "routerId":"2.0.0.0", + "areaLocalOpaqueLsa":{ + "areas":{ + "1.2.3.4":[ + ] + } + } + } + + # STEP 9 in test_ospf_opaque_interface_disable and STEP 64 in CI tests + step("Check that LSAs are added on r1") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + # STEP 10 in test_ospf_opaque_interface_disable and STEP 65 in CI tests + step("Check that LSAs are not added on r2") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", + opaque_area_empty_database, True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF area database contains opaque LSAs" + assert result is None, assertmsg + + # STEP 11 in test_ospf_opaque_interface_disable and STEP 66 in CI tests + step("Enable OSPF opaque LSA Copability on r1's interface to r2") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nip ospf capability opaque") + time.sleep(15) + + # STEP 12 in test_ospf_opaque_interface_disable and STEP 67 in CI tests + step("Verify no r1 configuration of 'no ip ospf capability opaque'") + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r1 configuration" + assert rc, assertmsg + + # STEP 13 in test_ospf_opaque_interface_disable and STEP 68 in CI tests + step("Verify the ospf opaque option is applied to the r1 interface") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + r1_neighbor_with_opaque = { + "neighbors": { + "2.0.0.0": [ + { + "optionsList": "*|O|-|-|-|-|E|-", + } + ] + } + } + r2_neighbor_with_opaque = { + "neighbors": { + "1.0.0.0": [ + { + "optionsList": "*|O|-|-|-|-|E|-", + } + ] + } + } + # STEP 14 in test_ospf_opaque_interface_disable and STEP 69 in CI tests + step("Verify that the r1 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 15 in test_ospf_opaque_interface_disable and STEP 70 in CI tests + step("Verify that the r2 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 16 in test_ospf_opaque_interface_disable and STEP 71 in CI tests + step("Check that LSAs are now added to r2") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF database doesn't contains opaque LSAs" + assert result is None, assertmsg + + # STEP 17 in test_ospf_opaque_interface_disable and STEP 72 in CI tests + step( + "Disable Opaque Capability on r2's interface to r1 using the interface address" + ) + r2.vtysh_multicmd( + "conf t\ninterface r2-eth0\nno ip ospf capability opaque 10.0.1.2" + ) + + # STEP 18 in test_ospf_opaque_interface_disable and STEP 73 in CI tests + step("Clear the OSPF process on r2 to clear the OSPF LSDB") + r2.vtysh_multicmd("clear ip ospf process") + time.sleep(15) + + # STEP 19 in test_ospf_opaque_interface_disable and STEP 74 in CI tests + step("Verify the r2 configuration of 'no ip ospf capability opaque 10.0.1.2'") + no_capability_opaque_cfg = ( + tgen.net["r2"] + .cmd_nostatus( + 'vtysh -c "show running ospfd" | grep "^ no ip ospf capability opaque 10.0.1.2"' + ) + .rstrip() + ) + assertmsg = "'no ip ospf capability opaque 10.0.1.2' applied, but not present in configuration" + assert ( + no_capability_opaque_cfg == " no ip ospf capability opaque 10.0.1.2" + ), assertmsg + + # STEP 20 in test_ospf_opaque_interface_disable and STEP 75 in CI tests + step("Verify the ospf opaque option is not applied to the r2 interface") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + # STEP 21 in test_ospf_opaque_interface_disable and STEP 76 in CI tests + step("Verify that the r1 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 22 in test_ospf_opaque_interface_disable and STEP 77 in CI tests + step("Verify that the r2 neighbor options don't include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor has opaque option in optionsList" + assert result is None, assertmsg + + # STEP 23 in test_ospf_opaque_interface_disable and STEP 78 in CI tests + step("Verify that r1 still has the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + # STEP 24 in test_ospf_opaque_interface_disable and STEP 79 in CI tests + step("Verify that r2 doesn't have the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", + opaque_area_empty_database, True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF area database contains opaque LSAs" + assert result is None, assertmsg + + # STEP 25 in test_ospf_opaque_interface_disable and STEP 80 in CI tests + step("Remove the 'no ip ospf capability opaque 10.0.1.2' config from r2 ") + r2.vtysh_multicmd( + "conf t\ninterface r2-eth0\nip ospf capability opaque 10.0.1.2" + ) + time.sleep(15) + + # STEP 26 in test_ospf_opaque_interface_disable and STEP 81 in CI tests + step("Verify the r2 removal of 'no ip ospf capability opaque 10.0.1.2'") + rc, _, _ = tgen.net["r2"].cmd_status( + "show running ospfd | grep -q 'ip ospf capability opaque'", warn=False + ) + assertmsg = "'no ip ospf capability opaque' not applied, but not present in r2 configuration" + assert rc, assertmsg + + # STEP 27 in test_ospf_opaque_interface_disable and STEP 82 in CI tests + step("Verify the ospf opaque option is applied to the r2 interface") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF interface doesn't have opaque capability disabled" + assert result is None, assertmsg + + # STEP 28 in test_ospf_opaque_interface_disable and STEP 83 in CI tests + step("Verify that the r2 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 29 in test_ospf_opaque_interface_disable and STEP 84 in CI tests + step("Verify that the r1 neighbor options include opaque") + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" + assert result is None, assertmsg + + # STEP 30 in test_ospf_opaque_interface_disable and STEP 85 in CLI tests + step("Verify that r2 now has the opaque LSAs") + test_func = partial( + topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "r2 OSPF database doesn't contain opaque LSAs" + assert result is None, assertmsg + + except Exception: + if p: + p.terminate() + if p.wait(): + comm_error(p) + p = None + raise + finally: + if pread: + pread.terminate() + pread.wait() + if p: + p.terminate() + p.wait() + + +@pytest.mark.parametrize("tgen", [2], indirect=True) +def test_ospf_opaque_interface_disable(tgen): + apibin = os.path.join(CLIENTDIR, "ospfclient.py") + rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) + _test_opaque_interface_disable(tgen, apibin) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) |
