diff options
| -rw-r--r-- | .travis.yml | 16 | ||||
| -rw-r--r-- | Makefile.am | 5 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | doc/developer/building-libyang.rst | 2 | ||||
| -rw-r--r-- | docker/centos-7/Dockerfile | 6 | ||||
| -rw-r--r-- | docker/centos-8/Dockerfile | 6 | ||||
| -rw-r--r-- | isisd/isis_sr.c | 9 | ||||
| -rw-r--r-- | lib/northbound_db.c | 17 | ||||
| -rw-r--r-- | lib/northbound_grpc.cpp | 100 | ||||
| -rw-r--r-- | lib/xref.h | 1 | ||||
| -rw-r--r-- | tests/topotests/lib/common_config.py | 1 | ||||
| -rw-r--r-- | tests/topotests/lib/ospf.py | 12 | ||||
| -rw-r--r-- | tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py | 85 | ||||
| -rw-r--r-- | tests/topotests/ospf_basic_functionality/test_ospf_single_area.py | 148 | 
14 files changed, 337 insertions, 73 deletions
diff --git a/.travis.yml b/.travis.yml index 010292bb6a..32b686c00e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,14 +5,14 @@ services:    - docker  jobs:    include: -   # - script: -   #     - docker/centos-7/build.sh -   #     - docker images -   #   name: centos7 -   # - script: -   #     - docker/centos-8/build.sh -   #     - docker images -   #   name: centos8 +   - script: +       - docker/centos-7/build.sh +       - docker images +     name: centos7 +   - script: +       - docker/centos-8/build.sh +       - docker images +     name: centos8     - script:         - sudo apt install -y linux-modules-extra-$(uname -r)         - docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile . diff --git a/Makefile.am b/Makefile.am index a5101df2f0..a38029dcfa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,11 @@ AM_CFLAGS = \  	$(SAN_FLAGS) \  	$(WERROR) \  	# end +AM_CXXFLAGS = \ +	$(AC_CXXFLAGS) \ +	$(LIBYANG_CFLAGS) \ +	$(WERROR) \ +	# end  # CPPFLAGS_BASE does not contain the include path for overriding assert.h,  # therefore should be used in tools that do *not* link libfrr or do not want diff --git a/configure.ac b/configure.ac index f84a3d3c5e..6ed438ace0 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@  ##  AC_PREREQ([2.69]) -AC_INIT([frr], [7.7-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [8.1-dev], [https://github.com/frrouting/frr/issues])  PACKAGE_URL="https://frrouting.org/"  AC_SUBST([PACKAGE_URL])  PACKAGE_FULLNAME="FRRouting" diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index a447f58309..3b33eb3879 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -10,7 +10,7 @@ The FRR project builds some binary ``libyang`` packages.  RPM packages are at our `RPM repository <https://rpm.frrouting.org>`_.  DEB packages are available as CI artifacts `here -<https://ci1.netdef.org/browse/LIBYANG-LIBYANG-V2/latestSuccessful/artifact>`_. +<https://ci1.netdef.org/browse/LIBYANG-LIBYANGV2/latestSuccessful/artifact>`_.  .. warning:: diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile index d2ec9f974b..748b5345a1 100644 --- a/docker/centos-7/Dockerfile +++ b/docker/centos-7/Dockerfile @@ -5,8 +5,8 @@ RUN yum install -y rpm-build autoconf automake libtool make \          readline-devel texinfo net-snmp-devel groff pkgconfig \          json-c-devel pam-devel bison flex pytest c-ares-devel \          python3-devel python3-sphinx systemd-devel libcap-devel \ -        https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ -        https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang-devel-1.0.184-0.x86_64.rpm \ +        https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ +        https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-devel-0.7.0-1.el7.centos.x86_64.rpm @@ -32,7 +32,7 @@ RUN echo '%_smp_mflags %( echo "-j$(/usr/bin/getconf _NPROCESSORS_ONLN)"; )' >>  # This stage installs frr from the rpm  FROM centos:centos7  RUN mkdir -p /pkgs/rpm \ -    && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ +    && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm  COPY --from=centos-7-builder /rpmbuild/RPMS/ /pkgs/rpm/ diff --git a/docker/centos-8/Dockerfile b/docker/centos-8/Dockerfile index 104501aabc..e273be055b 100644 --- a/docker/centos-8/Dockerfile +++ b/docker/centos-8/Dockerfile @@ -5,8 +5,8 @@ RUN dnf install --enablerepo=powertools -y rpm-build git autoconf pcre-devel \          automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \          groff pkgconfig json-c-devel pam-devel bison flex python3-pytest \          c-ares-devel python3-devel python3-sphinx systemd-devel libcap-devel platform-python-devel \ -        https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ -        https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang-devel-1.0.184-0.x86_64.rpm \ +        https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ +        https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-devel-0.7.0-1.el7.centos.x86_64.rpm @@ -33,7 +33,7 @@ RUN echo '%_smp_mflags %( echo "-j$(/usr/bin/getconf _NPROCESSORS_ONLN)"; )' >>  # This stage installs frr from the rpm  FROM centos:centos8  RUN mkdir -p /pkgs/rpm \ -    && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ +    && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \          https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm  COPY --from=centos-8-builder /rpmbuild/RPMS/ /pkgs/rpm/ diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index c4024772f5..f7cef43d0d 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -361,9 +361,9 @@ struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,  	pcfg->last_hop_behavior = yang_get_default_enum(  		"%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR); -	/* Set the N-flag when appropriate. */ +	/* Mark as node Sid if the prefix is host and configured in loopback */  	ifp = if_lookup_prefix(prefix, VRF_DEFAULT); -	if (ifp && sr_prefix_is_node_sid(ifp, prefix) && !pcfg->n_flag_clear) +	if (ifp && sr_prefix_is_node_sid(ifp, prefix))  		pcfg->node_sid = true;  	/* Save prefix-sid configuration. */ @@ -438,7 +438,7 @@ void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,  	}  	if (external)  		SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED); -	if (pcfg->node_sid) +	if (pcfg->node_sid && !pcfg->n_flag_clear)  		SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);  	/* Set SID value. */ @@ -948,8 +948,7 @@ static int sr_if_new_hook(struct interface *ifp)  		if (!pcfg)  			continue; -		if (sr_prefix_is_node_sid(ifp, &pcfg->prefix) -		    && !pcfg->n_flag_clear) { +		if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)) {  			pcfg->node_sid = true;  			lsp_regenerate_schedule(area, area->is_type, 0);  		} diff --git a/lib/northbound_db.c b/lib/northbound_db.c index 244e760b2b..dce9b2ec24 100644 --- a/lib/northbound_db.c +++ b/lib/northbound_db.c @@ -87,9 +87,12 @@ int nb_db_transaction_save(const struct nb_transaction *transaction,  		goto exit;  	client_name = nb_client_name(transaction->context->client); -	/* Always record configurations in the XML format. */ +	/* +	 * Always record configurations in the XML format, save the default +	 * values too, as this covers the case where defaults may change. +	 */  	if (lyd_print_mem(&config_str, transaction->config->dnode, LYD_XML, -			  LYP_FORMAT | LYP_WITHSIBLINGS) +			  LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL)  	    != 0)  		goto exit; @@ -149,6 +152,7 @@ struct nb_config *nb_db_transaction_load(uint32_t transaction_id)  	struct lyd_node *dnode;  	const char *config_str;  	struct sqlite3_stmt *ss; +	LY_ERR err;  	ss = db_prepare(  		"SELECT\n" @@ -169,10 +173,11 @@ struct nb_config *nb_db_transaction_load(uint32_t transaction_id)  	if (db_loadf(ss, "%s", &config_str) != 0)  		goto exit; -	dnode = lyd_parse_mem(ly_native_ctx, config_str, LYD_XML, -			      LYD_OPT_CONFIG); -	if (!dnode) -		flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_mem() failed", +	err = lyd_parse_data_mem(ly_native_ctx, config_str, LYD_XML, +				 LYD_PARSE_STRICT | LYD_PARSE_NO_STATE, +				 LYD_VALIDATE_NO_STATE, &dnode); +	if (err || !dnode) +		flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_data_mem() failed",  			  __func__);  	else  		config = nb_config_new(dnode); diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index dc2d29c11d..c61effdda5 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -199,9 +199,8 @@ class NorthboundImpl  				auto m = tag->response.add_supported_modules();  				m->set_name(module->name); -				if (module->info->rev_size) -					m->set_revision( -						module->info->rev[0].date); +				if (module->info->revision) +					m->set_revision(module->info->revision);  				m->set_organization(module->info->org);  			} @@ -1068,14 +1067,13 @@ class NorthboundImpl  				   const std::string &path,  				   const std::string &value)  	{ -		ly_errno = LY_SUCCESS; -		dnode = lyd_new_path(dnode, ly_native_ctx, path.c_str(), -				     (void *)value.c_str(), -				     (LYD_ANYDATA_VALUETYPE)0, -				     LYD_PATH_OPT_UPDATE); -		if (!dnode && ly_errno != LY_SUCCESS) { -			flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", -				  __func__); +		LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), +					  value.c_str(), LYD_NEW_PATH_UPDATE, +					  &dnode); +		if (err != LY_SUCCESS) { +			flog_warn(EC_LIB_LIBYANG, +				  "%s: lyd_new_path() failed: %s", __func__, +				  ly_errmsg(ly_native_ctx));  			return -1;  		} @@ -1089,7 +1087,7 @@ class NorthboundImpl  		if (!dnode)  			return -1; -		lyd_free(dnode); +		lyd_free_tree(dnode);  		return 0;  	} @@ -1132,46 +1130,53 @@ class NorthboundImpl  			std::string(date), std::string(comment)));  	} -	static int data_tree_from_dnode(frr::DataTree *dt, -					const struct lyd_node *dnode, -					LYD_FORMAT lyd_format, -					bool with_defaults) +	static LY_ERR data_tree_from_dnode(frr::DataTree *dt, +					   const struct lyd_node *dnode, +					   LYD_FORMAT lyd_format, +					   bool with_defaults)  	{  		char *strp;  		int options = 0; -		SET_FLAG(options, LYP_FORMAT | LYP_WITHSIBLINGS); +		SET_FLAG(options, LYD_PRINT_WITHSIBLINGS);  		if (with_defaults) -			SET_FLAG(options, LYP_WD_ALL); +			SET_FLAG(options, LYD_PRINT_WD_ALL);  		else -			SET_FLAG(options, LYP_WD_TRIM); +			SET_FLAG(options, LYD_PRINT_WD_TRIM); -		if (lyd_print_mem(&strp, dnode, lyd_format, options) == 0) { +		LY_ERR err = lyd_print_mem(&strp, dnode, lyd_format, options); +		if (err == LY_SUCCESS) {  			if (strp) {  				dt->set_data(strp);  				free(strp);  			} -			return 0;  		} - -		return -1; +		return err;  	}  	static struct lyd_node *dnode_from_data_tree(const frr::DataTree *dt,  						     bool config_only)  	{  		struct lyd_node *dnode; -		int options; - -		if (config_only) -			options = LYD_OPT_CONFIG; -		else -			options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB; - -		dnode = lyd_parse_mem(ly_native_ctx, dt->data().c_str(), -				      encoding2lyd_format(dt->encoding()), -				      options); +		int options, opt2; +		LY_ERR err; + +		if (config_only) { +			options = LYD_PARSE_STRICT | LYD_PARSE_NO_STATE; +			opt2 = LYD_VALIDATE_NO_STATE; +		} else { +			options = LYD_PARSE_STRICT; +			opt2 = 0; +		} +		err = lyd_parse_data_mem(ly_native_ctx, dt->data().c_str(), +					 encoding2lyd_format(dt->encoding()), +					 options, opt2, &dnode); +		if (err != LY_SUCCESS) { +			flog_warn(EC_LIB_LIBYANG, +				  "%s: lyd_parse_mem() failed: %s", __func__, +				  ly_errmsg(ly_native_ctx)); +		}  		return dnode;  	} @@ -1239,14 +1244,15 @@ class NorthboundImpl  			// Combine configuration and state data into a single  			// dnode.  			// -			if (lyd_merge(dnode_state, dnode_config, -				      LYD_OPT_EXPLICIT) -			    != 0) { +			if (lyd_merge_tree(&dnode_state, dnode_config, +					   LYD_MERGE_DESTRUCT) +			    != LY_SUCCESS) {  				yang_dnode_free(dnode_state);  				yang_dnode_free(dnode_config);  				return grpc::Status(  					grpc::StatusCode::INTERNAL, -					"Failed to merge configuration and state data"); +					"Failed to merge configuration and state data", +					ly_errmsg(ly_native_ctx));  			}  			dnode_final = dnode_state; @@ -1262,19 +1268,25 @@ class NorthboundImpl  		// Validate data to create implicit default nodes if necessary.  		int validate_opts = 0;  		if (type == frr::GetRequest_DataType_CONFIG) -			validate_opts = LYD_OPT_CONFIG; +			validate_opts = LYD_VALIDATE_NO_STATE;  		else -			validate_opts = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB; -		lyd_validate(&dnode_final, validate_opts, ly_native_ctx); +			validate_opts = 0; +		LY_ERR err = lyd_validate_all(&dnode_final, ly_native_ctx, +					      validate_opts, NULL); + +		if (err) +			flog_warn(EC_LIB_LIBYANG, +				  "%s: lyd_validate_all() failed: %s", __func__, +				  ly_errmsg(ly_native_ctx));  		// Dump data using the requested format. -		int ret = data_tree_from_dnode(dt, dnode_final, lyd_format, -					       with_defaults); +		if (!err) +			err = data_tree_from_dnode(dt, dnode_final, lyd_format, +						   with_defaults);  		yang_dnode_free(dnode_final); -		if (ret != 0) +		if (err)  			return grpc::Status(grpc::StatusCode::INTERNAL,  					    "Failed to dump data"); -  		return grpc::Status::OK;  	} diff --git a/lib/xref.h b/lib/xref.h index 949458b313..6cff1a3769 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -169,6 +169,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;  	static void __attribute__((used, _CONSTRUCTOR(1100)))                  \  			_xref_init(void) {                                     \  		static struct xref_block _xref_block = {                       \ +			.next = NULL,                                          \  			.start = __start_xref_array,                           \  			.stop = __stop_xref_array,                             \  		};                                                             \ diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index ba6004861e..5a904423c2 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1788,6 +1788,7 @@ def create_interfaces_cfg(tgen, topo, build=False):                      "network",                      "priority",                      "cost", +                    "mtu_ignore"                  ]                  if "ospf" in data:                      interface_data += _create_interfaces_ospf_cfg( diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 04a12d0eec..7ad64de4a1 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -352,6 +352,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=              data_ospf_auth = ospf_data.setdefault("authentication", None)              data_ospf_dr_priority = ospf_data.setdefault("priority", None)              data_ospf_cost = ospf_data.setdefault("cost", None) +            data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None)              try:                  intf = topo["routers"][router]["links"][lnk]["interface"] @@ -400,19 +401,26 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=                      config_data.append(cmd)              # interface ospf dr priority -            if data_ospf_dr_priority in ospf_data: +            if data_ospf_dr_priority:                  cmd = "ip ospf priority {}".format(ospf_data["priority"])                  if "del_action" in ospf_data:                      cmd = "no {}".format(cmd)                  config_data.append(cmd)              # interface ospf cost -            if data_ospf_cost in ospf_data: +            if data_ospf_cost:                  cmd = "ip ospf cost {}".format(ospf_data["cost"])                  if "del_action" in ospf_data:                      cmd = "no {}".format(cmd)                  config_data.append(cmd) +            # interface ospf mtu +            if data_ospf_mtu: +                cmd = "ip ospf mtu-ignore" +                if 'del_action' in ospf_data: +                    cmd = "no {}".format(cmd) +                config_data.append(cmd) +              if build:                  return config_data              else: diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index 1432a82b12..9dfde325f6 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -62,6 +62,8 @@ from lib.ospf import (      verify_ospf_rib,      create_router_ospf,      redistribute_ospf, +    config_ospf_interface, +    verify_ospf_interface,  )  # Global variables @@ -576,6 +578,89 @@ def test_ospf_redistribution_tc8_p1(request):      write_test_footer(tc_name) +def test_ospf_cost_tc52_p0(request): +    """OSPF Cost - verifying ospf interface cost functionality""" +    tc_name = request.node.name +    write_test_header(tc_name) +    tgen = get_topogen() +    global topo +    step("Bring up the base config.") +    reset_config_on_routers(tgen) + +    step( +        "Configure ospf cost as 20 on interface between R0 and R1. " +        "Configure ospf cost as 30 between interface between R0 and R2." +    ) + +    r0_ospf_cost = { +        "r0": {"links": {"r1": {"ospf": {"cost": 20}}, "r2": {"ospf": {"cost": 30}}}} +    } +    result = config_ospf_interface(tgen, topo, r0_ospf_cost) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step( +        "Verify that cost is updated in the ospf interface between" +        " r0 and r1 as 30 and r0 and r2 as 20" +    ) +    dut = "r0" +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Swap the costs between interfaces on r0, between r0 and r1 to 30" +        ", r0 and r2 to 20" +    ) + +    r0_ospf_cost = { +        "r0": {"links": {"r1": {"ospf": {"cost": 30}}, "r2": {"ospf": {"cost": 20}}}} +    } +    result = config_ospf_interface(tgen, topo, r0_ospf_cost) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step( +        "Verify that cost is updated in the ospf interface between r0 " +        "and r1 as 30 and r0 and r2 as 20." +    ) +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step(" Un configure cost from the interface r0 - r1.") + +    r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 30, "del_action": True}}}}} +    result = config_ospf_interface(tgen, topo, r0_ospf_cost) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    input_dict = { +        "r0": {"links": {"r1": {"ospf": {"cost": 10}}, "r2": {"ospf": {"cost": 20}}}} +    } +    step( +        "Verify that cost is updated in the ospf interface between r0" +        " and r1 as 10 and r0 and r2 as 20." +    ) + +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step(" Un configure cost from the interface r0 - r2.") + +    r0_ospf_cost = {"r0": {"links": {"r2": {"ospf": {"cost": 20, "del_action": True}}}}} +    result = config_ospf_interface(tgen, topo, r0_ospf_cost) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    step( +        "Verify that cost is updated in the ospf interface between r0" +        "and r1 as 10 and r0 and r2 as 10" +    ) + +    input_dict = { +        "r0": {"links": {"r1": {"ospf": {"cost": 10}}, "r2": {"ospf": {"cost": 10}}}} +    } +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + +  if __name__ == "__main__":      args = ["-s"] + sys.argv[1:]      sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 6f6b119abc..e94680d974 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -101,6 +101,7 @@ TESTCASES =  2. OSPF Timers - Verify OSPF interface timer hello interval functionality  3. OSPF Timers - Verify OSPF interface timer dead interval functionality  4. Verify ospf show commands with json output. +5. Verify NFSM events when ospf nbr changes with different MTU values.   """ @@ -976,6 +977,153 @@ def test_ospf_dead_tc11_p0(request):      write_test_footer(tc_name) +def test_ospf_tc4_mtu_ignore_p0(request): +    """ +    OSPF NFSM - MTU change + +    Verify NFSM events when ospf nbr changes with different MTU values +    """ +    tc_name = request.node.name +    write_test_header(tc_name) +    tgen = get_topogen() + +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    global topo +    step(" Bring up the base config as per the topology") +    step("Configure OSPF on all the routers of the topology.") +    step("Verify that OSPF neighbors are FULL.") +    reset_config_on_routers(tgen) +    result = verify_ospf_neighbor(tgen, topo) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Modify the MTU to non default Value on R0 to R1 interface. " +        "Reset ospf neighbors on R0." +    ) + +    rtr0 = tgen.routers()["r0"] +    rtr1 = tgen.routers()["r1"] + +    r0_r1_intf = topo["routers"]["r0"]["links"]["r1"]["interface"] +    r1_r0_intf = topo["routers"]["r1"]["links"]["r0"]["interface"] + +    rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + +    clear_ospf(tgen, "r0") + +    step( +        "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State." +    ) +    result = verify_ospf_neighbor(tgen, topo, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n OSPF nbrs are Full " +        "instead of Exstart. Error: {}".format(tc_name, result) +    ) + +    step( +        "Verify that configured MTU value is updated in the show ip " "ospf interface." +    ) + +    dut = "r0" +    input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuBytes": 1200}}}}} +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Modify the MTU to non default Value on R0 to R1 interface. " +        "Reset ospf neighbors on R0." +    ) +    rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + +    clear_ospf(tgen, "r0") + +    step("Verify that OSPF neighborship between R0 and R1 becomes full.") +    result = verify_ospf_neighbor(tgen, topo) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Configure mtu ignore and change the value of the mtu to non default" +        " on R0 to R1 interface. Reset ospf neighbors on R0." +    ) +    r0_ospf_mtu = {"r0": {"links": {"r1": {"ospf": {"mtu_ignore": True}}}}} +    result = config_ospf_interface(tgen, topo, r0_ospf_mtu) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    dut = "r0" +    input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuMismatchDetect": True}}}}} +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    r1_ospf_mtu = {"r1": {"links": {"r0": {"ospf": {"mtu_ignore": True}}}}} +    result = config_ospf_interface(tgen, topo, r1_ospf_mtu) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + +    clear_ospf(tgen, "r0") + +    step("Verify that OSPF neighborship between R0 and R1 becomes full.") +    result = verify_ospf_neighbor(tgen, topo) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Unconfigure mtu-ignore command from the interface. " +        "Reset ospf neighbors on R0." +    ) + +    r1_ospf_mtu = { +        "r1": {"links": {"r0": {"ospf": {"mtu_ignore": True, "delete": True}}}} +    } +    result = config_ospf_interface(tgen, topo, r1_ospf_mtu) +    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + +    clear_ospf(tgen, "r0") + +    step( +        "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State." +    ) +    result = verify_ospf_neighbor(tgen, topo, expected=False) +    assert result is not True, ( +        "Testcase {} : Failed \n OSPF nbrs are Full " +        "instead of Exstart. Error: {}".format(tc_name, result) +    ) + +    step("Modify the MTU to again default valaue on R0 to R1 interface.") + +    rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + +    clear_ospf(tgen, "r0") + +    step("Verify that OSPF neighborship between R0 and R1 becomes full.") +    result = verify_ospf_neighbor(tgen, topo) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step( +        "Configure ospf interface with jumbo MTU (9216)." "Reset ospf neighbors on R0." +    ) + +    rtr0.run("ifconfig {} mtu 9216".format(r0_r1_intf)) +    rtr1.run("ifconfig {} mtu 9216".format(r1_r0_intf)) + +    clear_ospf(tgen, "r0") +    clear_ospf(tgen, "r1") + +    step("Verify that OSPF neighborship between R0 and R1 becomes full.") +    result = verify_ospf_neighbor(tgen, topo) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    step("Verify that jumbo MTU is updated in the show ip ospf interface.") +    dut = "r0" +    input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuBytes": 9216}}}}} +    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + +    write_test_footer(tc_name) + +  if __name__ == "__main__":      args = ["-s"] + sys.argv[1:]      sys.exit(pytest.main(args))  | 
