diff --git a/config/main.py b/config/main.py index 16aea6b610..bb999522a2 100644 --- a/config/main.py +++ b/config/main.py @@ -4137,8 +4137,6 @@ def fec(ctx, interface_name, interface_fec, verbose): # Get the config_db connector config_db = ctx.obj['config_db'] - if interface_fec not in ["rs", "fc", "none"]: - ctx.fail("'fec not in ['rs', 'fc', 'none']!") if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: diff --git a/scripts/portconfig b/scripts/portconfig index dcb98cb403..83222a7171 100755 --- a/scripts/portconfig +++ b/scripts/portconfig @@ -60,7 +60,7 @@ SWITCH_CAPABILITY = "SWITCH_CAPABILITY|switch" # STATE_DB constants PORT_STATE_TABLE_NAME = "PORT_TABLE" PORT_STATE_SUPPORTED_SPEEDS = "supported_speeds" - +PORT_STATE_SUPPORTED_FECS = "supported_fecs" VALID_INTERFACE_TYPE_SET = set(['CR','CR2','CR4','CR8','SR','SR2','SR4','SR8', 'LR','LR4','LR8','KR','KR4','KR8','CAUI','GMII', @@ -126,6 +126,13 @@ class portconfig(object): def set_fec(self, port, fec): if self.verbose: print("Setting fec %s on port %s" % (fec, port)) + supported_fecs = self.get_supported_fecs(port) + if fec not in supported_fecs: + if supported_fecs: + print('fec {} is not in {}'.format(fec, supported_fecs)) + else: + print('Setting fec is not supported on port {}'.format(port)) + exit(1) self.db.mod_entry(PORT_TABLE_NAME, port, {PORT_FEC_CONFIG_FIELD_NAME: fec}) def set_mtu(self, port, mtu): @@ -213,6 +220,26 @@ class portconfig(object): state_db.connect(state_db.STATE_DB) return state_db.get(state_db.STATE_DB, '{}|{}'.format(PORT_STATE_TABLE_NAME, port), PORT_STATE_SUPPORTED_SPEEDS) + def get_supported_fecs(self, port): + # If there is supported_fecs exposed in STATE_DB, let's use it. + # Otherwise, take the default + if not self.namespace: + state_db = SonicV2Connector(host="127.0.0.1") + else: + state_db = SonicV2Connector(host="127.0.0.1", namespace=self.namespace, use_unix_socket_path=True) + state_db.connect(state_db.STATE_DB) + + supported_fecs_str = state_db.get(state_db.STATE_DB, '{}|{}'.format(PORT_STATE_TABLE_NAME, port), PORT_STATE_SUPPORTED_FECS) + if supported_fecs_str: + if supported_fecs_str != 'N/A': + supported_fecs_list = supported_fecs_str.split(',') + else: + supported_fecs_list = [] + else: + supported_fecs_list = ["rs", "fc", "none"] + + return supported_fecs_list + def set_tpid(self, port, tpid): if self.verbose: print("Setting tpid %s on port %s" % (tpid, port)) @@ -263,7 +290,7 @@ def main(): parser.add_argument('-p', '--port', type=str, help='port name (e.g. Ethernet0)', required=True, default=None) parser.add_argument('-l', '--list', action='store_true', help='list port parametars', default=False) parser.add_argument('-s', '--speed', type=int, help='port speed value in Mbit', default=None) - parser.add_argument('-f', '--fec', type=str, help='port fec mode value in (none, rs, fc)', default=None) + parser.add_argument('-f', '--fec', type=str, help='port fec mode value (default is: none, rs, fc)', default=None) parser.add_argument('-m', '--mtu', type=int, help='port mtu value in bytes', default=None) parser.add_argument('-tp', '--tpid', type=str, help='port TPID value in hex (e.g. 0x8100)', default=None) parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0') diff --git a/tests/config_an_test.py b/tests/config_an_test.py index 2da1879ebd..a888006354 100644 --- a/tests/config_an_test.py +++ b/tests/config_an_test.py @@ -84,6 +84,22 @@ def test_config_mtu(self, ctx): result = self.basic_check("mtu", ["PortChannel0001", "1514"], ctx, operator.ne) assert 'Invalid port PortChannel0001' in result.output + def test_config_fec(self, ctx): + # Set a fec mode which is in supported_fec list but not default + # on an interface with supported_fec + self.basic_check("fec", ["Ethernet0", "test"], ctx) + # Set a fec mode which is one of default values on an interface without supported_fecs + self.basic_check("fec", ["Ethernet4", "rs"], ctx) + # Negative case: Set a fec mode which is default but not in port's supported_fecs + result = self.basic_check("fec", ["Ethernet0", "fc"], ctx, operator.ne) + assert "fec fc is not in ['rs', 'none', 'test']" in result.output + # Negative case: set a fec mode which is not default on an interface without supported_fecs + result = self.basic_check("fec", ["Ethernet4", "test"], ctx, operator.ne) + assert "fec test is not in ['rs', 'fc', 'none']" in result.output + # Negative case: set a fec mode on a port where setting fec is not supported + result = self.basic_check("fec", ["Ethernet112", "test"], ctx, operator.ne) + assert "Setting fec is not supported" in result.output + def basic_check(self, command_name, para_list, ctx, op=operator.eq, expect_result=0): runner = CliRunner() result = runner.invoke(config.config.commands["interface"].commands[command_name], para_list, obj = ctx) diff --git a/tests/mock_tables/state_db.json b/tests/mock_tables/state_db.json index 8a323717af..08adcbef80 100644 --- a/tests/mock_tables/state_db.json +++ b/tests/mock_tables/state_db.json @@ -686,6 +686,7 @@ "rmt_adv_speeds" : "10,100,1000", "speed" : "100000", "supported_speeds": "10000,25000,40000,100000", + "supported_fecs": "rs,none,test", "link_training_status": "not_trained" }, "PORT_TABLE|Ethernet32": { @@ -693,6 +694,7 @@ }, "PORT_TABLE|Ethernet112": { "speed": "40000", + "supported_fecs": "N/A", "link_training_status": "off" }, "PCIE_DEVICE|00:01.0": {