2 # SPDX-License-Identifier: LGPL-2.1+
3 # systemd-networkd tests
14 from shutil
import copytree
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'
22 dnsmasq_pid_file
='/run/networkd-ci/test-test-dnsmasq.pid'
23 dnsmasq_log_file
='/run/networkd-ci/test-dnsmasq-log-file'
25 systemd_lib_paths
=['/usr/lib/systemd', '/lib/systemd']
26 which_paths
=':'.join(systemd_lib_paths
+ os
.getenv('PATH', os
.defpath
).lstrip(':').split(':'))
28 networkd_bin
=shutil
.which('systemd-networkd', path
=which_paths
)
29 resolved_bin
=shutil
.which('systemd-resolved', path
=which_paths
)
30 wait_online_bin
=shutil
.which('systemd-networkd-wait-online', path
=which_paths
)
31 networkctl_bin
=shutil
.which('networkctl', path
=which_paths
)
32 resolvectl_bin
=shutil
.which('resolvectl', path
=which_paths
)
33 timedatectl_bin
=shutil
.which('timedatectl', path
=which_paths
)
44 def check_output(*command
, **kwargs
):
45 # This replaces both check_output and check_call (output can be ignored)
46 command
= command
[0].split() + list(command
[1:])
47 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
49 def call(*command
, **kwargs
):
50 command
= command
[0].split() + list(command
[1:])
51 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
53 def run(*command
, **kwargs
):
54 command
= command
[0].split() + list(command
[1:])
55 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
57 def is_module_available(module_name
):
58 lsmod_output
= check_output('lsmod')
59 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
60 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
, stderr
=subprocess
.DEVNULL
)
62 def expectedFailureIfModuleIsNotAvailable(module_name
):
64 if not is_module_available(module_name
):
65 return unittest
.expectedFailure(func
)
70 def expectedFailureIfERSPANModuleIsNotAvailable():
72 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', stderr
=subprocess
.DEVNULL
)
74 call('ip link del erspan99')
77 return unittest
.expectedFailure(func
)
81 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
83 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7', stderr
=subprocess
.DEVNULL
)
85 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
88 return unittest
.expectedFailure(func
)
92 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
94 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7', stderr
=subprocess
.DEVNULL
)
96 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
99 return unittest
.expectedFailure(func
)
103 def expectedFailureIfLinkFileFieldIsNotSet():
106 rc
= call('ip link add name dummy99 type dummy', stderr
=subprocess
.DEVNULL
)
108 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
109 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
111 call('ip link del dummy99')
116 return unittest
.expectedFailure(func
)
120 def expectedFailureIfNexthopIsNotAvailable():
122 rc
= call('ip nexthop list', stderr
=subprocess
.DEVNULL
)
126 return unittest
.expectedFailure(func
)
130 def expectedFailureIfAlternativeNameIsNotAvailable():
132 call('ip link add dummy98 type dummy', stderr
=subprocess
.DEVNULL
)
133 rc
= call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr
=subprocess
.DEVNULL
)
137 return unittest
.expectedFailure(func
)
144 os
.makedirs(network_unit_file_path
, exist_ok
=True)
145 os
.makedirs(networkd_ci_path
, exist_ok
=True)
147 shutil
.rmtree(networkd_ci_path
)
148 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
150 for u
in ['systemd-networkd.socket', 'systemd-networkd.service', 'systemd-resolved.service', 'firewalld.service']:
151 if call(f
'systemctl is-active --quiet {u}') == 0:
152 check_output(f
'systemctl stop {u}')
153 running_units
.append(u
)
157 'StartLimitIntervalSec=0',
164 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
168 drop_in
+= ['ExecStart=!!' + networkd_bin
]
170 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
172 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
174 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
176 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
177 if asan_options
or lsan_options
or ubsan_options
:
178 drop_in
+= ['SystemCallFilter=']
179 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
180 drop_in
+= ['MemoryDenyWriteExecute=no']
182 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
183 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
184 f
.write('\n'.join(drop_in
))
192 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
194 drop_in
+= ['ExecStart=!!' + resolved_bin
]
196 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
198 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
200 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
202 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
203 if asan_options
or lsan_options
or ubsan_options
:
204 drop_in
+= ['SystemCallFilter=']
205 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
206 drop_in
+= ['MemoryDenyWriteExecute=no']
208 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
209 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
210 f
.write('\n'.join(drop_in
))
212 check_output('systemctl daemon-reload')
213 print(check_output('systemctl cat systemd-networkd.service'))
214 print(check_output('systemctl cat systemd-resolved.service'))
215 check_output('systemctl restart systemd-resolved')
217 def tearDownModule():
220 shutil
.rmtree(networkd_ci_path
)
222 for u
in ['systemd-networkd.service', 'systemd-resolved.service']:
223 check_output(f
'systemctl stop {u}')
225 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
226 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
227 check_output('systemctl daemon-reload')
229 for u
in running_units
:
230 check_output(f
'systemctl start {u}')
232 def read_link_attr(*args
):
233 with
open(os
.path
.join('/sys/class/net/', *args
)) as f
:
234 return f
.readline().strip()
236 def read_bridge_port_attr(bridge
, link
, attribute
):
237 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
238 path_port
= 'lower_' + link
+ '/brport'
239 path
= os
.path
.join(path_bridge
, path_port
)
241 with
open(os
.path
.join(path
, attribute
)) as f
:
242 return f
.readline().strip()
244 def link_exists(link
):
245 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
247 def remove_links(links
):
249 if link_exists(link
):
250 call('ip link del dev', link
)
253 def remove_fou_ports(ports
):
255 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
257 def remove_routing_policy_rule_tables(tables
):
261 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
263 def remove_routes(routes
):
264 for route_type
, addr
in routes
:
265 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
267 def remove_l2tp_tunnels(tunnel_ids
):
268 output
= check_output('ip l2tp show tunnel')
269 for tid
in tunnel_ids
:
270 words
='Tunnel ' + tid
+ ', encap'
272 call('ip l2tp del tunnel tid', tid
)
275 def read_ipv6_sysctl_attr(link
, attribute
):
276 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
277 return f
.readline().strip()
279 def read_ipv4_sysctl_attr(link
, attribute
):
280 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
281 return f
.readline().strip()
283 def copy_unit_to_networkd_unit_path(*units
, dropins
=True):
284 """Copy networkd unit files into the testbed.
286 Any networkd unit file type can be specified, as well as drop-in files.
288 By default, all drop-ins for a specified unit file are copied in;
289 to avoid that specify dropins=False.
291 When a drop-in file is specified, its unit file is also copied in automatically.
295 if dropins
and os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d')):
296 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
297 if unit
.endswith('.conf'):
299 dropindir
= os
.path
.join(network_unit_file_path
, os
.path
.dirname(dropin
))
300 os
.makedirs(dropindir
, exist_ok
=True)
301 shutil
.copy(os
.path
.join(networkd_ci_path
, dropin
), dropindir
)
302 unit
= os
.path
.dirname(dropin
).rstrip('.d')
303 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
305 def remove_unit_from_networkd_path(units
):
306 """Remove previously copied unit files from the testbed.
308 Drop-ins will be removed automatically.
311 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
312 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
313 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
314 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
316 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
317 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
318 check_output(dnsmasq_command
)
320 def stop_dnsmasq(pid_file
):
321 if os
.path
.exists(pid_file
):
322 with
open(pid_file
, 'r') as f
:
323 pid
= f
.read().rstrip(' \t\r\n\0')
324 os
.kill(int(pid
), signal
.SIGTERM
)
328 def search_words_in_dnsmasq_log(words
, show_all
=False):
329 if os
.path
.exists(dnsmasq_log_file
):
330 with
open (dnsmasq_log_file
) as in_file
:
331 contents
= in_file
.read()
334 for line
in contents
.splitlines():
337 print("%s, %s" % (words
, line
))
341 def remove_lease_file():
342 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
343 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
345 def remove_log_file():
346 if os
.path
.exists(dnsmasq_log_file
):
347 os
.remove(dnsmasq_log_file
)
349 def remove_networkd_state_files():
350 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
351 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
353 def stop_networkd(show_logs
=True, remove_state_files
=True):
355 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
356 check_output('systemctl stop systemd-networkd')
358 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
359 if remove_state_files
:
360 remove_networkd_state_files()
362 def start_networkd(sleep_sec
=0):
363 check_output('systemctl start systemd-networkd')
365 time
.sleep(sleep_sec
)
367 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
368 stop_networkd(show_logs
, remove_state_files
)
369 start_networkd(sleep_sec
)
371 def get_operstate(link
, show_status
=True, setup_state
='configured'):
372 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
375 for line
in output
.splitlines():
376 if 'State:' in line
and (not setup_state
or setup_state
in line
):
377 return line
.split()[1]
381 def check_link_exists(self
, link
):
382 self
.assertTrue(link_exists(link
))
384 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
385 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
387 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured', setup_timeout
=5):
388 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
392 check_output(*args
, env
=env
)
393 except subprocess
.CalledProcessError
:
394 for link
in links_with_operstate
:
395 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
398 if not bool_any
and setup_state
:
399 # check at least once now, then once per sec for setup_timeout secs
400 for secs
in range(setup_timeout
+ 1):
401 for link
in links_with_operstate
:
402 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0])
404 if not re
.search(rf
'(?m)^\s*State:.*({setup_state}).*$', output
):
405 # this link isn't in the right state; break into the sleep below
408 # all the links were in the right state; break to exit the timer loop
410 # don't bother sleeping if time is up
411 if secs
< setup_timeout
:
414 self
.fail(f
'link {link} state does not match {setup_state}')
416 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
417 for i
in range(timeout_sec
):
420 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
421 if re
.search(address_regex
, output
):
424 self
.assertRegex(output
, address_regex
)
426 class NetworkctlTests(unittest
.TestCase
, Utilities
):
436 '11-dummy-mtu.netdev',
440 '25-address-static.network',
442 'netdev-link-local-addressing-yes.network',
446 remove_links(self
.links
)
447 stop_networkd(show_logs
=False)
450 remove_links(self
.links
)
451 remove_unit_from_networkd_path(self
.units
)
452 stop_networkd(show_logs
=True)
454 @expectedFailureIfAlternativeNameIsNotAvailable()
455 def test_altname(self
):
456 copy_unit_to_networkd_unit_path('netdev-link-local-addressing-yes.network', '12-dummy.netdev', '12-dummy.link')
457 check_output('udevadm control --reload')
459 self
.wait_online(['dummy98:degraded'])
461 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
462 self
.assertRegex(output
, 'hogehogehogehogehogehoge')
464 def test_reconfigure(self
):
465 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
467 self
.wait_online(['dummy98:routable'])
469 output
= check_output('ip -4 address show dev dummy98')
471 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
472 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
473 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
475 check_output('ip address del 10.1.2.3/16 dev dummy98')
476 check_output('ip address del 10.1.2.4/16 dev dummy98')
477 check_output('ip address del 10.2.2.4/16 dev dummy98')
479 check_output(*networkctl_cmd
, 'reconfigure', 'dummy98', env
=env
)
480 self
.wait_online(['dummy98:routable'])
482 output
= check_output('ip -4 address show dev dummy98')
484 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
485 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
486 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
488 def test_reload(self
):
491 copy_unit_to_networkd_unit_path('11-dummy.netdev')
492 check_output(*networkctl_cmd
, 'reload', env
=env
)
494 self
.check_link_exists('test1')
495 self
.check_operstate('test1', 'off', setup_state
='unmanaged')
497 copy_unit_to_networkd_unit_path('11-dummy.network')
498 check_output(*networkctl_cmd
, 'reload', env
=env
)
499 self
.wait_online(['test1:degraded'])
501 remove_unit_from_networkd_path(['11-dummy.network'])
502 check_output(*networkctl_cmd
, 'reload', env
=env
)
504 self
.check_operstate('test1', 'degraded', setup_state
='unmanaged')
506 remove_unit_from_networkd_path(['11-dummy.netdev'])
507 check_output(*networkctl_cmd
, 'reload', env
=env
)
508 self
.check_operstate('test1', 'degraded', setup_state
='unmanaged')
510 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
511 check_output(*networkctl_cmd
, 'reload', env
=env
)
512 self
.check_operstate('test1', 'degraded')
515 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
518 self
.wait_online(['test1:degraded'])
520 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
521 self
.assertRegex(output
, '1 lo ')
522 self
.assertRegex(output
, 'test1')
524 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
525 self
.assertNotRegex(output
, '1 lo ')
526 self
.assertRegex(output
, 'test1')
528 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
529 self
.assertNotRegex(output
, '1 lo ')
530 self
.assertRegex(output
, 'test1')
532 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
533 self
.assertNotRegex(output
, '1: lo ')
534 self
.assertRegex(output
, 'test1')
536 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
537 self
.assertNotRegex(output
, '1: lo ')
538 self
.assertRegex(output
, 'test1')
541 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
544 self
.wait_online(['test1:degraded'])
546 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
547 self
.assertRegex(output
, 'MTU: 1600')
550 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
552 self
.wait_online(['test1:degraded'])
554 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
556 self
.assertRegex(output
, 'Type: ether')
558 output
= check_output(*networkctl_cmd
, 'status', 'lo', env
=env
)
560 self
.assertRegex(output
, 'Type: loopback')
562 @expectedFailureIfLinkFileFieldIsNotSet()
563 def test_udev_link_file(self
):
564 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
566 self
.wait_online(['test1:degraded'])
568 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
570 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
571 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
573 output
= check_output(*networkctl_cmd
, 'status', 'lo', env
=env
)
575 self
.assertRegex(output
, r
'Link File: (/usr)?/lib/systemd/network/99-default.link')
576 self
.assertRegex(output
, r
'Network File: n/a')
578 def test_delete_links(self
):
579 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
580 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
583 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
585 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99', env
=env
)
586 self
.assertFalse(link_exists('test1'))
587 self
.assertFalse(link_exists('veth99'))
588 self
.assertFalse(link_exists('veth-peer'))
590 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
592 links_remove_earlier
= [
657 '10-dropin-test.netdev',
661 '13-not-match-udev-property.network',
662 '14-match-udev-property.network',
663 '15-name-conflict-test.netdev',
666 '21-vlan-test1.network',
669 '25-6rd-tunnel.netdev',
671 '25-bond-balanced-tlb.netdev',
673 '25-bridge-configure-without-carrier.network',
675 '25-erspan-tunnel-local-any.netdev',
676 '25-erspan-tunnel.netdev',
677 '25-fou-gretap.netdev',
679 '25-fou-ipip.netdev',
680 '25-fou-ipproto-gre.netdev',
681 '25-fou-ipproto-ipip.netdev',
684 '25-gretap-tunnel-local-any.netdev',
685 '25-gretap-tunnel.netdev',
686 '25-gre-tunnel-any-any.netdev',
687 '25-gre-tunnel-local-any.netdev',
688 '25-gre-tunnel-remote-any.netdev',
689 '25-gre-tunnel.netdev',
691 '25-ip6gretap-tunnel-local-any.netdev',
692 '25-ip6gretap-tunnel.netdev',
693 '25-ip6gre-tunnel-any-any.netdev',
694 '25-ip6gre-tunnel-local-any.netdev',
695 '25-ip6gre-tunnel-remote-any.netdev',
696 '25-ip6gre-tunnel.netdev',
697 '25-ip6tnl-tunnel-any-any.netdev',
698 '25-ip6tnl-tunnel-local-any.netdev',
699 '25-ip6tnl-tunnel-remote-any.netdev',
700 '25-ip6tnl-tunnel.netdev',
701 '25-ipip-tunnel-any-any.netdev',
702 '25-ipip-tunnel-independent.netdev',
703 '25-ipip-tunnel-independent-loopback.netdev',
704 '25-ipip-tunnel-local-any.netdev',
705 '25-ipip-tunnel-remote-any.netdev',
706 '25-ipip-tunnel.netdev',
709 '25-isatap-tunnel.netdev',
714 '25-sit-tunnel-any-any.netdev',
715 '25-sit-tunnel-local-any.netdev',
716 '25-sit-tunnel-remote-any.netdev',
717 '25-sit-tunnel.netdev',
720 '25-tunnel-local-any.network',
721 '25-tunnel-remote-any.network',
726 '25-vti6-tunnel-any-any.netdev',
727 '25-vti6-tunnel-local-any.netdev',
728 '25-vti6-tunnel-remote-any.netdev',
729 '25-vti6-tunnel.netdev',
730 '25-vti-tunnel-any-any.netdev',
731 '25-vti-tunnel-local-any.netdev',
732 '25-vti-tunnel-remote-any.netdev',
733 '25-vti-tunnel.netdev',
736 '25-wireguard-23-peers.netdev',
737 '25-wireguard-23-peers.network',
738 '25-wireguard-preshared-key.txt',
739 '25-wireguard-private-key.txt',
740 '25-wireguard.netdev',
741 '25-wireguard.network',
743 '25-xfrm-independent.netdev',
759 'netdev-link-local-addressing-yes.network',
763 'vxlan-test1.network',
773 remove_fou_ports(self
.fou_ports
)
774 remove_links(self
.links_remove_earlier
)
775 remove_links(self
.links
)
776 stop_networkd(show_logs
=False)
779 remove_fou_ports(self
.fou_ports
)
780 remove_links(self
.links_remove_earlier
)
781 remove_links(self
.links
)
782 remove_unit_from_networkd_path(self
.units
)
783 stop_networkd(show_logs
=True)
785 def test_dropin_and_name_conflict(self
):
786 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
789 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
791 output
= check_output('ip link show dropin-test')
793 self
.assertRegex(output
, '00:50:56:c0:00:28')
795 def test_match_udev_property(self
):
796 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
798 self
.wait_online(['dummy98:routable'])
800 output
= check_output('networkctl status dummy98')
802 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
804 def test_wait_online_any(self
):
805 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
808 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
810 self
.check_operstate('bridge99', '(off|no-carrier)', setup_state
='configuring')
811 self
.check_operstate('test1', 'degraded')
813 def test_bridge(self
):
814 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
817 self
.wait_online(['bridge99:no-carrier'])
819 tick
= os
.sysconf('SC_CLK_TCK')
820 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
821 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
822 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'forward_delay')) / tick
))
823 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'ageing_time')) / tick
))
824 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge', 'priority')))
825 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_querier')))
826 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'multicast_snooping')))
827 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge', 'stp_state')))
828 self
.assertEqual(3, int(read_link_attr('bridge99', 'bridge', 'multicast_igmp_version')))
830 output
= check_output(*networkctl_cmd
, 'status', 'bridge99', env
=env
)
832 self
.assertRegex(output
, 'Priority: 9')
833 self
.assertRegex(output
, 'STP: yes')
834 self
.assertRegex(output
, 'Multicast IGMP Version: 3')
837 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
840 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
842 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
843 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
844 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
845 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
846 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
847 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
848 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
849 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
850 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
851 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
852 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
854 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
855 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
858 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
859 '21-vlan.network', '21-vlan-test1.network')
862 self
.wait_online(['test1:degraded', 'vlan99:routable'])
864 output
= check_output('ip -d link show test1')
866 self
.assertRegex(output
, ' mtu 2000 ')
868 output
= check_output('ip -d link show vlan99')
870 self
.assertRegex(output
, ' mtu 2000 ')
871 self
.assertRegex(output
, 'REORDER_HDR')
872 self
.assertRegex(output
, 'LOOSE_BINDING')
873 self
.assertRegex(output
, 'GVRP')
874 self
.assertRegex(output
, 'MVRP')
875 self
.assertRegex(output
, ' id 99 ')
877 output
= check_output('ip -4 address show dev test1')
879 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
880 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
882 output
= check_output('ip -4 address show dev vlan99')
884 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
886 def test_macvtap(self
):
887 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
888 with self
.subTest(mode
=mode
):
889 if mode
!= 'private':
891 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
892 '11-dummy.netdev', 'macvtap.network')
893 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
894 f
.write('[MACVTAP]\nMode=' + mode
)
897 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
899 output
= check_output('ip -d link show macvtap99')
901 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
903 def test_macvlan(self
):
904 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
905 with self
.subTest(mode
=mode
):
906 if mode
!= 'private':
908 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
909 '11-dummy.netdev', 'macvlan.network')
910 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
911 f
.write('[MACVLAN]\nMode=' + mode
)
914 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
916 output
= check_output('ip -d link show test1')
918 self
.assertRegex(output
, ' mtu 2000 ')
920 output
= check_output('ip -d link show macvlan99')
922 self
.assertRegex(output
, ' mtu 2000 ')
923 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
925 @expectedFailureIfModuleIsNotAvailable('ipvlan')
926 def test_ipvlan(self
):
927 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
928 with self
.subTest(mode
=mode
, flag
=flag
):
931 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
932 '11-dummy.netdev', 'ipvlan.network')
933 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
934 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
937 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
939 output
= check_output('ip -d link show ipvlan99')
941 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
943 @expectedFailureIfModuleIsNotAvailable('ipvtap')
944 def test_ipvtap(self
):
945 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
946 with self
.subTest(mode
=mode
, flag
=flag
):
949 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
950 '11-dummy.netdev', 'ipvtap.network')
951 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
952 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
955 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
957 output
= check_output('ip -d link show ipvtap99')
959 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
962 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
965 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
967 output
= check_output('ip -d link show veth99')
969 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
970 output
= check_output('ip -d link show veth-peer')
972 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
975 copy_unit_to_networkd_unit_path('25-tun.netdev')
978 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
980 output
= check_output('ip -d link show tun99')
982 # Old ip command does not support IFF_ flags
983 self
.assertRegex(output
, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
986 copy_unit_to_networkd_unit_path('25-tap.netdev')
989 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
991 output
= check_output('ip -d link show tap99')
993 # Old ip command does not support IFF_ flags
994 self
.assertRegex(output
, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
996 @expectedFailureIfModuleIsNotAvailable('vrf')
998 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
1001 self
.wait_online(['vrf99:carrier'])
1003 @expectedFailureIfModuleIsNotAvailable('vcan')
1004 def test_vcan(self
):
1005 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
1008 self
.wait_online(['vcan99:carrier'])
1010 @expectedFailureIfModuleIsNotAvailable('vxcan')
1011 def test_vxcan(self
):
1012 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
1015 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
1017 @expectedFailureIfModuleIsNotAvailable('wireguard')
1018 def test_wireguard(self
):
1019 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
1020 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
1021 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
1023 self
.wait_online(['wg99:carrier', 'wg98:routable'])
1025 if shutil
.which('wg'):
1028 output
= check_output('wg show wg99 listen-port')
1029 self
.assertRegex(output
, '51820')
1030 output
= check_output('wg show wg99 fwmark')
1031 self
.assertRegex(output
, '0x4d2')
1032 output
= check_output('wg show wg99 allowed-ips')
1033 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
1034 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
1035 output
= check_output('wg show wg99 persistent-keepalive')
1036 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
1037 output
= check_output('wg show wg99 endpoints')
1038 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
1039 output
= check_output('wg show wg99 private-key')
1040 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
1041 output
= check_output('wg show wg99 preshared-keys')
1042 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
1043 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
1045 output
= check_output('wg show wg98 private-key')
1046 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
1048 def test_geneve(self
):
1049 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
1052 self
.wait_online(['geneve99:degraded'])
1054 output
= check_output('ip -d link show geneve99')
1056 self
.assertRegex(output
, '192.168.22.1')
1057 self
.assertRegex(output
, '6082')
1058 self
.assertRegex(output
, 'udpcsum')
1059 self
.assertRegex(output
, 'udp6zerocsumrx')
1061 def test_ipip_tunnel(self
):
1062 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
1063 '25-ipip-tunnel.netdev', '25-tunnel.network',
1064 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1065 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1066 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1068 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
1070 output
= check_output('ip -d link show ipiptun99')
1072 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local 192.168.223.238 dev dummy98')
1073 output
= check_output('ip -d link show ipiptun98')
1075 self
.assertRegex(output
, 'ipip (ipip )?remote 192.169.224.239 local any dev dummy98')
1076 output
= check_output('ip -d link show ipiptun97')
1078 self
.assertRegex(output
, 'ipip (ipip )?remote any local 192.168.223.238 dev dummy98')
1079 output
= check_output('ip -d link show ipiptun96')
1081 self
.assertRegex(output
, 'ipip (ipip )?remote any local any dev dummy98')
1083 def test_gre_tunnel(self
):
1084 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
1085 '25-gre-tunnel.netdev', '25-tunnel.network',
1086 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1087 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1088 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1090 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
1092 output
= check_output('ip -d link show gretun99')
1094 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1095 self
.assertRegex(output
, 'ikey 1.2.3.103')
1096 self
.assertRegex(output
, 'okey 1.2.4.103')
1097 self
.assertRegex(output
, 'iseq')
1098 self
.assertRegex(output
, 'oseq')
1099 output
= check_output('ip -d link show gretun98')
1101 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
1102 self
.assertRegex(output
, 'ikey 0.0.0.104')
1103 self
.assertRegex(output
, 'okey 0.0.0.104')
1104 self
.assertNotRegex(output
, 'iseq')
1105 self
.assertNotRegex(output
, 'oseq')
1106 output
= check_output('ip -d link show gretun97')
1108 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
1109 self
.assertRegex(output
, 'ikey 0.0.0.105')
1110 self
.assertRegex(output
, 'okey 0.0.0.105')
1111 self
.assertNotRegex(output
, 'iseq')
1112 self
.assertNotRegex(output
, 'oseq')
1113 output
= check_output('ip -d link show gretun96')
1115 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
1116 self
.assertRegex(output
, 'ikey 0.0.0.106')
1117 self
.assertRegex(output
, 'okey 0.0.0.106')
1118 self
.assertNotRegex(output
, 'iseq')
1119 self
.assertNotRegex(output
, 'oseq')
1121 def test_ip6gre_tunnel(self
):
1122 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
1123 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
1124 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1125 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1126 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1129 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1131 self
.check_link_exists('dummy98')
1132 self
.check_link_exists('ip6gretun99')
1133 self
.check_link_exists('ip6gretun98')
1134 self
.check_link_exists('ip6gretun97')
1135 self
.check_link_exists('ip6gretun96')
1137 output
= check_output('ip -d link show ip6gretun99')
1139 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1140 output
= check_output('ip -d link show ip6gretun98')
1142 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1143 output
= check_output('ip -d link show ip6gretun97')
1145 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1146 output
= check_output('ip -d link show ip6gretun96')
1148 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1150 def test_gretap_tunnel(self
):
1151 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1152 '25-gretap-tunnel.netdev', '25-tunnel.network',
1153 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1155 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1157 output
= check_output('ip -d link show gretap99')
1159 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1160 self
.assertRegex(output
, 'ikey 0.0.0.106')
1161 self
.assertRegex(output
, 'okey 0.0.0.106')
1162 self
.assertRegex(output
, 'iseq')
1163 self
.assertRegex(output
, 'oseq')
1164 output
= check_output('ip -d link show gretap98')
1166 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1167 self
.assertRegex(output
, 'ikey 0.0.0.107')
1168 self
.assertRegex(output
, 'okey 0.0.0.107')
1169 self
.assertRegex(output
, 'iseq')
1170 self
.assertRegex(output
, 'oseq')
1172 def test_ip6gretap_tunnel(self
):
1173 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1174 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1175 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1177 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1179 output
= check_output('ip -d link show ip6gretap99')
1181 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1182 output
= check_output('ip -d link show ip6gretap98')
1184 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1186 def test_vti_tunnel(self
):
1187 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1188 '25-vti-tunnel.netdev', '25-tunnel.network',
1189 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1190 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1191 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1193 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1195 output
= check_output('ip -d link show vtitun99')
1197 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1198 output
= check_output('ip -d link show vtitun98')
1200 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1201 output
= check_output('ip -d link show vtitun97')
1203 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1204 output
= check_output('ip -d link show vtitun96')
1206 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1208 def test_vti6_tunnel(self
):
1209 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1210 '25-vti6-tunnel.netdev', '25-tunnel.network',
1211 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1212 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1214 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1216 output
= check_output('ip -d link show vti6tun99')
1218 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1219 output
= check_output('ip -d link show vti6tun98')
1221 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1222 output
= check_output('ip -d link show vti6tun97')
1224 self
.assertRegex(output
, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1226 def test_ip6tnl_tunnel(self
):
1227 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1228 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1229 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1230 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1232 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1234 output
= check_output('ip -d link show ip6tnl99')
1236 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1237 output
= check_output('ip -d link show ip6tnl98')
1239 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
1240 output
= check_output('ip -d link show ip6tnl97')
1242 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1244 def test_sit_tunnel(self
):
1245 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1246 '25-sit-tunnel.netdev', '25-tunnel.network',
1247 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1248 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1249 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1251 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1253 output
= check_output('ip -d link show sittun99')
1255 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1256 output
= check_output('ip -d link show sittun98')
1258 self
.assertRegex(output
, "sit (ip6ip )?remote 10.65.223.239 local any dev dummy98")
1259 output
= check_output('ip -d link show sittun97')
1261 self
.assertRegex(output
, "sit (ip6ip )?remote any local 10.65.223.238 dev dummy98")
1262 output
= check_output('ip -d link show sittun96')
1264 self
.assertRegex(output
, "sit (ip6ip )?remote any local any dev dummy98")
1266 def test_isatap_tunnel(self
):
1267 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1268 '25-isatap-tunnel.netdev', '25-tunnel.network')
1270 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1272 output
= check_output('ip -d link show isataptun99')
1274 self
.assertRegex(output
, "isatap ")
1276 def test_6rd_tunnel(self
):
1277 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1278 '25-6rd-tunnel.netdev', '25-tunnel.network')
1280 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1282 output
= check_output('ip -d link show sittun99')
1284 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1286 @expectedFailureIfERSPANModuleIsNotAvailable()
1287 def test_erspan_tunnel(self
):
1288 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1289 '25-erspan-tunnel.netdev', '25-tunnel.network',
1290 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1292 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1294 output
= check_output('ip -d link show erspan99')
1296 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1297 self
.assertRegex(output
, 'ikey 0.0.0.101')
1298 self
.assertRegex(output
, 'okey 0.0.0.101')
1299 self
.assertRegex(output
, 'iseq')
1300 self
.assertRegex(output
, 'oseq')
1301 output
= check_output('ip -d link show erspan98')
1303 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1304 self
.assertRegex(output
, '102')
1305 self
.assertRegex(output
, 'ikey 0.0.0.102')
1306 self
.assertRegex(output
, 'okey 0.0.0.102')
1307 self
.assertRegex(output
, 'iseq')
1308 self
.assertRegex(output
, 'oseq')
1310 def test_tunnel_independent(self
):
1311 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1314 self
.wait_online(['ipiptun99:carrier'])
1316 def test_tunnel_independent_loopback(self
):
1317 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1320 self
.wait_online(['ipiptun99:carrier'])
1322 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1323 def test_xfrm(self
):
1324 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1325 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1328 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1330 output
= check_output('ip link show dev xfrm99')
1333 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1334 def test_xfrm_independent(self
):
1335 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1338 self
.wait_online(['xfrm99:degraded'])
1340 @expectedFailureIfModuleIsNotAvailable('fou')
1342 # The following redundant check is necessary for CentOS CI.
1343 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1344 self
.assertTrue(is_module_available('fou'))
1346 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1347 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1348 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1351 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1353 output
= check_output('ip fou show')
1355 self
.assertRegex(output
, 'port 55555 ipproto 4')
1356 self
.assertRegex(output
, 'port 55556 ipproto 47')
1358 output
= check_output('ip -d link show ipiptun96')
1360 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1361 output
= check_output('ip -d link show sittun96')
1363 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1364 output
= check_output('ip -d link show gretun96')
1366 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1367 output
= check_output('ip -d link show gretap96')
1369 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1371 def test_vxlan(self
):
1372 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1373 '11-dummy.netdev', 'vxlan-test1.network')
1376 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1378 output
= check_output('ip -d link show vxlan99')
1380 self
.assertRegex(output
, '999')
1381 self
.assertRegex(output
, '5555')
1382 self
.assertRegex(output
, 'l2miss')
1383 self
.assertRegex(output
, 'l3miss')
1384 self
.assertRegex(output
, 'udpcsum')
1385 self
.assertRegex(output
, 'udp6zerocsumtx')
1386 self
.assertRegex(output
, 'udp6zerocsumrx')
1387 self
.assertRegex(output
, 'remcsumtx')
1388 self
.assertRegex(output
, 'remcsumrx')
1389 self
.assertRegex(output
, 'gbp')
1391 output
= check_output('bridge fdb show dev vxlan99')
1393 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1394 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1395 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1397 output
= check_output(*networkctl_cmd
, 'status', 'vxlan99', env
=env
)
1399 self
.assertRegex(output
, 'VNI: 999')
1400 self
.assertRegex(output
, 'Destination Port: 5555')
1401 self
.assertRegex(output
, 'Underlying Device: test1')
1403 def test_macsec(self
):
1404 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1405 'macsec.network', '12-dummy.netdev')
1408 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1410 output
= check_output('ip -d link show macsec99')
1412 self
.assertRegex(output
, 'macsec99@dummy98')
1413 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1414 self
.assertRegex(output
, 'encrypt on')
1416 output
= check_output('ip macsec show macsec99')
1418 self
.assertRegex(output
, 'encrypt on')
1419 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1420 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1421 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1422 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1423 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1424 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1425 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1426 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1427 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1428 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1429 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1431 def test_nlmon(self
):
1432 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1435 self
.wait_online(['nlmon99:carrier'])
1437 @expectedFailureIfModuleIsNotAvailable('ifb')
1439 copy_unit_to_networkd_unit_path('25-ifb.netdev', 'netdev-link-local-addressing-yes.network')
1442 self
.wait_online(['ifb99:degraded'])
1444 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1455 '25-l2tp-dummy.network',
1457 '25-l2tp-ip.netdev',
1458 '25-l2tp-udp.netdev']
1460 l2tp_tunnel_ids
= [ '10' ]
1463 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1464 remove_links(self
.links
)
1465 stop_networkd(show_logs
=False)
1468 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1469 remove_links(self
.links
)
1470 remove_unit_from_networkd_path(self
.units
)
1471 stop_networkd(show_logs
=True)
1473 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1474 def test_l2tp_udp(self
):
1475 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1476 '25-l2tp-udp.netdev', '25-l2tp.network')
1479 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1481 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1483 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1484 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1485 self
.assertRegex(output
, "Peer tunnel 11")
1486 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1487 self
.assertRegex(output
, "UDP checksum: enabled")
1489 output
= check_output('ip l2tp show session tid 10 session_id 15')
1491 self
.assertRegex(output
, "Session 15 in tunnel 10")
1492 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1493 self
.assertRegex(output
, "interface name: l2tp-ses1")
1495 output
= check_output('ip l2tp show session tid 10 session_id 17')
1497 self
.assertRegex(output
, "Session 17 in tunnel 10")
1498 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1499 self
.assertRegex(output
, "interface name: l2tp-ses2")
1501 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1502 def test_l2tp_ip(self
):
1503 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1504 '25-l2tp-ip.netdev', '25-l2tp.network')
1507 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1509 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1511 self
.assertRegex(output
, "Tunnel 10, encap IP")
1512 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1513 self
.assertRegex(output
, "Peer tunnel 12")
1515 output
= check_output('ip l2tp show session tid 10 session_id 25')
1517 self
.assertRegex(output
, "Session 25 in tunnel 10")
1518 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1519 self
.assertRegex(output
, "interface name: l2tp-ses3")
1521 output
= check_output('ip l2tp show session tid 10 session_id 27')
1523 self
.assertRegex(output
, "Session 27 in tunnel 10")
1524 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1525 self
.assertRegex(output
, "interface name: l2tp-ses4")
1527 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1541 '23-active-slave.network',
1542 '24-keep-configuration-static.network',
1543 '24-search-domain.network',
1544 '25-address-dad-veth-peer.network',
1545 '25-address-dad-veth99.network',
1546 '25-address-link-section.network',
1547 '25-address-preferred-lifetime-zero.network',
1548 '25-address-static.network',
1549 '25-bind-carrier.network',
1550 '25-bond-active-backup-slave.netdev',
1551 '25-fibrule-invert.network',
1552 '25-fibrule-port-range.network',
1553 '25-gre-tunnel-remote-any.netdev',
1554 '25-ip6gre-tunnel-remote-any.netdev',
1555 '25-ipv6-address-label-section.network',
1556 '25-link-local-addressing-no.network',
1557 '25-link-local-addressing-yes.network',
1558 '25-link-section-unmanaged.network',
1559 '25-neighbor-section.network',
1560 '25-neighbor-next.network',
1561 '25-neighbor-ipv6.network',
1562 '25-neighbor-ip-dummy.network',
1563 '25-neighbor-ip.network',
1564 '25-nexthop.network',
1565 '25-qdisc-fq-codel.network',
1566 '25-qdisc-netem-and-fqcodel.network',
1567 '25-qdisc-tbf-and-sfq.network',
1568 '25-route-ipv6-src.network',
1569 '25-route-static.network',
1570 '25-gateway-static.network',
1571 '25-gateway-next-static.network',
1572 '25-sysctl-disable-ipv6.network',
1573 '25-sysctl.network',
1574 '25-veth-peer.network',
1576 '26-link-local-addressing-ipv6.network',
1577 'configure-without-carrier.network',
1578 'routing-policy-rule-dummy98.network',
1579 'routing-policy-rule-test1.network']
1581 routing_policy_rule_tables
= ['7', '8', '9']
1582 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1585 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1586 remove_routes(self
.routes
)
1587 remove_links(self
.links
)
1588 stop_networkd(show_logs
=False)
1591 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1592 remove_routes(self
.routes
)
1593 remove_links(self
.links
)
1594 remove_unit_from_networkd_path(self
.units
)
1595 stop_networkd(show_logs
=True)
1597 def test_address_static(self
):
1598 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1601 self
.wait_online(['dummy98:routable'])
1603 output
= check_output('ip -4 address show dev dummy98')
1605 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1606 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1607 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1610 self
.assertNotRegex(output
, '10.10.0.1/16')
1611 self
.assertNotRegex(output
, '10.10.0.2/16')
1613 output
= check_output('ip -4 address show dev dummy98 label 32')
1614 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1616 output
= check_output('ip -4 address show dev dummy98 label 33')
1617 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1619 output
= check_output('ip -4 address show dev dummy98 label 34')
1620 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1622 output
= check_output('ip -4 address show dev dummy98 label 35')
1623 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1625 output
= check_output('ip -6 address show dev dummy98')
1627 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1628 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1629 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1630 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1631 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1632 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1634 def test_address_preferred_lifetime_zero_ipv6(self
):
1635 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
1638 self
.wait_online(['dummy98:routable'])
1640 output
= check_output('ip address show dummy98')
1642 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1643 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1645 output
= check_output('ip route show dev dummy98')
1647 self
.assertRegex(output
, 'default via 20.20.20.1 proto static')
1649 def test_address_dad(self
):
1650 copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network',
1653 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
1655 output
= check_output('ip -4 address show dev veth99')
1657 self
.assertRegex(output
, '192.168.100.10/24')
1659 output
= check_output('ip -4 address show dev veth-peer')
1661 self
.assertNotRegex(output
, '192.168.100.10/24')
1663 def test_configure_without_carrier(self
):
1664 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1666 self
.wait_online(['test1:routable'])
1668 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
1670 self
.assertRegex(output
, '192.168.0.15')
1671 self
.assertRegex(output
, '192.168.0.1')
1672 self
.assertRegex(output
, 'routable')
1674 def test_routing_policy_rule(self
):
1675 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1677 self
.wait_online(['test1:degraded'])
1679 output
= check_output('ip rule list iif test1 priority 111')
1681 self
.assertRegex(output
, '111:')
1682 self
.assertRegex(output
, 'from 192.168.100.18')
1683 self
.assertRegex(output
, r
'tos (0x08|throughput)\s')
1684 self
.assertRegex(output
, 'iif test1')
1685 self
.assertRegex(output
, 'oif test1')
1686 self
.assertRegex(output
, 'lookup 7')
1688 output
= check_output('ip rule list iif test1 priority 101')
1690 self
.assertRegex(output
, '101:')
1691 self
.assertRegex(output
, 'from all')
1692 self
.assertRegex(output
, 'iif test1')
1693 self
.assertRegex(output
, 'lookup 9')
1695 output
= check_output('ip -6 rule list iif test1 priority 100')
1697 self
.assertRegex(output
, '100:')
1698 self
.assertRegex(output
, 'from all')
1699 self
.assertRegex(output
, 'iif test1')
1700 self
.assertRegex(output
, 'lookup 8')
1702 output
= check_output('ip -6 rule list iif test1 priority 101')
1704 self
.assertRegex(output
, '101:')
1705 self
.assertRegex(output
, 'from all')
1706 self
.assertRegex(output
, 'iif test1')
1707 self
.assertRegex(output
, 'lookup 9')
1709 def test_routing_policy_rule_issue_11280(self
):
1710 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1711 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1713 for trial
in range(3):
1714 # Remove state files only first time
1716 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1719 output
= check_output('ip rule list table 7')
1721 self
.assertRegex(output
, '111: from 192.168.100.18 tos (0x08|throughput) iif test1 oif test1 lookup 7')
1723 output
= check_output('ip rule list table 8')
1725 self
.assertRegex(output
, '112: from 192.168.101.18 tos (0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1727 stop_networkd(remove_state_files
=False)
1729 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1730 def test_routing_policy_rule_port_range(self
):
1731 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1733 self
.wait_online(['test1:degraded'])
1735 output
= check_output('ip rule')
1737 self
.assertRegex(output
, '111')
1738 self
.assertRegex(output
, 'from 192.168.100.18')
1739 self
.assertRegex(output
, '1123-1150')
1740 self
.assertRegex(output
, '3224-3290')
1741 self
.assertRegex(output
, 'tcp')
1742 self
.assertRegex(output
, 'lookup 7')
1744 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1745 def test_routing_policy_rule_invert(self
):
1746 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1748 self
.wait_online(['test1:degraded'])
1750 output
= check_output('ip rule')
1752 self
.assertRegex(output
, '111')
1753 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1754 self
.assertRegex(output
, 'tcp')
1755 self
.assertRegex(output
, 'lookup 7')
1757 def test_route_static(self
):
1758 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1760 self
.wait_online(['dummy98:routable'])
1762 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1765 print('### ip -6 route show dev dummy98')
1766 output
= check_output('ip -6 route show dev dummy98')
1768 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1769 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1771 print('### ip -6 route show dev dummy98 default')
1772 output
= check_output('ip -6 route show dev dummy98 default')
1774 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1776 print('### ip -4 route show dev dummy98')
1777 output
= check_output('ip -4 route show dev dummy98')
1779 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1780 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1781 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1782 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1783 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1784 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1786 print('### ip -4 route show dev dummy98 default')
1787 output
= check_output('ip -4 route show dev dummy98 default')
1789 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1790 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1791 self
.assertRegex(output
, 'default proto static')
1793 print('### ip -4 route show table local dev dummy98')
1794 output
= check_output('ip -4 route show table local dev dummy98')
1796 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1797 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1798 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1800 print('### ip route show type blackhole')
1801 output
= check_output('ip route show type blackhole')
1803 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1805 print('### ip route show type unreachable')
1806 output
= check_output('ip route show type unreachable')
1808 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1810 print('### ip route show type prohibit')
1811 output
= check_output('ip route show type prohibit')
1813 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1815 print('### ip route show 192.168.10.1')
1816 output
= check_output('ip route show 192.168.10.1')
1818 self
.assertRegex(output
, '192.168.10.1 proto static')
1819 self
.assertRegex(output
, 'nexthop via 149.10.124.59 dev dummy98 weight 10')
1820 self
.assertRegex(output
, 'nexthop via 149.10.124.60 dev dummy98 weight 5')
1822 print('### ip route show 192.168.10.2')
1823 output
= check_output('ip route show 192.168.10.2')
1825 # old ip command does not show IPv6 gateways...
1826 self
.assertRegex(output
, '192.168.10.2 proto static')
1827 self
.assertRegex(output
, 'nexthop')
1828 self
.assertRegex(output
, 'dev dummy98 weight 10')
1829 self
.assertRegex(output
, 'dev dummy98 weight 5')
1831 print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1832 output
= check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff')
1834 # old ip command does not show 'nexthop' keyword and weight...
1835 self
.assertRegex(output
, '2001:1234:5:7fff:ff:ff:ff:ff')
1836 self
.assertRegex(output
, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98')
1837 self
.assertRegex(output
, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98')
1839 def test_gateway_reconfigure(self
):
1840 copy_unit_to_networkd_unit_path('25-gateway-static.network', '12-dummy.netdev')
1842 self
.wait_online(['dummy98:routable'])
1843 print('### ip -4 route show dev dummy98 default')
1844 output
= check_output('ip -4 route show dev dummy98 default')
1846 self
.assertRegex(output
, 'default via 149.10.124.59 proto static')
1847 self
.assertNotRegex(output
, '149.10.124.60')
1849 remove_unit_from_networkd_path(['25-gateway-static.network'])
1850 copy_unit_to_networkd_unit_path('25-gateway-next-static.network')
1852 self
.wait_online(['dummy98:routable'])
1853 print('### ip -4 route show dev dummy98 default')
1854 output
= check_output('ip -4 route show dev dummy98 default')
1856 self
.assertNotRegex(output
, '149.10.124.59')
1857 self
.assertRegex(output
, 'default via 149.10.124.60 proto static')
1859 def test_ip_route_ipv6_src_route(self
):
1860 # a dummy device does not make the addresses go through tentative state, so we
1861 # reuse a bond from an earlier test, which does make the addresses go through
1862 # tentative state, and do our test on that
1863 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1865 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1867 output
= check_output('ip -6 route list dev bond199')
1869 self
.assertRegex(output
, 'abcd::/16')
1870 self
.assertRegex(output
, 'src')
1871 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1873 def test_ip_link_mac_address(self
):
1874 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1876 self
.wait_online(['dummy98:degraded'])
1878 output
= check_output('ip link show dummy98')
1880 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1882 def test_ip_link_unmanaged(self
):
1883 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1886 self
.check_link_exists('dummy98')
1888 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1890 def test_ipv6_address_label(self
):
1891 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1893 self
.wait_online(['dummy98:degraded'])
1895 output
= check_output('ip addrlabel list')
1897 self
.assertRegex(output
, '2004:da8:1::/64')
1899 def test_neighbor_section(self
):
1900 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1902 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1904 print('### ip neigh list dev dummy98')
1905 output
= check_output('ip neigh list dev dummy98')
1907 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1908 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1910 def test_neighbor_reconfigure(self
):
1911 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1913 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1915 print('### ip neigh list dev dummy98')
1916 output
= check_output('ip neigh list dev dummy98')
1918 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1919 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1921 remove_unit_from_networkd_path(['25-neighbor-section.network'])
1922 copy_unit_to_networkd_unit_path('25-neighbor-next.network')
1924 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1925 print('### ip neigh list dev dummy98')
1926 output
= check_output('ip neigh list dev dummy98')
1928 self
.assertNotRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1929 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:66.*PERMANENT')
1930 self
.assertNotRegex(output
, '2004:da8:1::1.*PERMANENT')
1932 def test_neighbor_gre(self
):
1933 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network',
1934 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
1936 self
.wait_online(['dummy98:degraded', 'gretun97:routable', 'ip6gretun97:routable'], timeout
='40s')
1938 output
= check_output('ip neigh list dev gretun97')
1940 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
1942 output
= check_output('ip neigh list dev ip6gretun97')
1944 self
.assertRegex(output
, '2001:db8:0:f102::17 lladdr 2a:?00:ff:?de:45:?67:ed:?de:[0:]*:49:?88 PERMANENT')
1946 def test_link_local_addressing(self
):
1947 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1948 '25-link-local-addressing-no.network', '12-dummy.netdev')
1950 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
1952 output
= check_output('ip address show dev test1')
1954 self
.assertRegex(output
, 'inet .* scope link')
1955 self
.assertRegex(output
, 'inet6 .* scope link')
1957 output
= check_output('ip address show dev dummy98')
1959 self
.assertNotRegex(output
, 'inet6* .* scope link')
1962 Documentation/networking/ip-sysctl.txt
1964 addr_gen_mode - INTEGER
1965 Defines how link-local and autoconf addresses are generated.
1967 0: generate address based on EUI64 (default)
1968 1: do no generate a link-local address, use EUI64 for addresses generated
1970 2: generate stable privacy addresses, using the secret from
1971 stable_secret (RFC7217)
1972 3: generate stable privacy addresses, using a random secret if unset
1975 test1_addr_gen_mode
= ''
1976 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1977 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1981 # if stable_secret is unset, then EIO is returned
1982 test1_addr_gen_mode
= '0'
1984 test1_addr_gen_mode
= '2'
1986 test1_addr_gen_mode
= '0'
1988 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1989 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1991 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1992 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1994 def test_link_local_addressing_remove_ipv6ll(self
):
1995 copy_unit_to_networkd_unit_path('26-link-local-addressing-ipv6.network', '12-dummy.netdev')
1997 self
.wait_online(['dummy98:degraded'])
1999 output
= check_output('ip address show dev dummy98')
2001 self
.assertRegex(output
, 'inet6 .* scope link')
2003 copy_unit_to_networkd_unit_path('25-link-local-addressing-no.network')
2005 self
.wait_online(['dummy98:carrier'])
2007 output
= check_output('ip address show dev dummy98')
2009 self
.assertNotRegex(output
, 'inet6* .* scope link')
2011 def test_sysctl(self
):
2012 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
2014 self
.wait_online(['dummy98:degraded'])
2016 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
2017 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
2018 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
2019 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
2020 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
2021 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
2022 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
2024 def test_sysctl_disable_ipv6(self
):
2025 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
2027 print('## Disable ipv6')
2028 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
2029 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
2032 self
.wait_online(['dummy98:routable'])
2034 output
= check_output('ip -4 address show dummy98')
2036 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2037 output
= check_output('ip -6 address show dummy98')
2039 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2040 self
.assertRegex(output
, 'inet6 .* scope link')
2041 output
= check_output('ip -4 route show dev dummy98')
2043 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2044 output
= check_output('ip -6 route show dev dummy98')
2046 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2048 check_output('ip link del dummy98')
2050 print('## Enable ipv6')
2051 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
2052 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
2055 self
.wait_online(['dummy98:routable'])
2057 output
= check_output('ip -4 address show dummy98')
2059 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
2060 output
= check_output('ip -6 address show dummy98')
2062 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
2063 self
.assertRegex(output
, 'inet6 .* scope link')
2064 output
= check_output('ip -4 route show dev dummy98')
2066 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
2067 output
= check_output('ip -6 route show dev dummy98')
2069 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
2071 def test_bind_carrier(self
):
2072 check_output('ip link add dummy98 type dummy')
2073 check_output('ip link set dummy98 up')
2076 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
2078 self
.wait_online(['test1:routable'])
2080 output
= check_output('ip address show test1')
2082 self
.assertRegex(output
, 'UP,LOWER_UP')
2083 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2084 self
.check_operstate('test1', 'routable')
2086 check_output('ip link add dummy99 type dummy')
2087 check_output('ip link set dummy99 up')
2089 output
= check_output('ip address show test1')
2091 self
.assertRegex(output
, 'UP,LOWER_UP')
2092 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2093 self
.check_operstate('test1', 'routable')
2095 check_output('ip link del dummy98')
2097 output
= check_output('ip address show test1')
2099 self
.assertRegex(output
, 'UP,LOWER_UP')
2100 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2101 self
.check_operstate('test1', 'routable')
2103 check_output('ip link set dummy99 down')
2105 output
= check_output('ip address show test1')
2107 self
.assertNotRegex(output
, 'UP,LOWER_UP')
2108 self
.assertRegex(output
, 'DOWN')
2109 self
.assertNotRegex(output
, '192.168.10')
2110 self
.check_operstate('test1', 'off')
2112 check_output('ip link set dummy99 up')
2114 output
= check_output('ip address show test1')
2116 self
.assertRegex(output
, 'UP,LOWER_UP')
2117 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
2118 self
.check_operstate('test1', 'routable')
2120 def test_domain(self
):
2121 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
2123 self
.wait_online(['dummy98:routable'])
2125 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
2127 self
.assertRegex(output
, 'Address: 192.168.42.100')
2128 self
.assertRegex(output
, 'DNS: 192.168.42.1')
2129 self
.assertRegex(output
, 'Search Domains: one')
2131 def test_keep_configuration_static(self
):
2132 check_output('systemctl stop systemd-networkd')
2134 check_output('ip link add name dummy98 type dummy')
2135 check_output('ip address add 10.1.2.3/16 dev dummy98')
2136 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
2137 output
= check_output('ip address show dummy98')
2139 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2140 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2141 output
= check_output('ip route show dev dummy98')
2144 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
2146 self
.wait_online(['dummy98:routable'])
2148 output
= check_output('ip address show dummy98')
2150 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
2151 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
2153 @expectedFailureIfNexthopIsNotAvailable()
2154 def test_nexthop(self
):
2155 copy_unit_to_networkd_unit_path('25-nexthop.network', '25-veth.netdev', '25-veth-peer.network')
2157 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2159 output
= check_output('ip nexthop list dev veth99')
2161 self
.assertRegex(output
, '192.168.5.1')
2163 def test_qdisc(self
):
2164 copy_unit_to_networkd_unit_path('25-qdisc-netem-and-fqcodel.network', '12-dummy.netdev',
2165 '25-qdisc-tbf-and-sfq.network', '11-dummy.netdev')
2168 self
.wait_online(['dummy98:routable', 'test1:routable'])
2170 output
= check_output('tc qdisc show dev dummy98')
2172 self
.assertRegex(output
, 'qdisc netem')
2173 self
.assertRegex(output
, 'limit 100 delay 50.0ms 10.0ms loss 20%')
2174 self
.assertRegex(output
, 'qdisc fq_codel')
2175 self
.assertRegex(output
, 'limit 20480p flows 2048 quantum 1400 target 10.0ms ce_threshold 100.0ms interval 200.0ms memory_limit 64Mb ecn')
2176 output
= check_output('tc qdisc show dev test1')
2178 self
.assertRegex(output
, 'qdisc tbf')
2179 self
.assertRegex(output
, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70.0ms')
2180 self
.assertRegex(output
, 'qdisc sfq')
2181 self
.assertRegex(output
, 'perturb 5sec')
2183 def test_qdisc2(self
):
2184 copy_unit_to_networkd_unit_path('25-qdisc-fq-codel.network', '12-dummy.netdev')
2187 self
.wait_online(['dummy98:routable'])
2189 output
= check_output('tc qdisc show dev dummy98')
2191 self
.assertRegex(output
, 'qdisc fq')
2192 self
.assertRegex(output
, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511 quantum 1500 initial_quantum 13000 maxrate 1Mbit')
2193 self
.assertRegex(output
, 'qdisc codel')
2194 self
.assertRegex(output
, 'limit 2000p target 10.0ms ce_threshold 100.0ms interval 50.0ms ecn')
2196 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
2203 'state-file-tests.network',
2207 remove_links(self
.links
)
2208 stop_networkd(show_logs
=False)
2211 remove_links(self
.links
)
2212 remove_unit_from_networkd_path(self
.units
)
2213 stop_networkd(show_logs
=True)
2215 def test_state_file(self
):
2216 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
2218 self
.wait_online(['dummy98:routable'])
2220 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
2222 ifindex
= output
.split()[0]
2224 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
2225 self
.assertTrue(os
.path
.exists(path
))
2228 with
open(path
) as f
:
2230 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
2231 self
.assertRegex(data
, r
'OPER_STATE=routable')
2232 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
2233 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
2234 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
2235 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2236 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2237 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2238 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2239 self
.assertRegex(data
, r
'LLMNR=no')
2240 self
.assertRegex(data
, r
'MDNS=yes')
2241 self
.assertRegex(data
, r
'DNSSEC=no')
2242 self
.assertRegex(data
, r
'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
2244 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
2245 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
2246 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
2247 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
2248 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
2249 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
2252 with
open(path
) as f
:
2254 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2255 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
2256 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2257 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2258 self
.assertRegex(data
, r
'LLMNR=yes')
2259 self
.assertRegex(data
, r
'MDNS=no')
2260 self
.assertRegex(data
, r
'DNSSEC=yes')
2262 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
2265 with
open(path
) as f
:
2267 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
2268 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2269 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
2270 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
2271 self
.assertRegex(data
, r
'LLMNR=yes')
2272 self
.assertRegex(data
, r
'MDNS=no')
2273 self
.assertRegex(data
, r
'DNSSEC=yes')
2275 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
2278 with
open(path
) as f
:
2280 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
2281 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
2282 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
2283 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
2284 self
.assertRegex(data
, r
'LLMNR=no')
2285 self
.assertRegex(data
, r
'MDNS=yes')
2286 self
.assertRegex(data
, r
'DNSSEC=no')
2288 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
2298 '23-active-slave.network',
2299 '23-bond199.network',
2300 '23-primary-slave.network',
2301 '25-bond-active-backup-slave.netdev',
2304 'bond-slave.network']
2307 remove_links(self
.links
)
2308 stop_networkd(show_logs
=False)
2311 remove_links(self
.links
)
2312 remove_unit_from_networkd_path(self
.units
)
2313 stop_networkd(show_logs
=True)
2315 def test_bond_active_slave(self
):
2316 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2318 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2320 output
= check_output('ip -d link show bond199')
2322 self
.assertRegex(output
, 'active_slave dummy98')
2324 def test_bond_primary_slave(self
):
2325 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
2327 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2329 output
= check_output('ip -d link show bond199')
2331 self
.assertRegex(output
, 'primary dummy98')
2333 def test_bond_operstate(self
):
2334 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2335 'bond99.network','bond-slave.network')
2337 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2339 output
= check_output('ip -d link show dummy98')
2341 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2343 output
= check_output('ip -d link show test1')
2345 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2347 output
= check_output('ip -d link show bond99')
2349 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2351 self
.check_operstate('dummy98', 'enslaved')
2352 self
.check_operstate('test1', 'enslaved')
2353 self
.check_operstate('bond99', 'routable')
2355 check_output('ip link set dummy98 down')
2358 self
.check_operstate('dummy98', 'off')
2359 self
.check_operstate('test1', 'enslaved')
2360 self
.check_operstate('bond99', 'degraded-carrier')
2362 check_output('ip link set dummy98 up')
2365 self
.check_operstate('dummy98', 'enslaved')
2366 self
.check_operstate('test1', 'enslaved')
2367 self
.check_operstate('bond99', 'routable')
2369 check_output('ip link set dummy98 down')
2370 check_output('ip link set test1 down')
2373 self
.check_operstate('dummy98', 'off')
2374 self
.check_operstate('test1', 'off')
2376 for trial
in range(30):
2379 output
= check_output('ip address show bond99')
2381 if get_operstate('bond99') == 'no-carrier':
2384 # Huh? Kernel does not recognize that all slave interfaces are down?
2385 # Let's confirm that networkd's operstate is consistent with ip's result.
2386 self
.assertNotRegex(output
, 'NO-CARRIER')
2388 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2398 '26-bridge-slave-interface-1.network',
2399 '26-bridge-slave-interface-2.network',
2400 '26-bridge-vlan-master.network',
2401 '26-bridge-vlan-slave.network',
2402 'bridge99-ignore-carrier-loss.network',
2405 routing_policy_rule_tables
= ['100']
2408 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2409 remove_links(self
.links
)
2410 stop_networkd(show_logs
=False)
2413 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2414 remove_links(self
.links
)
2415 remove_unit_from_networkd_path(self
.units
)
2416 stop_networkd(show_logs
=True)
2418 def test_bridge_vlan(self
):
2419 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2420 '26-bridge.netdev', '26-bridge-vlan-master.network')
2422 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2424 output
= check_output('bridge vlan show dev test1')
2426 self
.assertNotRegex(output
, '4063')
2427 for i
in range(4064, 4095):
2428 self
.assertRegex(output
, f
'{i}')
2429 self
.assertNotRegex(output
, '4095')
2431 output
= check_output('bridge vlan show dev bridge99')
2433 self
.assertNotRegex(output
, '4059')
2434 for i
in range(4060, 4095):
2435 self
.assertRegex(output
, f
'{i}')
2436 self
.assertNotRegex(output
, '4095')
2438 def test_bridge_property(self
):
2439 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2440 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2443 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2445 output
= check_output('ip -d link show test1')
2447 self
.assertRegex(output
, 'master')
2448 self
.assertRegex(output
, 'bridge')
2450 output
= check_output('ip -d link show dummy98')
2452 self
.assertRegex(output
, 'master')
2453 self
.assertRegex(output
, 'bridge')
2455 output
= check_output('ip addr show bridge99')
2457 self
.assertRegex(output
, '192.168.0.15/24')
2459 output
= check_output('bridge -d link show dummy98')
2461 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2462 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2463 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2464 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2465 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2466 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2467 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2468 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2469 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2470 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2471 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2472 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2473 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2474 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2476 output
= check_output('bridge -d link show test1')
2478 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2480 check_output('ip address add 192.168.0.16/24 dev bridge99')
2483 output
= check_output('ip addr show bridge99')
2485 self
.assertRegex(output
, '192.168.0.16/24')
2488 print('### ip -6 route list table all dev bridge99')
2489 output
= check_output('ip -6 route list table all dev bridge99')
2491 self
.assertRegex(output
, 'ff00::/8 table local metric 256 pref medium')
2493 self
.assertEqual(call('ip link del test1'), 0)
2496 self
.check_operstate('bridge99', 'degraded-carrier')
2498 check_output('ip link del dummy98')
2501 self
.check_operstate('bridge99', 'no-carrier')
2503 output
= check_output('ip address show bridge99')
2505 self
.assertRegex(output
, 'NO-CARRIER')
2506 self
.assertNotRegex(output
, '192.168.0.15/24')
2507 self
.assertNotRegex(output
, '192.168.0.16/24')
2509 print('### ip -6 route list table all dev bridge99')
2510 output
= check_output('ip -6 route list table all dev bridge99')
2512 self
.assertRegex(output
, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
2514 def test_bridge_ignore_carrier_loss(self
):
2515 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2516 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2517 'bridge99-ignore-carrier-loss.network')
2519 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2521 check_output('ip address add 192.168.0.16/24 dev bridge99')
2524 check_output('ip link del test1')
2525 check_output('ip link del dummy98')
2528 output
= check_output('ip address show bridge99')
2530 self
.assertRegex(output
, 'NO-CARRIER')
2531 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2532 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2534 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2535 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2536 'bridge99-ignore-carrier-loss.network')
2538 self
.wait_online(['bridge99:no-carrier'])
2540 for trial
in range(4):
2541 check_output('ip link add dummy98 type dummy')
2542 check_output('ip link set dummy98 up')
2544 check_output('ip link del dummy98')
2546 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2548 output
= check_output('ip address show bridge99')
2550 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2552 output
= check_output('ip rule list table 100')
2554 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2556 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2560 '23-emit-lldp.network',
2565 remove_links(self
.links
)
2566 stop_networkd(show_logs
=False)
2569 remove_links(self
.links
)
2570 remove_unit_from_networkd_path(self
.units
)
2571 stop_networkd(show_logs
=True)
2573 def test_lldp(self
):
2574 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2576 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2578 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2580 self
.assertRegex(output
, 'veth-peer')
2581 self
.assertRegex(output
, 'veth99')
2583 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2588 'ipv6-prefix.network',
2589 'ipv6-prefix-veth.network']
2592 remove_links(self
.links
)
2593 stop_networkd(show_logs
=False)
2596 remove_links(self
.links
)
2597 remove_unit_from_networkd_path(self
.units
)
2598 stop_networkd(show_logs
=True)
2600 def test_ipv6_prefix_delegation(self
):
2601 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2603 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2605 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2607 self
.assertRegex(output
, '2002:da8:1:0')
2609 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2614 'dhcp-client.network',
2615 'dhcp-client-timezone-router.network',
2616 'dhcp-server.network',
2617 'dhcp-server-timezone-router.network']
2620 remove_links(self
.links
)
2621 stop_networkd(show_logs
=False)
2624 remove_links(self
.links
)
2625 remove_unit_from_networkd_path(self
.units
)
2626 stop_networkd(show_logs
=True)
2628 def test_dhcp_server(self
):
2629 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2631 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2633 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2635 self
.assertRegex(output
, '192.168.5.*')
2636 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2637 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2638 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2640 def test_emit_router_timezone(self
):
2641 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2643 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2645 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2647 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2648 self
.assertRegex(output
, '192.168.5.*')
2649 self
.assertRegex(output
, 'Europe/Berlin')
2651 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2660 'dhcp-client-anonymize.network',
2661 'dhcp-client-decline.network',
2662 'dhcp-client-gateway-onlink-implicit.network',
2663 'dhcp-client-ipv4-dhcp-settings.network',
2664 'dhcp-client-ipv4-only-ipv6-disabled.network',
2665 'dhcp-client-ipv4-only.network',
2666 'dhcp-client-ipv6-only.network',
2667 'dhcp-client-ipv6-rapid-commit.network',
2668 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2669 'dhcp-client-keep-configuration-dhcp.network',
2670 'dhcp-client-listen-port.network',
2671 'dhcp-client-reassign-static-routes-ipv4.network',
2672 'dhcp-client-reassign-static-routes-ipv6.network',
2673 'dhcp-client-route-metric.network',
2674 'dhcp-client-route-table.network',
2675 'dhcp-client-use-dns-ipv4-and-ra.network',
2676 'dhcp-client-use-dns-ipv4.network',
2677 'dhcp-client-use-dns-no.network',
2678 'dhcp-client-use-dns-yes.network',
2679 'dhcp-client-use-domains.network',
2680 'dhcp-client-use-routes-no.network',
2681 'dhcp-client-vrf.network',
2682 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2683 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2684 'dhcp-client-with-static-address.network',
2685 'dhcp-client.network',
2686 'dhcp-server-decline.network',
2687 'dhcp-server-veth-peer.network',
2688 'dhcp-v4-server-veth-peer.network',
2689 'dhcp-client-use-domains.network',
2693 stop_dnsmasq(dnsmasq_pid_file
)
2694 remove_links(self
.links
)
2695 stop_networkd(show_logs
=False)
2698 stop_dnsmasq(dnsmasq_pid_file
)
2701 remove_links(self
.links
)
2702 remove_unit_from_networkd_path(self
.units
)
2703 stop_networkd(show_logs
=True)
2705 def test_dhcp_client_ipv6_only(self
):
2706 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2709 self
.wait_online(['veth-peer:carrier'])
2711 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2713 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2715 self
.assertRegex(output
, '2600::')
2716 self
.assertNotRegex(output
, '192.168.5')
2718 # Confirm that ipv6 token is not set in the kernel
2719 output
= check_output('ip token show dev veth99')
2721 self
.assertRegex(output
, 'token :: dev veth99')
2723 def test_dhcp_client_ipv4_only(self
):
2724 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2727 self
.wait_online(['veth-peer:carrier'])
2728 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.6,192.168.5.7', lease_time
='2m')
2729 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2731 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2733 self
.assertNotRegex(output
, '2600::')
2734 self
.assertRegex(output
, '192.168.5')
2735 self
.assertRegex(output
, '192.168.5.6')
2736 self
.assertRegex(output
, '192.168.5.7')
2738 # checking routes to DNS servers
2739 output
= check_output('ip route show dev veth99')
2741 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2742 self
.assertRegex(output
, r
'192.168.5.6 proto dhcp scope link src 192.168.5.181 metric 1024')
2743 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2745 stop_dnsmasq(dnsmasq_pid_file
)
2746 start_dnsmasq(additional_options
='--dhcp-option=option:dns-server,192.168.5.1,192.168.5.7,192.168.5.8', lease_time
='2m')
2748 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2749 print('Wait for the dynamic address to be renewed')
2752 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2754 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2756 self
.assertNotRegex(output
, '2600::')
2757 self
.assertRegex(output
, '192.168.5')
2758 self
.assertNotRegex(output
, '192.168.5.6')
2759 self
.assertRegex(output
, '192.168.5.7')
2760 self
.assertRegex(output
, '192.168.5.8')
2762 # checking routes to DNS servers
2763 output
= check_output('ip route show dev veth99')
2765 self
.assertNotRegex(output
, r
'192.168.5.6')
2766 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.181 metric 1024')
2767 self
.assertRegex(output
, r
'192.168.5.7 proto dhcp scope link src 192.168.5.181 metric 1024')
2768 self
.assertRegex(output
, r
'192.168.5.8 proto dhcp scope link src 192.168.5.181 metric 1024')
2770 def test_dhcp_client_ipv4_ipv6(self
):
2771 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2772 'dhcp-client-ipv4-only.network')
2774 self
.wait_online(['veth-peer:carrier'])
2776 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2778 # link become 'routable' when at least one protocol provide an valid address.
2779 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2780 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2782 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2784 self
.assertRegex(output
, '2600::')
2785 self
.assertRegex(output
, '192.168.5')
2787 def test_dhcp_client_settings(self
):
2788 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2791 self
.wait_online(['veth-peer:carrier'])
2793 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2795 print('## ip address show dev veth99')
2796 output
= check_output('ip address show dev veth99')
2798 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2799 self
.assertRegex(output
, '192.168.5')
2800 self
.assertRegex(output
, '1492')
2802 print('## ip route show table main dev veth99')
2803 output
= check_output('ip route show table main dev veth99')
2806 main_table_is_empty
= output
== ''
2807 if not main_table_is_empty
:
2808 self
.assertNotRegex(output
, 'proto dhcp')
2810 print('## ip route show table 211 dev veth99')
2811 output
= check_output('ip route show table 211 dev veth99')
2813 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2814 if main_table_is_empty
:
2815 self
.assertRegex(output
, '192.168.5.0/24 proto dhcp')
2816 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2817 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2819 print('## dnsmasq log')
2820 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2821 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2822 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2823 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2825 def test_dhcp6_client_settings_rapidcommit_true(self
):
2826 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2828 self
.wait_online(['veth-peer:carrier'])
2830 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2832 output
= check_output('ip address show dev veth99')
2834 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2835 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2837 def test_dhcp6_client_settings_rapidcommit_false(self
):
2838 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2840 self
.wait_online(['veth-peer:carrier'])
2842 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2844 output
= check_output('ip address show dev veth99')
2846 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2847 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2849 def test_dhcp_client_settings_anonymize(self
):
2850 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2852 self
.wait_online(['veth-peer:carrier'])
2854 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2856 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2857 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2858 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2860 def test_dhcp_client_listen_port(self
):
2861 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2863 self
.wait_online(['veth-peer:carrier'])
2864 start_dnsmasq('--dhcp-alternate-port=67,5555')
2865 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2867 output
= check_output('ip -4 address show dev veth99')
2869 self
.assertRegex(output
, '192.168.5.* dynamic')
2871 def test_dhcp_client_with_static_address(self
):
2872 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2873 'dhcp-client-with-static-address.network')
2875 self
.wait_online(['veth-peer:carrier'])
2877 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2879 output
= check_output('ip address show dev veth99 scope global')
2881 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2882 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2884 output
= check_output('ip route show dev veth99')
2886 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2887 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2888 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2889 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2891 def test_dhcp_route_table_id(self
):
2892 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2894 self
.wait_online(['veth-peer:carrier'])
2896 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2898 output
= check_output('ip route show table 12')
2900 self
.assertRegex(output
, 'veth99 proto dhcp')
2901 self
.assertRegex(output
, '192.168.5.1')
2903 def test_dhcp_route_metric(self
):
2904 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2906 self
.wait_online(['veth-peer:carrier'])
2908 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2910 output
= check_output('ip route show dev veth99')
2912 self
.assertRegex(output
, 'metric 24')
2914 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2915 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2916 'dhcp-client-reassign-static-routes-ipv4.network')
2918 self
.wait_online(['veth-peer:carrier'])
2919 start_dnsmasq(lease_time
='2m')
2920 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2922 output
= check_output('ip address show dev veth99 scope global')
2924 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2926 output
= check_output('ip route show dev veth99')
2928 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2929 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2930 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2931 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2933 stop_dnsmasq(dnsmasq_pid_file
)
2934 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2936 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2937 print('Wait for the dynamic address to be renewed')
2940 self
.wait_online(['veth99:routable'])
2942 output
= check_output('ip route show dev veth99')
2944 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2945 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2946 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2947 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2949 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2950 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2951 'dhcp-client-reassign-static-routes-ipv6.network')
2953 self
.wait_online(['veth-peer:carrier'])
2954 start_dnsmasq(lease_time
='2m')
2955 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2957 output
= check_output('ip address show dev veth99 scope global')
2959 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (noprefixroute dynamic|dynamic noprefixroute)')
2961 output
= check_output('ip -6 route show dev veth99')
2963 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2964 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2966 stop_dnsmasq(dnsmasq_pid_file
)
2967 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
2969 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2970 print('Wait for the dynamic address to be renewed')
2973 self
.wait_online(['veth99:routable'])
2975 output
= check_output('ip -6 route show dev veth99')
2977 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2978 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2980 def test_dhcp_keep_configuration_dhcp(self
):
2981 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2983 self
.wait_online(['veth-peer:carrier'])
2984 start_dnsmasq(lease_time
='2m')
2985 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2987 output
= check_output('ip address show dev veth99 scope global')
2989 self
.assertRegex(output
, r
'192.168.5.*')
2991 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2993 self
.assertRegex(output
, r
'192.168.5.*')
2995 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2996 stop_dnsmasq(dnsmasq_pid_file
)
2998 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2999 print('Wait for the dynamic address to be expired')
3002 print('The lease address should be kept after lease expired')
3003 output
= check_output('ip address show dev veth99 scope global')
3005 self
.assertRegex(output
, r
'192.168.5.*')
3007 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3009 self
.assertRegex(output
, r
'192.168.5.*')
3011 check_output('systemctl stop systemd-networkd')
3013 print('The lease address should be kept after networkd stopped')
3014 output
= check_output('ip address show dev veth99 scope global')
3016 self
.assertRegex(output
, r
'192.168.5.*')
3018 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3020 self
.assertRegex(output
, r
'192.168.5.*')
3023 self
.wait_online(['veth-peer:routable'])
3025 print('Still the lease address should be kept after networkd restarted')
3026 output
= check_output('ip address show dev veth99 scope global')
3028 self
.assertRegex(output
, r
'192.168.5.*')
3030 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3032 self
.assertRegex(output
, r
'192.168.5.*')
3034 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
3035 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
3037 self
.wait_online(['veth-peer:carrier'])
3038 start_dnsmasq(lease_time
='2m')
3039 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3041 output
= check_output('ip address show dev veth99 scope global')
3043 self
.assertRegex(output
, r
'192.168.5.*')
3045 stop_dnsmasq(dnsmasq_pid_file
)
3046 check_output('systemctl stop systemd-networkd')
3048 output
= check_output('ip address show dev veth99 scope global')
3050 self
.assertRegex(output
, r
'192.168.5.*')
3053 self
.wait_online(['veth-peer:routable'])
3055 output
= check_output('ip address show dev veth99 scope global')
3057 self
.assertNotRegex(output
, r
'192.168.5.*')
3059 def test_dhcp_client_reuse_address_as_static(self
):
3060 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
3062 self
.wait_online(['veth-peer:carrier'])
3064 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3066 # link become 'routable' when at least one protocol provide an valid address.
3067 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3068 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3070 output
= check_output('ip address show dev veth99 scope global')
3072 self
.assertRegex(output
, '192.168.5')
3073 self
.assertRegex(output
, '2600::')
3075 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
3076 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
3077 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
3078 print(static_network
)
3080 remove_unit_from_networkd_path(['dhcp-client.network'])
3082 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
3083 f
.write(static_network
)
3085 # When networkd started, the links are already configured, so let's wait for 5 seconds
3086 # the links to be re-configured.
3088 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3090 output
= check_output('ip -4 address show dev veth99 scope global')
3092 self
.assertRegex(output
, '192.168.5')
3093 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3095 output
= check_output('ip -6 address show dev veth99 scope global')
3097 self
.assertRegex(output
, '2600::')
3098 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
3100 @expectedFailureIfModuleIsNotAvailable('vrf')
3101 def test_dhcp_client_vrf(self
):
3102 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
3103 '25-vrf.netdev', '25-vrf.network')
3105 self
.wait_online(['veth-peer:carrier'])
3107 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
3109 # link become 'routable' when at least one protocol provide an valid address.
3110 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3111 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3113 print('## ip -d link show dev vrf99')
3114 output
= check_output('ip -d link show dev vrf99')
3116 self
.assertRegex(output
, 'vrf table 42')
3118 print('## ip address show vrf vrf99')
3119 output
= check_output('ip address show vrf vrf99')
3121 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3122 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3123 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3124 self
.assertRegex(output
, 'inet6 .* scope link')
3126 print('## ip address show dev veth99')
3127 output
= check_output('ip address show dev veth99')
3129 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
3130 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3131 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
3132 self
.assertRegex(output
, 'inet6 .* scope link')
3134 print('## ip route show vrf vrf99')
3135 output
= check_output('ip route show vrf vrf99')
3137 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
3138 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
3139 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
3140 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
3141 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
3143 print('## ip route show table main dev veth99')
3144 output
= check_output('ip route show table main dev veth99')
3146 self
.assertEqual(output
, '')
3148 def test_dhcp_client_gateway_onlink_implicit(self
):
3149 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3150 'dhcp-client-gateway-onlink-implicit.network')
3152 self
.wait_online(['veth-peer:carrier'])
3154 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3156 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3158 self
.assertRegex(output
, '192.168.5')
3160 output
= check_output('ip route list dev veth99 10.0.0.0/8')
3162 self
.assertRegex(output
, 'onlink')
3163 output
= check_output('ip route list dev veth99 192.168.100.0/24')
3165 self
.assertRegex(output
, 'onlink')
3167 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
3168 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3169 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
3171 self
.wait_online(['veth-peer:carrier'])
3172 start_dnsmasq(lease_time
='2m')
3173 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3175 output
= check_output('ip address show dev veth99')
3178 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3179 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3180 output
= check_output('ip -6 address show dev veth99 scope link')
3181 self
.assertRegex(output
, 'inet6 .* scope link')
3182 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3183 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3184 output
= check_output('ip -4 address show dev veth99 scope link')
3185 self
.assertNotRegex(output
, 'inet .* scope link')
3187 print('Wait for the dynamic address to be expired')
3190 output
= check_output('ip address show dev veth99')
3193 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3194 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3195 output
= check_output('ip -6 address show dev veth99 scope link')
3196 self
.assertRegex(output
, 'inet6 .* scope link')
3197 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3198 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3199 output
= check_output('ip -4 address show dev veth99 scope link')
3200 self
.assertNotRegex(output
, 'inet .* scope link')
3202 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
3204 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
3205 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3206 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
3208 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
3210 output
= check_output('ip address show dev veth99')
3213 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
3214 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
3215 output
= check_output('ip -6 address show dev veth99 scope link')
3216 self
.assertRegex(output
, 'inet6 .* scope link')
3217 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3218 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3219 output
= check_output('ip -4 address show dev veth99 scope link')
3220 self
.assertRegex(output
, 'inet .* scope link')
3222 def test_dhcp_client_route_remove_on_renew(self
):
3223 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
3224 'dhcp-client-ipv4-only-ipv6-disabled.network')
3226 self
.wait_online(['veth-peer:carrier'])
3227 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
3228 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3230 # test for issue #12490
3232 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3234 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3236 for line
in output
.splitlines():
3237 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3238 address1
= line
.split()[1].split('/')[0]
3241 output
= check_output('ip -4 route show dev veth99')
3243 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3244 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3246 stop_dnsmasq(dnsmasq_pid_file
)
3247 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
3249 print('Wait for the dynamic address to be expired')
3252 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
3254 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
3256 for line
in output
.splitlines():
3257 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
3258 address2
= line
.split()[1].split('/')[0]
3261 self
.assertNotEqual(address1
, address2
)
3263 output
= check_output('ip -4 route show dev veth99')
3265 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
3266 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
3267 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
3268 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
3270 def test_dhcp_client_use_dns_yes(self
):
3271 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
3274 self
.wait_online(['veth-peer:carrier'])
3275 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3276 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3278 # link become 'routable' when at least one protocol provide an valid address.
3279 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3280 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3283 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3285 self
.assertRegex(output
, '192.168.5.1')
3286 self
.assertRegex(output
, '2600::1')
3288 def test_dhcp_client_use_dns_no(self
):
3289 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
3292 self
.wait_online(['veth-peer:carrier'])
3293 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3294 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3296 # link become 'routable' when at least one protocol provide an valid address.
3297 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3298 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3301 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3303 self
.assertNotRegex(output
, '192.168.5.1')
3304 self
.assertNotRegex(output
, '2600::1')
3306 def test_dhcp_client_use_dns_ipv4(self
):
3307 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
3310 self
.wait_online(['veth-peer:carrier'])
3311 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3312 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3314 # link become 'routable' when at least one protocol provide an valid address.
3315 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3316 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3319 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3321 self
.assertRegex(output
, '192.168.5.1')
3322 self
.assertNotRegex(output
, '2600::1')
3324 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
3325 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
3328 self
.wait_online(['veth-peer:carrier'])
3329 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
3330 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3332 # link become 'routable' when at least one protocol provide an valid address.
3333 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
3334 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
3337 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
3339 self
.assertRegex(output
, '192.168.5.1')
3340 self
.assertRegex(output
, '2600::1')
3342 def test_dhcp_client_use_domains(self
):
3343 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
3346 self
.wait_online(['veth-peer:carrier'])
3347 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
3348 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3350 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
3352 self
.assertRegex(output
, 'Search Domains: example.com')
3355 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
3357 self
.assertRegex(output
, 'example.com')
3359 def test_dhcp_client_decline(self
):
3360 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-decline.network', 'dhcp-client-decline.network')
3363 self
.wait_online(['veth-peer:carrier'])
3364 rc
= call(*wait_online_cmd
, '--timeout=10s', '--interface=veth99:routable', env
=env
)
3365 self
.assertTrue(rc
== 1)
3367 class NetworkdIPv6PrefixTests(unittest
.TestCase
, Utilities
):
3372 'ipv6ra-prefix-client.network',
3373 'ipv6ra-prefix.network'
3377 remove_links(self
.links
)
3378 stop_networkd(show_logs
=False)
3382 remove_links(self
.links
)
3383 remove_unit_from_networkd_path(self
.units
)
3384 stop_networkd(show_logs
=True)
3386 def test_ipv6_route_prefix(self
):
3387 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network')
3390 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
3392 output
= check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
3394 self
.assertRegex(output
, '2001:db8:0:1::/64 proto ra')
3396 class NetworkdMTUTests(unittest
.TestCase
, Utilities
):
3401 '12-dummy-mtu.netdev',
3402 '12-dummy-mtu.link',
3407 remove_links(self
.links
)
3408 stop_networkd(show_logs
=False)
3412 remove_links(self
.links
)
3413 remove_unit_from_networkd_path(self
.units
)
3414 stop_networkd(show_logs
=True)
3416 def check_mtu(self
, mtu
, ipv6_mtu
=None, reset
=True):
3422 self
.wait_online(['dummy98:routable'])
3423 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3424 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3426 # test normal restart
3428 self
.wait_online(['dummy98:routable'])
3429 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), ipv6_mtu
)
3430 self
.assertEqual(read_link_attr('dummy98', 'mtu'), mtu
)
3433 self
.reset_check_mtu(mtu
, ipv6_mtu
)
3435 def reset_check_mtu(self
, mtu
, ipv6_mtu
=None):
3436 ''' test setting mtu/ipv6_mtu with interface already up '''
3439 # note - changing the device mtu resets the ipv6 mtu
3440 run('ip link set up mtu 1501 dev dummy98')
3441 run('ip link set up mtu 1500 dev dummy98')
3442 self
.assertEqual(read_link_attr('dummy98', 'mtu'), '1500')
3443 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'mtu'), '1500')
3445 self
.check_mtu(mtu
, ipv6_mtu
, reset
=False)
3447 def test_mtu_network(self
):
3448 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf')
3449 self
.check_mtu('1600')
3451 def test_mtu_netdev(self
):
3452 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network', dropins
=False)
3453 # note - MTU set by .netdev happens ONLY at device creation!
3454 self
.check_mtu('1600', reset
=False)
3456 def test_mtu_link(self
):
3457 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network', dropins
=False)
3458 # must reload udev because it only picks up new files after 3 second delay
3459 call('udevadm control --reload')
3460 # note - MTU set by .link happens ONLY at udev processing of device 'add' uevent!
3461 self
.check_mtu('1600', reset
=False)
3463 def test_ipv6_mtu(self
):
3464 ''' set ipv6 mtu without setting device mtu '''
3465 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1400.conf')
3466 self
.check_mtu('1500', '1400')
3468 def test_ipv6_mtu_toolarge(self
):
3469 ''' try set ipv6 mtu over device mtu (it shouldn't work) '''
3470 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3471 self
.check_mtu('1500', '1500')
3473 def test_mtu_network_ipv6_mtu(self
):
3474 ''' set ipv6 mtu and set device mtu via network file '''
3475 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy.network.d/mtu.conf', '12-dummy.network.d/ipv6-mtu-1550.conf')
3476 self
.check_mtu('1600', '1550')
3478 def test_mtu_netdev_ipv6_mtu(self
):
3479 ''' set ipv6 mtu and set device mtu via netdev file '''
3480 copy_unit_to_networkd_unit_path('12-dummy-mtu.netdev', '12-dummy.network.d/ipv6-mtu-1550.conf')
3481 self
.check_mtu('1600', '1550', reset
=False)
3483 def test_mtu_link_ipv6_mtu(self
):
3484 ''' set ipv6 mtu and set device mtu via link file '''
3485 copy_unit_to_networkd_unit_path('12-dummy.netdev', '12-dummy-mtu.link', '12-dummy.network.d/ipv6-mtu-1550.conf')
3486 # must reload udev because it only picks up new files after 3 second delay
3487 call('udevadm control --reload')
3488 self
.check_mtu('1600', '1550', reset
=False)
3491 if __name__
== '__main__':
3492 parser
= argparse
.ArgumentParser()
3493 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
3494 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
3495 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
3496 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
3497 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
3498 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
3499 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
3500 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
3501 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
3502 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
3503 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3504 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3505 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3508 if ns
.networkd_bin
or ns
.resolved_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
or ns
.resolvectl_bin
or ns
.timedatectl_bin
:
3509 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3510 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3511 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3512 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3513 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3514 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3515 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3518 networkd_bin
= ns
.networkd_bin
3520 resolved_bin
= ns
.resolved_bin
3521 if ns
.wait_online_bin
:
3522 wait_online_bin
= ns
.wait_online_bin
3523 if ns
.networkctl_bin
:
3524 networkctl_bin
= ns
.networkctl_bin
3525 if ns
.resolvectl_bin
:
3526 resolvectl_bin
= ns
.resolvectl_bin
3527 if ns
.timedatectl_bin
:
3528 timedatectl_bin
= ns
.timedatectl_bin
3530 use_valgrind
= ns
.use_valgrind
3531 enable_debug
= ns
.enable_debug
3532 asan_options
= ns
.asan_options
3533 lsan_options
= ns
.lsan_options
3534 ubsan_options
= ns
.ubsan_options
3537 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3538 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3539 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3540 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3542 networkctl_cmd
= [networkctl_bin
]
3543 resolvectl_cmd
= [resolvectl_bin
]
3544 timedatectl_cmd
= [timedatectl_bin
]
3545 wait_online_cmd
= [wait_online_bin
]
3548 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3550 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3552 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3554 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3557 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,