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 networkd_bin
='/usr/lib/systemd/systemd-networkd'
26 resolved_bin
='/usr/lib/systemd/systemd-resolved'
27 wait_online_bin
='/usr/lib/systemd/systemd-networkd-wait-online'
28 networkctl_bin
='/usr/bin/networkctl'
29 resolvectl_bin
='/usr/bin/resolvectl'
30 timedatectl_bin
='/usr/bin/timedatectl'
38 def check_output(*command
, **kwargs
):
39 # This replaces both check_output and check_call (output can be ignored)
40 command
= command
[0].split() + list(command
[1:])
41 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
43 def call(*command
, **kwargs
):
44 command
= command
[0].split() + list(command
[1:])
45 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
47 def run(*command
, **kwargs
):
48 command
= command
[0].split() + list(command
[1:])
49 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
51 def is_module_available(module_name
):
52 lsmod_output
= check_output('lsmod')
53 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
54 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
)
56 def expectedFailureIfModuleIsNotAvailable(module_name
):
58 if not is_module_available(module_name
):
59 return unittest
.expectedFailure(func
)
64 def expectedFailureIfERSPANModuleIsNotAvailable():
66 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')
68 call('ip link del erspan99')
71 return unittest
.expectedFailure(func
)
75 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
77 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
79 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
82 return unittest
.expectedFailure(func
)
86 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
88 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
90 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
93 return unittest
.expectedFailure(func
)
97 def expectedFailureIfLinkFileFieldIsNotSet():
100 rc
= call('ip link add name dummy99 type dummy')
102 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
103 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
105 call('ip link del dummy99')
110 return unittest
.expectedFailure(func
)
115 os
.makedirs(network_unit_file_path
, exist_ok
=True)
116 os
.makedirs(networkd_ci_path
, exist_ok
=True)
118 shutil
.rmtree(networkd_ci_path
)
119 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
121 check_output('systemctl stop systemd-networkd.socket')
122 check_output('systemctl stop systemd-networkd.service')
123 check_output('systemctl stop systemd-resolved.service')
132 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
136 drop_in
+= ['ExecStart=!!' + networkd_bin
]
138 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
140 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
142 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
144 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
145 if asan_options
or lsan_options
or ubsan_options
:
146 drop_in
+= ['SystemCallFilter=']
147 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
148 drop_in
+= ['MemoryDenyWriteExecute=no']
150 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
151 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
152 f
.write('\n'.join(drop_in
))
160 drop_in
+= ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin
]
162 drop_in
+= ['ExecStart=!!' + resolved_bin
]
164 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
166 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
168 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
170 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
171 if asan_options
or lsan_options
or ubsan_options
:
172 drop_in
+= ['SystemCallFilter=']
173 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
174 drop_in
+= ['MemoryDenyWriteExecute=no']
176 os
.makedirs('/run/systemd/system/systemd-resolved.service.d', exist_ok
=True)
177 with
open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode
='w') as f
:
178 f
.write('\n'.join(drop_in
))
180 check_output('systemctl daemon-reload')
181 print(check_output('systemctl cat systemd-networkd.service'))
182 print(check_output('systemctl cat systemd-resolved.service'))
183 check_output('systemctl restart systemd-resolved')
185 def tearDownModule():
186 shutil
.rmtree(networkd_ci_path
)
188 check_output('systemctl stop systemd-networkd.service')
189 check_output('systemctl stop systemd-resolved.service')
191 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
192 shutil
.rmtree('/run/systemd/system/systemd-resolved.service.d')
193 check_output('systemctl daemon-reload')
195 check_output('systemctl start systemd-networkd.socket')
196 check_output('systemctl start systemd-resolved.service')
198 def read_link_attr(link
, dev
, attribute
):
199 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
200 return f
.readline().strip()
202 def read_bridge_port_attr(bridge
, link
, attribute
):
203 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
204 path_port
= 'lower_' + link
+ '/brport'
205 path
= os
.path
.join(path_bridge
, path_port
)
207 with
open(os
.path
.join(path
, attribute
)) as f
:
208 return f
.readline().strip()
210 def link_exists(link
):
211 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
213 def remove_links(links
):
215 if link_exists(link
):
216 call('ip link del dev', link
)
219 def remove_fou_ports(ports
):
221 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
223 def remove_routing_policy_rule_tables(tables
):
227 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
229 def remove_routes(routes
):
230 for route_type
, addr
in routes
:
231 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
233 def remove_l2tp_tunnels(tunnel_ids
):
234 output
= check_output('ip l2tp show tunnel')
235 for tid
in tunnel_ids
:
236 words
='Tunnel ' + tid
+ ', encap'
238 call('ip l2tp del tunnel tid', tid
)
241 def read_ipv6_sysctl_attr(link
, attribute
):
242 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
243 return f
.readline().strip()
245 def read_ipv4_sysctl_attr(link
, attribute
):
246 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
247 return f
.readline().strip()
249 def copy_unit_to_networkd_unit_path(*units
):
252 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
253 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
254 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
256 def remove_unit_from_networkd_path(units
):
258 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
259 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
260 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
261 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
263 def warn_about_firewalld():
264 rc
= call('systemctl -q is-active firewalld.service')
266 print('\nWARNING: firewalld.service is active. The test may fail.')
268 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
269 warn_about_firewalld()
270 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
271 check_output(dnsmasq_command
)
273 def stop_dnsmasq(pid_file
):
274 if os
.path
.exists(pid_file
):
275 with
open(pid_file
, 'r') as f
:
276 pid
= f
.read().rstrip(' \t\r\n\0')
277 os
.kill(int(pid
), signal
.SIGTERM
)
281 def search_words_in_dnsmasq_log(words
, show_all
=False):
282 if os
.path
.exists(dnsmasq_log_file
):
283 with
open (dnsmasq_log_file
) as in_file
:
284 contents
= in_file
.read()
287 for line
in contents
.splitlines():
290 print("%s, %s" % (words
, line
))
294 def remove_lease_file():
295 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
296 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
298 def remove_log_file():
299 if os
.path
.exists(dnsmasq_log_file
):
300 os
.remove(dnsmasq_log_file
)
302 def remove_networkd_state_files():
303 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
304 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
306 def stop_networkd(show_logs
=True, remove_state_files
=True):
308 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
309 check_output('systemctl stop systemd-networkd')
311 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
312 if remove_state_files
:
313 remove_networkd_state_files()
315 def start_networkd(sleep_sec
=0):
316 check_output('systemctl start systemd-networkd')
318 time
.sleep(sleep_sec
)
320 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
321 stop_networkd(show_logs
, remove_state_files
)
322 start_networkd(sleep_sec
)
324 def get_operstate(link
, show_status
=True, setup_state
='configured'):
325 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
328 for line
in output
.splitlines():
329 if 'State:' in line
and (not setup_state
or setup_state
in line
):
330 return line
.split()[1]
334 def check_link_exists(self
, link
):
335 self
.assertTrue(link_exists(link
))
337 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
338 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
340 def wait_online(self
, links_with_operstate
, timeout
='20s', bool_any
=False, setup_state
='configured'):
341 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
345 check_output(*args
, env
=env
)
346 except subprocess
.CalledProcessError
:
347 for link
in links_with_operstate
:
348 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
352 for link
in links_with_operstate
:
353 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0])
355 for line
in output
.splitlines():
357 self
.assertRegex(line
, setup_state
)
359 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
360 for i
in range(timeout_sec
):
363 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
364 if re
.search(address_regex
, output
):
367 self
.assertRegex(output
, address_regex
)
369 class NetworkctlTests(unittest
.TestCase
, Utilities
):
378 '11-dummy-mtu.netdev',
381 'netdev-link-local-addressing-yes.network',
385 remove_links(self
.links
)
386 stop_networkd(show_logs
=False)
389 remove_links(self
.links
)
390 remove_unit_from_networkd_path(self
.units
)
391 stop_networkd(show_logs
=True)
394 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
397 self
.wait_online(['test1:degraded'])
399 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
400 self
.assertRegex(output
, '1 lo ')
401 self
.assertRegex(output
, 'test1')
403 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
404 self
.assertNotRegex(output
, '1 lo ')
405 self
.assertRegex(output
, 'test1')
407 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
408 self
.assertNotRegex(output
, '1 lo ')
409 self
.assertRegex(output
, 'test1')
411 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
412 self
.assertNotRegex(output
, '1: lo ')
413 self
.assertRegex(output
, 'test1')
415 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
416 self
.assertNotRegex(output
, '1: lo ')
417 self
.assertRegex(output
, 'test1')
420 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
423 self
.wait_online(['test1:degraded'])
425 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
426 self
.assertRegex(output
, 'MTU: 1600')
429 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
431 self
.wait_online(['test1:degraded'])
433 output
= check_output(*networkctl_cmd
, 'status', 'test1')
435 self
.assertRegex(output
, 'Type: ether')
437 output
= check_output(*networkctl_cmd
, 'status', 'lo')
439 self
.assertRegex(output
, 'Type: loopback')
441 @expectedFailureIfLinkFileFieldIsNotSet()
442 def test_udev_link_file(self
):
443 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
445 self
.wait_online(['test1:degraded'])
447 output
= check_output(*networkctl_cmd
, 'status', 'test1')
449 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
450 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
452 output
= check_output(*networkctl_cmd
, 'status', 'lo')
454 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
455 self
.assertRegex(output
, r
'Network File: n/a')
457 def test_delete_links(self
):
458 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
459 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
462 self
.wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
464 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
465 self
.assertFalse(link_exists('test1'))
466 self
.assertFalse(link_exists('veth99'))
467 self
.assertFalse(link_exists('veth-peer'))
469 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
471 links_remove_earlier
= [
535 '10-dropin-test.netdev',
539 '13-not-match-udev-property.network',
540 '14-match-udev-property.network',
541 '15-name-conflict-test.netdev',
544 '21-vlan-test1.network',
547 '25-6rd-tunnel.netdev',
549 '25-bond-balanced-tlb.netdev',
551 '25-bridge-configure-without-carrier.network',
553 '25-erspan-tunnel-local-any.netdev',
554 '25-erspan-tunnel.netdev',
555 '25-fou-gretap.netdev',
557 '25-fou-ipip.netdev',
558 '25-fou-ipproto-gre.netdev',
559 '25-fou-ipproto-ipip.netdev',
562 '25-gretap-tunnel-local-any.netdev',
563 '25-gretap-tunnel.netdev',
564 '25-gre-tunnel-any-any.netdev',
565 '25-gre-tunnel-local-any.netdev',
566 '25-gre-tunnel-remote-any.netdev',
567 '25-gre-tunnel.netdev',
568 '25-ip6gretap-tunnel-local-any.netdev',
569 '25-ip6gretap-tunnel.netdev',
570 '25-ip6gre-tunnel-any-any.netdev',
571 '25-ip6gre-tunnel-local-any.netdev',
572 '25-ip6gre-tunnel-remote-any.netdev',
573 '25-ip6gre-tunnel.netdev',
574 '25-ip6tnl-tunnel-any-any.netdev',
575 '25-ip6tnl-tunnel-local-any.netdev',
576 '25-ip6tnl-tunnel-remote-any.netdev',
577 '25-ip6tnl-tunnel.netdev',
578 '25-ipip-tunnel-any-any.netdev',
579 '25-ipip-tunnel-independent.netdev',
580 '25-ipip-tunnel-independent-loopback.netdev',
581 '25-ipip-tunnel-local-any.netdev',
582 '25-ipip-tunnel-remote-any.netdev',
583 '25-ipip-tunnel.netdev',
586 '25-isatap-tunnel.netdev',
591 '25-sit-tunnel-any-any.netdev',
592 '25-sit-tunnel-local-any.netdev',
593 '25-sit-tunnel-remote-any.netdev',
594 '25-sit-tunnel.netdev',
597 '25-tunnel-local-any.network',
598 '25-tunnel-remote-any.network',
603 '25-vti6-tunnel-any-any.netdev',
604 '25-vti6-tunnel-local-any.netdev',
605 '25-vti6-tunnel-remote-any.netdev',
606 '25-vti6-tunnel.netdev',
607 '25-vti-tunnel-any-any.netdev',
608 '25-vti-tunnel-local-any.netdev',
609 '25-vti-tunnel-remote-any.netdev',
610 '25-vti-tunnel.netdev',
613 '25-wireguard-23-peers.netdev',
614 '25-wireguard-23-peers.network',
615 '25-wireguard-preshared-key.txt',
616 '25-wireguard-private-key.txt',
617 '25-wireguard.netdev',
618 '25-wireguard.network',
620 '25-xfrm-independent.netdev',
636 'netdev-link-local-addressing-yes.network',
640 'vxlan-test1.network',
650 remove_fou_ports(self
.fou_ports
)
651 remove_links(self
.links_remove_earlier
)
652 remove_links(self
.links
)
653 stop_networkd(show_logs
=False)
656 remove_fou_ports(self
.fou_ports
)
657 remove_links(self
.links_remove_earlier
)
658 remove_links(self
.links
)
659 remove_unit_from_networkd_path(self
.units
)
660 stop_networkd(show_logs
=True)
662 def test_dropin_and_name_conflict(self
):
663 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
666 self
.wait_online(['dropin-test:off'], setup_state
='unmanaged')
668 output
= check_output('ip link show dropin-test')
670 self
.assertRegex(output
, '00:50:56:c0:00:28')
672 def test_match_udev_property(self
):
673 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
675 self
.wait_online(['dummy98:routable'])
677 output
= check_output('networkctl status dummy98')
679 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
681 def test_wait_online_any(self
):
682 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
685 self
.wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
687 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
688 self
.check_operstate('test1', 'degraded')
690 def test_bridge(self
):
691 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
694 self
.wait_online(['bridge99:no-carrier'])
696 tick
= os
.sysconf('SC_CLK_TCK')
697 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
698 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
699 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
700 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
701 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
702 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
703 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
704 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
707 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
710 self
.wait_online(['bond99:off', 'bond98:off'], setup_state
='unmanaged')
712 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
713 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
714 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
715 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
716 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
717 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
718 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
719 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
720 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
721 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
722 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
724 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
725 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
728 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
729 '21-vlan.network', '21-vlan-test1.network')
732 self
.wait_online(['test1:degraded', 'vlan99:routable'])
734 output
= check_output('ip -d link show test1')
736 self
.assertRegex(output
, ' mtu 2000 ')
738 output
= check_output('ip -d link show vlan99')
740 self
.assertRegex(output
, ' mtu 2000 ')
741 self
.assertRegex(output
, 'REORDER_HDR')
742 self
.assertRegex(output
, 'LOOSE_BINDING')
743 self
.assertRegex(output
, 'GVRP')
744 self
.assertRegex(output
, 'MVRP')
745 self
.assertRegex(output
, ' id 99 ')
747 output
= check_output('ip -4 address show dev test1')
749 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
750 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
752 output
= check_output('ip -4 address show dev vlan99')
754 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
756 def test_macvtap(self
):
757 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
758 with self
.subTest(mode
=mode
):
759 if mode
!= 'private':
761 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
762 '11-dummy.netdev', 'macvtap.network')
763 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
764 f
.write('[MACVTAP]\nMode=' + mode
)
767 self
.wait_online(['macvtap99:degraded', 'test1:degraded'])
769 output
= check_output('ip -d link show macvtap99')
771 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
773 def test_macvlan(self
):
774 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
775 with self
.subTest(mode
=mode
):
776 if mode
!= 'private':
778 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
779 '11-dummy.netdev', 'macvlan.network')
780 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
781 f
.write('[MACVLAN]\nMode=' + mode
)
784 self
.wait_online(['macvlan99:degraded', 'test1:degraded'])
786 output
= check_output('ip -d link show test1')
788 self
.assertRegex(output
, ' mtu 2000 ')
790 output
= check_output('ip -d link show macvlan99')
792 self
.assertRegex(output
, ' mtu 2000 ')
793 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
795 @expectedFailureIfModuleIsNotAvailable('ipvlan')
796 def test_ipvlan(self
):
797 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
798 with self
.subTest(mode
=mode
, flag
=flag
):
801 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
802 '11-dummy.netdev', 'ipvlan.network')
803 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
804 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
807 self
.wait_online(['ipvlan99:degraded', 'test1:degraded'])
809 output
= check_output('ip -d link show ipvlan99')
811 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
813 @expectedFailureIfModuleIsNotAvailable('ipvtap')
814 def test_ipvtap(self
):
815 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
816 with self
.subTest(mode
=mode
, flag
=flag
):
819 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
820 '11-dummy.netdev', 'ipvtap.network')
821 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
822 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
825 self
.wait_online(['ipvtap99:degraded', 'test1:degraded'])
827 output
= check_output('ip -d link show ipvtap99')
829 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
832 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
835 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
837 output
= check_output('ip -d link show veth99')
839 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
840 output
= check_output('ip -d link show veth-peer')
842 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
845 copy_unit_to_networkd_unit_path('25-tun.netdev')
848 self
.wait_online(['tun99:off'], setup_state
='unmanaged')
850 output
= check_output('ip -d link show tun99')
852 # Old ip command does not support IFF_ flags
853 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
856 copy_unit_to_networkd_unit_path('25-tap.netdev')
859 self
.wait_online(['tap99:off'], setup_state
='unmanaged')
861 output
= check_output('ip -d link show tap99')
863 # Old ip command does not support IFF_ flags
864 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
866 @expectedFailureIfModuleIsNotAvailable('vrf')
868 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
871 self
.wait_online(['vrf99:carrier'])
873 @expectedFailureIfModuleIsNotAvailable('vcan')
875 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
878 self
.wait_online(['vcan99:carrier'])
880 @expectedFailureIfModuleIsNotAvailable('vxcan')
881 def test_vxcan(self
):
882 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
885 self
.wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
887 @expectedFailureIfModuleIsNotAvailable('wireguard')
888 def test_wireguard(self
):
889 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
890 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
891 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
893 self
.wait_online(['wg99:carrier', 'wg98:routable'])
895 if shutil
.which('wg'):
898 output
= check_output('wg show wg99 listen-port')
899 self
.assertRegex(output
, '51820')
900 output
= check_output('wg show wg99 fwmark')
901 self
.assertRegex(output
, '0x4d2')
902 output
= check_output('wg show wg99 allowed-ips')
903 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
904 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
905 output
= check_output('wg show wg99 persistent-keepalive')
906 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
907 output
= check_output('wg show wg99 endpoints')
908 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
909 output
= check_output('wg show wg99 private-key')
910 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
911 output
= check_output('wg show wg99 preshared-keys')
912 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
913 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
915 output
= check_output('wg show wg98 private-key')
916 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
918 def test_geneve(self
):
919 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
922 self
.wait_online(['geneve99:degraded'])
924 output
= check_output('ip -d link show geneve99')
926 self
.assertRegex(output
, '192.168.22.1')
927 self
.assertRegex(output
, '6082')
928 self
.assertRegex(output
, 'udpcsum')
929 self
.assertRegex(output
, 'udp6zerocsumrx')
931 def test_ipip_tunnel(self
):
932 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
933 '25-ipip-tunnel.netdev', '25-tunnel.network',
934 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
935 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
936 '25-ipip-tunnel-any-any.netdev', '25-tunnel-any-any.network')
938 self
.wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'ipiptun96:routable', 'dummy98:degraded'])
940 output
= check_output('ip -d link show ipiptun99')
942 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
943 output
= check_output('ip -d link show ipiptun98')
945 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
946 output
= check_output('ip -d link show ipiptun97')
948 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
949 output
= check_output('ip -d link show ipiptun96')
951 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local any dev dummy98')
953 def test_gre_tunnel(self
):
954 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
955 '25-gre-tunnel.netdev', '25-tunnel.network',
956 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
957 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
958 '25-gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
960 self
.wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'gretun96:routable', 'dummy98:degraded'])
962 output
= check_output('ip -d link show gretun99')
964 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
965 self
.assertRegex(output
, 'ikey 1.2.3.103')
966 self
.assertRegex(output
, 'okey 1.2.4.103')
967 self
.assertRegex(output
, 'iseq')
968 self
.assertRegex(output
, 'oseq')
969 output
= check_output('ip -d link show gretun98')
971 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
972 self
.assertRegex(output
, 'ikey 0.0.0.104')
973 self
.assertRegex(output
, 'okey 0.0.0.104')
974 self
.assertNotRegex(output
, 'iseq')
975 self
.assertNotRegex(output
, 'oseq')
976 output
= check_output('ip -d link show gretun97')
978 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
979 self
.assertRegex(output
, 'ikey 0.0.0.105')
980 self
.assertRegex(output
, 'okey 0.0.0.105')
981 self
.assertNotRegex(output
, 'iseq')
982 self
.assertNotRegex(output
, 'oseq')
983 output
= check_output('ip -d link show gretun96')
985 self
.assertRegex(output
, 'gre remote any local any dev dummy98')
986 self
.assertRegex(output
, 'ikey 0.0.0.106')
987 self
.assertRegex(output
, 'okey 0.0.0.106')
988 self
.assertNotRegex(output
, 'iseq')
989 self
.assertNotRegex(output
, 'oseq')
991 def test_ip6gre_tunnel(self
):
992 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
993 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
994 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
995 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
996 '25-ip6gre-tunnel-any-any.netdev', '25-tunnel-any-any.network')
999 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
1001 self
.check_link_exists('dummy98')
1002 self
.check_link_exists('ip6gretun99')
1003 self
.check_link_exists('ip6gretun98')
1004 self
.check_link_exists('ip6gretun97')
1005 self
.check_link_exists('ip6gretun96')
1007 output
= check_output('ip -d link show ip6gretun99')
1009 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1010 output
= check_output('ip -d link show ip6gretun98')
1012 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
1013 output
= check_output('ip -d link show ip6gretun97')
1015 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
1016 output
= check_output('ip -d link show ip6gretun96')
1018 self
.assertRegex(output
, 'ip6gre remote any local any dev dummy98')
1020 def test_gretap_tunnel(self
):
1021 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
1022 '25-gretap-tunnel.netdev', '25-tunnel.network',
1023 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1025 self
.wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
1027 output
= check_output('ip -d link show gretap99')
1029 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1030 self
.assertRegex(output
, 'ikey 0.0.0.106')
1031 self
.assertRegex(output
, 'okey 0.0.0.106')
1032 self
.assertRegex(output
, 'iseq')
1033 self
.assertRegex(output
, 'oseq')
1034 output
= check_output('ip -d link show gretap98')
1036 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1037 self
.assertRegex(output
, 'ikey 0.0.0.107')
1038 self
.assertRegex(output
, 'okey 0.0.0.107')
1039 self
.assertRegex(output
, 'iseq')
1040 self
.assertRegex(output
, 'oseq')
1042 def test_ip6gretap_tunnel(self
):
1043 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1044 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1045 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1047 self
.wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1049 output
= check_output('ip -d link show ip6gretap99')
1051 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1052 output
= check_output('ip -d link show ip6gretap98')
1054 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1056 def test_vti_tunnel(self
):
1057 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1058 '25-vti-tunnel.netdev', '25-tunnel.network',
1059 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1060 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1061 '25-vti-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1063 self
.wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'vtitun96:routable', 'dummy98:degraded'])
1065 output
= check_output('ip -d link show vtitun99')
1067 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1068 output
= check_output('ip -d link show vtitun98')
1070 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1071 output
= check_output('ip -d link show vtitun97')
1073 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1074 output
= check_output('ip -d link show vtitun96')
1076 self
.assertRegex(output
, 'vti remote any local any dev dummy98')
1078 def test_vti6_tunnel(self
):
1079 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1080 '25-vti6-tunnel.netdev', '25-tunnel.network',
1081 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1082 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1084 self
.wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1086 output
= check_output('ip -d link show vti6tun99')
1088 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1089 output
= check_output('ip -d link show vti6tun98')
1091 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1092 output
= check_output('ip -d link show vti6tun97')
1094 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1096 def test_ip6tnl_tunnel(self
):
1097 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1098 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1099 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1100 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1102 self
.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1104 output
= check_output('ip -d link show ip6tnl99')
1106 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1107 output
= check_output('ip -d link show ip6tnl98')
1109 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1110 output
= check_output('ip -d link show ip6tnl97')
1112 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1114 def test_sit_tunnel(self
):
1115 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1116 '25-sit-tunnel.netdev', '25-tunnel.network',
1117 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1118 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
1119 '25-sit-tunnel-any-any.netdev', '25-tunnel-any-any.network')
1121 self
.wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'sittun96:routable', 'dummy98:degraded'])
1123 output
= check_output('ip -d link show sittun99')
1125 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1126 output
= check_output('ip -d link show sittun98')
1128 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1129 output
= check_output('ip -d link show sittun97')
1131 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1132 output
= check_output('ip -d link show sittun96')
1134 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local any dev dummy98")
1136 def test_isatap_tunnel(self
):
1137 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1138 '25-isatap-tunnel.netdev', '25-tunnel.network')
1140 self
.wait_online(['isataptun99:routable', 'dummy98:degraded'])
1142 output
= check_output('ip -d link show isataptun99')
1144 self
.assertRegex(output
, "isatap ")
1146 def test_6rd_tunnel(self
):
1147 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1148 '25-6rd-tunnel.netdev', '25-tunnel.network')
1150 self
.wait_online(['sittun99:routable', 'dummy98:degraded'])
1152 output
= check_output('ip -d link show sittun99')
1154 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1156 @expectedFailureIfERSPANModuleIsNotAvailable()
1157 def test_erspan_tunnel(self
):
1158 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1159 '25-erspan-tunnel.netdev', '25-tunnel.network',
1160 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1162 self
.wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1164 output
= check_output('ip -d link show erspan99')
1166 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1167 self
.assertRegex(output
, 'ikey 0.0.0.101')
1168 self
.assertRegex(output
, 'okey 0.0.0.101')
1169 self
.assertRegex(output
, 'iseq')
1170 self
.assertRegex(output
, 'oseq')
1171 output
= check_output('ip -d link show erspan98')
1173 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1174 self
.assertRegex(output
, '102')
1175 self
.assertRegex(output
, 'ikey 0.0.0.102')
1176 self
.assertRegex(output
, 'okey 0.0.0.102')
1177 self
.assertRegex(output
, 'iseq')
1178 self
.assertRegex(output
, 'oseq')
1180 def test_tunnel_independent(self
):
1181 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1184 self
.wait_online(['ipiptun99:carrier'])
1186 def test_tunnel_independent_loopback(self
):
1187 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1190 self
.wait_online(['ipiptun99:carrier'])
1192 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1193 def test_xfrm(self
):
1194 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1195 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1198 self
.wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1200 output
= check_output('ip link show dev xfrm99')
1203 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1204 def test_xfrm_independent(self
):
1205 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1208 self
.wait_online(['xfrm99:degraded'])
1210 @expectedFailureIfModuleIsNotAvailable('fou')
1212 # The following redundant check is necessary for CentOS CI.
1213 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1214 self
.assertTrue(is_module_available('fou'))
1216 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1217 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1218 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1221 self
.wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'], setup_state
='unmanaged')
1223 output
= check_output('ip fou show')
1225 self
.assertRegex(output
, 'port 55555 ipproto 4')
1226 self
.assertRegex(output
, 'port 55556 ipproto 47')
1228 output
= check_output('ip -d link show ipiptun96')
1230 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1231 output
= check_output('ip -d link show sittun96')
1233 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1234 output
= check_output('ip -d link show gretun96')
1236 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1237 output
= check_output('ip -d link show gretap96')
1239 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1241 def test_vxlan(self
):
1242 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1243 '11-dummy.netdev', 'vxlan-test1.network')
1246 self
.wait_online(['test1:degraded', 'vxlan99:degraded'])
1248 output
= check_output('ip -d link show vxlan99')
1250 self
.assertRegex(output
, '999')
1251 self
.assertRegex(output
, '5555')
1252 self
.assertRegex(output
, 'l2miss')
1253 self
.assertRegex(output
, 'l3miss')
1254 self
.assertRegex(output
, 'udpcsum')
1255 self
.assertRegex(output
, 'udp6zerocsumtx')
1256 self
.assertRegex(output
, 'udp6zerocsumrx')
1257 self
.assertRegex(output
, 'remcsumtx')
1258 self
.assertRegex(output
, 'remcsumrx')
1259 self
.assertRegex(output
, 'gbp')
1261 output
= check_output('bridge fdb show dev vxlan99')
1263 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1264 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1265 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1267 def test_macsec(self
):
1268 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1269 'macsec.network', '12-dummy.netdev')
1272 self
.wait_online(['dummy98:degraded', 'macsec99:routable'])
1274 output
= check_output('ip -d link show macsec99')
1276 self
.assertRegex(output
, 'macsec99@dummy98')
1277 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1278 self
.assertRegex(output
, 'encrypt on')
1280 output
= check_output('ip macsec show macsec99')
1282 self
.assertRegex(output
, 'encrypt on')
1283 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1284 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1285 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1286 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1287 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1288 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1289 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1290 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1291 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1292 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1293 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1295 def test_nlmon(self
):
1296 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1299 self
.wait_online(['nlmon99:carrier'])
1301 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1312 '25-l2tp-dummy.network',
1314 '25-l2tp-ip.netdev',
1315 '25-l2tp-udp.netdev']
1317 l2tp_tunnel_ids
= [ '10' ]
1320 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1321 remove_links(self
.links
)
1322 stop_networkd(show_logs
=False)
1325 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1326 remove_links(self
.links
)
1327 remove_unit_from_networkd_path(self
.units
)
1328 stop_networkd(show_logs
=True)
1330 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1331 def test_l2tp_udp(self
):
1332 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1333 '25-l2tp-udp.netdev', '25-l2tp.network')
1336 self
.wait_online(['test1:routable', 'l2tp-ses1:degraded', 'l2tp-ses2:degraded'])
1338 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1340 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1341 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1342 self
.assertRegex(output
, "Peer tunnel 11")
1343 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1344 self
.assertRegex(output
, "UDP checksum: enabled")
1346 output
= check_output('ip l2tp show session tid 10 session_id 15')
1348 self
.assertRegex(output
, "Session 15 in tunnel 10")
1349 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1350 self
.assertRegex(output
, "interface name: l2tp-ses1")
1352 output
= check_output('ip l2tp show session tid 10 session_id 17')
1354 self
.assertRegex(output
, "Session 17 in tunnel 10")
1355 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1356 self
.assertRegex(output
, "interface name: l2tp-ses2")
1358 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1359 def test_l2tp_ip(self
):
1360 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network',
1361 '25-l2tp-ip.netdev', '25-l2tp.network')
1364 self
.wait_online(['test1:routable', 'l2tp-ses3:degraded', 'l2tp-ses4:degraded'])
1366 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1368 self
.assertRegex(output
, "Tunnel 10, encap IP")
1369 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1370 self
.assertRegex(output
, "Peer tunnel 12")
1372 output
= check_output('ip l2tp show session tid 10 session_id 25')
1374 self
.assertRegex(output
, "Session 25 in tunnel 10")
1375 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1376 self
.assertRegex(output
, "interface name: l2tp-ses3")
1378 output
= check_output('ip l2tp show session tid 10 session_id 27')
1380 self
.assertRegex(output
, "Session 27 in tunnel 10")
1381 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1382 self
.assertRegex(output
, "interface name: l2tp-ses4")
1384 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1396 '23-active-slave.network',
1397 '24-keep-configuration-static.network',
1398 '24-search-domain.network',
1399 '25-address-link-section.network',
1400 '25-address-preferred-lifetime-zero-ipv6.network',
1401 '25-address-static.network',
1402 '25-bind-carrier.network',
1403 '25-bond-active-backup-slave.netdev',
1404 '25-fibrule-invert.network',
1405 '25-fibrule-port-range.network',
1406 '25-gre-tunnel-remote-any.netdev',
1407 '25-ipv6-address-label-section.network',
1408 '25-neighbor-section.network',
1409 '25-neighbor-ip-dummy.network',
1410 '25-neighbor-ip.network',
1411 '25-link-local-addressing-no.network',
1412 '25-link-local-addressing-yes.network',
1413 '25-link-section-unmanaged.network',
1414 '25-route-ipv6-src.network',
1415 '25-route-static.network',
1416 '25-sysctl-disable-ipv6.network',
1417 '25-sysctl.network',
1418 'configure-without-carrier.network',
1419 'routing-policy-rule-dummy98.network',
1420 'routing-policy-rule-test1.network']
1422 routing_policy_rule_tables
= ['7', '8']
1423 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1426 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1427 remove_routes(self
.routes
)
1428 remove_links(self
.links
)
1429 stop_networkd(show_logs
=False)
1432 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1433 remove_routes(self
.routes
)
1434 remove_links(self
.links
)
1435 remove_unit_from_networkd_path(self
.units
)
1436 stop_networkd(show_logs
=True)
1438 def test_address_static(self
):
1439 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1442 self
.wait_online(['dummy98:routable'])
1444 output
= check_output('ip -4 address show dev dummy98')
1446 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1447 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1448 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1451 self
.assertNotRegex(output
, '10.10.0.1/16')
1452 self
.assertNotRegex(output
, '10.10.0.2/16')
1454 output
= check_output('ip -4 address show dev dummy98 label 32')
1455 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1457 output
= check_output('ip -4 address show dev dummy98 label 33')
1458 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1460 output
= check_output('ip -4 address show dev dummy98 label 34')
1461 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1463 output
= check_output('ip -4 address show dev dummy98 label 35')
1464 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1466 output
= check_output('ip -6 address show dev dummy98')
1468 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1469 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1470 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1471 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1472 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1473 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1475 def test_address_preferred_lifetime_zero_ipv6(self
):
1476 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1479 self
.check_link_exists('dummy98')
1480 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1482 output
= check_output('ip address show dummy98')
1484 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1485 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1487 def test_configure_without_carrier(self
):
1488 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1490 self
.wait_online(['test1:routable'])
1492 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1494 self
.assertRegex(output
, '192.168.0.15')
1495 self
.assertRegex(output
, '192.168.0.1')
1496 self
.assertRegex(output
, 'routable')
1498 def test_routing_policy_rule(self
):
1499 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1501 self
.wait_online(['test1:degraded'])
1503 output
= check_output('ip rule')
1505 self
.assertRegex(output
, '111')
1506 self
.assertRegex(output
, 'from 192.168.100.18')
1507 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1508 self
.assertRegex(output
, 'iif test1')
1509 self
.assertRegex(output
, 'oif test1')
1510 self
.assertRegex(output
, 'lookup 7')
1512 def test_routing_policy_rule_issue_11280(self
):
1513 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1514 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1516 for trial
in range(3):
1517 # Remove state files only first time
1519 self
.wait_online(['test1:degraded', 'dummy98:degraded'])
1522 output
= check_output('ip rule list table 7')
1524 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1526 output
= check_output('ip rule list table 8')
1528 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1530 stop_networkd(remove_state_files
=False)
1532 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1533 def test_routing_policy_rule_port_range(self
):
1534 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1536 self
.wait_online(['test1:degraded'])
1538 output
= check_output('ip rule')
1540 self
.assertRegex(output
, '111')
1541 self
.assertRegex(output
, 'from 192.168.100.18')
1542 self
.assertRegex(output
, '1123-1150')
1543 self
.assertRegex(output
, '3224-3290')
1544 self
.assertRegex(output
, 'tcp')
1545 self
.assertRegex(output
, 'lookup 7')
1547 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1548 def test_routing_policy_rule_invert(self
):
1549 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1551 self
.wait_online(['test1:degraded'])
1553 output
= check_output('ip rule')
1555 self
.assertRegex(output
, '111')
1556 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1557 self
.assertRegex(output
, 'tcp')
1558 self
.assertRegex(output
, 'lookup 7')
1560 def test_route_static(self
):
1561 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1563 self
.wait_online(['dummy98:routable'])
1565 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1568 print('### ip -6 route show dev dummy98')
1569 output
= check_output('ip -6 route show dev dummy98')
1571 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1572 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1574 print('### ip -6 route show dev dummy98 default')
1575 output
= check_output('ip -6 route show dev dummy98 default')
1577 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1579 print('### ip -4 route show dev dummy98')
1580 output
= check_output('ip -4 route show dev dummy98')
1582 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1583 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1584 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1585 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1586 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1587 self
.assertRegex(output
, 'multicast 149.10.123.4 proto static')
1589 print('### ip -4 route show dev dummy98 default')
1590 output
= check_output('ip -4 route show dev dummy98 default')
1592 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1593 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1594 self
.assertRegex(output
, 'default proto static')
1596 print('### ip -4 route show table local dev dummy98')
1597 output
= check_output('ip -4 route show table local dev dummy98')
1599 self
.assertRegex(output
, 'local 149.10.123.1 proto static scope host')
1600 self
.assertRegex(output
, 'anycast 149.10.123.2 proto static scope link')
1601 self
.assertRegex(output
, 'broadcast 149.10.123.3 proto static scope link')
1603 print('### ip route show type blackhole')
1604 output
= check_output('ip route show type blackhole')
1606 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1608 print('### ip route show type unreachable')
1609 output
= check_output('ip route show type unreachable')
1611 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1613 print('### ip route show type prohibit')
1614 output
= check_output('ip route show type prohibit')
1616 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1618 def test_ip_route_ipv6_src_route(self
):
1619 # a dummy device does not make the addresses go through tentative state, so we
1620 # reuse a bond from an earlier test, which does make the addresses go through
1621 # tentative state, and do our test on that
1622 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1624 self
.wait_online(['dummy98:enslaved', 'bond199:routable'])
1626 output
= check_output('ip -6 route list dev bond199')
1628 self
.assertRegex(output
, 'abcd::/16')
1629 self
.assertRegex(output
, 'src')
1630 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1632 def test_ip_link_mac_address(self
):
1633 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1635 self
.wait_online(['dummy98:degraded'])
1637 output
= check_output('ip link show dummy98')
1639 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1641 def test_ip_link_unmanaged(self
):
1642 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1645 self
.check_link_exists('dummy98')
1647 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1649 def test_ipv6_address_label(self
):
1650 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1652 self
.wait_online(['dummy98:degraded'])
1654 output
= check_output('ip addrlabel list')
1656 self
.assertRegex(output
, '2004:da8:1::/64')
1658 def test_neighbor_section(self
):
1659 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1661 self
.wait_online(['dummy98:degraded'], timeout
='40s')
1663 output
= check_output('ip neigh list dev dummy98')
1665 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1666 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1668 def test_neighbor_gre(self
):
1669 copy_unit_to_networkd_unit_path('25-neighbor-ip.network', '25-neighbor-ip-dummy.network',
1670 '12-dummy.netdev', '25-gre-tunnel-remote-any.netdev')
1672 self
.wait_online(['dummy98:degraded', 'gretun97:routable'], timeout
='40s')
1674 output
= check_output('ip neigh list dev gretun97')
1676 self
.assertRegex(output
, '10.0.0.22 lladdr 10.65.223.239 PERMANENT')
1678 def test_link_local_addressing(self
):
1679 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1680 '25-link-local-addressing-no.network', '12-dummy.netdev')
1682 self
.wait_online(['test1:degraded', 'dummy98:carrier'])
1684 output
= check_output('ip address show dev test1')
1686 self
.assertRegex(output
, 'inet .* scope link')
1687 self
.assertRegex(output
, 'inet6 .* scope link')
1689 output
= check_output('ip address show dev dummy98')
1691 self
.assertNotRegex(output
, 'inet6* .* scope link')
1694 Documentation/networking/ip-sysctl.txt
1696 addr_gen_mode - INTEGER
1697 Defines how link-local and autoconf addresses are generated.
1699 0: generate address based on EUI64 (default)
1700 1: do no generate a link-local address, use EUI64 for addresses generated
1702 2: generate stable privacy addresses, using the secret from
1703 stable_secret (RFC7217)
1704 3: generate stable privacy addresses, using a random secret if unset
1707 test1_addr_gen_mode
= ''
1708 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1709 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1713 # if stable_secret is unset, then EIO is returned
1714 test1_addr_gen_mode
= '0'
1716 test1_addr_gen_mode
= '2'
1718 test1_addr_gen_mode
= '0'
1720 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1721 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1723 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1724 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1726 def test_sysctl(self
):
1727 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1729 self
.wait_online(['dummy98:degraded'])
1731 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1732 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1733 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1734 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1735 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1736 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1737 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1739 def test_sysctl_disable_ipv6(self
):
1740 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1742 print('## Disable ipv6')
1743 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1744 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1747 self
.wait_online(['dummy98:routable'])
1749 output
= check_output('ip -4 address show dummy98')
1751 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1752 output
= check_output('ip -6 address show dummy98')
1754 self
.assertEqual(output
, '')
1755 output
= check_output('ip -4 route show dev dummy98')
1757 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1758 output
= check_output('ip -6 route show dev dummy98')
1760 self
.assertEqual(output
, '')
1762 check_output('ip link del dummy98')
1764 print('## Enable ipv6')
1765 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1766 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1769 self
.wait_online(['dummy98:routable'])
1771 output
= check_output('ip -4 address show dummy98')
1773 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1774 output
= check_output('ip -6 address show dummy98')
1776 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1777 self
.assertRegex(output
, 'inet6 .* scope link')
1778 output
= check_output('ip -4 route show dev dummy98')
1780 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1781 output
= check_output('ip -6 route show dev dummy98')
1783 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1785 def test_bind_carrier(self
):
1786 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1788 self
.wait_online(['test1:routable'])
1790 check_output('ip link add dummy98 type dummy')
1791 check_output('ip link set dummy98 up')
1793 output
= check_output('ip address show test1')
1795 self
.assertRegex(output
, 'UP,LOWER_UP')
1796 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1797 self
.check_operstate('test1', 'routable')
1799 check_output('ip link add dummy99 type dummy')
1800 check_output('ip link set dummy99 up')
1802 output
= check_output('ip address show test1')
1804 self
.assertRegex(output
, 'UP,LOWER_UP')
1805 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1806 self
.check_operstate('test1', 'routable')
1808 check_output('ip link del dummy98')
1810 output
= check_output('ip address show test1')
1812 self
.assertRegex(output
, 'UP,LOWER_UP')
1813 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1814 self
.check_operstate('test1', 'routable')
1816 check_output('ip link del dummy99')
1818 output
= check_output('ip address show test1')
1820 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1821 self
.assertRegex(output
, 'DOWN')
1822 self
.assertNotRegex(output
, '192.168.10')
1823 self
.check_operstate('test1', 'off')
1825 check_output('ip link add dummy98 type dummy')
1826 check_output('ip link set dummy98 up')
1828 output
= check_output('ip address show test1')
1830 self
.assertRegex(output
, 'UP,LOWER_UP')
1831 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1832 self
.check_operstate('test1', 'routable')
1834 def test_domain(self
):
1835 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1837 self
.wait_online(['dummy98:routable'])
1839 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1841 self
.assertRegex(output
, 'Address: 192.168.42.100')
1842 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1843 self
.assertRegex(output
, 'Search Domains: one')
1845 def test_keep_configuration_static(self
):
1846 check_output('systemctl stop systemd-networkd')
1848 check_output('ip link add name dummy98 type dummy')
1849 check_output('ip address add 10.1.2.3/16 dev dummy98')
1850 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1851 output
= check_output('ip address show dummy98')
1853 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1854 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1855 output
= check_output('ip route show dev dummy98')
1858 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1860 self
.wait_online(['dummy98:routable'])
1862 output
= check_output('ip address show dummy98')
1864 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1865 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1867 class NetworkdStateFileTests(unittest
.TestCase
, Utilities
):
1874 'state-file-tests.network',
1878 remove_links(self
.links
)
1879 stop_networkd(show_logs
=False)
1882 remove_links(self
.links
)
1883 remove_unit_from_networkd_path(self
.units
)
1884 stop_networkd(show_logs
=True)
1886 def test_state_file(self
):
1887 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'state-file-tests.network')
1889 self
.wait_online(['dummy98:routable'])
1891 output
= check_output(*networkctl_cmd
, '--no-legend', 'list', 'dummy98', env
=env
)
1893 ifindex
= output
.split()[0]
1895 path
= os
.path
.join('/run/systemd/netif/links/', ifindex
)
1896 self
.assertTrue(os
.path
.exists(path
))
1899 with
open(path
) as f
:
1901 self
.assertRegex(data
, r
'ADMIN_STATE=configured')
1902 self
.assertRegex(data
, r
'OPER_STATE=routable')
1903 self
.assertRegex(data
, r
'REQUIRED_FOR_ONLINE=yes')
1904 self
.assertRegex(data
, r
'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
1905 self
.assertRegex(data
, r
'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
1906 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
1907 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1908 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
1909 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
1910 self
.assertRegex(data
, r
'LLMNR=no')
1911 self
.assertRegex(data
, r
'MDNS=yes')
1912 self
.assertRegex(data
, r
'DNSSEC=no')
1913 self
.assertRegex(data
, r
'ADDRESSES=192.168.(?:10.10|12.12)/24 192.168.(?:12.12|10.10)/24')
1915 check_output(*resolvectl_cmd
, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env
=env
)
1916 check_output(*resolvectl_cmd
, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env
=env
)
1917 check_output(*resolvectl_cmd
, 'llmnr', 'dummy98', 'yes', env
=env
)
1918 check_output(*resolvectl_cmd
, 'mdns', 'dummy98', 'no', env
=env
)
1919 check_output(*resolvectl_cmd
, 'dnssec', 'dummy98', 'yes', env
=env
)
1920 check_output(*timedatectl_cmd
, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env
=env
)
1923 with
open(path
) as f
:
1925 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
1926 self
.assertRegex(data
, r
'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
1927 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
1928 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
1929 self
.assertRegex(data
, r
'LLMNR=yes')
1930 self
.assertRegex(data
, r
'MDNS=no')
1931 self
.assertRegex(data
, r
'DNSSEC=yes')
1933 check_output(*timedatectl_cmd
, 'revert', 'dummy98', env
=env
)
1936 with
open(path
) as f
:
1938 self
.assertRegex(data
, r
'DNS=10.10.10.12 10.10.10.13')
1939 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1940 self
.assertRegex(data
, r
'DOMAINS=hogehogehoge')
1941 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoofoo')
1942 self
.assertRegex(data
, r
'LLMNR=yes')
1943 self
.assertRegex(data
, r
'MDNS=no')
1944 self
.assertRegex(data
, r
'DNSSEC=yes')
1946 check_output(*resolvectl_cmd
, 'revert', 'dummy98', env
=env
)
1949 with
open(path
) as f
:
1951 self
.assertRegex(data
, r
'DNS=10.10.10.10 10.10.10.11')
1952 self
.assertRegex(data
, r
'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
1953 self
.assertRegex(data
, r
'DOMAINS=hogehoge')
1954 self
.assertRegex(data
, r
'ROUTE_DOMAINS=foofoo')
1955 self
.assertRegex(data
, r
'LLMNR=no')
1956 self
.assertRegex(data
, r
'MDNS=yes')
1957 self
.assertRegex(data
, r
'DNSSEC=no')
1959 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1969 '23-active-slave.network',
1970 '23-bond199.network',
1971 '23-primary-slave.network',
1972 '25-bond-active-backup-slave.netdev',
1975 'bond-slave.network']
1978 remove_links(self
.links
)
1979 stop_networkd(show_logs
=False)
1982 remove_links(self
.links
)
1983 remove_unit_from_networkd_path(self
.units
)
1984 stop_networkd(show_logs
=True)
1986 def test_bond_active_slave(self
):
1987 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1989 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
1991 output
= check_output('ip -d link show bond199')
1993 self
.assertRegex(output
, 'active_slave dummy98')
1995 def test_bond_primary_slave(self
):
1996 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1998 self
.wait_online(['dummy98:enslaved', 'bond199:degraded'])
2000 output
= check_output('ip -d link show bond199')
2002 self
.assertRegex(output
, 'primary dummy98')
2004 def test_bond_operstate(self
):
2005 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
2006 'bond99.network','bond-slave.network')
2008 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
2010 output
= check_output('ip -d link show dummy98')
2012 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2014 output
= check_output('ip -d link show test1')
2016 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
2018 output
= check_output('ip -d link show bond99')
2020 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
2022 self
.check_operstate('dummy98', 'enslaved')
2023 self
.check_operstate('test1', 'enslaved')
2024 self
.check_operstate('bond99', 'routable')
2026 check_output('ip link set dummy98 down')
2029 self
.check_operstate('dummy98', 'off')
2030 self
.check_operstate('test1', 'enslaved')
2031 self
.check_operstate('bond99', 'degraded-carrier')
2033 check_output('ip link set dummy98 up')
2036 self
.check_operstate('dummy98', 'enslaved')
2037 self
.check_operstate('test1', 'enslaved')
2038 self
.check_operstate('bond99', 'routable')
2040 check_output('ip link set dummy98 down')
2041 check_output('ip link set test1 down')
2044 self
.check_operstate('dummy98', 'off')
2045 self
.check_operstate('test1', 'off')
2047 for trial
in range(30):
2050 output
= check_output('ip address show bond99')
2052 if get_operstate('bond99') == 'no-carrier':
2055 # Huh? Kernel does not recognize that all slave interfaces are down?
2056 # Let's confirm that networkd's operstate is consistent with ip's result.
2057 self
.assertNotRegex(output
, 'NO-CARRIER')
2059 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
2069 '26-bridge-slave-interface-1.network',
2070 '26-bridge-slave-interface-2.network',
2071 '26-bridge-vlan-master.network',
2072 '26-bridge-vlan-slave.network',
2073 'bridge99-ignore-carrier-loss.network',
2076 routing_policy_rule_tables
= ['100']
2079 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2080 remove_links(self
.links
)
2081 stop_networkd(show_logs
=False)
2084 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
2085 remove_links(self
.links
)
2086 remove_unit_from_networkd_path(self
.units
)
2087 stop_networkd(show_logs
=True)
2089 def test_bridge_vlan(self
):
2090 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
2091 '26-bridge.netdev', '26-bridge-vlan-master.network')
2093 self
.wait_online(['test1:enslaved', 'bridge99:degraded'])
2095 output
= check_output('bridge vlan show dev test1')
2097 self
.assertNotRegex(output
, '4063')
2098 for i
in range(4064, 4095):
2099 self
.assertRegex(output
, f
'{i}')
2100 self
.assertNotRegex(output
, '4095')
2102 output
= check_output('bridge vlan show dev bridge99')
2104 self
.assertNotRegex(output
, '4059')
2105 for i
in range(4060, 4095):
2106 self
.assertRegex(output
, f
'{i}')
2107 self
.assertNotRegex(output
, '4095')
2109 def test_bridge_property(self
):
2110 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2111 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2114 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2116 output
= check_output('ip -d link show test1')
2118 self
.assertRegex(output
, 'master')
2119 self
.assertRegex(output
, 'bridge')
2121 output
= check_output('ip -d link show dummy98')
2123 self
.assertRegex(output
, 'master')
2124 self
.assertRegex(output
, 'bridge')
2126 output
= check_output('ip addr show bridge99')
2128 self
.assertRegex(output
, '192.168.0.15/24')
2130 output
= check_output('bridge -d link show dummy98')
2132 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
2133 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
2134 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
2135 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
2136 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
2137 # CONFIG_BRIDGE_IGMP_SNOOPING=y
2138 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
2139 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
2140 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
2141 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
2142 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
2143 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'priority'), '23')
2144 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard'), '1')
2145 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'root_block'), '1')
2147 output
= check_output('bridge -d link show test1')
2149 self
.assertEqual(read_bridge_port_attr('bridge99', 'test1', 'priority'), '0')
2151 check_output('ip address add 192.168.0.16/24 dev bridge99')
2154 output
= check_output('ip addr show bridge99')
2156 self
.assertRegex(output
, '192.168.0.16/24')
2158 self
.assertEqual(call('ip link del test1'), 0)
2161 self
.check_operstate('bridge99', 'degraded-carrier')
2163 check_output('ip link del dummy98')
2166 self
.check_operstate('bridge99', 'no-carrier')
2168 output
= check_output('ip address show bridge99')
2170 self
.assertRegex(output
, 'NO-CARRIER')
2171 self
.assertNotRegex(output
, '192.168.0.15/24')
2172 self
.assertNotRegex(output
, '192.168.0.16/24')
2174 def test_bridge_ignore_carrier_loss(self
):
2175 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
2176 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2177 'bridge99-ignore-carrier-loss.network')
2179 self
.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2181 check_output('ip address add 192.168.0.16/24 dev bridge99')
2184 check_output('ip link del test1')
2185 check_output('ip link del dummy98')
2188 output
= check_output('ip address show bridge99')
2190 self
.assertRegex(output
, 'NO-CARRIER')
2191 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2192 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2194 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2195 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2196 'bridge99-ignore-carrier-loss.network')
2198 self
.wait_online(['bridge99:no-carrier'])
2200 for trial
in range(4):
2201 check_output('ip link add dummy98 type dummy')
2202 check_output('ip link set dummy98 up')
2204 check_output('ip link del dummy98')
2206 self
.wait_online(['bridge99:routable', 'dummy98:enslaved'])
2208 output
= check_output('ip address show bridge99')
2210 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2212 output
= check_output('ip rule list table 100')
2214 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2216 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2220 '23-emit-lldp.network',
2225 remove_links(self
.links
)
2226 stop_networkd(show_logs
=False)
2229 remove_links(self
.links
)
2230 remove_unit_from_networkd_path(self
.units
)
2231 stop_networkd(show_logs
=True)
2233 def test_lldp(self
):
2234 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2236 self
.wait_online(['veth99:degraded', 'veth-peer:degraded'])
2238 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2240 self
.assertRegex(output
, 'veth-peer')
2241 self
.assertRegex(output
, 'veth99')
2243 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2248 'ipv6-prefix.network',
2249 'ipv6-prefix-veth.network']
2252 remove_links(self
.links
)
2253 stop_networkd(show_logs
=False)
2256 remove_links(self
.links
)
2257 remove_unit_from_networkd_path(self
.units
)
2258 stop_networkd(show_logs
=True)
2260 def test_ipv6_prefix_delegation(self
):
2261 warn_about_firewalld()
2262 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2264 self
.wait_online(['veth99:routable', 'veth-peer:degraded'])
2266 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2268 self
.assertRegex(output
, '2002:da8:1:0')
2270 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2275 'dhcp-client.network',
2276 'dhcp-client-timezone-router.network',
2277 'dhcp-server.network',
2278 'dhcp-server-timezone-router.network']
2281 remove_links(self
.links
)
2282 stop_networkd(show_logs
=False)
2285 remove_links(self
.links
)
2286 remove_unit_from_networkd_path(self
.units
)
2287 stop_networkd(show_logs
=True)
2289 def test_dhcp_server(self
):
2290 warn_about_firewalld()
2291 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2293 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2295 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2297 self
.assertRegex(output
, '192.168.5.*')
2298 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2299 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2300 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2302 def test_emit_router_timezone(self
):
2303 warn_about_firewalld()
2304 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2306 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2308 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2310 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2311 self
.assertRegex(output
, '192.168.5.*')
2312 self
.assertRegex(output
, 'Europe/Berlin')
2314 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2323 'dhcp-client-anonymize.network',
2324 'dhcp-client-gateway-onlink-implicit.network',
2325 'dhcp-client-ipv4-dhcp-settings.network',
2326 'dhcp-client-ipv4-only-ipv6-disabled.network',
2327 'dhcp-client-ipv4-only.network',
2328 'dhcp-client-ipv6-only.network',
2329 'dhcp-client-ipv6-rapid-commit.network',
2330 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2331 'dhcp-client-keep-configuration-dhcp.network',
2332 'dhcp-client-listen-port.network',
2333 'dhcp-client-reassign-static-routes-ipv4.network',
2334 'dhcp-client-reassign-static-routes-ipv6.network',
2335 'dhcp-client-route-metric.network',
2336 'dhcp-client-route-table.network',
2337 'dhcp-client-use-dns-ipv4-and-ra.network',
2338 'dhcp-client-use-dns-ipv4.network',
2339 'dhcp-client-use-dns-no.network',
2340 'dhcp-client-use-dns-yes.network',
2341 'dhcp-client-use-domains.network',
2342 'dhcp-client-use-routes-no.network',
2343 'dhcp-client-vrf.network',
2344 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2345 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2346 'dhcp-client-with-static-address.network',
2347 'dhcp-client.network',
2348 'dhcp-server-veth-peer.network',
2349 'dhcp-v4-server-veth-peer.network',
2350 'dhcp-client-use-domains.network',
2354 stop_dnsmasq(dnsmasq_pid_file
)
2355 remove_links(self
.links
)
2356 stop_networkd(show_logs
=False)
2359 stop_dnsmasq(dnsmasq_pid_file
)
2362 remove_links(self
.links
)
2363 remove_unit_from_networkd_path(self
.units
)
2364 stop_networkd(show_logs
=True)
2366 def test_dhcp_client_ipv6_only(self
):
2367 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2370 self
.wait_online(['veth-peer:carrier'])
2372 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2374 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2376 self
.assertRegex(output
, '2600::')
2377 self
.assertNotRegex(output
, '192.168.5')
2379 # Confirm that ipv6 token is not set in the kernel
2380 output
= check_output('ip token show dev veth99')
2382 self
.assertRegex(output
, 'token :: dev veth99')
2384 def test_dhcp_client_ipv4_only(self
):
2385 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2388 self
.wait_online(['veth-peer:carrier'])
2390 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2392 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2394 self
.assertNotRegex(output
, '2600::')
2395 self
.assertRegex(output
, '192.168.5')
2397 def test_dhcp_client_ipv4_ipv6(self
):
2398 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2399 'dhcp-client-ipv4-only.network')
2401 self
.wait_online(['veth-peer:carrier'])
2403 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2405 # link become 'routable' when at least one protocol provide an valid address.
2406 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2407 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2409 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2411 self
.assertRegex(output
, '2600::')
2412 self
.assertRegex(output
, '192.168.5')
2414 def test_dhcp_client_settings(self
):
2415 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2418 self
.wait_online(['veth-peer:carrier'])
2420 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2422 print('## ip address show dev veth99')
2423 output
= check_output('ip address show dev veth99')
2425 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2426 self
.assertRegex(output
, '192.168.5')
2427 self
.assertRegex(output
, '1492')
2430 print('## ip route show table main dev veth99')
2431 output
= check_output('ip route show table main dev veth99')
2433 self
.assertNotRegex(output
, 'proto dhcp')
2435 print('## ip route show table 211 dev veth99')
2436 output
= check_output('ip route show table 211 dev veth99')
2438 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2439 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2440 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2442 print('## dnsmasq log')
2443 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2444 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2445 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2446 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2448 def test_dhcp6_client_settings_rapidcommit_true(self
):
2449 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2451 self
.wait_online(['veth-peer:carrier'])
2453 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2455 output
= check_output('ip address show dev veth99')
2457 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2458 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2460 def test_dhcp6_client_settings_rapidcommit_false(self
):
2461 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2463 self
.wait_online(['veth-peer:carrier'])
2465 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2467 output
= check_output('ip address show dev veth99')
2469 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2470 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2472 def test_dhcp_client_settings_anonymize(self
):
2473 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2475 self
.wait_online(['veth-peer:carrier'])
2477 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2479 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2480 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2481 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2483 def test_dhcp_client_listen_port(self
):
2484 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2486 self
.wait_online(['veth-peer:carrier'])
2487 start_dnsmasq('--dhcp-alternate-port=67,5555')
2488 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2490 # link become 'routable' when at least one protocol provide an valid address.
2491 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2492 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2494 output
= check_output('ip -4 address show dev veth99')
2496 self
.assertRegex(output
, '192.168.5.* dynamic')
2498 def test_dhcp_client_with_static_address(self
):
2499 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2500 'dhcp-client-with-static-address.network')
2502 self
.wait_online(['veth-peer:carrier'])
2504 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2506 output
= check_output('ip address show dev veth99 scope global')
2508 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2509 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2511 output
= check_output('ip route show dev veth99')
2513 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2514 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2515 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2516 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2518 def test_dhcp_route_table_id(self
):
2519 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2521 self
.wait_online(['veth-peer:carrier'])
2523 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2525 output
= check_output('ip route show table 12')
2527 self
.assertRegex(output
, 'veth99 proto dhcp')
2528 self
.assertRegex(output
, '192.168.5.1')
2530 def test_dhcp_route_metric(self
):
2531 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2533 self
.wait_online(['veth-peer:carrier'])
2535 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2537 output
= check_output('ip route show dev veth99')
2539 self
.assertRegex(output
, 'metric 24')
2541 def test_dhcp_client_reassign_static_routes_ipv4(self
):
2542 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2543 'dhcp-client-reassign-static-routes-ipv4.network')
2545 self
.wait_online(['veth-peer:carrier'])
2546 start_dnsmasq(lease_time
='2m')
2547 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2549 output
= check_output('ip address show dev veth99 scope global')
2551 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2553 output
= check_output('ip route show dev veth99')
2555 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2556 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2557 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2558 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2560 stop_dnsmasq(dnsmasq_pid_file
)
2561 start_dnsmasq(ipv4_range
='192.168.5.210,192.168.5.220', lease_time
='2m')
2563 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2564 print('Wait for the dynamic address to be renewed')
2567 self
.wait_online(['veth99:routable'])
2569 output
= check_output('ip route show dev veth99')
2571 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2572 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2573 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2574 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2576 def test_dhcp_client_reassign_static_routes_ipv6(self
):
2577 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2578 'dhcp-client-reassign-static-routes-ipv6.network')
2580 self
.wait_online(['veth-peer:carrier'])
2581 start_dnsmasq(lease_time
='2m')
2582 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2584 output
= check_output('ip address show dev veth99 scope global')
2586 self
.assertRegex(output
, r
'inet6 2600::[0-9a-f]*/128 scope global (?:noprefixroute dynamic|dynamic noprefixroute)')
2588 output
= check_output('ip -6 route show dev veth99')
2590 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2591 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2593 stop_dnsmasq(dnsmasq_pid_file
)
2594 start_dnsmasq(ipv6_range
='2600::30,2600::40', lease_time
='2m')
2596 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2597 print('Wait for the dynamic address to be renewed')
2600 self
.wait_online(['veth99:routable'])
2602 output
= check_output('ip -6 route show dev veth99')
2604 self
.assertRegex(output
, r
'2600::/64 proto ra metric 1024')
2605 self
.assertRegex(output
, r
'2600:0:0:1::/64 proto static metric 1024 pref medium')
2607 def test_dhcp_keep_configuration_dhcp(self
):
2608 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2610 self
.wait_online(['veth-peer:carrier'])
2611 start_dnsmasq(lease_time
='2m')
2612 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2614 output
= check_output('ip address show dev veth99 scope global')
2616 self
.assertRegex(output
, r
'192.168.5.*')
2618 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2620 self
.assertRegex(output
, r
'192.168.5.*')
2622 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2623 stop_dnsmasq(dnsmasq_pid_file
)
2625 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2626 print('Wait for the dynamic address to be expired')
2629 print('The lease address should be kept after lease expired')
2630 output
= check_output('ip address show dev veth99 scope global')
2632 self
.assertRegex(output
, r
'192.168.5.*')
2634 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2636 self
.assertRegex(output
, r
'192.168.5.*')
2638 check_output('systemctl stop systemd-networkd')
2640 print('The lease address should be kept after networkd stopped')
2641 output
= check_output('ip address show dev veth99 scope global')
2643 self
.assertRegex(output
, r
'192.168.5.*')
2645 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2647 self
.assertRegex(output
, r
'192.168.5.*')
2650 self
.wait_online(['veth-peer:routable'])
2652 print('Still the lease address should be kept after networkd restarted')
2653 output
= check_output('ip address show dev veth99 scope global')
2655 self
.assertRegex(output
, r
'192.168.5.*')
2657 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2659 self
.assertRegex(output
, r
'192.168.5.*')
2661 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2662 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2664 self
.wait_online(['veth-peer:carrier'])
2665 start_dnsmasq(lease_time
='2m')
2666 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2668 output
= check_output('ip address show dev veth99 scope global')
2670 self
.assertRegex(output
, r
'192.168.5.*')
2672 stop_dnsmasq(dnsmasq_pid_file
)
2673 check_output('systemctl stop systemd-networkd')
2675 output
= check_output('ip address show dev veth99 scope global')
2677 self
.assertRegex(output
, r
'192.168.5.*')
2680 self
.wait_online(['veth-peer:routable'])
2682 output
= check_output('ip address show dev veth99 scope global')
2684 self
.assertNotRegex(output
, r
'192.168.5.*')
2686 def test_dhcp_client_reuse_address_as_static(self
):
2687 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2689 self
.wait_online(['veth-peer:carrier'])
2691 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2693 # link become 'routable' when at least one protocol provide an valid address.
2694 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2695 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2697 output
= check_output('ip address show dev veth99 scope global')
2699 self
.assertRegex(output
, '192.168.5')
2700 self
.assertRegex(output
, '2600::')
2702 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2703 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2704 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2705 print(static_network
)
2707 remove_unit_from_networkd_path(['dhcp-client.network'])
2709 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2710 f
.write(static_network
)
2712 # When networkd started, the links are already configured, so let's wait for 5 seconds
2713 # the links to be re-configured.
2715 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2717 output
= check_output('ip -4 address show dev veth99 scope global')
2719 self
.assertRegex(output
, '192.168.5')
2720 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2722 output
= check_output('ip -6 address show dev veth99 scope global')
2724 self
.assertRegex(output
, '2600::')
2725 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2727 @expectedFailureIfModuleIsNotAvailable('vrf')
2728 def test_dhcp_client_vrf(self
):
2729 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2730 '25-vrf.netdev', '25-vrf.network')
2732 self
.wait_online(['veth-peer:carrier'])
2734 self
.wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2736 # link become 'routable' when at least one protocol provide an valid address.
2737 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2738 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2740 print('## ip -d link show dev vrf99')
2741 output
= check_output('ip -d link show dev vrf99')
2743 self
.assertRegex(output
, 'vrf table 42')
2745 print('## ip address show vrf vrf99')
2746 output
= check_output('ip address show vrf vrf99')
2748 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2749 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2750 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2751 self
.assertRegex(output
, 'inet6 .* scope link')
2753 print('## ip address show dev veth99')
2754 output
= check_output('ip address show dev veth99')
2756 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2757 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2758 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2759 self
.assertRegex(output
, 'inet6 .* scope link')
2761 print('## ip route show vrf vrf99')
2762 output
= check_output('ip route show vrf vrf99')
2764 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2765 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2766 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2767 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2768 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2769 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2771 print('## ip route show table main dev veth99')
2772 output
= check_output('ip route show table main dev veth99')
2774 self
.assertEqual(output
, '')
2776 def test_dhcp_client_gateway_onlink_implicit(self
):
2777 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2778 'dhcp-client-gateway-onlink-implicit.network')
2780 self
.wait_online(['veth-peer:carrier'])
2782 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2784 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2786 self
.assertRegex(output
, '192.168.5')
2788 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2790 self
.assertRegex(output
, 'onlink')
2791 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2793 self
.assertRegex(output
, 'onlink')
2795 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2796 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2797 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2799 self
.wait_online(['veth-peer:carrier'])
2800 start_dnsmasq(lease_time
='2m')
2801 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2803 output
= check_output('ip address show dev veth99')
2806 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2807 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2808 output
= check_output('ip -6 address show dev veth99 scope link')
2809 self
.assertRegex(output
, 'inet6 .* scope link')
2810 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2811 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2812 output
= check_output('ip -4 address show dev veth99 scope link')
2813 self
.assertNotRegex(output
, 'inet .* scope link')
2815 print('Wait for the dynamic address to be expired')
2818 output
= check_output('ip address show dev veth99')
2821 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2822 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2823 output
= check_output('ip -6 address show dev veth99 scope link')
2824 self
.assertRegex(output
, 'inet6 .* scope link')
2825 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2826 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2827 output
= check_output('ip -4 address show dev veth99 scope link')
2828 self
.assertNotRegex(output
, 'inet .* scope link')
2830 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2832 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2833 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2834 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2836 self
.wait_online(['veth99:degraded', 'veth-peer:routable'])
2838 output
= check_output('ip address show dev veth99')
2841 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2842 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2843 output
= check_output('ip -6 address show dev veth99 scope link')
2844 self
.assertRegex(output
, 'inet6 .* scope link')
2845 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2846 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2847 output
= check_output('ip -4 address show dev veth99 scope link')
2848 self
.assertRegex(output
, 'inet .* scope link')
2850 def test_dhcp_client_route_remove_on_renew(self
):
2851 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2852 'dhcp-client-ipv4-only-ipv6-disabled.network')
2854 self
.wait_online(['veth-peer:carrier'])
2855 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2856 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2858 # test for issue #12490
2860 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2862 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2864 for line
in output
.splitlines():
2865 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2866 address1
= line
.split()[1].split('/')[0]
2869 output
= check_output('ip -4 route show dev veth99')
2871 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2872 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2874 stop_dnsmasq(dnsmasq_pid_file
)
2875 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2877 print('Wait for the dynamic address to be expired')
2880 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2882 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2884 for line
in output
.splitlines():
2885 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2886 address2
= line
.split()[1].split('/')[0]
2889 self
.assertNotEqual(address1
, address2
)
2891 output
= check_output('ip -4 route show dev veth99')
2893 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2894 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2895 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2896 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2898 def test_dhcp_client_use_dns_yes(self
):
2899 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-yes.network')
2902 self
.wait_online(['veth-peer:carrier'])
2903 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2904 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2906 # link become 'routable' when at least one protocol provide an valid address.
2907 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2908 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2911 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2913 self
.assertRegex(output
, '192.168.5.1')
2914 self
.assertRegex(output
, '2600::1')
2916 def test_dhcp_client_use_dns_no(self
):
2917 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-no.network')
2920 self
.wait_online(['veth-peer:carrier'])
2921 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2922 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2924 # link become 'routable' when at least one protocol provide an valid address.
2925 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2926 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2929 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2931 self
.assertNotRegex(output
, '192.168.5.1')
2932 self
.assertNotRegex(output
, '2600::1')
2934 def test_dhcp_client_use_dns_ipv4(self
):
2935 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4.network')
2938 self
.wait_online(['veth-peer:carrier'])
2939 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2940 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2942 # link become 'routable' when at least one protocol provide an valid address.
2943 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2944 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2947 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2949 self
.assertRegex(output
, '192.168.5.1')
2950 self
.assertNotRegex(output
, '2600::1')
2952 def test_dhcp_client_use_dns_ipv4_and_ra(self
):
2953 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-dns-ipv4-and-ra.network')
2956 self
.wait_online(['veth-peer:carrier'])
2957 start_dnsmasq('--dhcp-option=option:dns-server,192.168.5.1 --dhcp-option=option6:dns-server,[2600::1]')
2958 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2960 # link become 'routable' when at least one protocol provide an valid address.
2961 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2962 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2965 output
= check_output(*resolvectl_cmd
, 'dns', 'veth99', env
=env
)
2967 self
.assertRegex(output
, '192.168.5.1')
2968 self
.assertRegex(output
, '2600::1')
2970 def test_dhcp_client_use_domains(self
):
2971 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-use-domains.network')
2974 self
.wait_online(['veth-peer:carrier'])
2975 start_dnsmasq('--dhcp-option=option:domain-search,example.com')
2976 self
.wait_online(['veth99:routable', 'veth-peer:routable'])
2978 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2980 self
.assertRegex(output
, 'Search Domains: example.com')
2983 output
= check_output(*resolvectl_cmd
, 'domain', 'veth99', env
=env
)
2985 self
.assertRegex(output
, 'example.com')
2987 if __name__
== '__main__':
2988 parser
= argparse
.ArgumentParser()
2989 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2990 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2991 parser
.add_argument('--resolved', help='Path to systemd-resolved', dest
='resolved_bin')
2992 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2993 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2994 parser
.add_argument('--resolvectl', help='Path to resolvectl', dest
='resolvectl_bin')
2995 parser
.add_argument('--timedatectl', help='Path to timedatectl', dest
='timedatectl_bin')
2996 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2997 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2998 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2999 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
3000 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
3001 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
3004 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
:
3005 print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
3006 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
3007 resolved_bin
= os
.path
.join(ns
.build_dir
, 'systemd-resolved')
3008 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
3009 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
3010 resolvectl_bin
= os
.path
.join(ns
.build_dir
, 'resolvectl')
3011 timedatectl_bin
= os
.path
.join(ns
.build_dir
, 'timedatectl')
3014 networkd_bin
= ns
.networkd_bin
3016 resolved_bin
= ns
.resolved_bin
3017 if ns
.wait_online_bin
:
3018 wait_online_bin
= ns
.wait_online_bin
3019 if ns
.networkctl_bin
:
3020 networkctl_bin
= ns
.networkctl_bin
3021 if ns
.resolvectl_bin
:
3022 resolvectl_bin
= ns
.resolvectl_bin
3023 if ns
.timedatectl_bin
:
3024 timedatectl_bin
= ns
.timedatectl_bin
3026 use_valgrind
= ns
.use_valgrind
3027 enable_debug
= ns
.enable_debug
3028 asan_options
= ns
.asan_options
3029 lsan_options
= ns
.lsan_options
3030 ubsan_options
= ns
.ubsan_options
3033 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
3034 resolvectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin
]
3035 timedatectl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin
]
3036 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
3038 networkctl_cmd
= [networkctl_bin
]
3039 resolvectl_cmd
= [resolvectl_bin
]
3040 timedatectl_cmd
= [timedatectl_bin
]
3041 wait_online_cmd
= [wait_online_bin
]
3044 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
3046 env
.update({ 'ASAN_OPTIONS' : asan_options
})
3048 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
3050 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
3053 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,