test-network: rename l2tp_tunnel_remove -> remove_l2tp_tunnels
[thirdparty/systemd.git] / test / test-network / systemd-networkd-tests.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
4
5 import argparse
6 import os
7 import re
8 import shutil
9 import signal
10 import subprocess
11 import sys
12 import time
13 import unittest
14 from shutil import copytree
15
16 network_unit_file_path='/run/systemd/network'
17 networkd_runtime_directory='/run/systemd/netif'
18 networkd_ci_path='/run/networkd-ci'
19 network_sysctl_ipv6_path='/proc/sys/net/ipv6/conf'
20 network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
21
22 dnsmasq_pid_file='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file='/run/networkd-ci/test-dnsmasq-log-file'
24
25 networkd_bin='/usr/lib/systemd/systemd-networkd'
26 wait_online_bin='/usr/lib/systemd/systemd-networkd-wait-online'
27 networkctl_bin='/usr/bin/networkctl'
28 use_valgrind=False
29 enable_debug=False
30 env = {}
31 asan_options=None
32 lsan_options=None
33 ubsan_options=None
34
35 def check_output(*command, **kwargs):
36     # This replaces both check_output and check_call (output can be ignored)
37     command = command[0].split() + list(command[1:])
38     return subprocess.check_output(command, universal_newlines=True, **kwargs).rstrip()
39
40 def call(*command, **kwargs):
41     command = command[0].split() + list(command[1:])
42     return subprocess.call(command, universal_newlines=True, **kwargs)
43
44 def run(*command, **kwargs):
45     command = command[0].split() + list(command[1:])
46     return subprocess.run(command, universal_newlines=True, **kwargs)
47
48 def is_module_available(module_name):
49     lsmod_output = check_output('lsmod')
50     module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
51     return module_re.search(lsmod_output) or not call('modprobe', module_name)
52
53 def expectedFailureIfModuleIsNotAvailable(module_name):
54     def f(func):
55         if not is_module_available(module_name):
56             return unittest.expectedFailure(func)
57         return func
58
59     return f
60
61 def expectedFailureIfERSPANModuleIsNotAvailable():
62     def f(func):
63         rc = call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123')
64         if rc == 0:
65             call('ip link del erspan99')
66             return func
67         else:
68             return unittest.expectedFailure(func)
69
70     return f
71
72 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
73     def f(func):
74         rc = call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
75         if rc == 0:
76             call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
77             return func
78         else:
79             return unittest.expectedFailure(func)
80
81     return f
82
83 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
84     def f(func):
85         rc = call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
86         if rc == 0:
87             call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
88             return func
89         else:
90             return unittest.expectedFailure(func)
91
92     return f
93
94 def expectedFailureIfEthtoolDoesNotSupportDriver():
95     def f(func):
96         support = False
97         rc = call('ip link add name dummy99 type dummy')
98         if rc == 0:
99             ret = run('udevadm info -w10s /sys/class/net/dummy99', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
100             if ret.returncode == 0 and 'E: ID_NET_DRIVER=dummy' in ret.stdout.rstrip():
101                 support = True
102             call('ip link del dummy99')
103
104         if support:
105             return func
106         else:
107             return unittest.expectedFailure(func)
108
109     return f
110
111 def setUpModule():
112     os.makedirs(network_unit_file_path, exist_ok=True)
113     os.makedirs(networkd_ci_path, exist_ok=True)
114
115     shutil.rmtree(networkd_ci_path)
116     copytree(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'), networkd_ci_path)
117
118     check_output('systemctl stop systemd-networkd.socket')
119     check_output('systemctl stop systemd-networkd.service')
120
121     drop_in = [
122         '[Service]',
123         'Restart=no',
124         'ExecStart=',
125     ]
126     if use_valgrind:
127         drop_in += [
128             'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
129             'PrivateTmp=yes'
130         ]
131     else:
132         drop_in += ['ExecStart=!!' + networkd_bin]
133     if enable_debug:
134         drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
135     if asan_options:
136         drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
137     if lsan_options:
138         drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
139     if ubsan_options:
140         drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
141     if asan_options or lsan_options or ubsan_options:
142         drop_in += ['SystemCallFilter=']
143     if use_valgrind or asan_options or lsan_options or ubsan_options:
144         drop_in += ['MemoryDenyWriteExecute=no']
145
146     os.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok=True)
147     with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w') as f:
148         f.write('\n'.join(drop_in))
149
150     check_output('systemctl daemon-reload')
151     print(check_output('systemctl cat systemd-networkd.service'))
152
153 def tearDownModule():
154     shutil.rmtree(networkd_ci_path)
155
156     check_output('systemctl stop systemd-networkd.service')
157
158     shutil.rmtree('/run/systemd/system/systemd-networkd.service.d')
159     check_output('systemctl daemon-reload')
160
161     check_output('systemctl start systemd-networkd.socket')
162     check_output('systemctl start systemd-networkd.service')
163
164 def read_link_attr(link, dev, attribute):
165     with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
166         return f.readline().strip()
167
168 def read_bridge_port_attr(bridge, link, attribute):
169     path_bridge = os.path.join('/sys/devices/virtual/net', bridge)
170     path_port = 'lower_' + link + '/brport'
171     path = os.path.join(path_bridge, path_port)
172
173     with open(os.path.join(path, attribute)) as f:
174         return f.readline().strip()
175
176 def link_exists(link):
177     return os.path.exists(os.path.join('/sys/class/net', link))
178
179 def remove_links(links):
180     for link in links:
181         if link_exists(link):
182             call('ip link del dev', link)
183     time.sleep(1)
184
185 def remove_fou_ports(ports):
186     for port in ports:
187         call('ip fou del port', port, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
188
189 def remove_routing_policy_rule_tables(tables):
190     for table in tables:
191         rc = 0
192         while rc == 0:
193             rc = call('ip rule del table', table, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
194
195 def remove_routes(routes):
196     for route_type, addr in routes:
197         call('ip route del', route_type, addr, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
198
199 def remove_l2tp_tunnels(tunnel_ids):
200     output = check_output('ip l2tp show tunnel')
201     for tid in tunnel_ids:
202         words='Tunnel ' + tid + ', encap'
203         if words in output:
204             call('ip l2tp del tunnel tid', tid)
205     time.sleep(1)
206
207 def read_ipv6_sysctl_attr(link, attribute):
208     with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
209         return f.readline().strip()
210
211 def read_ipv4_sysctl_attr(link, attribute):
212     with open(os.path.join(os.path.join(network_sysctl_ipv4_path, link), attribute)) as f:
213         return f.readline().strip()
214
215 def copy_unit_to_networkd_unit_path(*units):
216     print()
217     for unit in units:
218         shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
219         if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
220             copytree(os.path.join(networkd_ci_path, unit + '.d'), os.path.join(network_unit_file_path, unit + '.d'))
221
222 def remove_unit_from_networkd_path(units):
223     for unit in units:
224         if (os.path.exists(os.path.join(network_unit_file_path, unit))):
225             os.remove(os.path.join(network_unit_file_path, unit))
226             if (os.path.exists(os.path.join(network_unit_file_path, unit + '.d'))):
227                 shutil.rmtree(os.path.join(network_unit_file_path, unit + '.d'))
228
229 def warn_about_firewalld():
230     rc = call('systemctl -q is-active firewalld.service')
231     if rc == 0:
232         print('\nWARNING: firewalld.service is active. The test may fail.')
233
234 def start_dnsmasq(additional_options='', ipv4_range='192.168.5.10,192.168.5.200', ipv6_range='2600::10,2600::20', lease_time='1h'):
235     warn_about_firewalld()
236     dnsmasq_command = f'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
237     check_output(dnsmasq_command)
238
239 def stop_dnsmasq(pid_file):
240     if os.path.exists(pid_file):
241         with open(pid_file, 'r') as f:
242             pid = f.read().rstrip(' \t\r\n\0')
243             os.kill(int(pid), signal.SIGTERM)
244
245         os.remove(pid_file)
246
247 def search_words_in_dnsmasq_log(words, show_all=False):
248     if os.path.exists(dnsmasq_log_file):
249         with open (dnsmasq_log_file) as in_file:
250             contents = in_file.read()
251             if show_all:
252                 print(contents)
253             for line in contents.splitlines():
254                 if words in line:
255                     in_file.close()
256                     print("%s, %s" % (words, line))
257                     return True
258     return False
259
260 def remove_lease_file():
261     if os.path.exists(os.path.join(networkd_ci_path, 'lease')):
262         os.remove(os.path.join(networkd_ci_path, 'lease'))
263
264 def remove_log_file():
265     if os.path.exists(dnsmasq_log_file):
266         os.remove(dnsmasq_log_file)
267
268 def start_networkd(sleep_sec=5, remove_state_files=True):
269     if (remove_state_files and
270         os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
271         check_output('systemctl stop systemd-networkd')
272         os.remove(os.path.join(networkd_runtime_directory, 'state'))
273         check_output('systemctl start systemd-networkd')
274     else:
275         check_output('systemctl restart systemd-networkd')
276     if sleep_sec > 0:
277         time.sleep(sleep_sec)
278
279 def wait_online(links_with_operstate, timeout='20s', bool_any=False):
280     args = wait_online_cmd + [f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
281     if bool_any:
282         args += ['--any']
283     try:
284         check_output(*args, env=env)
285     except subprocess.CalledProcessError:
286         for link in links_with_operstate:
287             output = check_output(*networkctl_cmd, 'status', link.split(':')[0], env=env)
288             print(output)
289         raise
290
291 def get_operstate(link, show_status=True, setup_state='configured'):
292     output = check_output(*networkctl_cmd, 'status', link, env=env)
293     if show_status:
294         print(output)
295     for line in output.splitlines():
296         if 'State:' in line and (not setup_state or setup_state in line):
297             return line.split()[1]
298     return None
299
300 class Utilities():
301     def check_link_exists(self, link):
302         self.assertTrue(link_exists(link))
303
304     def check_operstate(self, link, expected, show_status=True, setup_state='configured'):
305         self.assertRegex(get_operstate(link, show_status, setup_state), expected)
306
307     def wait_address(self, link, address_regex, scope='global', ipv='', timeout_sec=100):
308         for i in range(timeout_sec):
309             if i > 0:
310                 time.sleep(1)
311             output = check_output(f'ip {ipv} address show dev {link} scope {scope}')
312             if re.search(address_regex, output):
313                 break
314         else:
315             self.assertRegex(output, address_regex)
316
317 class NetworkctlTests(unittest.TestCase, Utilities):
318
319     links = [
320         'test1',
321         'veth99',
322     ]
323
324     units = [
325         '11-dummy.netdev',
326         '11-dummy-mtu.netdev',
327         '11-dummy.network',
328         '25-veth.netdev',
329         'netdev-link-local-addressing-yes.network',
330     ]
331
332     def setUp(self):
333         remove_links(self.links)
334
335     def tearDown(self):
336         remove_links(self.links)
337         remove_unit_from_networkd_path(self.units)
338
339     def test_glob(self):
340         copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
341         start_networkd(0)
342
343         wait_online(['test1:degraded'])
344
345         output = check_output(*networkctl_cmd, 'list', env=env)
346         self.assertRegex(output, '1 lo ')
347         self.assertRegex(output, 'test1')
348
349         output = check_output(*networkctl_cmd, 'list', 'test1', env=env)
350         self.assertNotRegex(output, '1 lo ')
351         self.assertRegex(output, 'test1')
352
353         output = check_output(*networkctl_cmd, 'list', 'te*', env=env)
354         self.assertNotRegex(output, '1 lo ')
355         self.assertRegex(output, 'test1')
356
357         output = check_output(*networkctl_cmd, 'status', 'te*', env=env)
358         self.assertNotRegex(output, '1: lo ')
359         self.assertRegex(output, 'test1')
360
361         output = check_output(*networkctl_cmd, 'status', 'tes[a-z][0-9]', env=env)
362         self.assertNotRegex(output, '1: lo ')
363         self.assertRegex(output, 'test1')
364
365     def test_mtu(self):
366         copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
367         start_networkd(0)
368
369         wait_online(['test1:degraded'])
370
371         output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
372         self.assertRegex(output, 'MTU: 1600')
373
374     @expectedFailureIfEthtoolDoesNotSupportDriver()
375     def test_udev_driver(self):
376         copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
377                                         '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
378         start_networkd(0)
379
380         wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
381
382         output = check_output(*networkctl_cmd, 'status', 'test1', env=env)
383         self.assertRegex(output, 'Driver: dummy')
384
385         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
386         self.assertRegex(output, 'Driver: veth')
387
388         output = check_output(*networkctl_cmd, 'status', 'veth-peer', env=env)
389         self.assertRegex(output, 'Driver: veth')
390
391     def test_delete_links(self):
392         copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
393                                         '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
394         start_networkd(0)
395
396         wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
397
398         check_output(*networkctl_cmd, 'delete', 'test1', 'veth99')
399         self.assertFalse(link_exists('test1'))
400         self.assertFalse(link_exists('veth99'))
401         self.assertFalse(link_exists('veth-peer'))
402
403 class NetworkdNetDevTests(unittest.TestCase, Utilities):
404
405     links =[
406         '6rdtun99',
407         'bond99',
408         'bridge99',
409         'dropin-test',
410         'dummy98',
411         'erspan98',
412         'erspan99',
413         'geneve99',
414         'gretap96',
415         'gretap98',
416         'gretap99',
417         'gretun96',
418         'gretun97',
419         'gretun98',
420         'gretun99',
421         'ip6gretap98',
422         'ip6gretap99',
423         'ip6gretun97',
424         'ip6gretun98',
425         'ip6gretun99',
426         'ip6tnl97',
427         'ip6tnl98',
428         'ip6tnl99',
429         'ipiptun96',
430         'ipiptun97',
431         'ipiptun98',
432         'ipiptun99',
433         'ipvlan99',
434         'ipvtap99',
435         'isataptun99',
436         'macvlan99',
437         'macvtap99',
438         'nlmon99',
439         'sittun96',
440         'sittun97',
441         'sittun98',
442         'sittun99',
443         'tap99',
444         'test1',
445         'tun99',
446         'vcan99',
447         'veth99',
448         'vlan99',
449         'vrf99',
450         'vti6tun97',
451         'vti6tun98',
452         'vti6tun99',
453         'vtitun97',
454         'vtitun98',
455         'vtitun99',
456         'vxcan99',
457         'vxlan99',
458         'wg98',
459         'wg99']
460
461     units = [
462         '10-dropin-test.netdev',
463         '11-dummy.netdev',
464         '11-dummy.network',
465         '12-dummy.netdev',
466         '15-name-conflict-test.netdev',
467         '21-macvlan.netdev',
468         '21-macvtap.netdev',
469         '21-vlan-test1.network',
470         '21-vlan.netdev',
471         '21-vlan.network',
472         '25-6rd-tunnel.netdev',
473         '25-bond.netdev',
474         '25-bond-balanced-tlb.netdev',
475         '25-bridge.netdev',
476         '25-bridge-configure-without-carrier.network',
477         '25-bridge.network',
478         '25-erspan-tunnel-local-any.netdev',
479         '25-erspan-tunnel.netdev',
480         '25-fou-gretap.netdev',
481         '25-fou-gre.netdev',
482         '25-fou-ipip.netdev',
483         '25-fou-ipproto-gre.netdev',
484         '25-fou-ipproto-ipip.netdev',
485         '25-fou-sit.netdev',
486         '25-geneve.netdev',
487         '25-gretap-tunnel-local-any.netdev',
488         '25-gretap-tunnel.netdev',
489         '25-gre-tunnel-local-any.netdev',
490         '25-gre-tunnel-remote-any.netdev',
491         '25-gre-tunnel.netdev',
492         '25-ip6gretap-tunnel-local-any.netdev',
493         '25-ip6gretap-tunnel.netdev',
494         '25-ip6gre-tunnel-local-any.netdev',
495         '25-ip6gre-tunnel-remote-any.netdev',
496         '25-ip6gre-tunnel.netdev',
497         '25-ip6tnl-tunnel-remote-any.netdev',
498         '25-ip6tnl-tunnel-local-any.netdev',
499         '25-ip6tnl-tunnel.netdev',
500         '25-ipip-tunnel-independent.netdev',
501         '25-ipip-tunnel-local-any.netdev',
502         '25-ipip-tunnel-remote-any.netdev',
503         '25-ipip-tunnel.netdev',
504         '25-ipvlan.netdev',
505         '25-ipvtap.netdev',
506         '25-isatap-tunnel.netdev',
507         '25-macsec.key',
508         '25-macsec.netdev',
509         '25-macsec.network',
510         '25-nlmon.netdev',
511         '25-sit-tunnel-local-any.netdev',
512         '25-sit-tunnel-remote-any.netdev',
513         '25-sit-tunnel.netdev',
514         '25-tap.netdev',
515         '25-tun.netdev',
516         '25-tunnel-local-any.network',
517         '25-tunnel-remote-any.network',
518         '25-tunnel.network',
519         '25-vcan.netdev',
520         '25-veth.netdev',
521         '25-vrf.netdev',
522         '25-vti6-tunnel-local-any.netdev',
523         '25-vti6-tunnel-remote-any.netdev',
524         '25-vti6-tunnel.netdev',
525         '25-vti-tunnel-local-any.netdev',
526         '25-vti-tunnel-remote-any.netdev',
527         '25-vti-tunnel.netdev',
528         '25-vxcan.netdev',
529         '25-vxlan.netdev',
530         '25-wireguard-23-peers.netdev',
531         '25-wireguard-23-peers.network',
532         '25-wireguard-preshared-key.txt',
533         '25-wireguard-private-key.txt',
534         '25-wireguard.netdev',
535         '25-wireguard.network',
536         '6rd.network',
537         'erspan.network',
538         'gre.network',
539         'gretap.network',
540         'gretun.network',
541         'ip6gretap.network',
542         'ip6gretun.network',
543         'ip6tnl.network',
544         'ipip.network',
545         'ipvlan.network',
546         'ipvtap.network',
547         'isatap.network',
548         'macsec.network',
549         'macvlan.network',
550         'macvtap.network',
551         'netdev-link-local-addressing-yes.network',
552         'sit.network',
553         'vti6.network',
554         'vti.network',
555         'vxlan-test1.network',
556         'vxlan.network']
557
558     fou_ports = [
559         '55555',
560         '55556']
561
562     def setUp(self):
563         remove_fou_ports(self.fou_ports)
564         remove_links(self.links)
565
566     def tearDown(self):
567         remove_fou_ports(self.fou_ports)
568         remove_links(self.links)
569         remove_unit_from_networkd_path(self.units)
570
571     def test_dropin_and_name_conflict(self):
572         copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
573         start_networkd(0)
574
575         wait_online(['dropin-test:off'])
576
577         output = check_output('ip link show dropin-test')
578         print(output)
579         self.assertRegex(output, '00:50:56:c0:00:28')
580
581     def test_wait_online_any(self):
582         copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
583         start_networkd(0)
584
585         wait_online(['bridge99', 'test1:degraded'], bool_any=True)
586
587         self.check_operstate('bridge99', '(?:off|no-carrier)', setup_state='configuring')
588         self.check_operstate('test1', 'degraded')
589
590     def test_bridge(self):
591         copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
592         start_networkd(0)
593
594         wait_online(['bridge99:no-carrier'])
595
596         tick = os.sysconf('SC_CLK_TCK')
597         self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick))
598         self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick))
599         self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick))
600         self.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick))
601         self.assertEqual(9,         int(read_link_attr('bridge99', 'bridge','priority')))
602         self.assertEqual(1,         int(read_link_attr('bridge99', 'bridge','multicast_querier')))
603         self.assertEqual(1,         int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
604         self.assertEqual(1,         int(read_link_attr('bridge99', 'bridge','stp_state')))
605
606     def test_bond(self):
607         copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
608         start_networkd(0)
609
610         wait_online(['bond99:off', 'bond98:off'])
611
612         self.assertEqual('802.3ad 4',         read_link_attr('bond99', 'bonding', 'mode'))
613         self.assertEqual('layer3+4 1',        read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
614         self.assertEqual('1000',              read_link_attr('bond99', 'bonding', 'miimon'))
615         self.assertEqual('fast 1',            read_link_attr('bond99', 'bonding', 'lacp_rate'))
616         self.assertEqual('2000',              read_link_attr('bond99', 'bonding', 'updelay'))
617         self.assertEqual('2000',              read_link_attr('bond99', 'bonding', 'downdelay'))
618         self.assertEqual('4',                 read_link_attr('bond99', 'bonding', 'resend_igmp'))
619         self.assertEqual('1',                 read_link_attr('bond99', 'bonding', 'min_links'))
620         self.assertEqual('1218',              read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
621         self.assertEqual('811',               read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
622         self.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
623
624         self.assertEqual('balance-tlb 5',     read_link_attr('bond98', 'bonding', 'mode'))
625         self.assertEqual('1',                 read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
626
627     def test_vlan(self):
628         copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
629                                         '21-vlan.network', '21-vlan-test1.network')
630         start_networkd(0)
631
632         wait_online(['test1:degraded', 'vlan99:routable'])
633
634         output = check_output('ip -d link show test1')
635         print(output)
636         self.assertRegex(output, ' mtu 2000 ')
637
638         output = check_output('ip -d link show vlan99')
639         print(output)
640         self.assertRegex(output, ' mtu 2000 ')
641         self.assertRegex(output, 'REORDER_HDR')
642         self.assertRegex(output, 'LOOSE_BINDING')
643         self.assertRegex(output, 'GVRP')
644         self.assertRegex(output, 'MVRP')
645         self.assertRegex(output, ' id 99 ')
646
647         output = check_output('ip -4 address show dev test1')
648         print(output)
649         self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
650         self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
651
652         output = check_output('ip -4 address show dev vlan99')
653         print(output)
654         self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
655
656     def test_macvtap(self):
657         for mode in ['private', 'vepa', 'bridge', 'passthru']:
658             with self.subTest(mode=mode):
659                 if mode != 'private':
660                     self.tearDown()
661                 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
662                                                 '11-dummy.netdev', 'macvtap.network')
663                 with open(os.path.join(network_unit_file_path, '21-macvtap.netdev'), mode='a') as f:
664                     f.write('[MACVTAP]\nMode=' + mode)
665                 start_networkd(0)
666
667                 wait_online(['macvtap99:degraded', 'test1:degraded'])
668
669                 output = check_output('ip -d link show macvtap99')
670                 print(output)
671                 self.assertRegex(output, 'macvtap mode ' + mode + ' ')
672
673     def test_macvlan(self):
674         for mode in ['private', 'vepa', 'bridge', 'passthru']:
675             with self.subTest(mode=mode):
676                 if mode != 'private':
677                     self.tearDown()
678                 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
679                                                 '11-dummy.netdev', 'macvlan.network')
680                 with open(os.path.join(network_unit_file_path, '21-macvlan.netdev'), mode='a') as f:
681                     f.write('[MACVLAN]\nMode=' + mode)
682                 start_networkd(0)
683
684                 wait_online(['macvlan99:degraded', 'test1:degraded'])
685
686                 output = check_output('ip -d link show test1')
687                 print(output)
688                 self.assertRegex(output, ' mtu 2000 ')
689
690                 output = check_output('ip -d link show macvlan99')
691                 print(output)
692                 self.assertRegex(output, ' mtu 2000 ')
693                 self.assertRegex(output, 'macvlan mode ' + mode + ' ')
694
695     @expectedFailureIfModuleIsNotAvailable('ipvlan')
696     def test_ipvlan(self):
697         for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
698             with self.subTest(mode=mode, flag=flag):
699                 if mode != 'L2':
700                     self.tearDown()
701                 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
702                                                 '11-dummy.netdev', 'ipvlan.network')
703                 with open(os.path.join(network_unit_file_path, '25-ipvlan.netdev'), mode='a') as f:
704                     f.write('[IPVLAN]\nMode=' + mode + '\nFlags=' + flag)
705
706                 start_networkd(0)
707                 wait_online(['ipvlan99:degraded', 'test1:degraded'])
708
709                 output = check_output('ip -d link show ipvlan99')
710                 print(output)
711                 self.assertRegex(output, 'ipvlan  *mode ' + mode.lower() + ' ' + flag)
712
713     @expectedFailureIfModuleIsNotAvailable('ipvtap')
714     def test_ipvtap(self):
715         for mode, flag in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
716             with self.subTest(mode=mode, flag=flag):
717                 if mode != 'L2':
718                     self.tearDown()
719                 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
720                                                 '11-dummy.netdev', 'ipvtap.network')
721                 with open(os.path.join(network_unit_file_path, '25-ipvtap.netdev'), mode='a') as f:
722                     f.write('[IPVTAP]\nMode=' + mode + '\nFlags=' + flag)
723
724                 start_networkd(0)
725                 wait_online(['ipvtap99:degraded', 'test1:degraded'])
726
727                 output = check_output('ip -d link show ipvtap99')
728                 print(output)
729                 self.assertRegex(output, 'ipvtap  *mode ' + mode.lower() + ' ' + flag)
730
731     def test_veth(self):
732         copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
733         start_networkd(0)
734
735         wait_online(['veth99:degraded', 'veth-peer:degraded'])
736
737         output = check_output('ip -d link show veth99')
738         print(output)
739         self.assertRegex(output, 'link/ether 12:34:56:78:9a:bc')
740         output = check_output('ip -d link show veth-peer')
741         print(output)
742         self.assertRegex(output, 'link/ether 12:34:56:78:9a:bd')
743
744     def test_tun(self):
745         copy_unit_to_networkd_unit_path('25-tun.netdev')
746         start_networkd(0)
747
748         wait_online(['tun99:off'])
749
750         output = check_output('ip -d link show tun99')
751         print(output)
752         # Old ip command does not support IFF_ flags
753         self.assertRegex(output, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
754
755     def test_tap(self):
756         copy_unit_to_networkd_unit_path('25-tap.netdev')
757         start_networkd(0)
758
759         wait_online(['tap99:off'])
760
761         output = check_output('ip -d link show tap99')
762         print(output)
763         # Old ip command does not support IFF_ flags
764         self.assertRegex(output, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
765
766     @expectedFailureIfModuleIsNotAvailable('vrf')
767     def test_vrf(self):
768         copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
769         start_networkd(0)
770
771         wait_online(['vrf99:carrier'])
772
773     @expectedFailureIfModuleIsNotAvailable('vcan')
774     def test_vcan(self):
775         copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
776         start_networkd(0)
777
778         wait_online(['vcan99:carrier'])
779
780     @expectedFailureIfModuleIsNotAvailable('vxcan')
781     def test_vxcan(self):
782         copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
783         start_networkd(0)
784
785         wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
786
787     @expectedFailureIfModuleIsNotAvailable('wireguard')
788     def test_wireguard(self):
789         copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
790                                         '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
791                                         '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
792         start_networkd(0)
793         wait_online(['wg99:carrier', 'wg98:routable'])
794
795         if shutil.which('wg'):
796             call('wg')
797
798             output = check_output('wg show wg99 listen-port')
799             self.assertRegex(output, '51820')
800             output = check_output('wg show wg99 fwmark')
801             self.assertRegex(output, '0x4d2')
802             output = check_output('wg show wg99 allowed-ips')
803             self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
804             self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
805             output = check_output('wg show wg99 persistent-keepalive')
806             self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
807             output = check_output('wg show wg99 endpoints')
808             self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
809             output = check_output('wg show wg99 private-key')
810             self.assertRegex(output, r'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
811             output = check_output('wg show wg99 preshared-keys')
812             self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=  IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
813             self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=     cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
814
815             output = check_output('wg show wg98 private-key')
816             self.assertRegex(output, r'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
817
818     def test_geneve(self):
819         copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
820         start_networkd(0)
821
822         wait_online(['geneve99:degraded'])
823
824         output = check_output('ip -d link show geneve99')
825         print(output)
826         self.assertRegex(output, '192.168.22.1')
827         self.assertRegex(output, '6082')
828         self.assertRegex(output, 'udpcsum')
829         self.assertRegex(output, 'udp6zerocsumrx')
830
831     def test_ipip_tunnel(self):
832         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
833                                         '25-ipip-tunnel.netdev', '25-tunnel.network',
834                                         '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
835                                         '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
836         start_networkd(0)
837         wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
838
839         output = check_output('ip -d link show ipiptun99')
840         print(output)
841         self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
842         output = check_output('ip -d link show ipiptun98')
843         print(output)
844         self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
845         output = check_output('ip -d link show ipiptun97')
846         print(output)
847         self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
848
849     def test_gre_tunnel(self):
850         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
851                                         '25-gre-tunnel.netdev', '25-tunnel.network',
852                                         '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
853                                         '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
854         start_networkd(0)
855         wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
856
857         output = check_output('ip -d link show gretun99')
858         print(output)
859         self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
860         self.assertRegex(output, 'ikey 1.2.3.103')
861         self.assertRegex(output, 'okey 1.2.4.103')
862         self.assertRegex(output, 'iseq')
863         self.assertRegex(output, 'oseq')
864         output = check_output('ip -d link show gretun98')
865         print(output)
866         self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
867         self.assertRegex(output, 'ikey 0.0.0.104')
868         self.assertRegex(output, 'okey 0.0.0.104')
869         self.assertNotRegex(output, 'iseq')
870         self.assertNotRegex(output, 'oseq')
871         output = check_output('ip -d link show gretun97')
872         print(output)
873         self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
874         self.assertRegex(output, 'ikey 0.0.0.105')
875         self.assertRegex(output, 'okey 0.0.0.105')
876         self.assertNotRegex(output, 'iseq')
877         self.assertNotRegex(output, 'oseq')
878
879     def test_ip6gre_tunnel(self):
880         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
881                                         '25-ip6gre-tunnel.netdev', '25-tunnel.network',
882                                         '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
883                                         '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
884         start_networkd(5)
885
886         # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
887
888         self.check_link_exists('dummy98')
889         self.check_link_exists('ip6gretun99')
890         self.check_link_exists('ip6gretun98')
891         self.check_link_exists('ip6gretun97')
892
893         output = check_output('ip -d link show ip6gretun99')
894         print(output)
895         self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
896         output = check_output('ip -d link show ip6gretun98')
897         print(output)
898         self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
899         output = check_output('ip -d link show ip6gretun97')
900         print(output)
901         self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
902
903     def test_gretap_tunnel(self):
904         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
905                                         '25-gretap-tunnel.netdev', '25-tunnel.network',
906                                         '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
907         start_networkd(0)
908         wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
909
910         output = check_output('ip -d link show gretap99')
911         print(output)
912         self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
913         self.assertRegex(output, 'ikey 0.0.0.106')
914         self.assertRegex(output, 'okey 0.0.0.106')
915         self.assertRegex(output, 'iseq')
916         self.assertRegex(output, 'oseq')
917         output = check_output('ip -d link show gretap98')
918         print(output)
919         self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
920         self.assertRegex(output, 'ikey 0.0.0.107')
921         self.assertRegex(output, 'okey 0.0.0.107')
922         self.assertRegex(output, 'iseq')
923         self.assertRegex(output, 'oseq')
924
925     def test_ip6gretap_tunnel(self):
926         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
927                                         '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
928                                         '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
929         start_networkd(0)
930         wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
931
932         output = check_output('ip -d link show ip6gretap99')
933         print(output)
934         self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
935         output = check_output('ip -d link show ip6gretap98')
936         print(output)
937         self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
938
939     def test_vti_tunnel(self):
940         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
941                                         '25-vti-tunnel.netdev', '25-tunnel.network',
942                                         '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
943                                         '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
944         start_networkd(0)
945         wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
946
947         output = check_output('ip -d link show vtitun99')
948         print(output)
949         self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
950         output = check_output('ip -d link show vtitun98')
951         print(output)
952         self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
953         output = check_output('ip -d link show vtitun97')
954         print(output)
955         self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
956
957     def test_vti6_tunnel(self):
958         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
959                                         '25-vti6-tunnel.netdev', '25-tunnel.network',
960                                         '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
961                                         '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
962         start_networkd(0)
963         wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
964
965         output = check_output('ip -d link show vti6tun99')
966         print(output)
967         self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
968         output = check_output('ip -d link show vti6tun98')
969         print(output)
970         self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
971         output = check_output('ip -d link show vti6tun97')
972         print(output)
973         self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
974
975     def test_ip6tnl_tunnel(self):
976         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
977                                         '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
978                                         '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
979                                         '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
980         start_networkd(0)
981         wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
982
983         output = check_output('ip -d link show ip6tnl99')
984         print(output)
985         self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
986         output = check_output('ip -d link show ip6tnl98')
987         print(output)
988         self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
989         output = check_output('ip -d link show ip6tnl97')
990         print(output)
991         self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
992
993     def test_sit_tunnel(self):
994         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
995                                         '25-sit-tunnel.netdev', '25-tunnel.network',
996                                         '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
997                                         '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
998         start_networkd(0)
999         wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1000
1001         output = check_output('ip -d link show sittun99')
1002         print(output)
1003         self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1004         output = check_output('ip -d link show sittun98')
1005         print(output)
1006         self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1007         output = check_output('ip -d link show sittun97')
1008         print(output)
1009         self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1010
1011     def test_isatap_tunnel(self):
1012         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1013                                         '25-isatap-tunnel.netdev', '25-tunnel.network')
1014         start_networkd(0)
1015         wait_online(['isataptun99:routable', 'dummy98:degraded'])
1016
1017         output = check_output('ip -d link show isataptun99')
1018         print(output)
1019         self.assertRegex(output, "isatap ")
1020
1021     def test_6rd_tunnel(self):
1022         copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1023                                         '25-6rd-tunnel.netdev', '25-tunnel.network')
1024         start_networkd(0)
1025         wait_online(['sittun99:routable', 'dummy98:degraded'])
1026
1027         output = check_output('ip -d link show sittun99')
1028         print(output)
1029         self.assertRegex(output, '6rd-prefix 2602::/24')
1030
1031     @expectedFailureIfERSPANModuleIsNotAvailable()
1032     def test_erspan_tunnel(self):
1033         copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1034                                         '25-erspan-tunnel.netdev', '25-tunnel.network',
1035                                         '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1036         start_networkd(0)
1037         wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1038
1039         output = check_output('ip -d link show erspan99')
1040         print(output)
1041         self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
1042         self.assertRegex(output, 'ikey 0.0.0.101')
1043         self.assertRegex(output, 'okey 0.0.0.101')
1044         self.assertRegex(output, 'iseq')
1045         self.assertRegex(output, 'oseq')
1046         output = check_output('ip -d link show erspan98')
1047         print(output)
1048         self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
1049         self.assertRegex(output, '102')
1050         self.assertRegex(output, 'ikey 0.0.0.102')
1051         self.assertRegex(output, 'okey 0.0.0.102')
1052         self.assertRegex(output, 'iseq')
1053         self.assertRegex(output, 'oseq')
1054
1055     def test_tunnel_independent(self):
1056         copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1057         start_networkd(0)
1058
1059         wait_online(['ipiptun99:carrier'])
1060
1061     @expectedFailureIfModuleIsNotAvailable('fou')
1062     def test_fou(self):
1063         # The following redundant check is necessary for CentOS CI.
1064         # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1065         self.assertTrue(is_module_available('fou'))
1066
1067         copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1068                                         '25-fou-ipip.netdev', '25-fou-sit.netdev',
1069                                         '25-fou-gre.netdev', '25-fou-gretap.netdev')
1070         start_networkd(0)
1071
1072         wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1073
1074         output = check_output('ip fou show')
1075         print(output)
1076         self.assertRegex(output, 'port 55555 ipproto 4')
1077         self.assertRegex(output, 'port 55556 ipproto 47')
1078
1079         output = check_output('ip -d link show ipiptun96')
1080         print(output)
1081         self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
1082         output = check_output('ip -d link show sittun96')
1083         print(output)
1084         self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
1085         output = check_output('ip -d link show gretun96')
1086         print(output)
1087         self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
1088         output = check_output('ip -d link show gretap96')
1089         print(output)
1090         self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
1091
1092     def test_vxlan(self):
1093         copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1094                                         '11-dummy.netdev', 'vxlan-test1.network')
1095         start_networkd(0)
1096
1097         wait_online(['test1:degraded', 'vxlan99:degraded'])
1098
1099         output = check_output('ip -d link show vxlan99')
1100         print(output)
1101         self.assertRegex(output, '999')
1102         self.assertRegex(output, '5555')
1103         self.assertRegex(output, 'l2miss')
1104         self.assertRegex(output, 'l3miss')
1105         self.assertRegex(output, 'udpcsum')
1106         self.assertRegex(output, 'udp6zerocsumtx')
1107         self.assertRegex(output, 'udp6zerocsumrx')
1108         self.assertRegex(output, 'remcsumtx')
1109         self.assertRegex(output, 'remcsumrx')
1110         self.assertRegex(output, 'gbp')
1111
1112         output = check_output('bridge fdb show dev vxlan99')
1113         print(output)
1114         self.assertRegex(output, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1115         self.assertRegex(output, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1116         self.assertRegex(output, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1117
1118     def test_macsec(self):
1119         copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1120                                         'macsec.network', '12-dummy.netdev')
1121         start_networkd(0)
1122
1123         wait_online(['dummy98:degraded', 'macsec99:routable'])
1124
1125         output = check_output('ip -d link show macsec99')
1126         print(output)
1127         self.assertRegex(output, 'macsec99@dummy98')
1128         self.assertRegex(output, 'macsec sci [0-9a-f]*000b')
1129         self.assertRegex(output, 'encrypt on')
1130
1131         output = check_output('ip macsec show macsec99')
1132         print(output)
1133         self.assertRegex(output, 'encrypt on')
1134         self.assertRegex(output, 'TXSC: [0-9a-f]*000b on SA 1')
1135         self.assertRegex(output, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1136         self.assertRegex(output, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1137         self.assertRegex(output, 'RXSC: c619528fe6a00100, state on')
1138         self.assertRegex(output, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1139         self.assertRegex(output, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1140         self.assertRegex(output, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1141         self.assertRegex(output, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1142         self.assertNotRegex(output, 'key 02030405067080900000000000000000')
1143         self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on')
1144         self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1145
1146     def test_nlmon(self):
1147         copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1148         start_networkd(0)
1149
1150         wait_online(['nlmon99:carrier'])
1151
1152 class NetworkdL2TPTests(unittest.TestCase, Utilities):
1153
1154     links =[
1155         'l2tp-ses1',
1156         'l2tp-ses2',
1157         'l2tp-ses3',
1158         'l2tp-ses4',
1159         'test1']
1160
1161     units = [
1162         '11-dummy.netdev',
1163         '25-l2tp-dummy.network',
1164         '25-l2tp-ip.netdev',
1165         '25-l2tp-udp.netdev']
1166
1167     l2tp_tunnel_ids = [ '10' ]
1168
1169     def setUp(self):
1170         remove_l2tp_tunnels(self.l2tp_tunnel_ids)
1171         remove_links(self.links)
1172
1173     def tearDown(self):
1174         remove_l2tp_tunnels(self.l2tp_tunnel_ids)
1175         remove_links(self.links)
1176         remove_unit_from_networkd_path(self.units)
1177
1178     @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1179     def test_l2tp_udp(self):
1180         copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1181         start_networkd(0)
1182
1183         wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1184
1185         output = check_output('ip l2tp show tunnel tunnel_id 10')
1186         print(output)
1187         self.assertRegex(output, "Tunnel 10, encap UDP")
1188         self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1189         self.assertRegex(output, "Peer tunnel 11")
1190         self.assertRegex(output, "UDP source / dest ports: 3000/4000")
1191         self.assertRegex(output, "UDP checksum: enabled")
1192
1193         output = check_output('ip l2tp show session tid 10 session_id 15')
1194         print(output)
1195         self.assertRegex(output, "Session 15 in tunnel 10")
1196         self.assertRegex(output, "Peer session 16, tunnel 11")
1197         self.assertRegex(output, "interface name: l2tp-ses1")
1198
1199         output = check_output('ip l2tp show session tid 10 session_id 17')
1200         print(output)
1201         self.assertRegex(output, "Session 17 in tunnel 10")
1202         self.assertRegex(output, "Peer session 18, tunnel 11")
1203         self.assertRegex(output, "interface name: l2tp-ses2")
1204
1205     @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1206     def test_l2tp_ip(self):
1207         copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1208         start_networkd(0)
1209
1210         wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1211
1212         output = check_output('ip l2tp show tunnel tunnel_id 10')
1213         print(output)
1214         self.assertRegex(output, "Tunnel 10, encap IP")
1215         self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
1216         self.assertRegex(output, "Peer tunnel 12")
1217
1218         output = check_output('ip l2tp show session tid 10 session_id 25')
1219         print(output)
1220         self.assertRegex(output, "Session 25 in tunnel 10")
1221         self.assertRegex(output, "Peer session 26, tunnel 12")
1222         self.assertRegex(output, "interface name: l2tp-ses3")
1223
1224         output = check_output('ip l2tp show session tid 10 session_id 27')
1225         print(output)
1226         self.assertRegex(output, "Session 27 in tunnel 10")
1227         self.assertRegex(output, "Peer session 28, tunnel 12")
1228         self.assertRegex(output, "interface name: l2tp-ses4")
1229
1230 class NetworkdNetworkTests(unittest.TestCase, Utilities):
1231     links = [
1232         'bond199',
1233         'dummy98',
1234         'dummy99',
1235         'test1']
1236
1237     units = [
1238         '11-dummy.netdev',
1239         '12-dummy.netdev',
1240         '23-active-slave.network',
1241         '24-keep-configuration-static.network',
1242         '24-search-domain.network',
1243         '25-address-link-section.network',
1244         '25-address-preferred-lifetime-zero-ipv6.network',
1245         '25-address-static.network',
1246         '25-bind-carrier.network',
1247         '25-bond-active-backup-slave.netdev',
1248         '25-fibrule-invert.network',
1249         '25-fibrule-port-range.network',
1250         '25-ipv6-address-label-section.network',
1251         '25-neighbor-section.network',
1252         '25-link-local-addressing-no.network',
1253         '25-link-local-addressing-yes.network',
1254         '25-link-section-unmanaged.network',
1255         '25-route-ipv6-src.network',
1256         '25-route-static.network',
1257         '25-sysctl-disable-ipv6.network',
1258         '25-sysctl.network',
1259         'configure-without-carrier.network',
1260         'routing-policy-rule-dummy98.network',
1261         'routing-policy-rule-test1.network']
1262
1263     routing_policy_rule_tables = ['7', '8']
1264     routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1265
1266     def setUp(self):
1267         remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1268         remove_routes(self.routes)
1269         remove_links(self.links)
1270
1271     def tearDown(self):
1272         remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1273         remove_routes(self.routes)
1274         remove_links(self.links)
1275         remove_unit_from_networkd_path(self.units)
1276
1277     def test_address_static(self):
1278         copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1279         start_networkd(0)
1280
1281         wait_online(['dummy98:routable'])
1282
1283         output = check_output('ip -4 address show dev dummy98')
1284         print(output)
1285         self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1286         self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1287         self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1288
1289         # invalid sections
1290         self.assertNotRegex(output, '10.10.0.1/16')
1291         self.assertNotRegex(output, '10.10.0.2/16')
1292
1293         output = check_output('ip -4 address show dev dummy98 label 32')
1294         self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1295
1296         output = check_output('ip -4 address show dev dummy98 label 33')
1297         self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1298
1299         output = check_output('ip -4 address show dev dummy98 label 34')
1300         self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1301
1302         output = check_output('ip -4 address show dev dummy98 label 35')
1303         self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1304
1305         output = check_output('ip -6 address show dev dummy98')
1306         print(output)
1307         self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
1308         self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
1309         self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
1310         self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
1311         self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1312         self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
1313
1314     def test_address_preferred_lifetime_zero_ipv6(self):
1315         copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1316         start_networkd(5)
1317
1318         self.check_link_exists('dummy98')
1319         self.check_operstate('dummy98', 'routable', setup_state='configuring')
1320
1321         output = check_output('ip address show dummy98')
1322         print(output)
1323         self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1324         self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
1325
1326     def test_configure_without_carrier(self):
1327         copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1328         start_networkd(0)
1329         wait_online(['test1:routable'])
1330
1331         output = check_output(*networkctl_cmd, 'status', 'test1')
1332         print(output)
1333         self.assertRegex(output, '192.168.0.15')
1334         self.assertRegex(output, '192.168.0.1')
1335         self.assertRegex(output, 'routable')
1336
1337     def test_routing_policy_rule(self):
1338         copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1339         start_networkd(0)
1340         wait_online(['test1:degraded'])
1341
1342         output = check_output('ip rule')
1343         print(output)
1344         self.assertRegex(output, '111')
1345         self.assertRegex(output, 'from 192.168.100.18')
1346         self.assertRegex(output, r'tos (?:0x08|throughput)\s')
1347         self.assertRegex(output, 'iif test1')
1348         self.assertRegex(output, 'oif test1')
1349         self.assertRegex(output, 'lookup 7')
1350
1351     def test_routing_policy_rule_issue_11280(self):
1352         copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1353                                         'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1354
1355         for trial in range(3):
1356             # Remove state files only first time
1357             start_networkd(0, remove_state_files=(trial == 0))
1358             wait_online(['test1:degraded', 'dummy98:degraded'])
1359             time.sleep(1)
1360
1361             output = check_output('ip rule list table 7')
1362             print(output)
1363             self.assertRegex(output, '111:      from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1364
1365             output = check_output('ip rule list table 8')
1366             print(output)
1367             self.assertRegex(output, '112:      from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1368
1369     @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1370     def test_routing_policy_rule_port_range(self):
1371         copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1372         start_networkd(0)
1373         wait_online(['test1:degraded'])
1374
1375         output = check_output('ip rule')
1376         print(output)
1377         self.assertRegex(output, '111')
1378         self.assertRegex(output, 'from 192.168.100.18')
1379         self.assertRegex(output, '1123-1150')
1380         self.assertRegex(output, '3224-3290')
1381         self.assertRegex(output, 'tcp')
1382         self.assertRegex(output, 'lookup 7')
1383
1384     @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1385     def test_routing_policy_rule_invert(self):
1386         copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1387         start_networkd(0)
1388         wait_online(['test1:degraded'])
1389
1390         output = check_output('ip rule')
1391         print(output)
1392         self.assertRegex(output, '111')
1393         self.assertRegex(output, 'not.*?from.*?192.168.100.18')
1394         self.assertRegex(output, 'tcp')
1395         self.assertRegex(output, 'lookup 7')
1396
1397     def test_route_static(self):
1398         copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1399         start_networkd(0)
1400         wait_online(['dummy98:routable'])
1401
1402         output = check_output('ip -6 route show dev dummy98')
1403         print(output)
1404         self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1405         self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
1406
1407         output = check_output('ip -6 route show dev dummy98 default')
1408         self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1409
1410         output = check_output('ip -4 route show dev dummy98')
1411         print(output)
1412         self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1413         self.assertRegex(output, '149.10.124.64 proto static scope link')
1414         self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048')
1415         self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
1416         self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
1417
1418         output = check_output('ip -4 route show dev dummy98 default')
1419         self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
1420         self.assertRegex(output, 'default via 149.10.124.64 proto static')
1421         self.assertRegex(output, 'default proto static')
1422
1423         output = check_output('ip route show type blackhole')
1424         print(output)
1425         self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
1426
1427         output = check_output('ip route show type unreachable')
1428         print(output)
1429         self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
1430
1431         output = check_output('ip route show type prohibit')
1432         print(output)
1433         self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
1434
1435     def test_ip_route_ipv6_src_route(self):
1436         # a dummy device does not make the addresses go through tentative state, so we
1437         # reuse a bond from an earlier test, which does make the addresses go through
1438         # tentative state, and do our test on that
1439         copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1440         start_networkd(0)
1441         wait_online(['dummy98:enslaved', 'bond199:routable'])
1442
1443         output = check_output('ip -6 route list dev bond199')
1444         print(output)
1445         self.assertRegex(output, 'abcd::/16')
1446         self.assertRegex(output, 'src')
1447         self.assertRegex(output, '2001:1234:56:8f63::2')
1448
1449     def test_ip_link_mac_address(self):
1450         copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1451         start_networkd(0)
1452         wait_online(['dummy98:degraded'])
1453
1454         output = check_output('ip link show dummy98')
1455         print(output)
1456         self.assertRegex(output, '00:01:02:aa:bb:cc')
1457
1458     def test_ip_link_unmanaged(self):
1459         copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1460         start_networkd(5)
1461
1462         self.check_link_exists('dummy98')
1463
1464         self.check_operstate('dummy98', 'off', setup_state='unmanaged')
1465
1466     def test_ipv6_address_label(self):
1467         copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1468         start_networkd(0)
1469         wait_online(['dummy98:degraded'])
1470
1471         output = check_output('ip addrlabel list')
1472         print(output)
1473         self.assertRegex(output, '2004:da8:1::/64')
1474
1475     def test_ipv6_neighbor(self):
1476         copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1477         start_networkd(0)
1478         wait_online(['dummy98:degraded'], timeout='40s')
1479
1480         output = check_output('ip neigh list dev dummy98')
1481         print(output)
1482         self.assertRegex(output, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1483         self.assertRegex(output, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1484
1485     def test_link_local_addressing(self):
1486         copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1487                                         '25-link-local-addressing-no.network', '12-dummy.netdev')
1488         start_networkd(0)
1489         wait_online(['test1:degraded', 'dummy98:carrier'])
1490
1491         output = check_output('ip address show dev test1')
1492         print(output)
1493         self.assertRegex(output, 'inet .* scope link')
1494         self.assertRegex(output, 'inet6 .* scope link')
1495
1496         output = check_output('ip address show dev dummy98')
1497         print(output)
1498         self.assertNotRegex(output, 'inet6* .* scope link')
1499
1500         '''
1501         Documentation/networking/ip-sysctl.txt
1502
1503         addr_gen_mode - INTEGER
1504         Defines how link-local and autoconf addresses are generated.
1505
1506         0: generate address based on EUI64 (default)
1507         1: do no generate a link-local address, use EUI64 for addresses generated
1508            from autoconf
1509         2: generate stable privacy addresses, using the secret from
1510            stable_secret (RFC7217)
1511         3: generate stable privacy addresses, using a random secret if unset
1512         '''
1513
1514         test1_addr_gen_mode = ''
1515         if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')):
1516             with open(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'stable_secret')) as f:
1517                 try:
1518                     f.readline()
1519                 except IOError:
1520                     # if stable_secret is unset, then EIO is returned
1521                     test1_addr_gen_mode = '0'
1522                 else:
1523                     test1_addr_gen_mode = '2'
1524         else:
1525             test1_addr_gen_mode = '0'
1526
1527         if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
1528             self.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
1529
1530         if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
1531             self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1532
1533     def test_sysctl(self):
1534         copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1535         start_networkd(0)
1536         wait_online(['dummy98:degraded'])
1537
1538         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1539         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1540         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1541         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1542         self.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1543         self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1544         self.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1545
1546     def test_sysctl_disable_ipv6(self):
1547         copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1548
1549         print('## Disable ipv6')
1550         check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1551         check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1552
1553         start_networkd(0)
1554         wait_online(['dummy98:routable'])
1555
1556         output = check_output('ip -4 address show dummy98')
1557         print(output)
1558         self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1559         output = check_output('ip -6 address show dummy98')
1560         print(output)
1561         self.assertEqual(output, '')
1562         output = check_output('ip -4 route show dev dummy98')
1563         print(output)
1564         self.assertEqual(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1565         output = check_output('ip -6 route show dev dummy98')
1566         print(output)
1567         self.assertEqual(output, '')
1568
1569         check_output('ip link del dummy98')
1570
1571         print('## Enable ipv6')
1572         check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1573         check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1574
1575         start_networkd(0)
1576         wait_online(['dummy98:routable'])
1577
1578         output = check_output('ip -4 address show dummy98')
1579         print(output)
1580         self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1581         output = check_output('ip -6 address show dummy98')
1582         print(output)
1583         self.assertRegex(output, 'inet6 2607:5300:203:3906::/64 scope global')
1584         self.assertRegex(output, 'inet6 .* scope link')
1585         output = check_output('ip -4 route show dev dummy98')
1586         print(output)
1587         self.assertEqual(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1588         output = check_output('ip -6 route show dev dummy98')
1589         print(output)
1590         self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1591
1592     def test_bind_carrier(self):
1593         copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1594         start_networkd(0)
1595         wait_online(['test1:routable'])
1596
1597         check_output('ip link add dummy98 type dummy')
1598         check_output('ip link set dummy98 up')
1599         time.sleep(2)
1600         output = check_output('ip address show test1')
1601         print(output)
1602         self.assertRegex(output, 'UP,LOWER_UP')
1603         self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1604         self.check_operstate('test1', 'routable')
1605
1606         check_output('ip link add dummy99 type dummy')
1607         check_output('ip link set dummy99 up')
1608         time.sleep(2)
1609         output = check_output('ip address show test1')
1610         print(output)
1611         self.assertRegex(output, 'UP,LOWER_UP')
1612         self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1613         self.check_operstate('test1', 'routable')
1614
1615         check_output('ip link del dummy98')
1616         time.sleep(2)
1617         output = check_output('ip address show test1')
1618         print(output)
1619         self.assertRegex(output, 'UP,LOWER_UP')
1620         self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1621         self.check_operstate('test1', 'routable')
1622
1623         check_output('ip link del dummy99')
1624         time.sleep(2)
1625         output = check_output('ip address show test1')
1626         print(output)
1627         self.assertNotRegex(output, 'UP,LOWER_UP')
1628         self.assertRegex(output, 'DOWN')
1629         self.assertNotRegex(output, '192.168.10')
1630         self.check_operstate('test1', 'off')
1631
1632         check_output('ip link add dummy98 type dummy')
1633         check_output('ip link set dummy98 up')
1634         time.sleep(2)
1635         output = check_output('ip address show test1')
1636         print(output)
1637         self.assertRegex(output, 'UP,LOWER_UP')
1638         self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1639         self.check_operstate('test1', 'routable')
1640
1641     def test_domain(self):
1642         copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1643         start_networkd(0)
1644         wait_online(['dummy98:routable'])
1645
1646         output = check_output(*networkctl_cmd, 'status', 'dummy98', env=env)
1647         print(output)
1648         self.assertRegex(output, 'Address: 192.168.42.100')
1649         self.assertRegex(output, 'DNS: 192.168.42.1')
1650         self.assertRegex(output, 'Search Domains: one')
1651
1652     def test_keep_configuration_static(self):
1653         check_output('systemctl stop systemd-networkd')
1654
1655         check_output('ip link add name dummy98 type dummy')
1656         check_output('ip address add 10.1.2.3/16 dev dummy98')
1657         check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1658         output = check_output('ip address show dummy98')
1659         print(output)
1660         self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
1661         self.assertRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1662         output = check_output('ip route show dev dummy98')
1663         print(output)
1664
1665         copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1666         start_networkd(0)
1667         wait_online(['dummy98:routable'])
1668
1669         output = check_output('ip address show dummy98')
1670         print(output)
1671         self.assertRegex(output, 'inet 10.1.2.3/16 scope global dummy98')
1672         self.assertNotRegex(output, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1673
1674 class NetworkdBondTests(unittest.TestCase, Utilities):
1675     links = [
1676         'bond199',
1677         'bond99',
1678         'dummy98',
1679         'test1']
1680
1681     units = [
1682         '11-dummy.netdev',
1683         '12-dummy.netdev',
1684         '23-active-slave.network',
1685         '23-bond199.network',
1686         '23-primary-slave.network',
1687         '23-test1-bond199.network',
1688         '25-bond-active-backup-slave.netdev',
1689         '25-bond.netdev',
1690         'bond99.network',
1691         'bond-slave.network']
1692
1693     def setUp(self):
1694         remove_links(self.links)
1695
1696     def tearDown(self):
1697         remove_links(self.links)
1698         remove_unit_from_networkd_path(self.units)
1699
1700     def test_bond_active_slave(self):
1701         copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1702         start_networkd()
1703
1704         self.check_link_exists('dummy98')
1705         self.check_link_exists('bond199')
1706
1707         output = check_output('ip -d link show bond199')
1708         print(output)
1709         self.assertRegex(output, 'active_slave dummy98')
1710
1711     def test_bond_primary_slave(self):
1712         copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1713         start_networkd()
1714
1715         self.check_link_exists('test1')
1716         self.check_link_exists('bond199')
1717
1718         output = check_output('ip -d link show bond199')
1719         print(output)
1720         self.assertRegex(output, 'primary test1')
1721
1722     def test_bond_operstate(self):
1723         copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1724                                         'bond99.network','bond-slave.network')
1725         start_networkd()
1726
1727         self.check_link_exists('bond99')
1728         self.check_link_exists('dummy98')
1729         self.check_link_exists('test1')
1730
1731         output = check_output('ip -d link show dummy98')
1732         print(output)
1733         self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1734
1735         output = check_output('ip -d link show test1')
1736         print(output)
1737         self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1738
1739         output = check_output('ip -d link show bond99')
1740         print(output)
1741         self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1742
1743         self.check_operstate('dummy98', 'enslaved')
1744         self.check_operstate('test1', 'enslaved')
1745         self.check_operstate('bond99', 'routable')
1746
1747         check_output('ip link set dummy98 down')
1748         time.sleep(2)
1749
1750         self.check_operstate('dummy98', 'off')
1751         self.check_operstate('test1', 'enslaved')
1752         self.check_operstate('bond99', 'degraded-carrier')
1753
1754         check_output('ip link set dummy98 up')
1755         time.sleep(2)
1756
1757         self.check_operstate('dummy98', 'enslaved')
1758         self.check_operstate('test1', 'enslaved')
1759         self.check_operstate('bond99', 'routable')
1760
1761         check_output('ip link set dummy98 down')
1762         check_output('ip link set test1 down')
1763         time.sleep(2)
1764
1765         self.check_operstate('dummy98', 'off')
1766         self.check_operstate('test1', 'off')
1767
1768         for trial in range(30):
1769             if trial > 0:
1770                 time.sleep(1)
1771             output = check_output('ip address show bond99')
1772             print(output)
1773             if get_operstate('bond99') == 'no-carrier':
1774                 break
1775         else:
1776             # Huh? Kernel does not recognize that all slave interfaces are down?
1777             # Let's confirm that networkd's operstate is consistent with ip's result.
1778             self.assertNotRegex(output, 'NO-CARRIER')
1779
1780 class NetworkdBridgeTests(unittest.TestCase, Utilities):
1781     links = [
1782         'bridge99',
1783         'dummy98',
1784         'test1']
1785
1786     units = [
1787         '11-dummy.netdev',
1788         '12-dummy.netdev',
1789         '26-bridge.netdev',
1790         '26-bridge-slave-interface-1.network',
1791         '26-bridge-slave-interface-2.network',
1792         'bridge99-ignore-carrier-loss.network',
1793         'bridge99.network']
1794
1795     def setUp(self):
1796         remove_links(self.links)
1797
1798     def tearDown(self):
1799         remove_links(self.links)
1800         remove_unit_from_networkd_path(self.units)
1801
1802     def test_bridge_property(self):
1803         copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1804                                         '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1805                                         'bridge99.network')
1806         start_networkd()
1807
1808         self.check_link_exists('dummy98')
1809         self.check_link_exists('test1')
1810         self.check_link_exists('bridge99')
1811
1812         output = check_output('ip -d link show test1')
1813         print(output)
1814         self.assertRegex(output, 'master')
1815         self.assertRegex(output, 'bridge')
1816
1817         output = check_output('ip -d link show dummy98')
1818         print(output)
1819         self.assertRegex(output, 'master')
1820         self.assertRegex(output, 'bridge')
1821
1822         output = check_output('ip addr show bridge99')
1823         print(output)
1824         self.assertRegex(output, '192.168.0.15/24')
1825
1826         output = check_output('bridge -d link show dummy98')
1827         print(output)
1828         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1829         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1830         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1831         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1832         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1833         if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1834             self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1835         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1836
1837         # CONFIG_BRIDGE_IGMP_SNOOPING=y
1838         if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1839             self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1840
1841         self.check_operstate('test1', 'enslaved')
1842         self.check_operstate('dummy98', 'enslaved')
1843         self.check_operstate('bridge99', 'routable')
1844
1845         check_output('ip address add 192.168.0.16/24 dev bridge99')
1846         time.sleep(1)
1847
1848         output = check_output('ip addr show bridge99')
1849         print(output)
1850         self.assertRegex(output, '192.168.0.16/24')
1851
1852         self.check_operstate('bridge99', 'routable')
1853
1854         self.assertEqual(call('ip link del test1'), 0)
1855         time.sleep(3)
1856
1857         self.check_operstate('bridge99', 'degraded-carrier')
1858
1859         check_output('ip link del dummy98')
1860         time.sleep(3)
1861
1862         self.check_operstate('bridge99', 'no-carrier')
1863
1864         output = check_output('ip address show bridge99')
1865         print(output)
1866         self.assertRegex(output, 'NO-CARRIER')
1867         self.assertNotRegex(output, '192.168.0.15/24')
1868         self.assertNotRegex(output, '192.168.0.16/24')
1869
1870     def test_bridge_ignore_carrier_loss(self):
1871         copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1872                                         '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1873                                         'bridge99-ignore-carrier-loss.network')
1874         call('ip rule del table 100')
1875
1876         start_networkd()
1877
1878         self.check_link_exists('dummy98')
1879         self.check_link_exists('test1')
1880         self.check_link_exists('bridge99')
1881
1882         check_output('ip address add 192.168.0.16/24 dev bridge99')
1883         time.sleep(1)
1884
1885         check_output('ip link del test1')
1886         check_output('ip link del dummy98')
1887         time.sleep(3)
1888
1889         output = check_output('ip address show bridge99')
1890         print(output)
1891         self.assertRegex(output, 'NO-CARRIER')
1892         self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1893         self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1894
1895         call('ip rule del table 100')
1896
1897     def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1898         copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1899                                         'bridge99-ignore-carrier-loss.network')
1900
1901         call('ip rule del table 100')
1902
1903         start_networkd()
1904
1905         self.check_link_exists('bridge99')
1906
1907         check_output('ip link add dummy98 type dummy')
1908         check_output('ip link set dummy98 up')
1909         check_output('ip link del dummy98')
1910
1911         check_output('ip link add dummy98 type dummy')
1912         check_output('ip link set dummy98 up')
1913         check_output('ip link del dummy98')
1914
1915         check_output('ip link add dummy98 type dummy')
1916         check_output('ip link set dummy98 up')
1917         check_output('ip link del dummy98')
1918
1919         check_output('ip link add dummy98 type dummy')
1920         check_output('ip link set dummy98 up')
1921
1922         for trial in range(30):
1923             if trial > 0:
1924                 time.sleep(1)
1925             if get_operstate('bridge99') == 'routable' and get_operstate('dummy98') == 'enslaved':
1926                 break
1927         else:
1928             self.assertTrue(False)
1929
1930         output = check_output('ip address show bridge99')
1931         print(output)
1932         self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1933
1934         output = check_output('ip rule list table 100')
1935         print(output)
1936         self.assertEqual(output, '0:    from all to 8.8.8.8 lookup 100')
1937
1938         call('ip rule del table 100')
1939
1940 class NetworkdLLDPTests(unittest.TestCase, Utilities):
1941     links = ['veth99']
1942
1943     units = [
1944         '23-emit-lldp.network',
1945         '24-lldp.network',
1946         '25-veth.netdev']
1947
1948     def setUp(self):
1949         remove_links(self.links)
1950
1951     def tearDown(self):
1952         remove_links(self.links)
1953         remove_unit_from_networkd_path(self.units)
1954
1955     def test_lldp(self):
1956         copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1957         start_networkd(0)
1958         wait_online(['veth99:degraded', 'veth-peer:degraded'])
1959
1960         output = check_output(*networkctl_cmd, 'lldp', env=env)
1961         print(output)
1962         self.assertRegex(output, 'veth-peer')
1963         self.assertRegex(output, 'veth99')
1964
1965 class NetworkdRATests(unittest.TestCase, Utilities):
1966     links = ['veth99']
1967
1968     units = [
1969         '25-veth.netdev',
1970         'ipv6-prefix.network',
1971         'ipv6-prefix-veth.network']
1972
1973     def setUp(self):
1974         remove_links(self.links)
1975
1976     def tearDown(self):
1977         remove_links(self.links)
1978         remove_unit_from_networkd_path(self.units)
1979
1980     def test_ipv6_prefix_delegation(self):
1981         warn_about_firewalld()
1982         copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1983         start_networkd(0)
1984         wait_online(['veth99:routable', 'veth-peer:degraded'])
1985
1986         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
1987         print(output)
1988         self.assertRegex(output, '2002:da8:1:0')
1989
1990 class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1991     links = ['veth99']
1992
1993     units = [
1994         '25-veth.netdev',
1995         'dhcp-client.network',
1996         'dhcp-client-timezone-router.network',
1997         'dhcp-server.network',
1998         'dhcp-server-timezone-router.network']
1999
2000     def setUp(self):
2001         remove_links(self.links)
2002
2003     def tearDown(self):
2004         remove_links(self.links)
2005         remove_unit_from_networkd_path(self.units)
2006
2007     def test_dhcp_server(self):
2008         warn_about_firewalld()
2009         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2010         start_networkd(0)
2011         wait_online(['veth99:routable', 'veth-peer:routable'])
2012
2013         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2014         print(output)
2015         self.assertRegex(output, '192.168.5.*')
2016         self.assertRegex(output, 'Gateway: 192.168.5.1')
2017         self.assertRegex(output, 'DNS: 192.168.5.1')
2018         self.assertRegex(output, 'NTP: 192.168.5.1')
2019
2020     def test_emit_router_timezone(self):
2021         warn_about_firewalld()
2022         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2023         start_networkd(0)
2024         wait_online(['veth99:routable', 'veth-peer:routable'])
2025
2026         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2027         print(output)
2028         self.assertRegex(output, 'Gateway: 192.168.5.*')
2029         self.assertRegex(output, '192.168.5.*')
2030         self.assertRegex(output, 'Europe/Berlin')
2031
2032 class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
2033     links = [
2034         'veth99',
2035         'vrf99']
2036
2037     units = [
2038         '25-veth.netdev',
2039         '25-vrf.netdev',
2040         '25-vrf.network',
2041         'dhcp-client-anonymize.network',
2042         'dhcp-client-gateway-onlink-implicit.network',
2043         'dhcp-client-ipv4-dhcp-settings.network',
2044         'dhcp-client-ipv4-only-ipv6-disabled.network',
2045         'dhcp-client-ipv4-only.network',
2046         'dhcp-client-ipv6-only.network',
2047         'dhcp-client-ipv6-rapid-commit.network',
2048         'dhcp-client-keep-configuration-dhcp-on-stop.network',
2049         'dhcp-client-keep-configuration-dhcp.network',
2050         'dhcp-client-listen-port.network',
2051         'dhcp-client-route-metric.network',
2052         'dhcp-client-route-table.network',
2053         'dhcp-client-vrf.network',
2054         'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2055         'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2056         'dhcp-client.network',
2057         'dhcp-server-veth-peer.network',
2058         'dhcp-v4-server-veth-peer.network',
2059         'static.network']
2060
2061     def setUp(self):
2062         stop_dnsmasq(dnsmasq_pid_file)
2063         remove_links(self.links)
2064
2065     def tearDown(self):
2066         stop_dnsmasq(dnsmasq_pid_file)
2067         remove_lease_file()
2068         remove_log_file()
2069         remove_links(self.links)
2070         remove_unit_from_networkd_path(self.units)
2071
2072     def test_dhcp_client_ipv6_only(self):
2073         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2074
2075         start_networkd(0)
2076         wait_online(['veth-peer:carrier'])
2077         start_dnsmasq()
2078         wait_online(['veth99:routable', 'veth-peer:routable'])
2079
2080         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2081         print(output)
2082         self.assertRegex(output, '2600::')
2083         self.assertNotRegex(output, '192.168.5')
2084
2085         # Confirm that ipv6 token is not set in the kernel
2086         output = check_output('ip token show dev veth99')
2087         print(output)
2088         self.assertRegex(output, 'token :: dev veth99')
2089
2090     def test_dhcp_client_ipv4_only(self):
2091         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2092
2093         start_networkd(0)
2094         wait_online(['veth-peer:carrier'])
2095         start_dnsmasq()
2096         wait_online(['veth99:routable', 'veth-peer:routable'])
2097
2098         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2099         print(output)
2100         self.assertNotRegex(output, '2600::')
2101         self.assertRegex(output, '192.168.5')
2102
2103     def test_dhcp_client_ipv4_ipv6(self):
2104         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2105                                         'dhcp-client-ipv4-only.network')
2106         start_networkd(0)
2107         wait_online(['veth-peer:carrier'])
2108         start_dnsmasq()
2109         wait_online(['veth99:routable', 'veth-peer:routable'])
2110
2111         # link become 'routable' when at least one protocol provide an valid address.
2112         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2113         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2114
2115         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2116         print(output)
2117         self.assertRegex(output, '2600::')
2118         self.assertRegex(output, '192.168.5')
2119
2120     def test_dhcp_client_settings(self):
2121         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2122
2123         start_networkd(0)
2124         wait_online(['veth-peer:carrier'])
2125         start_dnsmasq()
2126         wait_online(['veth99:routable', 'veth-peer:routable'])
2127
2128         print('## ip address show dev veth99')
2129         output = check_output('ip address show dev veth99')
2130         print(output)
2131         self.assertRegex(output, '12:34:56:78:9a:bc')
2132         self.assertRegex(output, '192.168.5')
2133         self.assertRegex(output, '1492')
2134
2135         # issue #8726
2136         print('## ip route show table main dev veth99')
2137         output = check_output('ip route show table main dev veth99')
2138         print(output)
2139         self.assertNotRegex(output, 'proto dhcp')
2140
2141         print('## ip route show table 211 dev veth99')
2142         output = check_output('ip route show table 211 dev veth99')
2143         print(output)
2144         self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2145         self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2146         self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2147
2148         print('## dnsmasq log')
2149         self.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2150         self.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2151         self.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2152         self.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2153
2154     def test_dhcp6_client_settings_rapidcommit_true(self):
2155         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2156         start_networkd(0)
2157         wait_online(['veth-peer:carrier'])
2158         start_dnsmasq()
2159         wait_online(['veth99:routable', 'veth-peer:routable'])
2160
2161         output = check_output('ip address show dev veth99')
2162         print(output)
2163         self.assertRegex(output, '12:34:56:78:9a:bc')
2164         self.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2165
2166     def test_dhcp6_client_settings_rapidcommit_false(self):
2167         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2168         start_networkd(0)
2169         wait_online(['veth-peer:carrier'])
2170         start_dnsmasq()
2171         wait_online(['veth99:routable', 'veth-peer:routable'])
2172
2173         output = check_output('ip address show dev veth99')
2174         print(output)
2175         self.assertRegex(output, '12:34:56:78:9a:bc')
2176         self.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2177
2178     def test_dhcp_client_settings_anonymize(self):
2179         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2180         start_networkd(0)
2181         wait_online(['veth-peer:carrier'])
2182         start_dnsmasq()
2183         wait_online(['veth99:routable', 'veth-peer:routable'])
2184
2185         self.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2186         self.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2187         self.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2188
2189     def test_dhcp_client_listen_port(self):
2190         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2191         start_networkd(0)
2192         wait_online(['veth-peer:carrier'])
2193         start_dnsmasq('--dhcp-alternate-port=67,5555')
2194         wait_online(['veth99:routable', 'veth-peer:routable'])
2195
2196         # link become 'routable' when at least one protocol provide an valid address.
2197         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2198         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2199
2200         output = check_output('ip -4 address show dev veth99')
2201         print(output)
2202         self.assertRegex(output, '192.168.5.* dynamic')
2203
2204     def test_dhcp_route_table_id(self):
2205         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2206         start_networkd(0)
2207         wait_online(['veth-peer:carrier'])
2208         start_dnsmasq()
2209         wait_online(['veth99:routable', 'veth-peer:routable'])
2210
2211         output = check_output('ip route show table 12')
2212         print(output)
2213         self.assertRegex(output, 'veth99 proto dhcp')
2214         self.assertRegex(output, '192.168.5.1')
2215
2216     def test_dhcp_route_metric(self):
2217         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2218         start_networkd(0)
2219         wait_online(['veth-peer:carrier'])
2220         start_dnsmasq()
2221         wait_online(['veth99:routable', 'veth-peer:routable'])
2222
2223         output = check_output('ip route show dev veth99')
2224         print(output)
2225         self.assertRegex(output, 'metric 24')
2226
2227     def test_dhcp_keep_configuration_dhcp(self):
2228         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2229         start_networkd(0)
2230         wait_online(['veth-peer:carrier'])
2231         start_dnsmasq(lease_time='2m')
2232         wait_online(['veth99:routable', 'veth-peer:routable'])
2233
2234         output = check_output('ip address show dev veth99 scope global')
2235         print(output)
2236         self.assertRegex(output, r'192.168.5.*')
2237
2238         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2239         print(output)
2240         self.assertRegex(output, r'192.168.5.*')
2241
2242         # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2243         stop_dnsmasq(dnsmasq_pid_file)
2244
2245         # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2246         print('Wait for the dynamic address to be expired')
2247         time.sleep(125)
2248
2249         print('The lease address should be kept after lease expired')
2250         output = check_output('ip address show dev veth99 scope global')
2251         print(output)
2252         self.assertRegex(output, r'192.168.5.*')
2253
2254         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2255         print(output)
2256         self.assertRegex(output, r'192.168.5.*')
2257
2258         check_output('systemctl stop systemd-networkd')
2259
2260         print('The lease address should be kept after networkd stopped')
2261         output = check_output('ip address show dev veth99 scope global')
2262         print(output)
2263         self.assertRegex(output, r'192.168.5.*')
2264
2265         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2266         print(output)
2267         self.assertRegex(output, r'192.168.5.*')
2268
2269         check_output('systemctl start systemd-networkd')
2270         wait_online(['veth-peer:routable'])
2271
2272         print('Still the lease address should be kept after networkd restarted')
2273         output = check_output('ip address show dev veth99 scope global')
2274         print(output)
2275         self.assertRegex(output, r'192.168.5.*')
2276
2277         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2278         print(output)
2279         self.assertRegex(output, r'192.168.5.*')
2280
2281     def test_dhcp_keep_configuration_dhcp_on_stop(self):
2282         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2283         start_networkd(0)
2284         wait_online(['veth-peer:carrier'])
2285         start_dnsmasq(lease_time='2m')
2286         wait_online(['veth99:routable', 'veth-peer:routable'])
2287
2288         output = check_output('ip address show dev veth99 scope global')
2289         print(output)
2290         self.assertRegex(output, r'192.168.5.*')
2291
2292         stop_dnsmasq(dnsmasq_pid_file)
2293         check_output('systemctl stop systemd-networkd')
2294
2295         output = check_output('ip address show dev veth99 scope global')
2296         print(output)
2297         self.assertRegex(output, r'192.168.5.*')
2298
2299         start_networkd(0)
2300         wait_online(['veth-peer:routable'])
2301
2302         output = check_output('ip address show dev veth99 scope global')
2303         print(output)
2304         self.assertNotRegex(output, r'192.168.5.*')
2305
2306     def test_dhcp_client_reuse_address_as_static(self):
2307         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2308         start_networkd(0)
2309         wait_online(['veth-peer:carrier'])
2310         start_dnsmasq()
2311         wait_online(['veth99:routable', 'veth-peer:routable'])
2312
2313         # link become 'routable' when at least one protocol provide an valid address.
2314         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2315         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2316
2317         output = check_output('ip address show dev veth99 scope global')
2318         print(output)
2319         self.assertRegex(output, '192.168.5')
2320         self.assertRegex(output, '2600::')
2321
2322         ipv4_address = re.search(r'192.168.5.[0-9]*/24', output)
2323         ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output)
2324         static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2325         print(static_network)
2326
2327         remove_unit_from_networkd_path(['dhcp-client.network'])
2328
2329         with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2330             f.write(static_network)
2331
2332         # When networkd started, the links are already configured, so let's wait for 5 seconds
2333         # the links to be re-configured.
2334         start_networkd(5)
2335         wait_online(['veth99:routable', 'veth-peer:routable'])
2336
2337         output = check_output('ip -4 address show dev veth99 scope global')
2338         print(output)
2339         self.assertRegex(output, '192.168.5')
2340         self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2341
2342         output = check_output('ip -6 address show dev veth99 scope global')
2343         print(output)
2344         self.assertRegex(output, '2600::')
2345         self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2346
2347     @expectedFailureIfModuleIsNotAvailable('vrf')
2348     def test_dhcp_client_vrf(self):
2349         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2350                                         '25-vrf.netdev', '25-vrf.network')
2351         start_networkd(0)
2352         wait_online(['veth-peer:carrier'])
2353         start_dnsmasq()
2354         wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2355
2356         # link become 'routable' when at least one protocol provide an valid address.
2357         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2358         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2359
2360         print('## ip -d link show dev vrf99')
2361         output = check_output('ip -d link show dev vrf99')
2362         print(output)
2363         self.assertRegex(output, 'vrf table 42')
2364
2365         print('## ip address show vrf vrf99')
2366         output = check_output('ip address show vrf vrf99')
2367         print(output)
2368         self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2369         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2370         self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2371         self.assertRegex(output, 'inet6 .* scope link')
2372
2373         print('## ip address show dev veth99')
2374         output = check_output('ip address show dev veth99')
2375         print(output)
2376         self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2377         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2378         self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2379         self.assertRegex(output, 'inet6 .* scope link')
2380
2381         print('## ip route show vrf vrf99')
2382         output = check_output('ip route show vrf vrf99')
2383         print(output)
2384         self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2385         self.assertRegex(output, 'default dev veth99 proto static scope link')
2386         self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2387         self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2388         self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2389         self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2390
2391         print('## ip route show table main dev veth99')
2392         output = check_output('ip route show table main dev veth99')
2393         print(output)
2394         self.assertEqual(output, '')
2395
2396     def test_dhcp_client_gateway_onlink_implicit(self):
2397         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2398                                         'dhcp-client-gateway-onlink-implicit.network')
2399         start_networkd(0)
2400         wait_online(['veth-peer:carrier'])
2401         start_dnsmasq()
2402         wait_online(['veth99:routable', 'veth-peer:routable'])
2403
2404         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2405         print(output)
2406         self.assertRegex(output, '192.168.5')
2407
2408         output = check_output('ip route list dev veth99 10.0.0.0/8')
2409         print(output)
2410         self.assertRegex(output, 'onlink')
2411         output = check_output('ip route list dev veth99 192.168.100.0/24')
2412         print(output)
2413         self.assertRegex(output, 'onlink')
2414
2415     def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
2416         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2417                                         'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2418         start_networkd(0)
2419         wait_online(['veth-peer:carrier'])
2420         start_dnsmasq(lease_time='2m')
2421         wait_online(['veth99:routable', 'veth-peer:routable'])
2422
2423         output = check_output('ip address show dev veth99')
2424         print(output)
2425
2426         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2427         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2428         output = check_output('ip -6 address show dev veth99 scope link')
2429         self.assertRegex(output, 'inet6 .* scope link')
2430         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2431         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2432         output = check_output('ip -4 address show dev veth99 scope link')
2433         self.assertNotRegex(output, 'inet .* scope link')
2434
2435         print('Wait for the dynamic address to be expired')
2436         time.sleep(130)
2437
2438         output = check_output('ip address show dev veth99')
2439         print(output)
2440
2441         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2442         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2443         output = check_output('ip -6 address show dev veth99 scope link')
2444         self.assertRegex(output, 'inet6 .* scope link')
2445         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2446         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2447         output = check_output('ip -4 address show dev veth99 scope link')
2448         self.assertNotRegex(output, 'inet .* scope link')
2449
2450         search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2451
2452     def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2453         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2454                                         'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2455         start_networkd(0)
2456         wait_online(['veth99:degraded', 'veth-peer:routable'])
2457
2458         output = check_output('ip address show dev veth99')
2459         print(output)
2460
2461         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2462         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2463         output = check_output('ip -6 address show dev veth99 scope link')
2464         self.assertRegex(output, 'inet6 .* scope link')
2465         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2466         self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2467         output = check_output('ip -4 address show dev veth99 scope link')
2468         self.assertRegex(output, 'inet .* scope link')
2469
2470     def test_dhcp_client_route_remove_on_renew(self):
2471         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2472                                         'dhcp-client-ipv4-only-ipv6-disabled.network')
2473         start_networkd(0)
2474         wait_online(['veth-peer:carrier'])
2475         start_dnsmasq(ipv4_range='192.168.5.100,192.168.5.199', lease_time='2m')
2476         wait_online(['veth99:routable', 'veth-peer:routable'])
2477
2478         # test for issue #12490
2479
2480         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2481         print(output)
2482         self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2483         address1=None
2484         for line in output.splitlines():
2485             if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2486                 address1 = line.split()[1].split('/')[0]
2487                 break
2488
2489         output = check_output('ip -4 route show dev veth99')
2490         print(output)
2491         self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2492         self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2493
2494         stop_dnsmasq(dnsmasq_pid_file)
2495         start_dnsmasq(ipv4_range='192.168.5.200,192.168.5.250', lease_time='2m')
2496
2497         print('Wait for the dynamic address to be expired')
2498         time.sleep(130)
2499
2500         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2501         print(output)
2502         self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2503         address2=None
2504         for line in output.splitlines():
2505             if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2506                 address2 = line.split()[1].split('/')[0]
2507                 break
2508
2509         self.assertNotEqual(address1, address2)
2510
2511         output = check_output('ip -4 route show dev veth99')
2512         print(output)
2513         self.assertNotRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2514         self.assertNotRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2515         self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2516         self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2517
2518 if __name__ == '__main__':
2519     parser = argparse.ArgumentParser()
2520     parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
2521     parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
2522     parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
2523     parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
2524     parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
2525     parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
2526     parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
2527     parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
2528     parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
2529     ns, args = parser.parse_known_args(namespace=unittest)
2530
2531     if ns.build_dir:
2532         if ns.networkd_bin or ns.wait_online_bin or ns.networkctl_bin:
2533             print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2534         networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
2535         wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
2536         networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
2537     else:
2538         if ns.networkd_bin:
2539             networkd_bin = ns.networkd_bin
2540         if ns.wait_online_bin:
2541             wait_online_bin = ns.wait_online_bin
2542         if ns.networkctl_bin:
2543             networkctl_bin = ns.networkctl_bin
2544
2545     use_valgrind = ns.use_valgrind
2546     enable_debug = ns.enable_debug
2547     asan_options = ns.asan_options
2548     lsan_options = ns.lsan_options
2549     ubsan_options = ns.ubsan_options
2550
2551     if use_valgrind:
2552         networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
2553         wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
2554     else:
2555         networkctl_cmd = [networkctl_bin]
2556         wait_online_cmd = [wait_online_bin]
2557
2558     if enable_debug:
2559         env.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2560     if asan_options:
2561         env.update({ 'ASAN_OPTIONS' : asan_options })
2562     if lsan_options:
2563         env.update({ 'LSAN_OPTIONS' : lsan_options })
2564     if ubsan_options:
2565         env.update({ 'UBSAN_OPTIONS' : ubsan_options })
2566
2567     sys.argv[1:] = args
2568     unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2569                                                      verbosity=3))