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 wait_online_bin
='/usr/lib/systemd/systemd-networkd-wait-online'
27 networkctl_bin
='/usr/bin/networkctl'
35 def check_output(*command
, **kwargs
):
36 # This replaces both check_output and check_call (output can be ignored)
37 command
= command
[0].split() + list(command
[1:])
38 return subprocess
.check_output(command
, universal_newlines
=True, **kwargs
).rstrip()
40 def call(*command
, **kwargs
):
41 command
= command
[0].split() + list(command
[1:])
42 return subprocess
.call(command
, universal_newlines
=True, **kwargs
)
44 def run(*command
, **kwargs
):
45 command
= command
[0].split() + list(command
[1:])
46 return subprocess
.run(command
, universal_newlines
=True, **kwargs
)
48 def is_module_available(module_name
):
49 lsmod_output
= check_output('lsmod')
50 module_re
= re
.compile(rf
'^{re.escape(module_name)}\b', re
.MULTILINE
)
51 return module_re
.search(lsmod_output
) or not call('modprobe', module_name
)
53 def expectedFailureIfModuleIsNotAvailable(module_name
):
55 if not is_module_available(module_name
):
56 return unittest
.expectedFailure(func
)
61 def expectedFailureIfERSPANModuleIsNotAvailable():
63 rc
= call('ip link add dev erspan99 type erspan seq key 30 local 192.168.1.4 remote 192.168.1.1 erspan_ver 1 erspan 123')
65 call('ip link del erspan99')
68 return unittest
.expectedFailure(func
)
72 def expectedFailureIfRoutingPolicyPortRangeIsNotAvailable():
74 rc
= call('ip rule add from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
76 call('ip rule del from 192.168.100.19 sport 1123-1150 dport 3224-3290 table 7')
79 return unittest
.expectedFailure(func
)
83 def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
85 rc
= call('ip rule add not from 192.168.100.19 ipproto tcp table 7')
87 call('ip rule del not from 192.168.100.19 ipproto tcp table 7')
90 return unittest
.expectedFailure(func
)
94 def expectedFailureIfLinkFileFieldIsNotSet():
97 rc
= call('ip link add name dummy99 type dummy')
99 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
100 if ret
.returncode
== 0 and 'E: ID_NET_LINK_FILE=' in ret
.stdout
.rstrip():
102 call('ip link del dummy99')
107 return unittest
.expectedFailure(func
)
111 def expectedFailureIfEthtoolDoesNotSupportDriver():
114 rc
= call('ip link add name dummy99 type dummy')
116 ret
= run('udevadm info -w10s /sys/class/net/dummy99', stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
117 if ret
.returncode
== 0 and 'E: ID_NET_DRIVER=dummy' in ret
.stdout
.rstrip():
119 call('ip link del dummy99')
124 return unittest
.expectedFailure(func
)
129 os
.makedirs(network_unit_file_path
, exist_ok
=True)
130 os
.makedirs(networkd_ci_path
, exist_ok
=True)
132 shutil
.rmtree(networkd_ci_path
)
133 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
135 check_output('systemctl stop systemd-networkd.socket')
136 check_output('systemctl stop systemd-networkd.service')
145 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
149 drop_in
+= ['ExecStart=!!' + networkd_bin
]
151 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
153 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
155 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
157 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
158 if asan_options
or lsan_options
or ubsan_options
:
159 drop_in
+= ['SystemCallFilter=']
160 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
161 drop_in
+= ['MemoryDenyWriteExecute=no']
163 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
164 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
165 f
.write('\n'.join(drop_in
))
167 check_output('systemctl daemon-reload')
168 print(check_output('systemctl cat systemd-networkd.service'))
170 def tearDownModule():
171 shutil
.rmtree(networkd_ci_path
)
173 check_output('systemctl stop systemd-networkd.service')
175 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
176 check_output('systemctl daemon-reload')
178 check_output('systemctl start systemd-networkd.socket')
179 check_output('systemctl start systemd-networkd.service')
181 def read_link_attr(link
, dev
, attribute
):
182 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
183 return f
.readline().strip()
185 def read_bridge_port_attr(bridge
, link
, attribute
):
186 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
187 path_port
= 'lower_' + link
+ '/brport'
188 path
= os
.path
.join(path_bridge
, path_port
)
190 with
open(os
.path
.join(path
, attribute
)) as f
:
191 return f
.readline().strip()
193 def link_exists(link
):
194 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
196 def remove_links(links
):
198 if link_exists(link
):
199 call('ip link del dev', link
)
202 def remove_fou_ports(ports
):
204 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
206 def remove_routing_policy_rule_tables(tables
):
210 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
212 def remove_routes(routes
):
213 for route_type
, addr
in routes
:
214 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
216 def remove_l2tp_tunnels(tunnel_ids
):
217 output
= check_output('ip l2tp show tunnel')
218 for tid
in tunnel_ids
:
219 words
='Tunnel ' + tid
+ ', encap'
221 call('ip l2tp del tunnel tid', tid
)
224 def read_ipv6_sysctl_attr(link
, attribute
):
225 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
226 return f
.readline().strip()
228 def read_ipv4_sysctl_attr(link
, attribute
):
229 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
230 return f
.readline().strip()
232 def copy_unit_to_networkd_unit_path(*units
):
235 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
236 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
237 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
239 def remove_unit_from_networkd_path(units
):
241 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
242 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
243 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
244 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
246 def warn_about_firewalld():
247 rc
= call('systemctl -q is-active firewalld.service')
249 print('\nWARNING: firewalld.service is active. The test may fail.')
251 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
252 warn_about_firewalld()
253 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
254 check_output(dnsmasq_command
)
256 def stop_dnsmasq(pid_file
):
257 if os
.path
.exists(pid_file
):
258 with
open(pid_file
, 'r') as f
:
259 pid
= f
.read().rstrip(' \t\r\n\0')
260 os
.kill(int(pid
), signal
.SIGTERM
)
264 def search_words_in_dnsmasq_log(words
, show_all
=False):
265 if os
.path
.exists(dnsmasq_log_file
):
266 with
open (dnsmasq_log_file
) as in_file
:
267 contents
= in_file
.read()
270 for line
in contents
.splitlines():
273 print("%s, %s" % (words
, line
))
277 def remove_lease_file():
278 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
279 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
281 def remove_log_file():
282 if os
.path
.exists(dnsmasq_log_file
):
283 os
.remove(dnsmasq_log_file
)
285 def remove_networkd_state_files():
286 if os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state')):
287 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
289 def stop_networkd(show_logs
=True, remove_state_files
=True):
291 invocation_id
= check_output('systemctl show systemd-networkd -p InvocationID --value')
292 check_output('systemctl stop systemd-networkd')
294 print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id
))
295 if remove_state_files
:
296 remove_networkd_state_files()
298 def start_networkd(sleep_sec
=0):
299 check_output('systemctl start systemd-networkd')
301 time
.sleep(sleep_sec
)
303 def restart_networkd(sleep_sec
=0, show_logs
=True, remove_state_files
=True):
304 stop_networkd(show_logs
, remove_state_files
)
305 start_networkd(sleep_sec
)
307 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
308 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
312 check_output(*args
, env
=env
)
313 except subprocess
.CalledProcessError
:
314 for link
in links_with_operstate
:
315 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
319 def get_operstate(link
, show_status
=True, setup_state
='configured'):
320 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
323 for line
in output
.splitlines():
324 if 'State:' in line
and (not setup_state
or setup_state
in line
):
325 return line
.split()[1]
329 def check_link_exists(self
, link
):
330 self
.assertTrue(link_exists(link
))
332 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
333 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
335 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
336 for i
in range(timeout_sec
):
339 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
340 if re
.search(address_regex
, output
):
343 self
.assertRegex(output
, address_regex
)
345 class NetworkctlTests(unittest
.TestCase
, Utilities
):
354 '11-dummy-mtu.netdev',
357 'netdev-link-local-addressing-yes.network',
361 remove_links(self
.links
)
362 stop_networkd(show_logs
=False)
365 remove_links(self
.links
)
366 remove_unit_from_networkd_path(self
.units
)
367 stop_networkd(show_logs
=True)
370 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
373 wait_online(['test1:degraded'])
375 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
376 self
.assertRegex(output
, '1 lo ')
377 self
.assertRegex(output
, 'test1')
379 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
380 self
.assertNotRegex(output
, '1 lo ')
381 self
.assertRegex(output
, 'test1')
383 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
384 self
.assertNotRegex(output
, '1 lo ')
385 self
.assertRegex(output
, 'test1')
387 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
388 self
.assertNotRegex(output
, '1: lo ')
389 self
.assertRegex(output
, 'test1')
391 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
392 self
.assertNotRegex(output
, '1: lo ')
393 self
.assertRegex(output
, 'test1')
396 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
399 wait_online(['test1:degraded'])
401 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
402 self
.assertRegex(output
, 'MTU: 1600')
405 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
407 wait_online(['test1:degraded'])
409 output
= check_output(*networkctl_cmd
, 'status', 'test1')
411 self
.assertRegex(output
, 'Type: ether')
413 output
= check_output(*networkctl_cmd
, 'status', 'lo')
415 self
.assertRegex(output
, 'Type: loopback')
417 @expectedFailureIfLinkFileFieldIsNotSet()
418 def test_udev_link_file(self
):
419 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
421 wait_online(['test1:degraded'])
423 output
= check_output(*networkctl_cmd
, 'status', 'test1')
425 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
426 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
428 output
= check_output(*networkctl_cmd
, 'status', 'lo')
430 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
431 self
.assertRegex(output
, r
'Network File: n/a')
433 @expectedFailureIfEthtoolDoesNotSupportDriver()
434 def test_udev_driver(self
):
435 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
436 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
439 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
441 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
442 self
.assertRegex(output
, 'Driver: dummy')
444 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
445 self
.assertRegex(output
, 'Driver: veth')
447 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
448 self
.assertRegex(output
, 'Driver: veth')
450 def test_delete_links(self
):
451 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
452 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
455 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
457 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
458 self
.assertFalse(link_exists('test1'))
459 self
.assertFalse(link_exists('veth99'))
460 self
.assertFalse(link_exists('veth-peer'))
462 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
464 links_remove_earlier
= [
526 '10-dropin-test.netdev',
530 '13-not-match-udev-property.network',
531 '14-match-udev-property.network',
532 '15-name-conflict-test.netdev',
535 '21-vlan-test1.network',
538 '25-6rd-tunnel.netdev',
540 '25-bond-balanced-tlb.netdev',
542 '25-bridge-configure-without-carrier.network',
544 '25-erspan-tunnel-local-any.netdev',
545 '25-erspan-tunnel.netdev',
546 '25-fou-gretap.netdev',
548 '25-fou-ipip.netdev',
549 '25-fou-ipproto-gre.netdev',
550 '25-fou-ipproto-ipip.netdev',
553 '25-gretap-tunnel-local-any.netdev',
554 '25-gretap-tunnel.netdev',
555 '25-gre-tunnel-local-any.netdev',
556 '25-gre-tunnel-remote-any.netdev',
557 '25-gre-tunnel.netdev',
558 '25-ip6gretap-tunnel-local-any.netdev',
559 '25-ip6gretap-tunnel.netdev',
560 '25-ip6gre-tunnel-local-any.netdev',
561 '25-ip6gre-tunnel-remote-any.netdev',
562 '25-ip6gre-tunnel.netdev',
563 '25-ip6tnl-tunnel-remote-any.netdev',
564 '25-ip6tnl-tunnel-local-any.netdev',
565 '25-ip6tnl-tunnel.netdev',
566 '25-ipip-tunnel-independent.netdev',
567 '25-ipip-tunnel-independent-loopback.netdev',
568 '25-ipip-tunnel-local-any.netdev',
569 '25-ipip-tunnel-remote-any.netdev',
570 '25-ipip-tunnel.netdev',
573 '25-isatap-tunnel.netdev',
578 '25-sit-tunnel-local-any.netdev',
579 '25-sit-tunnel-remote-any.netdev',
580 '25-sit-tunnel.netdev',
583 '25-tunnel-local-any.network',
584 '25-tunnel-remote-any.network',
589 '25-vti6-tunnel-local-any.netdev',
590 '25-vti6-tunnel-remote-any.netdev',
591 '25-vti6-tunnel.netdev',
592 '25-vti-tunnel-local-any.netdev',
593 '25-vti-tunnel-remote-any.netdev',
594 '25-vti-tunnel.netdev',
597 '25-wireguard-23-peers.netdev',
598 '25-wireguard-23-peers.network',
599 '25-wireguard-preshared-key.txt',
600 '25-wireguard-private-key.txt',
601 '25-wireguard.netdev',
602 '25-wireguard.network',
604 '25-xfrm-independent.netdev',
620 'netdev-link-local-addressing-yes.network',
624 'vxlan-test1.network',
634 remove_fou_ports(self
.fou_ports
)
635 remove_links(self
.links_remove_earlier
)
636 remove_links(self
.links
)
637 stop_networkd(show_logs
=False)
640 remove_fou_ports(self
.fou_ports
)
641 remove_links(self
.links_remove_earlier
)
642 remove_links(self
.links
)
643 remove_unit_from_networkd_path(self
.units
)
644 stop_networkd(show_logs
=True)
646 def test_dropin_and_name_conflict(self
):
647 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
650 wait_online(['dropin-test:off'])
652 output
= check_output('ip link show dropin-test')
654 self
.assertRegex(output
, '00:50:56:c0:00:28')
656 def test_match_udev_property(self
):
657 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
659 wait_online(['dummy98:routable'])
661 output
= check_output('networkctl status dummy98')
663 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
665 def test_wait_online_any(self
):
666 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
669 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
671 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
672 self
.check_operstate('test1', 'degraded')
674 def test_bridge(self
):
675 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
678 wait_online(['bridge99:no-carrier'])
680 tick
= os
.sysconf('SC_CLK_TCK')
681 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
682 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
683 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
684 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
685 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
686 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
687 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
688 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
691 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
694 wait_online(['bond99:off', 'bond98:off'])
696 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
697 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
698 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
699 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
700 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
701 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
702 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
703 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
704 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
705 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
706 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
708 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
709 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
712 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
713 '21-vlan.network', '21-vlan-test1.network')
716 wait_online(['test1:degraded', 'vlan99:routable'])
718 output
= check_output('ip -d link show test1')
720 self
.assertRegex(output
, ' mtu 2000 ')
722 output
= check_output('ip -d link show vlan99')
724 self
.assertRegex(output
, ' mtu 2000 ')
725 self
.assertRegex(output
, 'REORDER_HDR')
726 self
.assertRegex(output
, 'LOOSE_BINDING')
727 self
.assertRegex(output
, 'GVRP')
728 self
.assertRegex(output
, 'MVRP')
729 self
.assertRegex(output
, ' id 99 ')
731 output
= check_output('ip -4 address show dev test1')
733 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
734 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
736 output
= check_output('ip -4 address show dev vlan99')
738 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
740 def test_macvtap(self
):
741 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
742 with self
.subTest(mode
=mode
):
743 if mode
!= 'private':
745 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
746 '11-dummy.netdev', 'macvtap.network')
747 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
748 f
.write('[MACVTAP]\nMode=' + mode
)
751 wait_online(['macvtap99:degraded', 'test1:degraded'])
753 output
= check_output('ip -d link show macvtap99')
755 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
757 def test_macvlan(self
):
758 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
759 with self
.subTest(mode
=mode
):
760 if mode
!= 'private':
762 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
763 '11-dummy.netdev', 'macvlan.network')
764 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
765 f
.write('[MACVLAN]\nMode=' + mode
)
768 wait_online(['macvlan99:degraded', 'test1:degraded'])
770 output
= check_output('ip -d link show test1')
772 self
.assertRegex(output
, ' mtu 2000 ')
774 output
= check_output('ip -d link show macvlan99')
776 self
.assertRegex(output
, ' mtu 2000 ')
777 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
779 @expectedFailureIfModuleIsNotAvailable('ipvlan')
780 def test_ipvlan(self
):
781 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
782 with self
.subTest(mode
=mode
, flag
=flag
):
785 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
786 '11-dummy.netdev', 'ipvlan.network')
787 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
788 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
791 wait_online(['ipvlan99:degraded', 'test1:degraded'])
793 output
= check_output('ip -d link show ipvlan99')
795 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
797 @expectedFailureIfModuleIsNotAvailable('ipvtap')
798 def test_ipvtap(self
):
799 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
800 with self
.subTest(mode
=mode
, flag
=flag
):
803 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
804 '11-dummy.netdev', 'ipvtap.network')
805 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
806 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
809 wait_online(['ipvtap99:degraded', 'test1:degraded'])
811 output
= check_output('ip -d link show ipvtap99')
813 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
816 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
819 wait_online(['veth99:degraded', 'veth-peer:degraded'])
821 output
= check_output('ip -d link show veth99')
823 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
824 output
= check_output('ip -d link show veth-peer')
826 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
829 copy_unit_to_networkd_unit_path('25-tun.netdev')
832 wait_online(['tun99:off'])
834 output
= check_output('ip -d link show tun99')
836 # Old ip command does not support IFF_ flags
837 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
840 copy_unit_to_networkd_unit_path('25-tap.netdev')
843 wait_online(['tap99:off'])
845 output
= check_output('ip -d link show tap99')
847 # Old ip command does not support IFF_ flags
848 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
850 @expectedFailureIfModuleIsNotAvailable('vrf')
852 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
855 wait_online(['vrf99:carrier'])
857 @expectedFailureIfModuleIsNotAvailable('vcan')
859 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
862 wait_online(['vcan99:carrier'])
864 @expectedFailureIfModuleIsNotAvailable('vxcan')
865 def test_vxcan(self
):
866 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
869 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
871 @expectedFailureIfModuleIsNotAvailable('wireguard')
872 def test_wireguard(self
):
873 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
874 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
875 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
877 wait_online(['wg99:carrier', 'wg98:routable'])
879 if shutil
.which('wg'):
882 output
= check_output('wg show wg99 listen-port')
883 self
.assertRegex(output
, '51820')
884 output
= check_output('wg show wg99 fwmark')
885 self
.assertRegex(output
, '0x4d2')
886 output
= check_output('wg show wg99 allowed-ips')
887 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
888 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
889 output
= check_output('wg show wg99 persistent-keepalive')
890 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
891 output
= check_output('wg show wg99 endpoints')
892 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
893 output
= check_output('wg show wg99 private-key')
894 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
895 output
= check_output('wg show wg99 preshared-keys')
896 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
897 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
899 output
= check_output('wg show wg98 private-key')
900 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
902 def test_geneve(self
):
903 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
906 wait_online(['geneve99:degraded'])
908 output
= check_output('ip -d link show geneve99')
910 self
.assertRegex(output
, '192.168.22.1')
911 self
.assertRegex(output
, '6082')
912 self
.assertRegex(output
, 'udpcsum')
913 self
.assertRegex(output
, 'udp6zerocsumrx')
915 def test_ipip_tunnel(self
):
916 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
917 '25-ipip-tunnel.netdev', '25-tunnel.network',
918 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
919 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
921 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
923 output
= check_output('ip -d link show ipiptun99')
925 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
926 output
= check_output('ip -d link show ipiptun98')
928 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
929 output
= check_output('ip -d link show ipiptun97')
931 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
933 def test_gre_tunnel(self
):
934 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
935 '25-gre-tunnel.netdev', '25-tunnel.network',
936 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
937 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
939 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
941 output
= check_output('ip -d link show gretun99')
943 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
944 self
.assertRegex(output
, 'ikey 1.2.3.103')
945 self
.assertRegex(output
, 'okey 1.2.4.103')
946 self
.assertRegex(output
, 'iseq')
947 self
.assertRegex(output
, 'oseq')
948 output
= check_output('ip -d link show gretun98')
950 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
951 self
.assertRegex(output
, 'ikey 0.0.0.104')
952 self
.assertRegex(output
, 'okey 0.0.0.104')
953 self
.assertNotRegex(output
, 'iseq')
954 self
.assertNotRegex(output
, 'oseq')
955 output
= check_output('ip -d link show gretun97')
957 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
958 self
.assertRegex(output
, 'ikey 0.0.0.105')
959 self
.assertRegex(output
, 'okey 0.0.0.105')
960 self
.assertNotRegex(output
, 'iseq')
961 self
.assertNotRegex(output
, 'oseq')
963 def test_ip6gre_tunnel(self
):
964 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
965 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
966 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
967 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
970 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
972 self
.check_link_exists('dummy98')
973 self
.check_link_exists('ip6gretun99')
974 self
.check_link_exists('ip6gretun98')
975 self
.check_link_exists('ip6gretun97')
977 output
= check_output('ip -d link show ip6gretun99')
979 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
980 output
= check_output('ip -d link show ip6gretun98')
982 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
983 output
= check_output('ip -d link show ip6gretun97')
985 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
987 def test_gretap_tunnel(self
):
988 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
989 '25-gretap-tunnel.netdev', '25-tunnel.network',
990 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
992 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
994 output
= check_output('ip -d link show gretap99')
996 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
997 self
.assertRegex(output
, 'ikey 0.0.0.106')
998 self
.assertRegex(output
, 'okey 0.0.0.106')
999 self
.assertRegex(output
, 'iseq')
1000 self
.assertRegex(output
, 'oseq')
1001 output
= check_output('ip -d link show gretap98')
1003 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
1004 self
.assertRegex(output
, 'ikey 0.0.0.107')
1005 self
.assertRegex(output
, 'okey 0.0.0.107')
1006 self
.assertRegex(output
, 'iseq')
1007 self
.assertRegex(output
, 'oseq')
1009 def test_ip6gretap_tunnel(self
):
1010 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
1011 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
1012 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1014 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
1016 output
= check_output('ip -d link show ip6gretap99')
1018 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1019 output
= check_output('ip -d link show ip6gretap98')
1021 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
1023 def test_vti_tunnel(self
):
1024 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
1025 '25-vti-tunnel.netdev', '25-tunnel.network',
1026 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1027 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1029 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
1031 output
= check_output('ip -d link show vtitun99')
1033 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1034 output
= check_output('ip -d link show vtitun98')
1036 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1037 output
= check_output('ip -d link show vtitun97')
1039 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1041 def test_vti6_tunnel(self
):
1042 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1043 '25-vti6-tunnel.netdev', '25-tunnel.network',
1044 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1045 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1047 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1049 output
= check_output('ip -d link show vti6tun99')
1051 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1052 output
= check_output('ip -d link show vti6tun98')
1054 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1055 output
= check_output('ip -d link show vti6tun97')
1057 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1059 def test_ip6tnl_tunnel(self
):
1060 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1061 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1062 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1063 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1065 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1067 output
= check_output('ip -d link show ip6tnl99')
1069 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1070 output
= check_output('ip -d link show ip6tnl98')
1072 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1073 output
= check_output('ip -d link show ip6tnl97')
1075 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1077 def test_sit_tunnel(self
):
1078 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1079 '25-sit-tunnel.netdev', '25-tunnel.network',
1080 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1081 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1083 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1085 output
= check_output('ip -d link show sittun99')
1087 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1088 output
= check_output('ip -d link show sittun98')
1090 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1091 output
= check_output('ip -d link show sittun97')
1093 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1095 def test_isatap_tunnel(self
):
1096 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1097 '25-isatap-tunnel.netdev', '25-tunnel.network')
1099 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1101 output
= check_output('ip -d link show isataptun99')
1103 self
.assertRegex(output
, "isatap ")
1105 def test_6rd_tunnel(self
):
1106 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1107 '25-6rd-tunnel.netdev', '25-tunnel.network')
1109 wait_online(['sittun99:routable', 'dummy98:degraded'])
1111 output
= check_output('ip -d link show sittun99')
1113 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1115 @expectedFailureIfERSPANModuleIsNotAvailable()
1116 def test_erspan_tunnel(self
):
1117 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1118 '25-erspan-tunnel.netdev', '25-tunnel.network',
1119 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1121 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1123 output
= check_output('ip -d link show erspan99')
1125 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1126 self
.assertRegex(output
, 'ikey 0.0.0.101')
1127 self
.assertRegex(output
, 'okey 0.0.0.101')
1128 self
.assertRegex(output
, 'iseq')
1129 self
.assertRegex(output
, 'oseq')
1130 output
= check_output('ip -d link show erspan98')
1132 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1133 self
.assertRegex(output
, '102')
1134 self
.assertRegex(output
, 'ikey 0.0.0.102')
1135 self
.assertRegex(output
, 'okey 0.0.0.102')
1136 self
.assertRegex(output
, 'iseq')
1137 self
.assertRegex(output
, 'oseq')
1139 def test_tunnel_independent(self
):
1140 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1143 wait_online(['ipiptun99:carrier'])
1145 def test_tunnel_independent_loopback(self
):
1146 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent-loopback.netdev', 'netdev-link-local-addressing-yes.network')
1149 wait_online(['ipiptun99:carrier'])
1151 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1152 def test_xfrm(self
):
1153 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'xfrm.network',
1154 '25-xfrm.netdev', 'netdev-link-local-addressing-yes.network')
1157 wait_online(['xfrm99:degraded', 'dummy98:degraded'])
1159 output
= check_output('ip link show dev xfrm99')
1162 @expectedFailureIfModuleIsNotAvailable('xfrm_interface')
1163 def test_xfrm_independent(self
):
1164 copy_unit_to_networkd_unit_path('25-xfrm-independent.netdev', 'netdev-link-local-addressing-yes.network')
1167 wait_online(['xfrm99:degraded'])
1169 @expectedFailureIfModuleIsNotAvailable('fou')
1171 # The following redundant check is necessary for CentOS CI.
1172 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1173 self
.assertTrue(is_module_available('fou'))
1175 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1176 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1177 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1180 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1182 output
= check_output('ip fou show')
1184 self
.assertRegex(output
, 'port 55555 ipproto 4')
1185 self
.assertRegex(output
, 'port 55556 ipproto 47')
1187 output
= check_output('ip -d link show ipiptun96')
1189 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1190 output
= check_output('ip -d link show sittun96')
1192 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1193 output
= check_output('ip -d link show gretun96')
1195 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1196 output
= check_output('ip -d link show gretap96')
1198 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1200 def test_vxlan(self
):
1201 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1202 '11-dummy.netdev', 'vxlan-test1.network')
1205 wait_online(['test1:degraded', 'vxlan99:degraded'])
1207 output
= check_output('ip -d link show vxlan99')
1209 self
.assertRegex(output
, '999')
1210 self
.assertRegex(output
, '5555')
1211 self
.assertRegex(output
, 'l2miss')
1212 self
.assertRegex(output
, 'l3miss')
1213 self
.assertRegex(output
, 'udpcsum')
1214 self
.assertRegex(output
, 'udp6zerocsumtx')
1215 self
.assertRegex(output
, 'udp6zerocsumrx')
1216 self
.assertRegex(output
, 'remcsumtx')
1217 self
.assertRegex(output
, 'remcsumrx')
1218 self
.assertRegex(output
, 'gbp')
1220 output
= check_output('bridge fdb show dev vxlan99')
1222 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1223 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1224 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1226 def test_macsec(self
):
1227 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1228 'macsec.network', '12-dummy.netdev')
1231 wait_online(['dummy98:degraded', 'macsec99:routable'])
1233 output
= check_output('ip -d link show macsec99')
1235 self
.assertRegex(output
, 'macsec99@dummy98')
1236 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1237 self
.assertRegex(output
, 'encrypt on')
1239 output
= check_output('ip macsec show macsec99')
1241 self
.assertRegex(output
, 'encrypt on')
1242 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1243 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1244 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1245 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1246 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1247 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1248 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1249 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1250 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1251 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1252 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1254 def test_nlmon(self
):
1255 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1258 wait_online(['nlmon99:carrier'])
1260 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1271 '25-l2tp-dummy.network',
1272 '25-l2tp-ip.netdev',
1273 '25-l2tp-udp.netdev']
1275 l2tp_tunnel_ids
= [ '10' ]
1278 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1279 remove_links(self
.links
)
1280 stop_networkd(show_logs
=False)
1283 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1284 remove_links(self
.links
)
1285 remove_unit_from_networkd_path(self
.units
)
1286 stop_networkd(show_logs
=True)
1288 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1289 def test_l2tp_udp(self
):
1290 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1293 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1295 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1297 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1298 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1299 self
.assertRegex(output
, "Peer tunnel 11")
1300 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1301 self
.assertRegex(output
, "UDP checksum: enabled")
1303 output
= check_output('ip l2tp show session tid 10 session_id 15')
1305 self
.assertRegex(output
, "Session 15 in tunnel 10")
1306 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1307 self
.assertRegex(output
, "interface name: l2tp-ses1")
1309 output
= check_output('ip l2tp show session tid 10 session_id 17')
1311 self
.assertRegex(output
, "Session 17 in tunnel 10")
1312 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1313 self
.assertRegex(output
, "interface name: l2tp-ses2")
1315 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1316 def test_l2tp_ip(self
):
1317 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1320 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1322 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1324 self
.assertRegex(output
, "Tunnel 10, encap IP")
1325 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1326 self
.assertRegex(output
, "Peer tunnel 12")
1328 output
= check_output('ip l2tp show session tid 10 session_id 25')
1330 self
.assertRegex(output
, "Session 25 in tunnel 10")
1331 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1332 self
.assertRegex(output
, "interface name: l2tp-ses3")
1334 output
= check_output('ip l2tp show session tid 10 session_id 27')
1336 self
.assertRegex(output
, "Session 27 in tunnel 10")
1337 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1338 self
.assertRegex(output
, "interface name: l2tp-ses4")
1340 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1350 '23-active-slave.network',
1351 '24-keep-configuration-static.network',
1352 '24-search-domain.network',
1353 '25-address-link-section.network',
1354 '25-address-preferred-lifetime-zero-ipv6.network',
1355 '25-address-static.network',
1356 '25-bind-carrier.network',
1357 '25-bond-active-backup-slave.netdev',
1358 '25-fibrule-invert.network',
1359 '25-fibrule-port-range.network',
1360 '25-ipv6-address-label-section.network',
1361 '25-neighbor-section.network',
1362 '25-link-local-addressing-no.network',
1363 '25-link-local-addressing-yes.network',
1364 '25-link-section-unmanaged.network',
1365 '25-route-ipv6-src.network',
1366 '25-route-static.network',
1367 '25-sysctl-disable-ipv6.network',
1368 '25-sysctl.network',
1369 'configure-without-carrier.network',
1370 'routing-policy-rule-dummy98.network',
1371 'routing-policy-rule-test1.network']
1373 routing_policy_rule_tables
= ['7', '8']
1374 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1377 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1378 remove_routes(self
.routes
)
1379 remove_links(self
.links
)
1380 stop_networkd(show_logs
=False)
1383 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1384 remove_routes(self
.routes
)
1385 remove_links(self
.links
)
1386 remove_unit_from_networkd_path(self
.units
)
1387 stop_networkd(show_logs
=True)
1389 def test_address_static(self
):
1390 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1393 wait_online(['dummy98:routable'])
1395 output
= check_output('ip -4 address show dev dummy98')
1397 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1398 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1399 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1402 self
.assertNotRegex(output
, '10.10.0.1/16')
1403 self
.assertNotRegex(output
, '10.10.0.2/16')
1405 output
= check_output('ip -4 address show dev dummy98 label 32')
1406 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1408 output
= check_output('ip -4 address show dev dummy98 label 33')
1409 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1411 output
= check_output('ip -4 address show dev dummy98 label 34')
1412 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1414 output
= check_output('ip -4 address show dev dummy98 label 35')
1415 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1417 output
= check_output('ip -6 address show dev dummy98')
1419 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1420 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1421 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1422 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1423 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1424 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1426 def test_address_preferred_lifetime_zero_ipv6(self
):
1427 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1430 self
.check_link_exists('dummy98')
1431 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1433 output
= check_output('ip address show dummy98')
1435 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1436 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1438 def test_configure_without_carrier(self
):
1439 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1441 wait_online(['test1:routable'])
1443 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1445 self
.assertRegex(output
, '192.168.0.15')
1446 self
.assertRegex(output
, '192.168.0.1')
1447 self
.assertRegex(output
, 'routable')
1449 def test_routing_policy_rule(self
):
1450 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1452 wait_online(['test1:degraded'])
1454 output
= check_output('ip rule')
1456 self
.assertRegex(output
, '111')
1457 self
.assertRegex(output
, 'from 192.168.100.18')
1458 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1459 self
.assertRegex(output
, 'iif test1')
1460 self
.assertRegex(output
, 'oif test1')
1461 self
.assertRegex(output
, 'lookup 7')
1463 def test_routing_policy_rule_issue_11280(self
):
1464 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1465 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1467 for trial
in range(3):
1468 # Remove state files only first time
1470 wait_online(['test1:degraded', 'dummy98:degraded'])
1473 output
= check_output('ip rule list table 7')
1475 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1477 output
= check_output('ip rule list table 8')
1479 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1481 stop_networkd(remove_state_files
=False)
1483 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1484 def test_routing_policy_rule_port_range(self
):
1485 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1487 wait_online(['test1:degraded'])
1489 output
= check_output('ip rule')
1491 self
.assertRegex(output
, '111')
1492 self
.assertRegex(output
, 'from 192.168.100.18')
1493 self
.assertRegex(output
, '1123-1150')
1494 self
.assertRegex(output
, '3224-3290')
1495 self
.assertRegex(output
, 'tcp')
1496 self
.assertRegex(output
, 'lookup 7')
1498 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1499 def test_routing_policy_rule_invert(self
):
1500 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1502 wait_online(['test1:degraded'])
1504 output
= check_output('ip rule')
1506 self
.assertRegex(output
, '111')
1507 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1508 self
.assertRegex(output
, 'tcp')
1509 self
.assertRegex(output
, 'lookup 7')
1511 def test_route_static(self
):
1512 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1514 wait_online(['dummy98:routable'])
1516 output
= check_output('ip -6 route show dev dummy98')
1518 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1519 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1521 output
= check_output('ip -6 route show dev dummy98 default')
1522 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1524 output
= check_output('ip -4 route show dev dummy98')
1526 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1527 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1528 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1529 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1530 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1532 output
= check_output('ip -4 route show dev dummy98 default')
1533 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1534 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1535 self
.assertRegex(output
, 'default proto static')
1537 output
= check_output('ip route show type blackhole')
1539 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1541 output
= check_output('ip route show type unreachable')
1543 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1545 output
= check_output('ip route show type prohibit')
1547 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1549 def test_ip_route_ipv6_src_route(self
):
1550 # a dummy device does not make the addresses go through tentative state, so we
1551 # reuse a bond from an earlier test, which does make the addresses go through
1552 # tentative state, and do our test on that
1553 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1555 wait_online(['dummy98:enslaved', 'bond199:routable'])
1557 output
= check_output('ip -6 route list dev bond199')
1559 self
.assertRegex(output
, 'abcd::/16')
1560 self
.assertRegex(output
, 'src')
1561 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1563 def test_ip_link_mac_address(self
):
1564 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1566 wait_online(['dummy98:degraded'])
1568 output
= check_output('ip link show dummy98')
1570 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1572 def test_ip_link_unmanaged(self
):
1573 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1576 self
.check_link_exists('dummy98')
1578 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1580 def test_ipv6_address_label(self
):
1581 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1583 wait_online(['dummy98:degraded'])
1585 output
= check_output('ip addrlabel list')
1587 self
.assertRegex(output
, '2004:da8:1::/64')
1589 def test_ipv6_neighbor(self
):
1590 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1592 wait_online(['dummy98:degraded'], timeout
='40s')
1594 output
= check_output('ip neigh list dev dummy98')
1596 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1597 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1599 def test_link_local_addressing(self
):
1600 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1601 '25-link-local-addressing-no.network', '12-dummy.netdev')
1603 wait_online(['test1:degraded', 'dummy98:carrier'])
1605 output
= check_output('ip address show dev test1')
1607 self
.assertRegex(output
, 'inet .* scope link')
1608 self
.assertRegex(output
, 'inet6 .* scope link')
1610 output
= check_output('ip address show dev dummy98')
1612 self
.assertNotRegex(output
, 'inet6* .* scope link')
1615 Documentation/networking/ip-sysctl.txt
1617 addr_gen_mode - INTEGER
1618 Defines how link-local and autoconf addresses are generated.
1620 0: generate address based on EUI64 (default)
1621 1: do no generate a link-local address, use EUI64 for addresses generated
1623 2: generate stable privacy addresses, using the secret from
1624 stable_secret (RFC7217)
1625 3: generate stable privacy addresses, using a random secret if unset
1628 test1_addr_gen_mode
= ''
1629 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1630 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1634 # if stable_secret is unset, then EIO is returned
1635 test1_addr_gen_mode
= '0'
1637 test1_addr_gen_mode
= '2'
1639 test1_addr_gen_mode
= '0'
1641 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1642 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1644 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1645 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1647 def test_sysctl(self
):
1648 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1650 wait_online(['dummy98:degraded'])
1652 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1653 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1654 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1655 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1656 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1657 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1658 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1660 def test_sysctl_disable_ipv6(self
):
1661 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1663 print('## Disable ipv6')
1664 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1665 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1668 wait_online(['dummy98:routable'])
1670 output
= check_output('ip -4 address show dummy98')
1672 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1673 output
= check_output('ip -6 address show dummy98')
1675 self
.assertEqual(output
, '')
1676 output
= check_output('ip -4 route show dev dummy98')
1678 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1679 output
= check_output('ip -6 route show dev dummy98')
1681 self
.assertEqual(output
, '')
1683 check_output('ip link del dummy98')
1685 print('## Enable ipv6')
1686 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1687 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1690 wait_online(['dummy98:routable'])
1692 output
= check_output('ip -4 address show dummy98')
1694 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1695 output
= check_output('ip -6 address show dummy98')
1697 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1698 self
.assertRegex(output
, 'inet6 .* scope link')
1699 output
= check_output('ip -4 route show dev dummy98')
1701 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1702 output
= check_output('ip -6 route show dev dummy98')
1704 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1706 def test_bind_carrier(self
):
1707 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1709 wait_online(['test1:routable'])
1711 check_output('ip link add dummy98 type dummy')
1712 check_output('ip link set dummy98 up')
1714 output
= check_output('ip address show test1')
1716 self
.assertRegex(output
, 'UP,LOWER_UP')
1717 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1718 self
.check_operstate('test1', 'routable')
1720 check_output('ip link add dummy99 type dummy')
1721 check_output('ip link set dummy99 up')
1723 output
= check_output('ip address show test1')
1725 self
.assertRegex(output
, 'UP,LOWER_UP')
1726 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1727 self
.check_operstate('test1', 'routable')
1729 check_output('ip link del dummy98')
1731 output
= check_output('ip address show test1')
1733 self
.assertRegex(output
, 'UP,LOWER_UP')
1734 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1735 self
.check_operstate('test1', 'routable')
1737 check_output('ip link del dummy99')
1739 output
= check_output('ip address show test1')
1741 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1742 self
.assertRegex(output
, 'DOWN')
1743 self
.assertNotRegex(output
, '192.168.10')
1744 self
.check_operstate('test1', 'off')
1746 check_output('ip link add dummy98 type dummy')
1747 check_output('ip link set dummy98 up')
1749 output
= check_output('ip address show test1')
1751 self
.assertRegex(output
, 'UP,LOWER_UP')
1752 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1753 self
.check_operstate('test1', 'routable')
1755 def test_domain(self
):
1756 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1758 wait_online(['dummy98:routable'])
1760 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1762 self
.assertRegex(output
, 'Address: 192.168.42.100')
1763 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1764 self
.assertRegex(output
, 'Search Domains: one')
1766 def test_keep_configuration_static(self
):
1767 check_output('systemctl stop systemd-networkd')
1769 check_output('ip link add name dummy98 type dummy')
1770 check_output('ip address add 10.1.2.3/16 dev dummy98')
1771 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1772 output
= check_output('ip address show dummy98')
1774 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1775 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1776 output
= check_output('ip route show dev dummy98')
1779 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1781 wait_online(['dummy98:routable'])
1783 output
= check_output('ip address show dummy98')
1785 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1786 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1788 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1798 '23-active-slave.network',
1799 '23-bond199.network',
1800 '23-primary-slave.network',
1801 '25-bond-active-backup-slave.netdev',
1804 'bond-slave.network']
1807 remove_links(self
.links
)
1808 stop_networkd(show_logs
=False)
1811 remove_links(self
.links
)
1812 remove_unit_from_networkd_path(self
.units
)
1813 stop_networkd(show_logs
=True)
1815 def test_bond_active_slave(self
):
1816 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1818 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1820 output
= check_output('ip -d link show bond199')
1822 self
.assertRegex(output
, 'active_slave dummy98')
1824 def test_bond_primary_slave(self
):
1825 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1827 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1829 output
= check_output('ip -d link show bond199')
1831 self
.assertRegex(output
, 'primary dummy98')
1833 def test_bond_operstate(self
):
1834 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1835 'bond99.network','bond-slave.network')
1837 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1839 output
= check_output('ip -d link show dummy98')
1841 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1843 output
= check_output('ip -d link show test1')
1845 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1847 output
= check_output('ip -d link show bond99')
1849 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1851 self
.check_operstate('dummy98', 'enslaved')
1852 self
.check_operstate('test1', 'enslaved')
1853 self
.check_operstate('bond99', 'routable')
1855 check_output('ip link set dummy98 down')
1858 self
.check_operstate('dummy98', 'off')
1859 self
.check_operstate('test1', 'enslaved')
1860 self
.check_operstate('bond99', 'degraded-carrier')
1862 check_output('ip link set dummy98 up')
1865 self
.check_operstate('dummy98', 'enslaved')
1866 self
.check_operstate('test1', 'enslaved')
1867 self
.check_operstate('bond99', 'routable')
1869 check_output('ip link set dummy98 down')
1870 check_output('ip link set test1 down')
1873 self
.check_operstate('dummy98', 'off')
1874 self
.check_operstate('test1', 'off')
1876 for trial
in range(30):
1879 output
= check_output('ip address show bond99')
1881 if get_operstate('bond99') == 'no-carrier':
1884 # Huh? Kernel does not recognize that all slave interfaces are down?
1885 # Let's confirm that networkd's operstate is consistent with ip's result.
1886 self
.assertNotRegex(output
, 'NO-CARRIER')
1888 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1898 '26-bridge-slave-interface-1.network',
1899 '26-bridge-slave-interface-2.network',
1900 '26-bridge-vlan-master.network',
1901 '26-bridge-vlan-slave.network',
1902 'bridge99-ignore-carrier-loss.network',
1905 routing_policy_rule_tables
= ['100']
1908 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1909 remove_links(self
.links
)
1910 stop_networkd(show_logs
=False)
1913 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1914 remove_links(self
.links
)
1915 remove_unit_from_networkd_path(self
.units
)
1916 stop_networkd(show_logs
=True)
1918 def test_bridge_vlan(self
):
1919 copy_unit_to_networkd_unit_path('11-dummy.netdev', '26-bridge-vlan-slave.network',
1920 '26-bridge.netdev', '26-bridge-vlan-master.network')
1922 wait_online(['test1:enslaved', 'bridge99:degraded'])
1924 output
= check_output('bridge vlan show dev test1')
1926 self
.assertNotRegex(output
, '4063')
1927 for i
in range(4064, 4095):
1928 self
.assertRegex(output
, f
'{i}')
1929 self
.assertNotRegex(output
, '4095')
1931 output
= check_output('bridge vlan show dev bridge99')
1933 self
.assertNotRegex(output
, '4059')
1934 for i
in range(4060, 4095):
1935 self
.assertRegex(output
, f
'{i}')
1936 self
.assertNotRegex(output
, '4095')
1938 def test_bridge_property(self
):
1939 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1940 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1943 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1945 output
= check_output('ip -d link show test1')
1947 self
.assertRegex(output
, 'master')
1948 self
.assertRegex(output
, 'bridge')
1950 output
= check_output('ip -d link show dummy98')
1952 self
.assertRegex(output
, 'master')
1953 self
.assertRegex(output
, 'bridge')
1955 output
= check_output('ip addr show bridge99')
1957 self
.assertRegex(output
, '192.168.0.15/24')
1959 output
= check_output('bridge -d link show dummy98')
1961 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1962 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1963 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1964 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1965 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1966 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1967 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1968 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1970 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1971 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1972 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1974 check_output('ip address add 192.168.0.16/24 dev bridge99')
1977 output
= check_output('ip addr show bridge99')
1979 self
.assertRegex(output
, '192.168.0.16/24')
1981 self
.assertEqual(call('ip link del test1'), 0)
1984 self
.check_operstate('bridge99', 'degraded-carrier')
1986 check_output('ip link del dummy98')
1989 self
.check_operstate('bridge99', 'no-carrier')
1991 output
= check_output('ip address show bridge99')
1993 self
.assertRegex(output
, 'NO-CARRIER')
1994 self
.assertNotRegex(output
, '192.168.0.15/24')
1995 self
.assertNotRegex(output
, '192.168.0.16/24')
1997 def test_bridge_ignore_carrier_loss(self
):
1998 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1999 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
2000 'bridge99-ignore-carrier-loss.network')
2002 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
2004 check_output('ip address add 192.168.0.16/24 dev bridge99')
2007 check_output('ip link del test1')
2008 check_output('ip link del dummy98')
2011 output
= check_output('ip address show bridge99')
2013 self
.assertRegex(output
, 'NO-CARRIER')
2014 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2015 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
2017 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
2018 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
2019 'bridge99-ignore-carrier-loss.network')
2021 wait_online(['bridge99:no-carrier'])
2023 for trial
in range(4):
2024 check_output('ip link add dummy98 type dummy')
2025 check_output('ip link set dummy98 up')
2027 check_output('ip link del dummy98')
2029 wait_online(['bridge99:routable', 'dummy98:enslaved'])
2031 output
= check_output('ip address show bridge99')
2033 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
2035 output
= check_output('ip rule list table 100')
2037 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
2039 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
2043 '23-emit-lldp.network',
2048 remove_links(self
.links
)
2049 stop_networkd(show_logs
=False)
2052 remove_links(self
.links
)
2053 remove_unit_from_networkd_path(self
.units
)
2054 stop_networkd(show_logs
=True)
2056 def test_lldp(self
):
2057 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
2059 wait_online(['veth99:degraded', 'veth-peer:degraded'])
2061 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
2063 self
.assertRegex(output
, 'veth-peer')
2064 self
.assertRegex(output
, 'veth99')
2066 class NetworkdRATests(unittest
.TestCase
, Utilities
):
2071 'ipv6-prefix.network',
2072 'ipv6-prefix-veth.network']
2075 remove_links(self
.links
)
2076 stop_networkd(show_logs
=False)
2079 remove_links(self
.links
)
2080 remove_unit_from_networkd_path(self
.units
)
2081 stop_networkd(show_logs
=True)
2083 def test_ipv6_prefix_delegation(self
):
2084 warn_about_firewalld()
2085 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2087 wait_online(['veth99:routable', 'veth-peer:degraded'])
2089 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2091 self
.assertRegex(output
, '2002:da8:1:0')
2093 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2098 'dhcp-client.network',
2099 'dhcp-client-timezone-router.network',
2100 'dhcp-server.network',
2101 'dhcp-server-timezone-router.network']
2104 remove_links(self
.links
)
2105 stop_networkd(show_logs
=False)
2108 remove_links(self
.links
)
2109 remove_unit_from_networkd_path(self
.units
)
2110 stop_networkd(show_logs
=True)
2112 def test_dhcp_server(self
):
2113 warn_about_firewalld()
2114 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2116 wait_online(['veth99:routable', 'veth-peer:routable'])
2118 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2120 self
.assertRegex(output
, '192.168.5.*')
2121 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2122 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2123 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2125 def test_emit_router_timezone(self
):
2126 warn_about_firewalld()
2127 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2129 wait_online(['veth99:routable', 'veth-peer:routable'])
2131 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2133 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2134 self
.assertRegex(output
, '192.168.5.*')
2135 self
.assertRegex(output
, 'Europe/Berlin')
2137 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2146 'dhcp-client-anonymize.network',
2147 'dhcp-client-gateway-onlink-implicit.network',
2148 'dhcp-client-ipv4-dhcp-settings.network',
2149 'dhcp-client-ipv4-only-ipv6-disabled.network',
2150 'dhcp-client-ipv4-only.network',
2151 'dhcp-client-ipv6-only.network',
2152 'dhcp-client-ipv6-rapid-commit.network',
2153 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2154 'dhcp-client-keep-configuration-dhcp.network',
2155 'dhcp-client-listen-port.network',
2156 'dhcp-client-route-metric.network',
2157 'dhcp-client-route-table.network',
2158 'dhcp-client-use-routes-no.network',
2159 'dhcp-client-vrf.network',
2160 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2161 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2162 'dhcp-client-with-static-address.network',
2163 'dhcp-client.network',
2164 'dhcp-server-veth-peer.network',
2165 'dhcp-v4-server-veth-peer.network',
2169 stop_dnsmasq(dnsmasq_pid_file
)
2170 remove_links(self
.links
)
2171 stop_networkd(show_logs
=False)
2174 stop_dnsmasq(dnsmasq_pid_file
)
2177 remove_links(self
.links
)
2178 remove_unit_from_networkd_path(self
.units
)
2179 stop_networkd(show_logs
=True)
2181 def test_dhcp_client_ipv6_only(self
):
2182 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2185 wait_online(['veth-peer:carrier'])
2187 wait_online(['veth99:routable', 'veth-peer:routable'])
2189 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2191 self
.assertRegex(output
, '2600::')
2192 self
.assertNotRegex(output
, '192.168.5')
2194 # Confirm that ipv6 token is not set in the kernel
2195 output
= check_output('ip token show dev veth99')
2197 self
.assertRegex(output
, 'token :: dev veth99')
2199 def test_dhcp_client_ipv4_only(self
):
2200 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2203 wait_online(['veth-peer:carrier'])
2205 wait_online(['veth99:routable', 'veth-peer:routable'])
2207 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2209 self
.assertNotRegex(output
, '2600::')
2210 self
.assertRegex(output
, '192.168.5')
2212 def test_dhcp_client_ipv4_ipv6(self
):
2213 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2214 'dhcp-client-ipv4-only.network')
2216 wait_online(['veth-peer:carrier'])
2218 wait_online(['veth99:routable', 'veth-peer:routable'])
2220 # link become 'routable' when at least one protocol provide an valid address.
2221 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2222 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2224 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2226 self
.assertRegex(output
, '2600::')
2227 self
.assertRegex(output
, '192.168.5')
2229 def test_dhcp_client_settings(self
):
2230 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2233 wait_online(['veth-peer:carrier'])
2235 wait_online(['veth99:routable', 'veth-peer:routable'])
2237 print('## ip address show dev veth99')
2238 output
= check_output('ip address show dev veth99')
2240 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2241 self
.assertRegex(output
, '192.168.5')
2242 self
.assertRegex(output
, '1492')
2245 print('## ip route show table main dev veth99')
2246 output
= check_output('ip route show table main dev veth99')
2248 self
.assertNotRegex(output
, 'proto dhcp')
2250 print('## ip route show table 211 dev veth99')
2251 output
= check_output('ip route show table 211 dev veth99')
2253 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2254 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2255 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2257 print('## dnsmasq log')
2258 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2259 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2260 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2261 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2263 def test_dhcp6_client_settings_rapidcommit_true(self
):
2264 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2266 wait_online(['veth-peer:carrier'])
2268 wait_online(['veth99:routable', 'veth-peer:routable'])
2270 output
= check_output('ip address show dev veth99')
2272 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2273 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2275 def test_dhcp6_client_settings_rapidcommit_false(self
):
2276 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2278 wait_online(['veth-peer:carrier'])
2280 wait_online(['veth99:routable', 'veth-peer:routable'])
2282 output
= check_output('ip address show dev veth99')
2284 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2285 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2287 def test_dhcp_client_settings_anonymize(self
):
2288 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2290 wait_online(['veth-peer:carrier'])
2292 wait_online(['veth99:routable', 'veth-peer:routable'])
2294 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2295 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2296 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2298 def test_dhcp_client_listen_port(self
):
2299 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2301 wait_online(['veth-peer:carrier'])
2302 start_dnsmasq('--dhcp-alternate-port=67,5555')
2303 wait_online(['veth99:routable', 'veth-peer:routable'])
2305 # link become 'routable' when at least one protocol provide an valid address.
2306 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2307 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2309 output
= check_output('ip -4 address show dev veth99')
2311 self
.assertRegex(output
, '192.168.5.* dynamic')
2313 def test_dhcp_client_with_static_address(self
):
2314 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network',
2315 'dhcp-client-with-static-address.network')
2317 wait_online(['veth-peer:carrier'])
2319 wait_online(['veth99:routable', 'veth-peer:routable'])
2321 output
= check_output('ip address show dev veth99 scope global')
2323 self
.assertRegex(output
, r
'inet 192.168.5.250/24 brd 192.168.5.255 scope global veth99')
2324 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global secondary dynamic veth99')
2326 output
= check_output('ip route show dev veth99')
2328 self
.assertRegex(output
, r
'default via 192.168.5.1 proto dhcp src 192.168.5.[0-9]* metric 1024')
2329 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.250')
2330 self
.assertRegex(output
, r
'192.168.5.0/24 via 192.168.5.5 proto dhcp src 192.168.5.[0-9]* metric 1024')
2331 self
.assertRegex(output
, r
'192.168.5.1 proto dhcp scope link src 192.168.5.[0-9]* metric 1024')
2333 def test_dhcp_route_table_id(self
):
2334 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2336 wait_online(['veth-peer:carrier'])
2338 wait_online(['veth99:routable', 'veth-peer:routable'])
2340 output
= check_output('ip route show table 12')
2342 self
.assertRegex(output
, 'veth99 proto dhcp')
2343 self
.assertRegex(output
, '192.168.5.1')
2345 def test_dhcp_route_metric(self
):
2346 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2348 wait_online(['veth-peer:carrier'])
2350 wait_online(['veth99:routable', 'veth-peer:routable'])
2352 output
= check_output('ip route show dev veth99')
2354 self
.assertRegex(output
, 'metric 24')
2356 def test_dhcp_client_use_routes_no(self
):
2357 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2358 'dhcp-client-use-routes-no.network')
2360 wait_online(['veth-peer:carrier'])
2361 start_dnsmasq(lease_time
='2m')
2362 wait_online(['veth99:routable', 'veth-peer:routable'])
2364 output
= check_output('ip address show dev veth99 scope global')
2366 self
.assertRegex(output
, r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2368 output
= check_output('ip route show dev veth99')
2370 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2371 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2372 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2373 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2375 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2376 print('Wait for the dynamic address to be renewed')
2379 wait_online(['veth99:routable'])
2381 output
= check_output('ip route show dev veth99')
2383 self
.assertRegex(output
, r
'192.168.5.0/24 proto kernel scope link src 192.168.5.[0-9]*')
2384 self
.assertRegex(output
, r
'192.168.5.0/24 proto static')
2385 self
.assertRegex(output
, r
'192.168.6.0/24 proto static')
2386 self
.assertRegex(output
, r
'192.168.7.0/24 proto static')
2388 def test_dhcp_keep_configuration_dhcp(self
):
2389 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2391 wait_online(['veth-peer:carrier'])
2392 start_dnsmasq(lease_time
='2m')
2393 wait_online(['veth99:routable', 'veth-peer:routable'])
2395 output
= check_output('ip address show dev veth99 scope global')
2397 self
.assertRegex(output
, r
'192.168.5.*')
2399 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2401 self
.assertRegex(output
, r
'192.168.5.*')
2403 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2404 stop_dnsmasq(dnsmasq_pid_file
)
2406 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2407 print('Wait for the dynamic address to be expired')
2410 print('The lease address should be kept after lease expired')
2411 output
= check_output('ip address show dev veth99 scope global')
2413 self
.assertRegex(output
, r
'192.168.5.*')
2415 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2417 self
.assertRegex(output
, r
'192.168.5.*')
2419 check_output('systemctl stop systemd-networkd')
2421 print('The lease address should be kept after networkd stopped')
2422 output
= check_output('ip address show dev veth99 scope global')
2424 self
.assertRegex(output
, r
'192.168.5.*')
2426 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2428 self
.assertRegex(output
, r
'192.168.5.*')
2430 check_output('systemctl start systemd-networkd')
2431 wait_online(['veth-peer:routable'])
2433 print('Still the lease address should be kept after networkd restarted')
2434 output
= check_output('ip address show dev veth99 scope global')
2436 self
.assertRegex(output
, r
'192.168.5.*')
2438 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2440 self
.assertRegex(output
, r
'192.168.5.*')
2442 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2443 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2445 wait_online(['veth-peer:carrier'])
2446 start_dnsmasq(lease_time
='2m')
2447 wait_online(['veth99:routable', 'veth-peer:routable'])
2449 output
= check_output('ip address show dev veth99 scope global')
2451 self
.assertRegex(output
, r
'192.168.5.*')
2453 stop_dnsmasq(dnsmasq_pid_file
)
2454 check_output('systemctl stop systemd-networkd')
2456 output
= check_output('ip address show dev veth99 scope global')
2458 self
.assertRegex(output
, r
'192.168.5.*')
2461 wait_online(['veth-peer:routable'])
2463 output
= check_output('ip address show dev veth99 scope global')
2465 self
.assertNotRegex(output
, r
'192.168.5.*')
2467 def test_dhcp_client_reuse_address_as_static(self
):
2468 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2470 wait_online(['veth-peer:carrier'])
2472 wait_online(['veth99:routable', 'veth-peer:routable'])
2474 # link become 'routable' when at least one protocol provide an valid address.
2475 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2476 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2478 output
= check_output('ip address show dev veth99 scope global')
2480 self
.assertRegex(output
, '192.168.5')
2481 self
.assertRegex(output
, '2600::')
2483 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2484 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2485 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2486 print(static_network
)
2488 remove_unit_from_networkd_path(['dhcp-client.network'])
2490 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2491 f
.write(static_network
)
2493 # When networkd started, the links are already configured, so let's wait for 5 seconds
2494 # the links to be re-configured.
2496 wait_online(['veth99:routable', 'veth-peer:routable'])
2498 output
= check_output('ip -4 address show dev veth99 scope global')
2500 self
.assertRegex(output
, '192.168.5')
2501 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2503 output
= check_output('ip -6 address show dev veth99 scope global')
2505 self
.assertRegex(output
, '2600::')
2506 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2508 @expectedFailureIfModuleIsNotAvailable('vrf')
2509 def test_dhcp_client_vrf(self
):
2510 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2511 '25-vrf.netdev', '25-vrf.network')
2513 wait_online(['veth-peer:carrier'])
2515 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2517 # link become 'routable' when at least one protocol provide an valid address.
2518 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2519 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2521 print('## ip -d link show dev vrf99')
2522 output
= check_output('ip -d link show dev vrf99')
2524 self
.assertRegex(output
, 'vrf table 42')
2526 print('## ip address show vrf vrf99')
2527 output
= check_output('ip address show vrf vrf99')
2529 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2530 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2531 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2532 self
.assertRegex(output
, 'inet6 .* scope link')
2534 print('## ip address show dev veth99')
2535 output
= check_output('ip address show dev veth99')
2537 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2538 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2539 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2540 self
.assertRegex(output
, 'inet6 .* scope link')
2542 print('## ip route show vrf vrf99')
2543 output
= check_output('ip route show vrf vrf99')
2545 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2546 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2547 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2548 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2549 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2550 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2552 print('## ip route show table main dev veth99')
2553 output
= check_output('ip route show table main dev veth99')
2555 self
.assertEqual(output
, '')
2557 def test_dhcp_client_gateway_onlink_implicit(self
):
2558 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2559 'dhcp-client-gateway-onlink-implicit.network')
2561 wait_online(['veth-peer:carrier'])
2563 wait_online(['veth99:routable', 'veth-peer:routable'])
2565 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2567 self
.assertRegex(output
, '192.168.5')
2569 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2571 self
.assertRegex(output
, 'onlink')
2572 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2574 self
.assertRegex(output
, 'onlink')
2576 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2577 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2578 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2580 wait_online(['veth-peer:carrier'])
2581 start_dnsmasq(lease_time
='2m')
2582 wait_online(['veth99:routable', 'veth-peer:routable'])
2584 output
= check_output('ip address show dev veth99')
2587 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2588 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2589 output
= check_output('ip -6 address show dev veth99 scope link')
2590 self
.assertRegex(output
, 'inet6 .* scope link')
2591 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2592 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2593 output
= check_output('ip -4 address show dev veth99 scope link')
2594 self
.assertNotRegex(output
, 'inet .* scope link')
2596 print('Wait for the dynamic address to be expired')
2599 output
= check_output('ip address show dev veth99')
2602 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2603 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2604 output
= check_output('ip -6 address show dev veth99 scope link')
2605 self
.assertRegex(output
, 'inet6 .* scope link')
2606 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2607 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2608 output
= check_output('ip -4 address show dev veth99 scope link')
2609 self
.assertNotRegex(output
, 'inet .* scope link')
2611 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2613 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2614 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2615 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2617 wait_online(['veth99:degraded', 'veth-peer:routable'])
2619 output
= check_output('ip address show dev veth99')
2622 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2623 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2624 output
= check_output('ip -6 address show dev veth99 scope link')
2625 self
.assertRegex(output
, 'inet6 .* scope link')
2626 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2627 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2628 output
= check_output('ip -4 address show dev veth99 scope link')
2629 self
.assertRegex(output
, 'inet .* scope link')
2631 def test_dhcp_client_route_remove_on_renew(self
):
2632 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2633 'dhcp-client-ipv4-only-ipv6-disabled.network')
2635 wait_online(['veth-peer:carrier'])
2636 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2637 wait_online(['veth99:routable', 'veth-peer:routable'])
2639 # test for issue #12490
2641 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2643 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2645 for line
in output
.splitlines():
2646 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2647 address1
= line
.split()[1].split('/')[0]
2650 output
= check_output('ip -4 route show dev veth99')
2652 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2653 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2655 stop_dnsmasq(dnsmasq_pid_file
)
2656 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2658 print('Wait for the dynamic address to be expired')
2661 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2663 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2665 for line
in output
.splitlines():
2666 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2667 address2
= line
.split()[1].split('/')[0]
2670 self
.assertNotEqual(address1
, address2
)
2672 output
= check_output('ip -4 route show dev veth99')
2674 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2675 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2676 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2677 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2679 if __name__
== '__main__':
2680 parser
= argparse
.ArgumentParser()
2681 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2682 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2683 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2684 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2685 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2686 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2687 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2688 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2689 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2690 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2693 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2694 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2695 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2696 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2697 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2700 networkd_bin
= ns
.networkd_bin
2701 if ns
.wait_online_bin
:
2702 wait_online_bin
= ns
.wait_online_bin
2703 if ns
.networkctl_bin
:
2704 networkctl_bin
= ns
.networkctl_bin
2706 use_valgrind
= ns
.use_valgrind
2707 enable_debug
= ns
.enable_debug
2708 asan_options
= ns
.asan_options
2709 lsan_options
= ns
.lsan_options
2710 ubsan_options
= ns
.ubsan_options
2713 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2714 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2716 networkctl_cmd
= [networkctl_bin
]
2717 wait_online_cmd
= [wait_online_bin
]
2720 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2722 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2724 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2726 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2729 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,