[macsec] Parse masec_enabled and macsec_profile from minigraph (#10917)
* Updates needed to parse the macsec config from minigraph * Add unit tests in tests/test_cfggen.py::TestCfgGen, and updates
This commit is contained in:
parent
f17d55dc67
commit
37c9b27ce2
@ -890,6 +890,7 @@ def parse_meta(meta, hname):
|
||||
switch_type = None
|
||||
max_cores = None
|
||||
kube_data = {}
|
||||
macsec_profile = {}
|
||||
device_metas = meta.find(str(QName(ns, "Devices")))
|
||||
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
|
||||
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
|
||||
@ -930,7 +931,9 @@ def parse_meta(meta, hname):
|
||||
kube_data["enable"] = value
|
||||
elif name == "KubernetesServerIp":
|
||||
kube_data["ip"] = value
|
||||
return syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data
|
||||
elif name == 'MacSecProfile':
|
||||
macsec_profile = parse_macsec_profile(value)
|
||||
return syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile
|
||||
|
||||
|
||||
def parse_system_defaults(meta):
|
||||
@ -979,6 +982,7 @@ def parse_linkmeta(meta, hname):
|
||||
upper_tor_hostname = ''
|
||||
lower_tor_hostname = ''
|
||||
auto_negotiation = None
|
||||
macsec_enabled = False
|
||||
|
||||
properties = linkmeta.find(str(QName(ns1, "Properties")))
|
||||
for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))):
|
||||
@ -994,6 +998,8 @@ def parse_linkmeta(meta, hname):
|
||||
lower_tor_hostname = value
|
||||
elif name == "AutoNegotiation":
|
||||
auto_negotiation = value
|
||||
elif name == "MacSecEnabled":
|
||||
macsec_enabled = value
|
||||
|
||||
linkmetas[port] = {}
|
||||
if fec_disabled:
|
||||
@ -1005,14 +1011,28 @@ def parse_linkmeta(meta, hname):
|
||||
linkmetas[port]["PeerSwitch"] = upper_tor_hostname
|
||||
if auto_negotiation:
|
||||
linkmetas[port]["AutoNegotiation"] = auto_negotiation
|
||||
if macsec_enabled:
|
||||
linkmetas[port]["MacSecEnabled"] = macsec_enabled
|
||||
return linkmetas
|
||||
|
||||
def parse_macsec_profile(val_string):
|
||||
macsec_profile = {}
|
||||
values = val_string.strip().split()
|
||||
for val in values:
|
||||
keys = val.strip().split('=')
|
||||
if keys[0] == 'PrimaryKey':
|
||||
macsec_profile['PrimaryKey'] = keys[1].strip('\"')
|
||||
elif keys[0] == 'FallbackKey':
|
||||
macsec_profile['FallbackKey'] = keys[1].strip('\"')
|
||||
|
||||
return macsec_profile
|
||||
|
||||
def parse_asic_meta(meta, hname):
|
||||
sub_role = None
|
||||
switch_id = None
|
||||
switch_type = None
|
||||
max_cores = None
|
||||
macsec_profile = {}
|
||||
device_metas = meta.find(str(QName(ns, "Devices")))
|
||||
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
|
||||
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
|
||||
@ -1028,7 +1048,10 @@ def parse_asic_meta(meta, hname):
|
||||
switch_type = value
|
||||
elif name == "MaxCores":
|
||||
max_cores = value
|
||||
return sub_role, switch_id, switch_type, max_cores
|
||||
elif name == 'MacSecProfile':
|
||||
macsec_profile = parse_macsec_profile(value)
|
||||
|
||||
return sub_role, switch_id, switch_type, max_cores, macsec_profile
|
||||
|
||||
def parse_deviceinfo(meta, hwsku):
|
||||
port_speeds = {}
|
||||
@ -1289,6 +1312,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
|
||||
kube_data = {}
|
||||
static_routes = {}
|
||||
system_defaults = {}
|
||||
macsec_profile = {}
|
||||
|
||||
hwsku_qn = QName(ns, "HwSku")
|
||||
hostname_qn = QName(ns, "Hostname")
|
||||
@ -1319,7 +1343,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
|
||||
elif child.tag == str(QName(ns, "UngDec")):
|
||||
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname, None)
|
||||
elif child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
(syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data) = parse_meta(child, hostname)
|
||||
(syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile) = parse_meta(child, hostname)
|
||||
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
|
||||
linkmetas = parse_linkmeta(child, hostname)
|
||||
elif child.tag == str(QName(ns, "DeviceInfos")):
|
||||
@ -1335,7 +1359,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
|
||||
elif child.tag == str(QName(ns, "PngDec")):
|
||||
(neighbors, devices, port_speed_png) = parse_asic_png(child, asic_name, hostname)
|
||||
elif child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
(sub_role, switch_id, switch_type, max_cores ) = parse_asic_meta(child, asic_name)
|
||||
(sub_role, switch_id, switch_type, max_cores, macsec_profile) = parse_asic_meta(child, asic_name)
|
||||
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
|
||||
linkmetas = parse_linkmeta(child, hostname)
|
||||
elif child.tag == str(QName(ns, "DeviceInfos")):
|
||||
@ -1538,6 +1562,11 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
|
||||
if autoneg:
|
||||
port['autoneg'] = 'on' if autoneg.lower() == 'true' else 'off'
|
||||
|
||||
# If macsec is enabled on interface, and profile is valid, add the profile to port
|
||||
macsec_enabled = linkmetas.get(alias, {}).get('MacSecEnabled')
|
||||
if macsec_enabled and 'PrimaryKey' in macsec_profile:
|
||||
port['macsec'] = macsec_profile['PrimaryKey']
|
||||
|
||||
# If connected to a smart cable, get the connection position
|
||||
for port_name, port in ports.items():
|
||||
if port_name in mux_cable_ports:
|
||||
@ -1872,7 +1901,7 @@ def parse_asic_sub_role(filename, asic_name):
|
||||
root = ET.parse(filename).getroot()
|
||||
for child in root:
|
||||
if child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
sub_role, _, _, _ = parse_asic_meta(child, asic_name)
|
||||
sub_role, _, _, _, _= parse_asic_meta(child, asic_name)
|
||||
return sub_role
|
||||
|
||||
def parse_asic_switch_type(filename, asic_name):
|
||||
@ -1880,7 +1909,7 @@ def parse_asic_switch_type(filename, asic_name):
|
||||
root = ET.parse(filename).getroot()
|
||||
for child in root:
|
||||
if child.tag == str(QName(ns, "MetadataDeclaration")):
|
||||
_, _, switch_type, _ = parse_asic_meta(child, asic_name)
|
||||
_, _, switch_type, _, _ = parse_asic_meta(child, asic_name)
|
||||
return switch_type
|
||||
return None
|
||||
|
||||
|
@ -61,6 +61,7 @@ class YangWrapper(object):
|
||||
parser.add_argument("-n", "--namespace", help="namespace name", nargs='?', const=None, default=None)
|
||||
parser.add_argument("-p", "--port-config", help="port config file, used with -m or -k", nargs='?', const=None)
|
||||
parser.add_argument("-S", "--hwsku-config", help="hwsku config file, used with -p and -m or -k", nargs='?', const=None)
|
||||
parser.add_argument("-j", "--json", help="additional json file input, used with -p, -S and -m or -k", nargs='?', const=None)
|
||||
args, unknown = parser.parse_known_args(shlex.split(argument))
|
||||
|
||||
print('\n Validating yang schema')
|
||||
@ -73,6 +74,8 @@ class YangWrapper(object):
|
||||
cmd += ' -p ' + args.port_config
|
||||
if args.namespace is not None:
|
||||
cmd += ' -n ' + args.namespace
|
||||
if args.json is not None:
|
||||
cmd += ' -j ' + args.json
|
||||
cmd += ' --print-data'
|
||||
output = subprocess.check_output(cmd, shell=True).decode()
|
||||
try:
|
||||
|
22
src/sonic-config-engine/tests/macsec_profile.json
Normal file
22
src/sonic-config-engine/tests/macsec_profile.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"MACSEC_PROFILE":{
|
||||
"macsec-profile": {
|
||||
"cipher_suite": "GCM-AES-XPN-256",
|
||||
"primary_cak": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
|
||||
"primary_ckn": "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435",
|
||||
"fallback_cak": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"fallback_ckn": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"priority": "0",
|
||||
"rekey_period": "60"
|
||||
},
|
||||
"macsec-profile2": {
|
||||
"cipher_suite": "GCM-AES-XPN-256",
|
||||
"primary_cak": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
|
||||
"primary_ckn": "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435",
|
||||
"fallback_cak": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"fallback_ckn": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"priority": "0",
|
||||
"rekey_period": "60"
|
||||
}
|
||||
}
|
||||
}
|
@ -67,6 +67,21 @@
|
||||
<DownstreamSummarySet xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"/>
|
||||
</DeviceDataPlaneInfo>
|
||||
</DpgDec>
|
||||
<LinkMetadataDeclaration>
|
||||
<Link xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution">
|
||||
<a:LinkMetadata>
|
||||
<a:Name i:nil="true"/>
|
||||
<a:Properties>
|
||||
<a:DeviceProperty>
|
||||
<a:Name>MacSecEnabled</a:Name>
|
||||
<a:Value>True</a:Value>
|
||||
</a:DeviceProperty>
|
||||
</a:Properties>
|
||||
<a:Key>linecard-1:Ethernet1/1;ARISTA01-RH:Ethernet1/1</a:Key>
|
||||
</a:LinkMetadata>
|
||||
</Link>
|
||||
<Properties xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"/>
|
||||
</LinkMetadataDeclaration>
|
||||
<PngDec>
|
||||
<DeviceInterfaceLinks/>
|
||||
<Devices>
|
||||
@ -144,6 +159,10 @@
|
||||
<a:Reference i:nil="true"/>
|
||||
<a:Value>16</a:Value>
|
||||
</a:DeviceProperty>
|
||||
<a:DeviceProperty>
|
||||
<a:Name>MacSecProfile</a:Name>
|
||||
<a:Value>PrimaryKey="macsec-profile" FallbackKey="macsec-profile2" MacsecPolicy=""</a:Value>
|
||||
</a:DeviceProperty>
|
||||
</a:Properties>
|
||||
</a:DeviceMetadata>
|
||||
</Devices>
|
||||
@ -157,44 +176,31 @@
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/0</InterfaceName>
|
||||
<InterfaceName>Ethernet1/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
<Priority>0</Priority>
|
||||
<Speed>10000</Speed>
|
||||
<Speed>100000</Speed>
|
||||
</a:EthernetInterface>
|
||||
<a:EthernetInterface>
|
||||
<ElementType>DeviceInterface</ElementType>
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/4</InterfaceName>
|
||||
<InterfaceName>Ethernet2/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
<Priority>0</Priority>
|
||||
<Speed>25000</Speed>
|
||||
<Speed>100000</Speed>
|
||||
</a:EthernetInterface>
|
||||
<a:EthernetInterface>
|
||||
<ElementType>DeviceInterface</ElementType>
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/8</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
<Priority>0</Priority>
|
||||
<Speed>40000</Speed>
|
||||
<Description>Interface description</Description>
|
||||
</a:EthernetInterface>
|
||||
<a:EthernetInterface>
|
||||
<ElementType>DeviceInterface</ElementType>
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/12</InterfaceName>
|
||||
<InterfaceName>Ethernet3/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
@ -207,7 +213,20 @@
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/16</InterfaceName>
|
||||
<InterfaceName>Ethernet4/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
<Priority>0</Priority>
|
||||
<Speed>100000</Speed>
|
||||
<Description>Interface description</Description>
|
||||
</a:EthernetInterface>
|
||||
<a:EthernetInterface>
|
||||
<ElementType>DeviceInterface</ElementType>
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>Ethernet5/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
@ -219,7 +238,7 @@
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/20</InterfaceName>
|
||||
<InterfaceName>Ethernet6/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
@ -231,7 +250,7 @@
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/24</InterfaceName>
|
||||
<InterfaceName>Ethernet7/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
@ -243,7 +262,7 @@
|
||||
<AlternateSpeeds i:nil="true"/>
|
||||
<EnableFlowControl>true</EnableFlowControl>
|
||||
<Index>1</Index>
|
||||
<InterfaceName>fortyGigE0/28</InterfaceName>
|
||||
<InterfaceName>Ethernetr8/1</InterfaceName>
|
||||
<InterfaceType i:nil="true"/>
|
||||
<MultiPortsInterface>false</MultiPortsInterface>
|
||||
<PortName>0</PortName>
|
||||
|
@ -38,6 +38,7 @@ class TestCfgGen(TestCase):
|
||||
self.voq_port_config = os.path.join(self.test_dir, 'voq-sample-port-config.ini')
|
||||
self.packet_chassis_graph = os.path.join(self.test_dir, 'sample-chassis-packet-lc-graph.xml')
|
||||
self.packet_chassis_port_ini = os.path.join(self.test_dir, 'sample-chassis-packet-lc-port-config.ini')
|
||||
self.macsec_profile = os.path.join(self.test_dir, 'macsec_profile.json')
|
||||
# To ensure that mock config_db data is used for unit-test cases
|
||||
os.environ["CFGGEN_UNIT_TESTING"] = "2"
|
||||
|
||||
@ -839,7 +840,7 @@ class TestCfgGen(TestCase):
|
||||
self.assertEqual(output, '')
|
||||
|
||||
def test_minigraph_voq_metadata(self):
|
||||
argument = "-m {} -p {} --var-json DEVICE_METADATA".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json DEVICE_METADATA".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
output = json.loads(self.run_script(argument))
|
||||
self.assertEqual(output['localhost']['asic_name'], 'Asic0')
|
||||
self.assertEqual(output['localhost']['switch_id'], '0')
|
||||
@ -847,7 +848,7 @@ class TestCfgGen(TestCase):
|
||||
self.assertEqual(output['localhost']['max_cores'], '16')
|
||||
|
||||
def test_minigraph_voq_system_ports(self):
|
||||
argument = "-m {} -p {} --var-json SYSTEM_PORT".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json SYSTEM_PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
self.assertDictEqual(
|
||||
json.loads(self.run_script(argument)),
|
||||
{
|
||||
@ -865,8 +866,16 @@ class TestCfgGen(TestCase):
|
||||
}
|
||||
)
|
||||
|
||||
def test_minigraph_voq_port_macsec_enabled(self):
|
||||
argument = '-j "' + self.macsec_profile + '" -m "' + self.sample_graph_voq + '" -p "' + self.voq_port_config + '" -v "PORT[\'Ethernet0\']"'
|
||||
output = self.run_script(argument)
|
||||
self.assertEqual(
|
||||
utils.to_dict(output.strip()),
|
||||
utils.to_dict("{'lanes': '6,7', 'fec': 'rs', 'alias': 'Ethernet1/1', 'index': '1', 'role': 'Ext', 'speed': '100000', 'macsec': 'macsec-profile', 'description': 'Ethernet1/1', 'mtu': '9100', 'tpid': '0x8100', 'pfc_asym': 'off'}")
|
||||
)
|
||||
|
||||
def test_minigraph_voq_inband_interface_vlan(self):
|
||||
argument = "-m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
output = self.run_script(argument)
|
||||
output_dict = utils.to_dict(output.strip())
|
||||
self.assertDictEqual(
|
||||
@ -879,7 +888,7 @@ class TestCfgGen(TestCase):
|
||||
)
|
||||
|
||||
def test_minigraph_voq_inband_interface_port(self):
|
||||
argument = "-m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
output = self.run_script(argument)
|
||||
output_dict = utils.to_dict(output.strip())
|
||||
self.assertDictEqual(
|
||||
@ -892,7 +901,7 @@ class TestCfgGen(TestCase):
|
||||
)
|
||||
|
||||
def test_minigraph_voq_inband_port(self):
|
||||
argument = "-m {} -p {} --var-json PORT".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
output = self.run_script(argument)
|
||||
output_dict = utils.to_dict(output.strip())
|
||||
self.assertDictEqual(
|
||||
@ -910,7 +919,7 @@ class TestCfgGen(TestCase):
|
||||
})
|
||||
|
||||
def test_minigraph_voq_recirc_ports(self):
|
||||
argument = "-m {} -p {} --var-json PORT".format(self.sample_graph_voq, self.voq_port_config)
|
||||
argument = "-j {} -m {} -p {} --var-json PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
|
||||
output = self.run_script(argument)
|
||||
output_dict = utils.to_dict(output.strip())
|
||||
self.assertDictEqual(
|
||||
@ -968,4 +977,3 @@ class TestCfgGen(TestCase):
|
||||
utils.to_dict(output.strip()),
|
||||
utils.to_dict("{('PortChannel32.2', '192.168.1.4/24'): {}, 'PortChannel32.2': {'admin_status': 'up'}, ('PortChannel33.2', '192.168.2.4/24'): {}, 'PortChannel33.2': {'admin_status': 'up'}}")
|
||||
)
|
||||
|
||||
|
Reference in New Issue
Block a user