Skip to content

Commit 37c9b27

Browse files
judyjosephyxieca
authored andcommitted
[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
1 parent f17d55d commit 37c9b27

File tree

5 files changed

+105
-24
lines changed

5 files changed

+105
-24
lines changed

src/sonic-config-engine/minigraph.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,7 @@ def parse_meta(meta, hname):
890890
switch_type = None
891891
max_cores = None
892892
kube_data = {}
893+
macsec_profile = {}
893894
device_metas = meta.find(str(QName(ns, "Devices")))
894895
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
895896
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
@@ -930,7 +931,9 @@ def parse_meta(meta, hname):
930931
kube_data["enable"] = value
931932
elif name == "KubernetesServerIp":
932933
kube_data["ip"] = value
933-
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
934+
elif name == 'MacSecProfile':
935+
macsec_profile = parse_macsec_profile(value)
936+
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
934937

935938

936939
def parse_system_defaults(meta):
@@ -979,6 +982,7 @@ def parse_linkmeta(meta, hname):
979982
upper_tor_hostname = ''
980983
lower_tor_hostname = ''
981984
auto_negotiation = None
985+
macsec_enabled = False
982986

983987
properties = linkmeta.find(str(QName(ns1, "Properties")))
984988
for device_property in properties.findall(str(QName(ns1, "DeviceProperty"))):
@@ -994,6 +998,8 @@ def parse_linkmeta(meta, hname):
994998
lower_tor_hostname = value
995999
elif name == "AutoNegotiation":
9961000
auto_negotiation = value
1001+
elif name == "MacSecEnabled":
1002+
macsec_enabled = value
9971003

9981004
linkmetas[port] = {}
9991005
if fec_disabled:
@@ -1005,14 +1011,28 @@ def parse_linkmeta(meta, hname):
10051011
linkmetas[port]["PeerSwitch"] = upper_tor_hostname
10061012
if auto_negotiation:
10071013
linkmetas[port]["AutoNegotiation"] = auto_negotiation
1014+
if macsec_enabled:
1015+
linkmetas[port]["MacSecEnabled"] = macsec_enabled
10081016
return linkmetas
10091017

1018+
def parse_macsec_profile(val_string):
1019+
macsec_profile = {}
1020+
values = val_string.strip().split()
1021+
for val in values:
1022+
keys = val.strip().split('=')
1023+
if keys[0] == 'PrimaryKey':
1024+
macsec_profile['PrimaryKey'] = keys[1].strip('\"')
1025+
elif keys[0] == 'FallbackKey':
1026+
macsec_profile['FallbackKey'] = keys[1].strip('\"')
1027+
1028+
return macsec_profile
10101029

10111030
def parse_asic_meta(meta, hname):
10121031
sub_role = None
10131032
switch_id = None
10141033
switch_type = None
10151034
max_cores = None
1035+
macsec_profile = {}
10161036
device_metas = meta.find(str(QName(ns, "Devices")))
10171037
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
10181038
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
@@ -1028,7 +1048,10 @@ def parse_asic_meta(meta, hname):
10281048
switch_type = value
10291049
elif name == "MaxCores":
10301050
max_cores = value
1031-
return sub_role, switch_id, switch_type, max_cores
1051+
elif name == 'MacSecProfile':
1052+
macsec_profile = parse_macsec_profile(value)
1053+
1054+
return sub_role, switch_id, switch_type, max_cores, macsec_profile
10321055

10331056
def parse_deviceinfo(meta, hwsku):
10341057
port_speeds = {}
@@ -1289,6 +1312,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
12891312
kube_data = {}
12901313
static_routes = {}
12911314
system_defaults = {}
1315+
macsec_profile = {}
12921316

12931317
hwsku_qn = QName(ns, "HwSku")
12941318
hostname_qn = QName(ns, "Hostname")
@@ -1319,7 +1343,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
13191343
elif child.tag == str(QName(ns, "UngDec")):
13201344
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname, None)
13211345
elif child.tag == str(QName(ns, "MetadataDeclaration")):
1322-
(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)
1346+
(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)
13231347
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
13241348
linkmetas = parse_linkmeta(child, hostname)
13251349
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
13351359
elif child.tag == str(QName(ns, "PngDec")):
13361360
(neighbors, devices, port_speed_png) = parse_asic_png(child, asic_name, hostname)
13371361
elif child.tag == str(QName(ns, "MetadataDeclaration")):
1338-
(sub_role, switch_id, switch_type, max_cores ) = parse_asic_meta(child, asic_name)
1362+
(sub_role, switch_id, switch_type, max_cores, macsec_profile) = parse_asic_meta(child, asic_name)
13391363
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
13401364
linkmetas = parse_linkmeta(child, hostname)
13411365
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
15381562
if autoneg:
15391563
port['autoneg'] = 'on' if autoneg.lower() == 'true' else 'off'
15401564

1565+
# If macsec is enabled on interface, and profile is valid, add the profile to port
1566+
macsec_enabled = linkmetas.get(alias, {}).get('MacSecEnabled')
1567+
if macsec_enabled and 'PrimaryKey' in macsec_profile:
1568+
port['macsec'] = macsec_profile['PrimaryKey']
1569+
15411570
# If connected to a smart cable, get the connection position
15421571
for port_name, port in ports.items():
15431572
if port_name in mux_cable_ports:
@@ -1872,15 +1901,15 @@ def parse_asic_sub_role(filename, asic_name):
18721901
root = ET.parse(filename).getroot()
18731902
for child in root:
18741903
if child.tag == str(QName(ns, "MetadataDeclaration")):
1875-
sub_role, _, _, _ = parse_asic_meta(child, asic_name)
1904+
sub_role, _, _, _, _= parse_asic_meta(child, asic_name)
18761905
return sub_role
18771906

18781907
def parse_asic_switch_type(filename, asic_name):
18791908
if os.path.isfile(filename):
18801909
root = ET.parse(filename).getroot()
18811910
for child in root:
18821911
if child.tag == str(QName(ns, "MetadataDeclaration")):
1883-
_, _, switch_type, _ = parse_asic_meta(child, asic_name)
1912+
_, _, switch_type, _, _ = parse_asic_meta(child, asic_name)
18841913
return switch_type
18851914
return None
18861915

src/sonic-config-engine/tests/common_utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def validate(self, argument):
6161
parser.add_argument("-n", "--namespace", help="namespace name", nargs='?', const=None, default=None)
6262
parser.add_argument("-p", "--port-config", help="port config file, used with -m or -k", nargs='?', const=None)
6363
parser.add_argument("-S", "--hwsku-config", help="hwsku config file, used with -p and -m or -k", nargs='?', const=None)
64+
parser.add_argument("-j", "--json", help="additional json file input, used with -p, -S and -m or -k", nargs='?', const=None)
6465
args, unknown = parser.parse_known_args(shlex.split(argument))
6566

6667
print('\n Validating yang schema')
@@ -73,6 +74,8 @@ def validate(self, argument):
7374
cmd += ' -p ' + args.port_config
7475
if args.namespace is not None:
7576
cmd += ' -n ' + args.namespace
77+
if args.json is not None:
78+
cmd += ' -j ' + args.json
7679
cmd += ' --print-data'
7780
output = subprocess.check_output(cmd, shell=True).decode()
7881
try:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"MACSEC_PROFILE":{
3+
"macsec-profile": {
4+
"cipher_suite": "GCM-AES-XPN-256",
5+
"primary_cak": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
6+
"primary_ckn": "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435",
7+
"fallback_cak": "0000000000000000000000000000000000000000000000000000000000000000",
8+
"fallback_ckn": "1111111111111111111111111111111111111111111111111111111111111111",
9+
"priority": "0",
10+
"rekey_period": "60"
11+
},
12+
"macsec-profile2": {
13+
"cipher_suite": "GCM-AES-XPN-256",
14+
"primary_cak": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
15+
"primary_ckn": "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435",
16+
"fallback_cak": "0000000000000000000000000000000000000000000000000000000000000000",
17+
"fallback_ckn": "1111111111111111111111111111111111111111111111111111111111111111",
18+
"priority": "0",
19+
"rekey_period": "60"
20+
}
21+
}
22+
}

src/sonic-config-engine/tests/sample-voq-graph.xml

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@
6767
<DownstreamSummarySet xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"/>
6868
</DeviceDataPlaneInfo>
6969
</DpgDec>
70+
<LinkMetadataDeclaration>
71+
<Link xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution">
72+
<a:LinkMetadata>
73+
<a:Name i:nil="true"/>
74+
<a:Properties>
75+
<a:DeviceProperty>
76+
<a:Name>MacSecEnabled</a:Name>
77+
<a:Value>True</a:Value>
78+
</a:DeviceProperty>
79+
</a:Properties>
80+
<a:Key>linecard-1:Ethernet1/1;ARISTA01-RH:Ethernet1/1</a:Key>
81+
</a:LinkMetadata>
82+
</Link>
83+
<Properties xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"/>
84+
</LinkMetadataDeclaration>
7085
<PngDec>
7186
<DeviceInterfaceLinks/>
7287
<Devices>
@@ -144,6 +159,10 @@
144159
<a:Reference i:nil="true"/>
145160
<a:Value>16</a:Value>
146161
</a:DeviceProperty>
162+
<a:DeviceProperty>
163+
<a:Name>MacSecProfile</a:Name>
164+
<a:Value>PrimaryKey="macsec-profile" FallbackKey="macsec-profile2" MacsecPolicy=""</a:Value>
165+
</a:DeviceProperty>
147166
</a:Properties>
148167
</a:DeviceMetadata>
149168
</Devices>
@@ -157,44 +176,44 @@
157176
<AlternateSpeeds i:nil="true"/>
158177
<EnableFlowControl>true</EnableFlowControl>
159178
<Index>1</Index>
160-
<InterfaceName>fortyGigE0/0</InterfaceName>
179+
<InterfaceName>Ethernet1/1</InterfaceName>
161180
<InterfaceType i:nil="true"/>
162181
<MultiPortsInterface>false</MultiPortsInterface>
163182
<PortName>0</PortName>
164183
<Priority>0</Priority>
165-
<Speed>10000</Speed>
184+
<Speed>100000</Speed>
166185
</a:EthernetInterface>
167186
<a:EthernetInterface>
168187
<ElementType>DeviceInterface</ElementType>
169188
<AlternateSpeeds i:nil="true"/>
170189
<EnableFlowControl>true</EnableFlowControl>
171190
<Index>1</Index>
172-
<InterfaceName>fortyGigE0/4</InterfaceName>
191+
<InterfaceName>Ethernet2/1</InterfaceName>
173192
<InterfaceType i:nil="true"/>
174193
<MultiPortsInterface>false</MultiPortsInterface>
175194
<PortName>0</PortName>
176195
<Priority>0</Priority>
177-
<Speed>25000</Speed>
196+
<Speed>100000</Speed>
178197
</a:EthernetInterface>
179198
<a:EthernetInterface>
180199
<ElementType>DeviceInterface</ElementType>
181200
<AlternateSpeeds i:nil="true"/>
182201
<EnableFlowControl>true</EnableFlowControl>
183202
<Index>1</Index>
184-
<InterfaceName>fortyGigE0/8</InterfaceName>
203+
<InterfaceName>Ethernet3/1</InterfaceName>
185204
<InterfaceType i:nil="true"/>
186205
<MultiPortsInterface>false</MultiPortsInterface>
187206
<PortName>0</PortName>
188207
<Priority>0</Priority>
189-
<Speed>40000</Speed>
208+
<Speed>100000</Speed>
190209
<Description>Interface description</Description>
191210
</a:EthernetInterface>
192211
<a:EthernetInterface>
193212
<ElementType>DeviceInterface</ElementType>
194213
<AlternateSpeeds i:nil="true"/>
195214
<EnableFlowControl>true</EnableFlowControl>
196215
<Index>1</Index>
197-
<InterfaceName>fortyGigE0/12</InterfaceName>
216+
<InterfaceName>Ethernet4/1</InterfaceName>
198217
<InterfaceType i:nil="true"/>
199218
<MultiPortsInterface>false</MultiPortsInterface>
200219
<PortName>0</PortName>
@@ -207,7 +226,7 @@
207226
<AlternateSpeeds i:nil="true"/>
208227
<EnableFlowControl>true</EnableFlowControl>
209228
<Index>1</Index>
210-
<InterfaceName>fortyGigE0/16</InterfaceName>
229+
<InterfaceName>Ethernet5/1</InterfaceName>
211230
<InterfaceType i:nil="true"/>
212231
<MultiPortsInterface>false</MultiPortsInterface>
213232
<PortName>0</PortName>
@@ -219,7 +238,7 @@
219238
<AlternateSpeeds i:nil="true"/>
220239
<EnableFlowControl>true</EnableFlowControl>
221240
<Index>1</Index>
222-
<InterfaceName>fortyGigE0/20</InterfaceName>
241+
<InterfaceName>Ethernet6/1</InterfaceName>
223242
<InterfaceType i:nil="true"/>
224243
<MultiPortsInterface>false</MultiPortsInterface>
225244
<PortName>0</PortName>
@@ -231,7 +250,7 @@
231250
<AlternateSpeeds i:nil="true"/>
232251
<EnableFlowControl>true</EnableFlowControl>
233252
<Index>1</Index>
234-
<InterfaceName>fortyGigE0/24</InterfaceName>
253+
<InterfaceName>Ethernet7/1</InterfaceName>
235254
<InterfaceType i:nil="true"/>
236255
<MultiPortsInterface>false</MultiPortsInterface>
237256
<PortName>0</PortName>
@@ -243,7 +262,7 @@
243262
<AlternateSpeeds i:nil="true"/>
244263
<EnableFlowControl>true</EnableFlowControl>
245264
<Index>1</Index>
246-
<InterfaceName>fortyGigE0/28</InterfaceName>
265+
<InterfaceName>Ethernetr8/1</InterfaceName>
247266
<InterfaceType i:nil="true"/>
248267
<MultiPortsInterface>false</MultiPortsInterface>
249268
<PortName>0</PortName>

src/sonic-config-engine/tests/test_cfggen.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def setUp(self):
3838
self.voq_port_config = os.path.join(self.test_dir, 'voq-sample-port-config.ini')
3939
self.packet_chassis_graph = os.path.join(self.test_dir, 'sample-chassis-packet-lc-graph.xml')
4040
self.packet_chassis_port_ini = os.path.join(self.test_dir, 'sample-chassis-packet-lc-port-config.ini')
41+
self.macsec_profile = os.path.join(self.test_dir, 'macsec_profile.json')
4142
# To ensure that mock config_db data is used for unit-test cases
4243
os.environ["CFGGEN_UNIT_TESTING"] = "2"
4344

@@ -839,15 +840,15 @@ def test_show_run_interfaces(self):
839840
self.assertEqual(output, '')
840841

841842
def test_minigraph_voq_metadata(self):
842-
argument = "-m {} -p {} --var-json DEVICE_METADATA".format(self.sample_graph_voq, self.voq_port_config)
843+
argument = "-j {} -m {} -p {} --var-json DEVICE_METADATA".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
843844
output = json.loads(self.run_script(argument))
844845
self.assertEqual(output['localhost']['asic_name'], 'Asic0')
845846
self.assertEqual(output['localhost']['switch_id'], '0')
846847
self.assertEqual(output['localhost']['switch_type'], 'voq')
847848
self.assertEqual(output['localhost']['max_cores'], '16')
848849

849850
def test_minigraph_voq_system_ports(self):
850-
argument = "-m {} -p {} --var-json SYSTEM_PORT".format(self.sample_graph_voq, self.voq_port_config)
851+
argument = "-j {} -m {} -p {} --var-json SYSTEM_PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
851852
self.assertDictEqual(
852853
json.loads(self.run_script(argument)),
853854
{
@@ -865,8 +866,16 @@ def test_minigraph_voq_system_ports(self):
865866
}
866867
)
867868

869+
def test_minigraph_voq_port_macsec_enabled(self):
870+
argument = '-j "' + self.macsec_profile + '" -m "' + self.sample_graph_voq + '" -p "' + self.voq_port_config + '" -v "PORT[\'Ethernet0\']"'
871+
output = self.run_script(argument)
872+
self.assertEqual(
873+
utils.to_dict(output.strip()),
874+
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'}")
875+
)
876+
868877
def test_minigraph_voq_inband_interface_vlan(self):
869-
argument = "-m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.sample_graph_voq, self.voq_port_config)
878+
argument = "-j {} -m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
870879
output = self.run_script(argument)
871880
output_dict = utils.to_dict(output.strip())
872881
self.assertDictEqual(
@@ -879,7 +888,7 @@ def test_minigraph_voq_inband_interface_vlan(self):
879888
)
880889

881890
def test_minigraph_voq_inband_interface_port(self):
882-
argument = "-m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.sample_graph_voq, self.voq_port_config)
891+
argument = "-j {} -m {} -p {} --var-json VOQ_INBAND_INTERFACE".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
883892
output = self.run_script(argument)
884893
output_dict = utils.to_dict(output.strip())
885894
self.assertDictEqual(
@@ -892,7 +901,7 @@ def test_minigraph_voq_inband_interface_port(self):
892901
)
893902

894903
def test_minigraph_voq_inband_port(self):
895-
argument = "-m {} -p {} --var-json PORT".format(self.sample_graph_voq, self.voq_port_config)
904+
argument = "-j {} -m {} -p {} --var-json PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
896905
output = self.run_script(argument)
897906
output_dict = utils.to_dict(output.strip())
898907
self.assertDictEqual(
@@ -910,7 +919,7 @@ def test_minigraph_voq_inband_port(self):
910919
})
911920

912921
def test_minigraph_voq_recirc_ports(self):
913-
argument = "-m {} -p {} --var-json PORT".format(self.sample_graph_voq, self.voq_port_config)
922+
argument = "-j {} -m {} -p {} --var-json PORT".format(self.macsec_profile, self.sample_graph_voq, self.voq_port_config)
914923
output = self.run_script(argument)
915924
output_dict = utils.to_dict(output.strip())
916925
self.assertDictEqual(
@@ -968,4 +977,3 @@ def test_minigraph_bgp_packet_chassis_vlan_subintf(self):
968977
utils.to_dict(output.strip()),
969978
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'}}")
970979
)
971-

0 commit comments

Comments
 (0)