]>
Commit | Line | Data |
---|---|---|
ead573d8 | 1 | # Test cases for MACsec/MKA |
b21540e6 | 2 | # Copyright (c) 2018-2019, Jouni Malinen <j@w1.fi> |
ead573d8 JM |
3 | # |
4 | # This software may be distributed under the terms of the BSD license. | |
5 | # See README for more details. | |
6 | ||
7 | import logging | |
8 | logger = logging.getLogger() | |
e1810300 | 9 | import binascii |
ead573d8 JM |
10 | import os |
11 | import signal | |
12 | import subprocess | |
13 | import time | |
14 | ||
15 | from wpasupplicant import WpaSupplicant | |
16 | import hwsim_utils | |
344929a9 | 17 | from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger |
ead573d8 JM |
18 | |
19 | def cleanup_macsec(): | |
b21540e6 | 20 | wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False) |
ead573d8 JM |
21 | wpas.interface_remove("veth0") |
22 | wpas.interface_remove("veth1") | |
b21540e6 | 23 | del wpas |
ead573d8 JM |
24 | subprocess.call(["ip", "link", "del", "veth0"], |
25 | stderr=open('/dev/null', 'w')) | |
26 | ||
27 | def test_macsec_psk(dev, apdev, params): | |
28 | """MACsec PSK""" | |
29 | try: | |
30 | run_macsec_psk(dev, apdev, params, "macsec_psk") | |
31 | finally: | |
32 | cleanup_macsec() | |
33 | ||
34 | def test_macsec_psk_mka_life_time(dev, apdev, params): | |
35 | """MACsec PSK - MKA life time""" | |
36 | try: | |
37 | run_macsec_psk(dev, apdev, params, "macsec_psk_mka_life_time") | |
b21540e6 | 38 | wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False) |
ead573d8 | 39 | wpas.interface_remove("veth1") |
b21540e6 | 40 | del wpas |
ead573d8 JM |
41 | # Wait for live peer to be removed on veth0 |
42 | time.sleep(6.1) | |
43 | finally: | |
44 | cleanup_macsec() | |
45 | ||
46 | def test_macsec_psk_integ_only(dev, apdev, params): | |
47 | """MACsec PSK (integrity only)""" | |
48 | try: | |
49 | run_macsec_psk(dev, apdev, params, "macsec_psk_integ_only", | |
50 | integ_only=True) | |
51 | finally: | |
52 | cleanup_macsec() | |
53 | ||
54 | def test_macsec_psk_port(dev, apdev, params): | |
55 | """MACsec PSK (port)""" | |
56 | try: | |
57 | run_macsec_psk(dev, apdev, params, "macsec_psk_port", | |
58 | port0=65534, port1=65534) | |
59 | finally: | |
60 | cleanup_macsec() | |
61 | ||
62 | def test_macsec_psk_different_ports(dev, apdev, params): | |
63 | """MACsec PSK (different ports)""" | |
64 | try: | |
65 | run_macsec_psk(dev, apdev, params, "macsec_psk_different_ports", | |
66 | port0=2, port1=3) | |
67 | finally: | |
68 | cleanup_macsec() | |
69 | ||
70 | def test_macsec_psk_shorter_ckn(dev, apdev, params): | |
71 | """MACsec PSK (shorter CKN)""" | |
72 | try: | |
73 | ckn = "11223344" | |
74 | run_macsec_psk(dev, apdev, params, "macsec_psk_shorter_ckn", | |
75 | ckn0=ckn, ckn1=ckn) | |
76 | finally: | |
77 | cleanup_macsec() | |
78 | ||
79 | def test_macsec_psk_shorter_ckn2(dev, apdev, params): | |
80 | """MACsec PSK (shorter CKN, unaligned)""" | |
81 | try: | |
82 | ckn = "112233" | |
83 | run_macsec_psk(dev, apdev, params, "macsec_psk_shorter_ckn2", | |
84 | ckn0=ckn, ckn1=ckn) | |
85 | finally: | |
86 | cleanup_macsec() | |
87 | ||
88 | def test_macsec_psk_ckn_mismatch(dev, apdev, params): | |
89 | """MACsec PSK (CKN mismatch)""" | |
90 | try: | |
91 | ckn0 = "11223344" | |
92 | ckn1 = "1122334455667788" | |
93 | run_macsec_psk(dev, apdev, params, "macsec_psk_ckn_mismatch", | |
94 | ckn0=ckn0, ckn1=ckn1, expect_failure=True) | |
95 | finally: | |
96 | cleanup_macsec() | |
97 | ||
98 | def test_macsec_psk_cak_mismatch(dev, apdev, params): | |
99 | """MACsec PSK (CAK mismatch)""" | |
100 | try: | |
101 | cak0 = 16*"11" | |
102 | cak1 = 16*"22" | |
103 | run_macsec_psk(dev, apdev, params, "macsec_psk_cak_mismatch", | |
104 | cak0=cak0, cak1=cak1, expect_failure=True) | |
105 | finally: | |
106 | cleanup_macsec() | |
107 | ||
108 | def test_macsec_psk_256(dev, apdev, params): | |
109 | """MACsec PSK with 256-bit keys""" | |
110 | try: | |
111 | cak = "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" | |
112 | run_macsec_psk(dev, apdev, params, "macsec_psk_256", cak0=cak, cak1=cak) | |
113 | finally: | |
114 | cleanup_macsec() | |
115 | ||
116 | def set_mka_psk_config(dev, mka_priority=None, integ_only=False, port=None, | |
117 | ckn=None, cak=None): | |
118 | dev.set("eapol_version", "3") | |
119 | dev.set("ap_scan", "0") | |
120 | dev.set("fast_reauth", "1") | |
121 | ||
122 | id = dev.add_network() | |
123 | dev.set_network(id, "key_mgmt", "NONE") | |
124 | if cak is None: | |
125 | cak = "000102030405060708090a0b0c0d0e0f" | |
126 | dev.set_network(id, "mka_cak", cak) | |
127 | if ckn is None: | |
128 | ckn = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" | |
129 | dev.set_network(id, "mka_ckn", ckn) | |
130 | dev.set_network(id, "eapol_flags", "0") | |
131 | dev.set_network(id, "macsec_policy", "1") | |
132 | if integ_only: | |
133 | dev.set_network(id, "macsec_integ_only", "1") | |
134 | if mka_priority is not None: | |
135 | dev.set_network(id, "mka_priority", str(mka_priority)) | |
136 | if port is not None: | |
137 | dev.set_network(id, "macsec_port", str(port)) | |
138 | ||
139 | dev.select_network(id) | |
140 | ||
141 | def log_ip_macsec(): | |
fab49f61 | 142 | cmd = subprocess.Popen(["ip", "macsec", "show"], |
ead573d8 JM |
143 | stdout=subprocess.PIPE, |
144 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 145 | res = cmd.stdout.read().decode() |
ead573d8 JM |
146 | cmd.stdout.close() |
147 | logger.info("ip macsec:\n" + res) | |
148 | ||
149 | def log_ip_link(): | |
fab49f61 | 150 | cmd = subprocess.Popen(["ip", "link", "show"], |
ead573d8 | 151 | stdout=subprocess.PIPE) |
1c48c9bc | 152 | res = cmd.stdout.read().decode() |
ead573d8 JM |
153 | cmd.stdout.close() |
154 | logger.info("ip link:\n" + res) | |
155 | ||
344929a9 | 156 | def add_veth(): |
ead573d8 | 157 | try: |
fab49f61 JM |
158 | subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth", |
159 | "peer", "name", "veth1"]) | |
ead573d8 JM |
160 | except subprocess.CalledProcessError: |
161 | raise HwsimSkip("veth not supported (kernel CONFIG_VETH)") | |
162 | ||
344929a9 JM |
163 | def add_wpas_interfaces(count=2): |
164 | wpa = [] | |
165 | try: | |
166 | for i in range(count): | |
167 | wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5') | |
168 | wpas.interface_add("veth%d" % i, driver="macsec_linux") | |
169 | wpa.append(wpas) | |
bab493b9 | 170 | except Exception as e: |
344929a9 | 171 | if "Failed to add a dynamic wpa_supplicant interface" in str(e): |
3281c159 | 172 | raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)") |
344929a9 JM |
173 | raise |
174 | ||
175 | return wpa | |
176 | ||
0d09bd08 JM |
177 | def lower_addr(addr1, addr2): |
178 | a1 = addr1.split(':') | |
179 | a2 = addr2.split(':') | |
180 | for i in range(6): | |
e1810300 | 181 | if binascii.unhexlify(a1[i]) < binascii.unhexlify(a2[i]): |
0d09bd08 | 182 | return True |
e1810300 | 183 | if binascii.unhexlify(a1[i]) > binascii.unhexlify(a2[i]): |
0d09bd08 JM |
184 | return False |
185 | return False | |
186 | ||
187 | def wait_mka_done(wpa, expect_failure=False): | |
344929a9 JM |
188 | max_iter = 14 if expect_failure else 40 |
189 | for i in range(max_iter): | |
0d09bd08 JM |
190 | done = True |
191 | for w in wpa: | |
192 | secured = w.get_status_field("Secured") | |
193 | peers = int(w.get_status_field("live_peers")) | |
194 | if expect_failure and (secured == "Yes" or peers > 0): | |
195 | raise Exception("MKA completed unexpectedly") | |
196 | if peers != len(wpa) - 1 or secured != "Yes": | |
197 | done = False | |
198 | break | |
199 | w.dump_monitor() | |
200 | if done: | |
201 | break | |
344929a9 JM |
202 | time.sleep(0.5) |
203 | ||
204 | if expect_failure: | |
344929a9 JM |
205 | return |
206 | ||
0d09bd08 JM |
207 | if not done: |
208 | raise Exception("MKA not completed successfully") | |
209 | ||
210 | key_server = None | |
211 | ks_prio = 999 | |
212 | for w in wpa: | |
213 | logger.info("%s STATUS:\n%s" % (w.ifname, w.request("STATUS"))) | |
214 | addr = w.get_status_field("address") | |
215 | prio = int(w.get_status_field("Actor Priority")) | |
216 | if key_server is None or prio < ks_prio or \ | |
217 | (prio == ks_prio and lower_addr(addr, ks_addr)): | |
218 | key_server = w | |
219 | ks_addr = addr | |
220 | ks_prio = prio | |
221 | ||
222 | logger.info("Expected key server: " + key_server.ifname) | |
223 | if key_server.get_status_field("is_key_server") != "Yes": | |
224 | raise Exception("Expected key server was not elected") | |
225 | for w in wpa: | |
226 | if w != key_server and w.get_status_field("is_key_server") == "Yes": | |
227 | raise Exception("Unexpected key server") | |
344929a9 JM |
228 | |
229 | def run_macsec_psk(dev, apdev, params, prefix, integ_only=False, port0=None, | |
230 | port1=None, ckn0=None, ckn1=None, cak0=None, cak1=None, | |
231 | expect_failure=False): | |
232 | add_veth() | |
233 | ||
ead573d8 JM |
234 | cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap") |
235 | cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap") | |
236 | cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap") | |
237 | cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap") | |
238 | ||
239 | for i in range(2): | |
fab49f61 | 240 | subprocess.check_call(["ip", "link", "set", "dev", "veth%d" % i, "up"]) |
ead573d8 JM |
241 | |
242 | cmd = {} | |
243 | cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth0', | |
244 | '-w', cap_veth0, '-s', '2000', | |
245 | '--immediate-mode'], | |
246 | stderr=open('/dev/null', 'w')) | |
247 | cmd[1] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'veth1', | |
248 | '-w', cap_veth1, '-s', '2000', | |
249 | '--immediate-mode'], | |
250 | stderr=open('/dev/null', 'w')) | |
251 | ||
344929a9 JM |
252 | wpa = add_wpas_interfaces() |
253 | wpas0 = wpa[0] | |
254 | wpas1 = wpa[1] | |
ead573d8 JM |
255 | |
256 | set_mka_psk_config(wpas0, integ_only=integ_only, port=port0, ckn=ckn0, | |
257 | cak=cak0) | |
258 | set_mka_psk_config(wpas1, mka_priority=100, integ_only=integ_only, | |
259 | port=port1, ckn=ckn1, cak=cak1) | |
260 | ||
261 | log_ip_macsec() | |
262 | log_ip_link() | |
263 | ||
264 | logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS")) | |
265 | logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS")) | |
266 | logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER")) | |
267 | logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER")) | |
268 | macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname") | |
269 | macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname") | |
270 | ||
0d09bd08 | 271 | wait_mka_done(wpa, expect_failure=expect_failure) |
ead573d8 JM |
272 | |
273 | if expect_failure: | |
ead573d8 JM |
274 | for i in range(len(cmd)): |
275 | cmd[i].terminate() | |
276 | return | |
277 | ||
278 | cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname0, | |
279 | '-w', cap_macsec0, '-s', '2000', | |
280 | '--immediate-mode'], | |
281 | stderr=open('/dev/null', 'w')) | |
282 | cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', macsec_ifname1, | |
283 | '-w', cap_macsec1, '-s', '2000', | |
284 | '--immediate-mode'], | |
285 | stderr=open('/dev/null', 'w')) | |
286 | time.sleep(0.5) | |
287 | ||
90eb910e JM |
288 | mi0 = wpas0.get_status_field("mi") |
289 | mi1 = wpas1.get_status_field("mi") | |
290 | sci0 = wpas0.get_status_field("actor_sci") | |
291 | sci1 = wpas1.get_status_field("actor_sci") | |
292 | logger.info("wpas0 MIB:\n" + wpas0.request("MIB")) | |
293 | logger.info("wpas1 MIB:\n" + wpas1.request("MIB")) | |
294 | mib0 = wpas0.get_mib() | |
295 | mib1 = wpas1.get_mib() | |
296 | ||
297 | if mib0['ieee8021XKayMkaPeerListMI'] != mi1: | |
298 | raise Exception("Unexpected ieee8021XKayMkaPeerListMI value (0)") | |
299 | if mib0['ieee8021XKayMkaPeerListType'] != "1": | |
300 | raise Exception("Unexpected ieee8021XKayMkaPeerListType value (0)") | |
301 | if mib0['ieee8021XKayMkaPeerListSCI'] != sci1: | |
302 | raise Exception("Unexpected ieee8021XKayMkaPeerListSCI value (0)") | |
303 | if mib1['ieee8021XKayMkaPeerListMI'] != mi0: | |
304 | raise Exception("Unexpected ieee8021XKayMkaPeerListMI value (1)") | |
305 | if mib1['ieee8021XKayMkaPeerListType'] != "1": | |
306 | raise Exception("Unexpected ieee8021XKayMkaPeerListType value (1)") | |
307 | if mib1['ieee8021XKayMkaPeerListSCI'] != sci0: | |
308 | raise Exception("Unexpected ieee8021XKayMkaPeerListSCI value (1)") | |
309 | ||
ead573d8 JM |
310 | logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS")) |
311 | logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS")) | |
312 | log_ip_macsec() | |
313 | hwsim_utils.test_connectivity(wpas0, wpas1, | |
314 | ifname1=macsec_ifname0, | |
315 | ifname2=macsec_ifname1, | |
316 | send_len=1400) | |
317 | log_ip_macsec() | |
318 | ||
319 | time.sleep(1) | |
320 | for i in range(len(cmd)): | |
321 | cmd[i].terminate() | |
322 | ||
a2acadf6 | 323 | def cleanup_macsec_br(count): |
b21540e6 | 324 | wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5', monitor=False) |
a2acadf6 JM |
325 | for i in range(count): |
326 | wpas.interface_remove("veth%d" % i) | |
327 | subprocess.call(["ip", "link", "del", "veth%d" % i], | |
328 | stderr=open('/dev/null', 'w')) | |
fe5400dd | 329 | del wpas |
a2acadf6 JM |
330 | subprocess.call(["ip", "link", "set", "brveth", "down"]) |
331 | subprocess.call(["brctl", "delbr", "brveth"]) | |
332 | ||
333 | def test_macsec_psk_br2(dev, apdev): | |
334 | """MACsec PSK (bridge; 2 devices)""" | |
335 | try: | |
336 | run_macsec_psk_br(dev, apdev, 2, [10, 20]) | |
337 | finally: | |
338 | cleanup_macsec_br(count=2) | |
339 | ||
340 | def test_macsec_psk_br2_same_prio(dev, apdev): | |
341 | """MACsec PSK (bridge; 2 devices, same mka_priority)""" | |
342 | try: | |
343 | run_macsec_psk_br(dev, apdev, 2, [None, None]) | |
344 | finally: | |
345 | cleanup_macsec_br(count=2) | |
346 | ||
347 | def test_macsec_psk_br3(dev, apdev): | |
348 | """MACsec PSK (bridge; 3 devices)""" | |
349 | try: | |
350 | run_macsec_psk_br(dev, apdev, 3, [10, 20, 30]) | |
351 | finally: | |
352 | cleanup_macsec_br(count=3) | |
353 | ||
354 | def test_macsec_psk_br3_same_prio(dev, apdev): | |
355 | """MACsec PSK (bridge; 3 devices, same mka_priority)""" | |
356 | try: | |
357 | run_macsec_psk_br(dev, apdev, 3, [None, None, None]) | |
358 | finally: | |
359 | cleanup_macsec_br(count=3) | |
360 | ||
361 | def run_macsec_psk_br(dev, apdev, count, mka_priority): | |
362 | subprocess.check_call(["brctl", "addbr", "brveth"]) | |
363 | subprocess.call(["echo 8 > /sys/devices/virtual/net/brveth/bridge/group_fwd_mask"], | |
364 | shell=True) | |
365 | ||
366 | try: | |
367 | for i in range(count): | |
fab49f61 JM |
368 | subprocess.check_call(["ip", "link", "add", "veth%d" % i, |
369 | "type", "veth", | |
370 | "peer", "name", "vethbr%d" % i]) | |
a2acadf6 | 371 | subprocess.check_call(["ip", "link", "set", "vethbr%d" % i, "up"]) |
fab49f61 JM |
372 | subprocess.check_call(["brctl", "addif", "brveth", |
373 | "vethbr%d" % i]) | |
a2acadf6 JM |
374 | except subprocess.CalledProcessError: |
375 | raise HwsimSkip("veth not supported (kernel CONFIG_VETH)") | |
376 | ||
377 | subprocess.check_call(["ip", "link", "set", "brveth", "up"]) | |
378 | ||
379 | log_ip_link() | |
380 | ||
381 | wpa = add_wpas_interfaces(count=count) | |
382 | for i in range(count): | |
383 | set_mka_psk_config(wpa[i], mka_priority=mka_priority[i]) | |
384 | wpa[i].dump_monitor() | |
385 | wait_mka_done(wpa) | |
386 | ||
387 | macsec_ifname = [] | |
388 | for i in range(count): | |
389 | macsec_ifname.append(wpa[i].get_driver_status_field("parent_ifname")) | |
390 | ||
391 | timeout = 2 | |
392 | max_tries = 2 if count > 2 else 1 | |
393 | success_seen = False | |
394 | failure_seen = False | |
395 | for i in range(1, count): | |
396 | try: | |
397 | hwsim_utils.test_connectivity(wpa[0], wpa[i], | |
398 | ifname1=macsec_ifname[0], | |
399 | ifname2=macsec_ifname[i], | |
400 | send_len=1400, | |
401 | timeout=timeout, max_tries=max_tries) | |
402 | success_seen = True | |
403 | logger.info("Traffic test %d<->%d success" % (0, i)) | |
404 | except: | |
405 | failure_seen = True | |
406 | logger.info("Traffic test %d<->%d failure" % (0, i)) | |
407 | for i in range(2, count): | |
408 | try: | |
409 | hwsim_utils.test_connectivity(wpa[1], wpa[i], | |
410 | ifname1=macsec_ifname[1], | |
411 | ifname2=macsec_ifname[i], | |
412 | send_len=1400, | |
413 | timeout=timeout, max_tries=max_tries) | |
414 | success_seen = True | |
415 | logger.info("Traffic test %d<->%d success" % (1, i)) | |
416 | except: | |
417 | failure_seen = True | |
418 | logger.info("Traffic test %d<->%d failure" % (1, i)) | |
419 | ||
420 | if not success_seen: | |
421 | raise Exception("None of the data traffic tests succeeded") | |
422 | ||
423 | # Something seems to be failing with three device tests semi-regularly, so | |
424 | # do not report this as a failed test case until the real reason behind | |
425 | # those failures have been determined. | |
426 | if failure_seen: | |
427 | if count < 3: | |
428 | raise Exception("Data traffic test failed") | |
429 | else: | |
430 | logger.info("Data traffic test failed - ignore for now for >= 3 device cases") | |
431 | ||
fe5400dd | 432 | for i in range(count): |
b21540e6 | 433 | wpa[i].close_monitor() |
fe5400dd | 434 | for i in range(count): |
b21540e6 | 435 | wpa[0].close_control() |
fe5400dd JM |
436 | del wpa[0] |
437 | ||
ead573d8 JM |
438 | def test_macsec_psk_ns(dev, apdev, params): |
439 | """MACsec PSK (netns)""" | |
440 | try: | |
441 | run_macsec_psk_ns(dev, apdev, params) | |
442 | finally: | |
443 | prefix = "macsec_psk_ns" | |
444 | pidfile = os.path.join(params['logdir'], prefix + ".pid") | |
445 | for i in range(2): | |
446 | was_running = False | |
447 | if os.path.exists(pidfile + str(i)): | |
448 | with open(pidfile + str(i), 'r') as f: | |
449 | pid = int(f.read().strip()) | |
450 | logger.info("wpa_supplicant for wpas%d still running with pid %d - kill it" % (i, pid)) | |
451 | was_running = True | |
452 | os.kill(pid, signal.SIGTERM) | |
453 | if was_running: | |
454 | time.sleep(1) | |
455 | ||
456 | subprocess.call(["ip", "netns", "exec", "ns0", | |
457 | "ip", "link", "del", "veth0"], | |
458 | stderr=open('/dev/null', 'w')) | |
459 | subprocess.call(["ip", "link", "del", "veth0"], | |
460 | stderr=open('/dev/null', 'w')) | |
461 | log_ip_link_ns() | |
462 | subprocess.call(["ip", "netns", "delete", "ns0"], | |
463 | stderr=open('/dev/null', 'w')) | |
464 | subprocess.call(["ip", "netns", "delete", "ns1"], | |
465 | stderr=open('/dev/null', 'w')) | |
466 | ||
467 | def log_ip_macsec_ns(): | |
fab49f61 | 468 | cmd = subprocess.Popen(["ip", "macsec", "show"], |
ead573d8 JM |
469 | stdout=subprocess.PIPE, |
470 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 471 | res = cmd.stdout.read().decode() |
ead573d8 JM |
472 | cmd.stdout.close() |
473 | logger.info("ip macsec show:\n" + res) | |
474 | ||
fab49f61 JM |
475 | cmd = subprocess.Popen(["ip", "netns", "exec", "ns0", |
476 | "ip", "macsec", "show"], | |
ead573d8 JM |
477 | stdout=subprocess.PIPE, |
478 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 479 | res = cmd.stdout.read().decode() |
ead573d8 JM |
480 | cmd.stdout.close() |
481 | logger.info("ip macsec show (ns0):\n" + res) | |
482 | ||
fab49f61 JM |
483 | cmd = subprocess.Popen(["ip", "netns", "exec", "ns1", |
484 | "ip", "macsec", "show"], | |
ead573d8 JM |
485 | stdout=subprocess.PIPE, |
486 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 487 | res = cmd.stdout.read().decode() |
ead573d8 JM |
488 | cmd.stdout.close() |
489 | logger.info("ip macsec show (ns1):\n" + res) | |
490 | ||
491 | def log_ip_link_ns(): | |
fab49f61 | 492 | cmd = subprocess.Popen(["ip", "link", "show"], |
ead573d8 | 493 | stdout=subprocess.PIPE) |
1c48c9bc | 494 | res = cmd.stdout.read().decode() |
ead573d8 JM |
495 | cmd.stdout.close() |
496 | logger.info("ip link:\n" + res) | |
497 | ||
fab49f61 JM |
498 | cmd = subprocess.Popen(["ip", "netns", "exec", "ns0", |
499 | "ip", "link", "show"], | |
ead573d8 JM |
500 | stdout=subprocess.PIPE, |
501 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 502 | res = cmd.stdout.read().decode() |
ead573d8 JM |
503 | cmd.stdout.close() |
504 | logger.info("ip link show (ns0):\n" + res) | |
505 | ||
fab49f61 JM |
506 | cmd = subprocess.Popen(["ip", "netns", "exec", "ns1", |
507 | "ip", "link", "show"], | |
ead573d8 JM |
508 | stdout=subprocess.PIPE, |
509 | stderr=open('/dev/null', 'w')) | |
1c48c9bc | 510 | res = cmd.stdout.read().decode() |
ead573d8 JM |
511 | cmd.stdout.close() |
512 | logger.info("ip link show (ns1):\n" + res) | |
513 | ||
514 | def write_conf(conffile, mka_priority=None): | |
515 | with open(conffile, 'w') as f: | |
516 | f.write("ctrl_interface=DIR=/var/run/wpa_supplicant\n") | |
517 | f.write("eapol_version=3\n") | |
518 | f.write("ap_scan=0\n") | |
519 | f.write("fast_reauth=1\n") | |
520 | f.write("network={\n") | |
26b0c290 MH |
521 | f.write(" key_mgmt=NONE\n") |
522 | f.write(" mka_cak=000102030405060708090a0b0c0d0e0f\n") | |
523 | f.write(" mka_ckn=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\n") | |
ead573d8 JM |
524 | if mka_priority is not None: |
525 | f.write(" mka_priority=%d\n" % mka_priority) | |
26b0c290 MH |
526 | f.write(" eapol_flags=0\n") |
527 | f.write(" macsec_policy=1\n") | |
ead573d8 JM |
528 | f.write("}\n") |
529 | ||
530 | def run_macsec_psk_ns(dev, apdev, params): | |
531 | try: | |
fab49f61 JM |
532 | subprocess.check_call(["ip", "link", "add", "veth0", "type", "veth", |
533 | "peer", "name", "veth1"]) | |
ead573d8 JM |
534 | except subprocess.CalledProcessError: |
535 | raise HwsimSkip("veth not supported (kernel CONFIG_VETH)") | |
536 | ||
537 | prefix = "macsec_psk_ns" | |
538 | conffile = os.path.join(params['logdir'], prefix + ".conf") | |
539 | pidfile = os.path.join(params['logdir'], prefix + ".pid") | |
540 | logfile0 = os.path.join(params['logdir'], prefix + ".veth0.log") | |
541 | logfile1 = os.path.join(params['logdir'], prefix + ".veth1.log") | |
542 | cap_veth0 = os.path.join(params['logdir'], prefix + ".veth0.pcap") | |
543 | cap_veth1 = os.path.join(params['logdir'], prefix + ".veth1.pcap") | |
544 | cap_macsec0 = os.path.join(params['logdir'], prefix + ".macsec0.pcap") | |
545 | cap_macsec1 = os.path.join(params['logdir'], prefix + ".macsec1.pcap") | |
546 | ||
547 | for i in range(2): | |
548 | try: | |
fab49f61 | 549 | subprocess.check_call(["ip", "netns", "add", "ns%d" % i]) |
ead573d8 JM |
550 | except subprocess.CalledProcessError: |
551 | raise HwsimSkip("network namespace not supported (kernel CONFIG_NAMESPACES, CONFIG_NET_NS)") | |
fab49f61 JM |
552 | subprocess.check_call(["ip", "link", "set", "veth%d" % i, |
553 | "netns", "ns%d" %i]) | |
554 | subprocess.check_call(["ip", "netns", "exec", "ns%d" % i, | |
555 | "ip", "link", "set", "dev", "veth%d" % i, | |
556 | "up"]) | |
ead573d8 JM |
557 | |
558 | cmd = {} | |
559 | cmd[0] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0', | |
560 | 'tcpdump', '-p', '-U', '-i', 'veth0', | |
561 | '-w', cap_veth0, '-s', '2000', | |
562 | '--immediate-mode'], | |
563 | stderr=open('/dev/null', 'w')) | |
564 | cmd[1] = subprocess.Popen(['ip', 'netns', 'exec', 'ns1', | |
565 | 'tcpdump', '-p', '-U', '-i', 'veth1', | |
566 | '-w', cap_veth1, '-s', '2000', | |
567 | '--immediate-mode'], | |
568 | stderr=open('/dev/null', 'w')) | |
569 | ||
570 | write_conf(conffile + '0') | |
571 | write_conf(conffile + '1', mka_priority=100) | |
572 | ||
573 | prg = os.path.join(params['logdir'], | |
574 | 'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant') | |
575 | if not os.path.exists(prg): | |
576 | prg = '../../wpa_supplicant/wpa_supplicant' | |
577 | ||
fab49f61 JM |
578 | arg = ["ip", "netns", "exec", "ns0", |
579 | prg, '-BdddtKW', '-P', pidfile + '0', '-f', logfile0, | |
580 | '-g', '/tmp/wpas-veth0', | |
581 | '-Dmacsec_linux', '-c', conffile + '0', '-i', "veth0"] | |
ead573d8 JM |
582 | logger.info("Start wpa_supplicant: " + str(arg)) |
583 | try: | |
584 | subprocess.check_call(arg) | |
585 | except subprocess.CalledProcessError: | |
3281c159 | 586 | raise HwsimSkip("macsec supported (wpa_supplicant CONFIG_MACSEC, CONFIG_DRIVER_MACSEC_LINUX; kernel CONFIG_MACSEC)") |
ead573d8 JM |
587 | |
588 | if os.path.exists("wpa_supplicant-macsec2"): | |
589 | logger.info("Use alternative wpa_supplicant binary for one of the macsec devices") | |
590 | prg = "wpa_supplicant-macsec2" | |
591 | ||
fab49f61 JM |
592 | arg = ["ip", "netns", "exec", "ns1", |
593 | prg, '-BdddtKW', '-P', pidfile + '1', '-f', logfile1, | |
594 | '-g', '/tmp/wpas-veth1', | |
595 | '-Dmacsec_linux', '-c', conffile + '1', '-i', "veth1"] | |
ead573d8 JM |
596 | logger.info("Start wpa_supplicant: " + str(arg)) |
597 | subprocess.check_call(arg) | |
598 | ||
599 | wpas0 = WpaSupplicant('veth0', '/tmp/wpas-veth0') | |
600 | wpas1 = WpaSupplicant('veth1', '/tmp/wpas-veth1') | |
601 | ||
602 | log_ip_macsec_ns() | |
603 | log_ip_link_ns() | |
604 | ||
605 | logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS")) | |
606 | logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS")) | |
607 | logger.info("wpas0 STATUS-DRIVER:\n" + wpas0.request("STATUS-DRIVER")) | |
608 | logger.info("wpas1 STATUS-DRIVER:\n" + wpas1.request("STATUS-DRIVER")) | |
ead573d8 JM |
609 | |
610 | for i in range(10): | |
658ed3ba JM |
611 | macsec_ifname0 = wpas0.get_driver_status_field("parent_ifname") |
612 | macsec_ifname1 = wpas1.get_driver_status_field("parent_ifname") | |
613 | if "Number of Keys" in wpas0.request("STATUS"): | |
614 | key_tx0 = int(wpas0.get_status_field("Number of Keys Distributed")) | |
615 | key_rx0 = int(wpas0.get_status_field("Number of Keys Received")) | |
616 | else: | |
617 | key_tx0 = 0 | |
618 | key_rx0 = 0 | |
619 | if "Number of Keys" in wpas1.request("STATUS"): | |
620 | key_tx1 = int(wpas1.get_status_field("Number of Keys Distributed")) | |
621 | key_rx1 = int(wpas1.get_status_field("Number of Keys Received")) | |
622 | else: | |
623 | key_tx1 = 0 | |
624 | key_rx1 = 0 | |
ead573d8 JM |
625 | if key_rx0 > 0 and key_tx1 > 0: |
626 | break | |
627 | time.sleep(1) | |
628 | ||
629 | cmd[2] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0', | |
630 | 'tcpdump', '-p', '-U', '-i', macsec_ifname0, | |
631 | '-w', cap_macsec0, '-s', '2000', | |
632 | '--immediate-mode'], | |
633 | stderr=open('/dev/null', 'w')) | |
634 | cmd[3] = subprocess.Popen(['ip', 'netns', 'exec', 'ns0', | |
635 | 'tcpdump', '-p', '-U', '-i', macsec_ifname1, | |
636 | '-w', cap_macsec1, '-s', '2000', | |
637 | '--immediate-mode'], | |
638 | stderr=open('/dev/null', 'w')) | |
639 | time.sleep(0.5) | |
640 | ||
641 | logger.info("wpas0 STATUS:\n" + wpas0.request("STATUS")) | |
642 | logger.info("wpas1 STATUS:\n" + wpas1.request("STATUS")) | |
643 | log_ip_macsec_ns() | |
644 | hwsim_utils.test_connectivity(wpas0, wpas1, | |
645 | ifname1=macsec_ifname0, | |
646 | ifname2=macsec_ifname1, | |
647 | send_len=1400) | |
648 | log_ip_macsec_ns() | |
649 | ||
650 | subprocess.check_call(['ip', 'netns', 'exec', 'ns0', | |
651 | 'ip', 'addr', 'add', '192.168.248.17/30', | |
652 | 'dev', macsec_ifname0]) | |
653 | subprocess.check_call(['ip', 'netns', 'exec', 'ns1', | |
654 | 'ip', 'addr', 'add', '192.168.248.18/30', | |
655 | 'dev', macsec_ifname1]) | |
656 | c = subprocess.Popen(['ip', 'netns', 'exec', 'ns0', | |
657 | 'ping', '-c', '2', '192.168.248.18'], | |
658 | stdout=subprocess.PIPE) | |
1c48c9bc | 659 | res = c.stdout.read().decode() |
ead573d8 JM |
660 | c.stdout.close() |
661 | logger.info("ping:\n" + res) | |
662 | if "2 packets transmitted, 2 received" not in res: | |
663 | raise Exception("ping did not work") | |
664 | ||
b21540e6 | 665 | wpas0.close_monitor() |
ead573d8 | 666 | wpas0.request("TERMINATE") |
b21540e6 | 667 | wpas0.close_control() |
ead573d8 | 668 | del wpas0 |
b21540e6 | 669 | wpas1.close_monitor() |
ead573d8 | 670 | wpas1.request("TERMINATE") |
b21540e6 | 671 | wpas1.close_control() |
ead573d8 JM |
672 | del wpas1 |
673 | ||
674 | time.sleep(1) | |
675 | for i in range(len(cmd)): | |
676 | cmd[i].terminate() | |
344929a9 JM |
677 | |
678 | def test_macsec_psk_fail_cp(dev, apdev): | |
679 | """MACsec PSK local failures in CP state machine""" | |
680 | try: | |
681 | add_veth() | |
682 | wpa = add_wpas_interfaces() | |
683 | set_mka_psk_config(wpa[0]) | |
684 | with alloc_fail(wpa[0], 1, "sm_CP_RECEIVE_Enter"): | |
685 | set_mka_psk_config(wpa[1]) | |
686 | wait_fail_trigger(wpa[0], "GET_ALLOC_FAIL", max_iter=100) | |
687 | ||
0d09bd08 | 688 | wait_mka_done(wpa) |
344929a9 JM |
689 | finally: |
690 | cleanup_macsec() | |
691 | ||
692 | def test_macsec_psk_fail_cp2(dev, apdev): | |
693 | """MACsec PSK local failures in CP state machine (2)""" | |
694 | try: | |
695 | add_veth() | |
696 | wpa = add_wpas_interfaces() | |
697 | set_mka_psk_config(wpa[0]) | |
698 | with alloc_fail(wpa[1], 1, "ieee802_1x_cp_sm_init"): | |
699 | set_mka_psk_config(wpa[1]) | |
700 | wait_fail_trigger(wpa[1], "GET_ALLOC_FAIL", max_iter=100) | |
701 | ||
0d09bd08 | 702 | wait_mka_done(wpa) |
344929a9 JM |
703 | finally: |
704 | cleanup_macsec() |