[macsec]: show macsec: add --profile option, include profile name in show command output (#13940)

This PR is to add the following

Add a new options "--profile" to the show macsec command, to show all profiles in device
Update the currentl show macsec command, to show profile in each interface o/p. This will tell which macsec profile the interface is attached to.
This commit is contained in:
judyjoseph 2023-04-27 08:51:28 -07:00 committed by mssonicbld
parent 80aba31433
commit 4b30d09903
3 changed files with 168 additions and 15 deletions

View File

@ -0,0 +1,75 @@
{
"MACSEC_PROFILE|macsec_profile": {
"cipher_suite": "GCM-AES-XPN-256",
"policy": "security",
"primary_cak": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
"primary_ckn": "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435",
"priority": "0",
"rekey_period": "900",
"send_sci": "true"
},
"PORT|Ethernet0": {
"alias": "Ethernet1/1",
"asic_port_name": "Eth0-ASIC0",
"coreid": "1",
"coreportid": "1",
"description": "Ethernet1/1",
"index": "1",
"lanes": "72,73,74,75,76,77,78,79",
"macsec": "macsec_profile",
"mtu": "9100",
"numvoq": "8",
"pfc_asym": "off",
"role": "Ext",
"speed": "400000",
"tpid": "0x8100"
},
"PORT|Ethernet1": {
"alias": "Ethernet2/1",
"asic_port_name": "Eth0-ASIC0",
"coreid": "1",
"coreportid": "1",
"description": "Ethernet2/1",
"index": "1",
"lanes": "72,73,74,75,76,77,78,79",
"macsec": "macsec_profile",
"mtu": "9100",
"numvoq": "8",
"pfc_asym": "off",
"role": "Ext",
"speed": "400000",
"tpid": "0x8100"
},
"PORT|Ethernet4": {
"alias": "Ethernet5/1",
"asic_port_name": "Eth0-ASIC0",
"coreid": "1",
"coreportid": "1",
"description": "Ethernet5/1",
"index": "1",
"lanes": "72,73,74,75,76,77,78,79",
"macsec": "macsec_profile",
"mtu": "9100",
"numvoq": "8",
"pfc_asym": "off",
"role": "Ext",
"speed": "400000",
"tpid": "0x8100"
},
"PORT|Ethernet5": {
"alias": "Ethernet6/1",
"asic_port_name": "Eth0-ASIC0",
"coreid": "1",
"coreportid": "1",
"description": "Ethernet6/1",
"index": "1",
"lanes": "72,73,74,75,76,77,78,79",
"macsec": "macsec_profile",
"mtu": "9100",
"numvoq": "8",
"pfc_asym": "off",
"role": "Ext",
"speed": "400000",
"tpid": "0x8100"
}
}

View File

@ -23,3 +23,7 @@ class TestShowMACsec(object):
result = runner.invoke(show_macsec.macsec,["Ethernet1"]) result = runner.invoke(show_macsec.macsec,["Ethernet1"])
assert result.exit_code == 0, "exit code: {}, Exception: {}, Traceback: {}".format(result.exit_code, result.exception, result.exc_info) assert result.exit_code == 0, "exit code: {}, Exception: {}, Traceback: {}".format(result.exit_code, result.exception, result.exc_info)
def test_show_profile(self):
runner = CliRunner()
result = runner.invoke(show_macsec.macsec,["--profile"])
assert result.exit_code == 0, "exit code: {}, Exception: {}, Traceback: {}".format(result.exit_code, result.exception, result.exc_info)

View File

@ -18,6 +18,17 @@ CACHE_FILE = os.path.join(CACHE_MANAGER.get_directory(), "macsecstats{}")
DB_CONNECTOR = None DB_CONNECTOR = None
COUNTER_TABLE = None COUNTER_TABLE = None
class MACsecCfgMeta(object):
def __init__(self, *args) -> None:
SEPARATOR = DB_CONNECTOR.get_db_separator(DB_CONNECTOR.CONFIG_DB)
self.key = self.__class__.get_cfg_table_name() + SEPARATOR + \
SEPARATOR.join(args)
self.cfgMeta = DB_CONNECTOR.get_all(
DB_CONNECTOR.CONFIG_DB, self.key)
if len(self.cfgMeta) == 0:
raise ValueError("No such MACsecCfgMeta: {}".format(self.key))
for k, v in self.cfgMeta.items():
setattr(self, k, v)
class MACsecAppMeta(object): class MACsecAppMeta(object):
def __init__(self, *args) -> None: def __init__(self, *args) -> None:
@ -126,23 +137,55 @@ class MACsecEgressSC(MACsecSC):
return "MACsec Egress SC ({})\n".format(self.sci) return "MACsec Egress SC ({})\n".format(self.sci)
class MACsecPort(MACsecAppMeta): class MACsecPort(MACsecAppMeta, MACsecCfgMeta):
def __init__(self, port_name: str) -> None: def __init__(self, port_name: str) -> None:
self.port_name = port_name self.port_name = port_name
super(MACsecPort, self).__init__(port_name) MACsecAppMeta.__init__(self, port_name)
MACsecCfgMeta.__init__(self, port_name)
@classmethod @classmethod
def get_appl_table_name(cls) -> str: def get_appl_table_name(cls) -> str:
return "MACSEC_PORT_TABLE" return "MACSEC_PORT_TABLE"
@classmethod
def get_cfg_table_name(cls) -> str:
return "PORT"
def dump_str(self, cache = None) -> str: def dump_str(self, cache = None) -> str:
buffer = self.get_header() buffer = self.get_header()
# Add the profile information to the meta dict from config meta dict
self.meta["profile"] = self.cfgMeta["macsec"]
buffer += tabulate(sorted(self.meta.items(), key=lambda x: x[0])) buffer += tabulate(sorted(self.meta.items(), key=lambda x: x[0]))
return buffer return buffer
def get_header(self) -> str: def get_header(self) -> str:
return "MACsec port({})\n".format(self.port_name) return "MACsec port({})\n".format(self.port_name)
class MACsecProfile(MACsecCfgMeta):
def __init__(self, profile_name: str) -> None:
self.profile_name = profile_name
super(MACsecProfile, self).__init__(profile_name)
@classmethod
def get_cfg_table_name(cls) -> str:
return "MACSEC_PROFILE"
def dump_str(self, cache = None) -> str:
buffer = self.get_header()
# Don't display the primary and fallback CAK
if 'primary_cak' in self.cfgMeta: del self.cfgMeta['primary_cak']
if 'fallback_cak' in self.cfgMeta: del self.cfgMeta['fallback_cak']
t_buffer = tabulate(sorted(self.cfgMeta.items(), key=lambda x: x[0]))
t_buffer = "\n".join(["\t" + line for line in t_buffer.splitlines()])
buffer += t_buffer
return buffer
def get_header(self) -> str:
return "MACsec profile : {}\n".format(self.profile_name)
def create_macsec_obj(key: str) -> MACsecAppMeta: def create_macsec_obj(key: str) -> MACsecAppMeta:
attr = key.split(":") attr = key.split(":")
@ -161,6 +204,14 @@ def create_macsec_obj(key: str) -> MACsecAppMeta:
except ValueError as e: except ValueError as e:
return None return None
def create_macsec_profile_obj(key: str) -> MACsecCfgMeta:
attr = key.split("|")
try:
if attr[0] == MACsecProfile.get_cfg_table_name():
return MACsecProfile(attr[1])
raise TypeError("Unknown MACsec object type")
except ValueError as e:
return None
def create_macsec_objs(interface_name: str) -> typing.List[MACsecAppMeta]: def create_macsec_objs(interface_name: str) -> typing.List[MACsecAppMeta]:
objs = [] objs = []
@ -192,6 +243,12 @@ def create_macsec_objs(interface_name: str) -> typing.List[MACsecAppMeta]:
return objs return objs
def create_macsec_profiles_objs(profile_name: str) -> typing.List[MACsecCfgMeta]:
objs = []
objs.append(create_macsec_profile_obj(MACsecProfile.get_cfg_table_name() + "|" + profile_name))
return objs
def cache_find(cache: dict, target: MACsecAppMeta) -> MACsecAppMeta: def cache_find(cache: dict, target: MACsecAppMeta) -> MACsecAppMeta:
if not cache or not cache["objs"]: if not cache or not cache["objs"]:
return None return None
@ -207,10 +264,14 @@ def cache_find(cache: dict, target: MACsecAppMeta) -> MACsecAppMeta:
@click.command() @click.command()
@click.argument('interface_name', required=False) @click.argument('interface_name', required=False)
@click.option('--dump-file', is_flag=True, required=False, default=False) @click.option('--profile', is_flag=True, required=False, default=False, help="show all macsec profiles")
@click.option('--dump-file', is_flag=True, required=False, default=False, help="store show output to a file")
@multi_asic_util.multi_asic_click_options @multi_asic_util.multi_asic_click_options
def macsec(interface_name, dump_file, namespace, display): def macsec(interface_name, dump_file, namespace, display, profile):
MacsecContext(namespace, display).show(interface_name, dump_file) if interface_name is not None and profile:
click.echo('Interface name is not valid with profile option')
return
MacsecContext(namespace, display).show(interface_name, dump_file, profile)
class MacsecContext(object): class MacsecContext(object):
@ -218,23 +279,36 @@ class MacsecContext(object):
self.db = None self.db = None
self.multi_asic = multi_asic_util.MultiAsic( self.multi_asic = multi_asic_util.MultiAsic(
display_option, namespace_option) display_option, namespace_option)
self.macsec_profiles = []
@multi_asic_util.run_on_multi_asic @multi_asic_util.run_on_multi_asic
def show(self, interface_name, dump_file): def show(self, interface_name, dump_file, profile):
global DB_CONNECTOR global DB_CONNECTOR
global COUNTER_TABLE global COUNTER_TABLE
DB_CONNECTOR = self.db DB_CONNECTOR = self.db
COUNTER_TABLE = CounterTable(self.db.get_redis_client(self.db.COUNTERS_DB))
interface_names = [name.split(":")[1] for name in self.db.keys(self.db.APPL_DB, "MACSEC_PORT*")] if not profile:
if interface_name is not None: COUNTER_TABLE = CounterTable(self.db.get_redis_client(self.db.COUNTERS_DB))
if interface_name not in interface_names:
return
interface_names = [interface_name]
objs = []
for interface_name in natsorted(interface_names): interface_names = [name.split(":")[1] for name in self.db.keys(self.db.APPL_DB, "MACSEC_PORT*")]
objs += create_macsec_objs(interface_name) if interface_name is not None:
if interface_name not in interface_names:
return
interface_names = [interface_name]
objs = []
for interface_name in natsorted(interface_names):
objs += create_macsec_objs(interface_name)
else:
profile_names = [name.split("|")[1] for name in self.db.keys(self.db.CONFIG_DB, "MACSEC_PROFILE*")]
objs = []
for profile_name in natsorted(profile_names):
# Check if this macsec profile is already added to profile list. This is in case of
# multi-asic devices where all namespaces will have the same macsec profile defined.
if profile_name not in self.macsec_profiles and not dump_file:
self.macsec_profiles.append(profile_name)
objs += create_macsec_profiles_objs(profile_name)
cache = {} cache = {}
if os.path.isfile(CACHE_FILE.format(self.multi_asic.current_namespace)): if os.path.isfile(CACHE_FILE.format(self.multi_asic.current_namespace)):