3f50b7239ed7aaf763475a2b69d8e11af1d16be7
[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         '25-bond-active-backup-slave.netdev',
1688         '25-bond.netdev',
1689         'bond99.network',
1690         'bond-slave.network']
1691
1692     def setUp(self):
1693         remove_links(self.links)
1694
1695     def tearDown(self):
1696         remove_links(self.links)
1697         remove_unit_from_networkd_path(self.units)
1698
1699     def test_bond_active_slave(self):
1700         copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1701         start_networkd(0)
1702         wait_online(['dummy98:enslaved', 'bond199:degraded'])
1703
1704         output = check_output('ip -d link show bond199')
1705         print(output)
1706         self.assertRegex(output, 'active_slave dummy98')
1707
1708     def test_bond_primary_slave(self):
1709         copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1710         start_networkd(0)
1711         wait_online(['dummy98:enslaved', 'bond199:degraded'])
1712
1713         output = check_output('ip -d link show bond199')
1714         print(output)
1715         self.assertRegex(output, 'primary dummy98')
1716
1717     def test_bond_operstate(self):
1718         copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1719                                         'bond99.network','bond-slave.network')
1720         start_networkd(0)
1721         wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1722
1723         output = check_output('ip -d link show dummy98')
1724         print(output)
1725         self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1726
1727         output = check_output('ip -d link show test1')
1728         print(output)
1729         self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
1730
1731         output = check_output('ip -d link show bond99')
1732         print(output)
1733         self.assertRegex(output, 'MASTER,UP,LOWER_UP')
1734
1735         self.check_operstate('dummy98', 'enslaved')
1736         self.check_operstate('test1', 'enslaved')
1737         self.check_operstate('bond99', 'routable')
1738
1739         check_output('ip link set dummy98 down')
1740         time.sleep(2)
1741
1742         self.check_operstate('dummy98', 'off')
1743         self.check_operstate('test1', 'enslaved')
1744         self.check_operstate('bond99', 'degraded-carrier')
1745
1746         check_output('ip link set dummy98 up')
1747         time.sleep(2)
1748
1749         self.check_operstate('dummy98', 'enslaved')
1750         self.check_operstate('test1', 'enslaved')
1751         self.check_operstate('bond99', 'routable')
1752
1753         check_output('ip link set dummy98 down')
1754         check_output('ip link set test1 down')
1755         time.sleep(2)
1756
1757         self.check_operstate('dummy98', 'off')
1758         self.check_operstate('test1', 'off')
1759
1760         for trial in range(30):
1761             if trial > 0:
1762                 time.sleep(1)
1763             output = check_output('ip address show bond99')
1764             print(output)
1765             if get_operstate('bond99') == 'no-carrier':
1766                 break
1767         else:
1768             # Huh? Kernel does not recognize that all slave interfaces are down?
1769             # Let's confirm that networkd's operstate is consistent with ip's result.
1770             self.assertNotRegex(output, 'NO-CARRIER')
1771
1772 class NetworkdBridgeTests(unittest.TestCase, Utilities):
1773     links = [
1774         'bridge99',
1775         'dummy98',
1776         'test1']
1777
1778     units = [
1779         '11-dummy.netdev',
1780         '12-dummy.netdev',
1781         '26-bridge.netdev',
1782         '26-bridge-slave-interface-1.network',
1783         '26-bridge-slave-interface-2.network',
1784         'bridge99-ignore-carrier-loss.network',
1785         'bridge99.network']
1786
1787     routing_policy_rule_tables = ['100']
1788
1789     def setUp(self):
1790         remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1791         remove_links(self.links)
1792
1793     def tearDown(self):
1794         remove_routing_policy_rule_tables(self.routing_policy_rule_tables)
1795         remove_links(self.links)
1796         remove_unit_from_networkd_path(self.units)
1797
1798     def test_bridge_property(self):
1799         copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1800                                         '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1801                                         'bridge99.network')
1802         start_networkd(0)
1803         wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1804
1805         output = check_output('ip -d link show test1')
1806         print(output)
1807         self.assertRegex(output, 'master')
1808         self.assertRegex(output, 'bridge')
1809
1810         output = check_output('ip -d link show dummy98')
1811         print(output)
1812         self.assertRegex(output, 'master')
1813         self.assertRegex(output, 'bridge')
1814
1815         output = check_output('ip addr show bridge99')
1816         print(output)
1817         self.assertRegex(output, '192.168.0.15/24')
1818
1819         output = check_output('bridge -d link show dummy98')
1820         print(output)
1821         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1822         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1823         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1824         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1825         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1826         if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1827             self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1828         self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1829
1830         # CONFIG_BRIDGE_IGMP_SNOOPING=y
1831         if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1832             self.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1833
1834         check_output('ip address add 192.168.0.16/24 dev bridge99')
1835         time.sleep(1)
1836
1837         output = check_output('ip addr show bridge99')
1838         print(output)
1839         self.assertRegex(output, '192.168.0.16/24')
1840
1841         self.assertEqual(call('ip link del test1'), 0)
1842         time.sleep(3)
1843
1844         self.check_operstate('bridge99', 'degraded-carrier')
1845
1846         check_output('ip link del dummy98')
1847         time.sleep(3)
1848
1849         self.check_operstate('bridge99', 'no-carrier')
1850
1851         output = check_output('ip address show bridge99')
1852         print(output)
1853         self.assertRegex(output, 'NO-CARRIER')
1854         self.assertNotRegex(output, '192.168.0.15/24')
1855         self.assertNotRegex(output, '192.168.0.16/24')
1856
1857     def test_bridge_ignore_carrier_loss(self):
1858         copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1859                                         '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1860                                         'bridge99-ignore-carrier-loss.network')
1861         start_networkd(0)
1862         wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1863
1864         check_output('ip address add 192.168.0.16/24 dev bridge99')
1865         time.sleep(1)
1866
1867         check_output('ip link del test1')
1868         check_output('ip link del dummy98')
1869         time.sleep(3)
1870
1871         output = check_output('ip address show bridge99')
1872         print(output)
1873         self.assertRegex(output, 'NO-CARRIER')
1874         self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1875         self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
1876
1877     def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
1878         copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1879                                         'bridge99-ignore-carrier-loss.network')
1880         start_networkd(0)
1881         wait_online(['bridge99:no-carrier'])
1882
1883         for trial in range(4):
1884             check_output('ip link add dummy98 type dummy')
1885             check_output('ip link set dummy98 up')
1886             if trial < 3:
1887                 check_output('ip link del dummy98')
1888
1889         wait_online(['bridge99:routable', 'dummy98:enslaved'])
1890
1891         output = check_output('ip address show bridge99')
1892         print(output)
1893         self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1894
1895         output = check_output('ip rule list table 100')
1896         print(output)
1897         self.assertEqual(output, '0:    from all to 8.8.8.8 lookup 100')
1898
1899 class NetworkdLLDPTests(unittest.TestCase, Utilities):
1900     links = ['veth99']
1901
1902     units = [
1903         '23-emit-lldp.network',
1904         '24-lldp.network',
1905         '25-veth.netdev']
1906
1907     def setUp(self):
1908         remove_links(self.links)
1909
1910     def tearDown(self):
1911         remove_links(self.links)
1912         remove_unit_from_networkd_path(self.units)
1913
1914     def test_lldp(self):
1915         copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1916         start_networkd(0)
1917         wait_online(['veth99:degraded', 'veth-peer:degraded'])
1918
1919         output = check_output(*networkctl_cmd, 'lldp', env=env)
1920         print(output)
1921         self.assertRegex(output, 'veth-peer')
1922         self.assertRegex(output, 'veth99')
1923
1924 class NetworkdRATests(unittest.TestCase, Utilities):
1925     links = ['veth99']
1926
1927     units = [
1928         '25-veth.netdev',
1929         'ipv6-prefix.network',
1930         'ipv6-prefix-veth.network']
1931
1932     def setUp(self):
1933         remove_links(self.links)
1934
1935     def tearDown(self):
1936         remove_links(self.links)
1937         remove_unit_from_networkd_path(self.units)
1938
1939     def test_ipv6_prefix_delegation(self):
1940         warn_about_firewalld()
1941         copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1942         start_networkd(0)
1943         wait_online(['veth99:routable', 'veth-peer:degraded'])
1944
1945         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
1946         print(output)
1947         self.assertRegex(output, '2002:da8:1:0')
1948
1949 class NetworkdDHCPServerTests(unittest.TestCase, Utilities):
1950     links = ['veth99']
1951
1952     units = [
1953         '25-veth.netdev',
1954         'dhcp-client.network',
1955         'dhcp-client-timezone-router.network',
1956         'dhcp-server.network',
1957         'dhcp-server-timezone-router.network']
1958
1959     def setUp(self):
1960         remove_links(self.links)
1961
1962     def tearDown(self):
1963         remove_links(self.links)
1964         remove_unit_from_networkd_path(self.units)
1965
1966     def test_dhcp_server(self):
1967         warn_about_firewalld()
1968         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
1969         start_networkd(0)
1970         wait_online(['veth99:routable', 'veth-peer:routable'])
1971
1972         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
1973         print(output)
1974         self.assertRegex(output, '192.168.5.*')
1975         self.assertRegex(output, 'Gateway: 192.168.5.1')
1976         self.assertRegex(output, 'DNS: 192.168.5.1')
1977         self.assertRegex(output, 'NTP: 192.168.5.1')
1978
1979     def test_emit_router_timezone(self):
1980         warn_about_firewalld()
1981         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
1982         start_networkd(0)
1983         wait_online(['veth99:routable', 'veth-peer:routable'])
1984
1985         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
1986         print(output)
1987         self.assertRegex(output, 'Gateway: 192.168.5.*')
1988         self.assertRegex(output, '192.168.5.*')
1989         self.assertRegex(output, 'Europe/Berlin')
1990
1991 class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
1992     links = [
1993         'veth99',
1994         'vrf99']
1995
1996     units = [
1997         '25-veth.netdev',
1998         '25-vrf.netdev',
1999         '25-vrf.network',
2000         'dhcp-client-anonymize.network',
2001         'dhcp-client-gateway-onlink-implicit.network',
2002         'dhcp-client-ipv4-dhcp-settings.network',
2003         'dhcp-client-ipv4-only-ipv6-disabled.network',
2004         'dhcp-client-ipv4-only.network',
2005         'dhcp-client-ipv6-only.network',
2006         'dhcp-client-ipv6-rapid-commit.network',
2007         'dhcp-client-keep-configuration-dhcp-on-stop.network',
2008         'dhcp-client-keep-configuration-dhcp.network',
2009         'dhcp-client-listen-port.network',
2010         'dhcp-client-route-metric.network',
2011         'dhcp-client-route-table.network',
2012         'dhcp-client-vrf.network',
2013         'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2014         'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2015         'dhcp-client.network',
2016         'dhcp-server-veth-peer.network',
2017         'dhcp-v4-server-veth-peer.network',
2018         'static.network']
2019
2020     def setUp(self):
2021         stop_dnsmasq(dnsmasq_pid_file)
2022         remove_links(self.links)
2023
2024     def tearDown(self):
2025         stop_dnsmasq(dnsmasq_pid_file)
2026         remove_lease_file()
2027         remove_log_file()
2028         remove_links(self.links)
2029         remove_unit_from_networkd_path(self.units)
2030
2031     def test_dhcp_client_ipv6_only(self):
2032         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2033
2034         start_networkd(0)
2035         wait_online(['veth-peer:carrier'])
2036         start_dnsmasq()
2037         wait_online(['veth99:routable', 'veth-peer:routable'])
2038
2039         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2040         print(output)
2041         self.assertRegex(output, '2600::')
2042         self.assertNotRegex(output, '192.168.5')
2043
2044         # Confirm that ipv6 token is not set in the kernel
2045         output = check_output('ip token show dev veth99')
2046         print(output)
2047         self.assertRegex(output, 'token :: dev veth99')
2048
2049     def test_dhcp_client_ipv4_only(self):
2050         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2051
2052         start_networkd(0)
2053         wait_online(['veth-peer:carrier'])
2054         start_dnsmasq()
2055         wait_online(['veth99:routable', 'veth-peer:routable'])
2056
2057         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2058         print(output)
2059         self.assertNotRegex(output, '2600::')
2060         self.assertRegex(output, '192.168.5')
2061
2062     def test_dhcp_client_ipv4_ipv6(self):
2063         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2064                                         'dhcp-client-ipv4-only.network')
2065         start_networkd(0)
2066         wait_online(['veth-peer:carrier'])
2067         start_dnsmasq()
2068         wait_online(['veth99:routable', 'veth-peer:routable'])
2069
2070         # link become 'routable' when at least one protocol provide an valid address.
2071         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2072         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2073
2074         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2075         print(output)
2076         self.assertRegex(output, '2600::')
2077         self.assertRegex(output, '192.168.5')
2078
2079     def test_dhcp_client_settings(self):
2080         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2081
2082         start_networkd(0)
2083         wait_online(['veth-peer:carrier'])
2084         start_dnsmasq()
2085         wait_online(['veth99:routable', 'veth-peer:routable'])
2086
2087         print('## ip address show dev veth99')
2088         output = check_output('ip address show dev veth99')
2089         print(output)
2090         self.assertRegex(output, '12:34:56:78:9a:bc')
2091         self.assertRegex(output, '192.168.5')
2092         self.assertRegex(output, '1492')
2093
2094         # issue #8726
2095         print('## ip route show table main dev veth99')
2096         output = check_output('ip route show table main dev veth99')
2097         print(output)
2098         self.assertNotRegex(output, 'proto dhcp')
2099
2100         print('## ip route show table 211 dev veth99')
2101         output = check_output('ip route show table 211 dev veth99')
2102         print(output)
2103         self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
2104         self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2105         self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
2106
2107         print('## dnsmasq log')
2108         self.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2109         self.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2110         self.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2111         self.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2112
2113     def test_dhcp6_client_settings_rapidcommit_true(self):
2114         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2115         start_networkd(0)
2116         wait_online(['veth-peer:carrier'])
2117         start_dnsmasq()
2118         wait_online(['veth99:routable', 'veth-peer:routable'])
2119
2120         output = check_output('ip address show dev veth99')
2121         print(output)
2122         self.assertRegex(output, '12:34:56:78:9a:bc')
2123         self.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2124
2125     def test_dhcp6_client_settings_rapidcommit_false(self):
2126         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2127         start_networkd(0)
2128         wait_online(['veth-peer:carrier'])
2129         start_dnsmasq()
2130         wait_online(['veth99:routable', 'veth-peer:routable'])
2131
2132         output = check_output('ip address show dev veth99')
2133         print(output)
2134         self.assertRegex(output, '12:34:56:78:9a:bc')
2135         self.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2136
2137     def test_dhcp_client_settings_anonymize(self):
2138         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2139         start_networkd(0)
2140         wait_online(['veth-peer:carrier'])
2141         start_dnsmasq()
2142         wait_online(['veth99:routable', 'veth-peer:routable'])
2143
2144         self.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2145         self.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2146         self.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2147
2148     def test_dhcp_client_listen_port(self):
2149         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2150         start_networkd(0)
2151         wait_online(['veth-peer:carrier'])
2152         start_dnsmasq('--dhcp-alternate-port=67,5555')
2153         wait_online(['veth99:routable', 'veth-peer:routable'])
2154
2155         # link become 'routable' when at least one protocol provide an valid address.
2156         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2157         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2158
2159         output = check_output('ip -4 address show dev veth99')
2160         print(output)
2161         self.assertRegex(output, '192.168.5.* dynamic')
2162
2163     def test_dhcp_route_table_id(self):
2164         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2165         start_networkd(0)
2166         wait_online(['veth-peer:carrier'])
2167         start_dnsmasq()
2168         wait_online(['veth99:routable', 'veth-peer:routable'])
2169
2170         output = check_output('ip route show table 12')
2171         print(output)
2172         self.assertRegex(output, 'veth99 proto dhcp')
2173         self.assertRegex(output, '192.168.5.1')
2174
2175     def test_dhcp_route_metric(self):
2176         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2177         start_networkd(0)
2178         wait_online(['veth-peer:carrier'])
2179         start_dnsmasq()
2180         wait_online(['veth99:routable', 'veth-peer:routable'])
2181
2182         output = check_output('ip route show dev veth99')
2183         print(output)
2184         self.assertRegex(output, 'metric 24')
2185
2186     def test_dhcp_keep_configuration_dhcp(self):
2187         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2188         start_networkd(0)
2189         wait_online(['veth-peer:carrier'])
2190         start_dnsmasq(lease_time='2m')
2191         wait_online(['veth99:routable', 'veth-peer:routable'])
2192
2193         output = check_output('ip address show dev veth99 scope global')
2194         print(output)
2195         self.assertRegex(output, r'192.168.5.*')
2196
2197         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2198         print(output)
2199         self.assertRegex(output, r'192.168.5.*')
2200
2201         # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2202         stop_dnsmasq(dnsmasq_pid_file)
2203
2204         # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2205         print('Wait for the dynamic address to be expired')
2206         time.sleep(125)
2207
2208         print('The lease address should be kept after lease expired')
2209         output = check_output('ip address show dev veth99 scope global')
2210         print(output)
2211         self.assertRegex(output, r'192.168.5.*')
2212
2213         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2214         print(output)
2215         self.assertRegex(output, r'192.168.5.*')
2216
2217         check_output('systemctl stop systemd-networkd')
2218
2219         print('The lease address should be kept after networkd stopped')
2220         output = check_output('ip address show dev veth99 scope global')
2221         print(output)
2222         self.assertRegex(output, r'192.168.5.*')
2223
2224         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2225         print(output)
2226         self.assertRegex(output, r'192.168.5.*')
2227
2228         check_output('systemctl start systemd-networkd')
2229         wait_online(['veth-peer:routable'])
2230
2231         print('Still the lease address should be kept after networkd restarted')
2232         output = check_output('ip address show dev veth99 scope global')
2233         print(output)
2234         self.assertRegex(output, r'192.168.5.*')
2235
2236         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2237         print(output)
2238         self.assertRegex(output, r'192.168.5.*')
2239
2240     def test_dhcp_keep_configuration_dhcp_on_stop(self):
2241         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2242         start_networkd(0)
2243         wait_online(['veth-peer:carrier'])
2244         start_dnsmasq(lease_time='2m')
2245         wait_online(['veth99:routable', 'veth-peer:routable'])
2246
2247         output = check_output('ip address show dev veth99 scope global')
2248         print(output)
2249         self.assertRegex(output, r'192.168.5.*')
2250
2251         stop_dnsmasq(dnsmasq_pid_file)
2252         check_output('systemctl stop systemd-networkd')
2253
2254         output = check_output('ip address show dev veth99 scope global')
2255         print(output)
2256         self.assertRegex(output, r'192.168.5.*')
2257
2258         start_networkd(0)
2259         wait_online(['veth-peer:routable'])
2260
2261         output = check_output('ip address show dev veth99 scope global')
2262         print(output)
2263         self.assertNotRegex(output, r'192.168.5.*')
2264
2265     def test_dhcp_client_reuse_address_as_static(self):
2266         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2267         start_networkd(0)
2268         wait_online(['veth-peer:carrier'])
2269         start_dnsmasq()
2270         wait_online(['veth99:routable', 'veth-peer:routable'])
2271
2272         # link become 'routable' when at least one protocol provide an valid address.
2273         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2274         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2275
2276         output = check_output('ip address show dev veth99 scope global')
2277         print(output)
2278         self.assertRegex(output, '192.168.5')
2279         self.assertRegex(output, '2600::')
2280
2281         ipv4_address = re.search(r'192.168.5.[0-9]*/24', output)
2282         ipv6_address = re.search(r'2600::[0-9a-f:]*/128', output)
2283         static_network = '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address.group(), 'Address=' + ipv6_address.group()])
2284         print(static_network)
2285
2286         remove_unit_from_networkd_path(['dhcp-client.network'])
2287
2288         with open(os.path.join(network_unit_file_path, 'static.network'), mode='w') as f:
2289             f.write(static_network)
2290
2291         # When networkd started, the links are already configured, so let's wait for 5 seconds
2292         # the links to be re-configured.
2293         start_networkd(5)
2294         wait_online(['veth99:routable', 'veth-peer:routable'])
2295
2296         output = check_output('ip -4 address show dev veth99 scope global')
2297         print(output)
2298         self.assertRegex(output, '192.168.5')
2299         self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2300
2301         output = check_output('ip -6 address show dev veth99 scope global')
2302         print(output)
2303         self.assertRegex(output, '2600::')
2304         self.assertRegex(output, 'valid_lft forever preferred_lft forever')
2305
2306     @expectedFailureIfModuleIsNotAvailable('vrf')
2307     def test_dhcp_client_vrf(self):
2308         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2309                                         '25-vrf.netdev', '25-vrf.network')
2310         start_networkd(0)
2311         wait_online(['veth-peer:carrier'])
2312         start_dnsmasq()
2313         wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2314
2315         # link become 'routable' when at least one protocol provide an valid address.
2316         self.wait_address('veth99', r'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv='-4')
2317         self.wait_address('veth99', r'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv='-6')
2318
2319         print('## ip -d link show dev vrf99')
2320         output = check_output('ip -d link show dev vrf99')
2321         print(output)
2322         self.assertRegex(output, 'vrf table 42')
2323
2324         print('## ip address show vrf vrf99')
2325         output = check_output('ip address show vrf vrf99')
2326         print(output)
2327         self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2328         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2329         self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2330         self.assertRegex(output, 'inet6 .* scope link')
2331
2332         print('## ip address show dev veth99')
2333         output = check_output('ip address show dev veth99')
2334         print(output)
2335         self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2336         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2337         self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2338         self.assertRegex(output, 'inet6 .* scope link')
2339
2340         print('## ip route show vrf vrf99')
2341         output = check_output('ip route show vrf vrf99')
2342         print(output)
2343         self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2344         self.assertRegex(output, 'default dev veth99 proto static scope link')
2345         self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2346         self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2347         self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2348         self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2349
2350         print('## ip route show table main dev veth99')
2351         output = check_output('ip route show table main dev veth99')
2352         print(output)
2353         self.assertEqual(output, '')
2354
2355     def test_dhcp_client_gateway_onlink_implicit(self):
2356         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2357                                         'dhcp-client-gateway-onlink-implicit.network')
2358         start_networkd(0)
2359         wait_online(['veth-peer:carrier'])
2360         start_dnsmasq()
2361         wait_online(['veth99:routable', 'veth-peer:routable'])
2362
2363         output = check_output(*networkctl_cmd, 'status', 'veth99', env=env)
2364         print(output)
2365         self.assertRegex(output, '192.168.5')
2366
2367         output = check_output('ip route list dev veth99 10.0.0.0/8')
2368         print(output)
2369         self.assertRegex(output, 'onlink')
2370         output = check_output('ip route list dev veth99 192.168.100.0/24')
2371         print(output)
2372         self.assertRegex(output, 'onlink')
2373
2374     def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
2375         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2376                                         'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2377         start_networkd(0)
2378         wait_online(['veth-peer:carrier'])
2379         start_dnsmasq(lease_time='2m')
2380         wait_online(['veth99:routable', 'veth-peer:routable'])
2381
2382         output = check_output('ip address show dev veth99')
2383         print(output)
2384
2385         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2386         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2387         output = check_output('ip -6 address show dev veth99 scope link')
2388         self.assertRegex(output, 'inet6 .* scope link')
2389         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2390         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2391         output = check_output('ip -4 address show dev veth99 scope link')
2392         self.assertNotRegex(output, 'inet .* scope link')
2393
2394         print('Wait for the dynamic address to be expired')
2395         time.sleep(130)
2396
2397         output = check_output('ip address show dev veth99')
2398         print(output)
2399
2400         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2401         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2402         output = check_output('ip -6 address show dev veth99 scope link')
2403         self.assertRegex(output, 'inet6 .* scope link')
2404         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2405         self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2406         output = check_output('ip -4 address show dev veth99 scope link')
2407         self.assertNotRegex(output, 'inet .* scope link')
2408
2409         search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
2410
2411     def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
2412         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2413                                         'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2414         start_networkd(0)
2415         wait_online(['veth99:degraded', 'veth-peer:routable'])
2416
2417         output = check_output('ip address show dev veth99')
2418         print(output)
2419
2420         output = check_output('ip -6 address show dev veth99 scope global dynamic')
2421         self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2422         output = check_output('ip -6 address show dev veth99 scope link')
2423         self.assertRegex(output, 'inet6 .* scope link')
2424         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2425         self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2426         output = check_output('ip -4 address show dev veth99 scope link')
2427         self.assertRegex(output, 'inet .* scope link')
2428
2429     def test_dhcp_client_route_remove_on_renew(self):
2430         copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2431                                         'dhcp-client-ipv4-only-ipv6-disabled.network')
2432         start_networkd(0)
2433         wait_online(['veth-peer:carrier'])
2434         start_dnsmasq(ipv4_range='192.168.5.100,192.168.5.199', lease_time='2m')
2435         wait_online(['veth99:routable', 'veth-peer:routable'])
2436
2437         # test for issue #12490
2438
2439         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2440         print(output)
2441         self.assertRegex(output, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2442         address1=None
2443         for line in output.splitlines():
2444             if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2445                 address1 = line.split()[1].split('/')[0]
2446                 break
2447
2448         output = check_output('ip -4 route show dev veth99')
2449         print(output)
2450         self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2451         self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2452
2453         stop_dnsmasq(dnsmasq_pid_file)
2454         start_dnsmasq(ipv4_range='192.168.5.200,192.168.5.250', lease_time='2m')
2455
2456         print('Wait for the dynamic address to be expired')
2457         time.sleep(130)
2458
2459         output = check_output('ip -4 address show dev veth99 scope global dynamic')
2460         print(output)
2461         self.assertRegex(output, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2462         address2=None
2463         for line in output.splitlines():
2464             if 'brd 192.168.5.255 scope global dynamic veth99' in line:
2465                 address2 = line.split()[1].split('/')[0]
2466                 break
2467
2468         self.assertNotEqual(address1, address2)
2469
2470         output = check_output('ip -4 route show dev veth99')
2471         print(output)
2472         self.assertNotRegex(output, f'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2473         self.assertNotRegex(output, f'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2474         self.assertRegex(output, f'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2475         self.assertRegex(output, f'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2476
2477 if __name__ == '__main__':
2478     parser = argparse.ArgumentParser()
2479     parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
2480     parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
2481     parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
2482     parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
2483     parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
2484     parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
2485     parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
2486     parser.add_argument('--lsan-options', help='LSAN options', dest='lsan_options')
2487     parser.add_argument('--ubsan-options', help='UBSAN options', dest='ubsan_options')
2488     ns, args = parser.parse_known_args(namespace=unittest)
2489
2490     if ns.build_dir:
2491         if ns.networkd_bin or ns.wait_online_bin or ns.networkctl_bin:
2492             print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2493         networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
2494         wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
2495         networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
2496     else:
2497         if ns.networkd_bin:
2498             networkd_bin = ns.networkd_bin
2499         if ns.wait_online_bin:
2500             wait_online_bin = ns.wait_online_bin
2501         if ns.networkctl_bin:
2502             networkctl_bin = ns.networkctl_bin
2503
2504     use_valgrind = ns.use_valgrind
2505     enable_debug = ns.enable_debug
2506     asan_options = ns.asan_options
2507     lsan_options = ns.lsan_options
2508     ubsan_options = ns.ubsan_options
2509
2510     if use_valgrind:
2511         networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
2512         wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
2513     else:
2514         networkctl_cmd = [networkctl_bin]
2515         wait_online_cmd = [wait_online_bin]
2516
2517     if enable_debug:
2518         env.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2519     if asan_options:
2520         env.update({ 'ASAN_OPTIONS' : asan_options })
2521     if lsan_options:
2522         env.update({ 'LSAN_OPTIONS' : lsan_options })
2523     if ubsan_options:
2524         env.update({ 'UBSAN_OPTIONS' : ubsan_options })
2525
2526     sys.argv[1:] = args
2527     unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
2528                                                      verbosity=3))