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 start_networkd(sleep_sec
=0, remove_state_files
=True):
286 if (remove_state_files
and
287 os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state'))):
288 check_output('systemctl stop systemd-networkd')
289 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
290 check_output('systemctl start systemd-networkd')
292 check_output('systemctl restart systemd-networkd')
294 time
.sleep(sleep_sec
)
296 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
297 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
301 check_output(*args
, env
=env
)
302 except subprocess
.CalledProcessError
:
303 for link
in links_with_operstate
:
304 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
308 def get_operstate(link
, show_status
=True, setup_state
='configured'):
309 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
312 for line
in output
.splitlines():
313 if 'State:' in line
and (not setup_state
or setup_state
in line
):
314 return line
.split()[1]
318 def check_link_exists(self
, link
):
319 self
.assertTrue(link_exists(link
))
321 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
322 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
324 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
325 for i
in range(timeout_sec
):
328 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
329 if re
.search(address_regex
, output
):
332 self
.assertRegex(output
, address_regex
)
334 class NetworkctlTests(unittest
.TestCase
, Utilities
):
343 '11-dummy-mtu.netdev',
346 'netdev-link-local-addressing-yes.network',
350 remove_links(self
.links
)
353 remove_links(self
.links
)
354 remove_unit_from_networkd_path(self
.units
)
357 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
360 wait_online(['test1:degraded'])
362 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
363 self
.assertRegex(output
, '1 lo ')
364 self
.assertRegex(output
, 'test1')
366 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
367 self
.assertNotRegex(output
, '1 lo ')
368 self
.assertRegex(output
, 'test1')
370 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
371 self
.assertNotRegex(output
, '1 lo ')
372 self
.assertRegex(output
, 'test1')
374 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
375 self
.assertNotRegex(output
, '1: lo ')
376 self
.assertRegex(output
, 'test1')
378 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
379 self
.assertNotRegex(output
, '1: lo ')
380 self
.assertRegex(output
, 'test1')
383 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
386 wait_online(['test1:degraded'])
388 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
389 self
.assertRegex(output
, 'MTU: 1600')
392 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
394 wait_online(['test1:degraded'])
396 output
= check_output(*networkctl_cmd
, 'status', 'test1')
398 self
.assertRegex(output
, 'Type: ether')
400 output
= check_output(*networkctl_cmd
, 'status', 'lo')
402 self
.assertRegex(output
, 'Type: loopback')
404 @expectedFailureIfLinkFileFieldIsNotSet()
405 def test_udev_link_file(self
):
406 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
408 wait_online(['test1:degraded'])
410 output
= check_output(*networkctl_cmd
, 'status', 'test1')
412 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
413 self
.assertRegex(output
, r
'Network File: /run/systemd/network/11-dummy.network')
415 output
= check_output(*networkctl_cmd
, 'status', 'lo')
417 self
.assertRegex(output
, r
'Link File: (?:/usr)/lib/systemd/network/99-default.link')
418 self
.assertRegex(output
, r
'Network File: n/a')
420 @expectedFailureIfEthtoolDoesNotSupportDriver()
421 def test_udev_driver(self
):
422 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
423 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
426 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
428 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
429 self
.assertRegex(output
, 'Driver: dummy')
431 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
432 self
.assertRegex(output
, 'Driver: veth')
434 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
435 self
.assertRegex(output
, 'Driver: veth')
437 def test_delete_links(self
):
438 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
439 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
442 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
444 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
445 self
.assertFalse(link_exists('test1'))
446 self
.assertFalse(link_exists('veth99'))
447 self
.assertFalse(link_exists('veth-peer'))
449 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
508 '10-dropin-test.netdev',
512 '13-not-match-udev-property.network',
513 '14-match-udev-property.network',
514 '15-name-conflict-test.netdev',
517 '21-vlan-test1.network',
520 '25-6rd-tunnel.netdev',
522 '25-bond-balanced-tlb.netdev',
524 '25-bridge-configure-without-carrier.network',
526 '25-erspan-tunnel-local-any.netdev',
527 '25-erspan-tunnel.netdev',
528 '25-fou-gretap.netdev',
530 '25-fou-ipip.netdev',
531 '25-fou-ipproto-gre.netdev',
532 '25-fou-ipproto-ipip.netdev',
535 '25-gretap-tunnel-local-any.netdev',
536 '25-gretap-tunnel.netdev',
537 '25-gre-tunnel-local-any.netdev',
538 '25-gre-tunnel-remote-any.netdev',
539 '25-gre-tunnel.netdev',
540 '25-ip6gretap-tunnel-local-any.netdev',
541 '25-ip6gretap-tunnel.netdev',
542 '25-ip6gre-tunnel-local-any.netdev',
543 '25-ip6gre-tunnel-remote-any.netdev',
544 '25-ip6gre-tunnel.netdev',
545 '25-ip6tnl-tunnel-remote-any.netdev',
546 '25-ip6tnl-tunnel-local-any.netdev',
547 '25-ip6tnl-tunnel.netdev',
548 '25-ipip-tunnel-independent.netdev',
549 '25-ipip-tunnel-local-any.netdev',
550 '25-ipip-tunnel-remote-any.netdev',
551 '25-ipip-tunnel.netdev',
554 '25-isatap-tunnel.netdev',
559 '25-sit-tunnel-local-any.netdev',
560 '25-sit-tunnel-remote-any.netdev',
561 '25-sit-tunnel.netdev',
564 '25-tunnel-local-any.network',
565 '25-tunnel-remote-any.network',
570 '25-vti6-tunnel-local-any.netdev',
571 '25-vti6-tunnel-remote-any.netdev',
572 '25-vti6-tunnel.netdev',
573 '25-vti-tunnel-local-any.netdev',
574 '25-vti-tunnel-remote-any.netdev',
575 '25-vti-tunnel.netdev',
578 '25-wireguard-23-peers.netdev',
579 '25-wireguard-23-peers.network',
580 '25-wireguard-preshared-key.txt',
581 '25-wireguard-private-key.txt',
582 '25-wireguard.netdev',
583 '25-wireguard.network',
599 'netdev-link-local-addressing-yes.network',
603 'vxlan-test1.network',
611 remove_fou_ports(self
.fou_ports
)
612 remove_links(self
.links
)
615 remove_fou_ports(self
.fou_ports
)
616 remove_links(self
.links
)
617 remove_unit_from_networkd_path(self
.units
)
619 def test_dropin_and_name_conflict(self
):
620 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
623 wait_online(['dropin-test:off'])
625 output
= check_output('ip link show dropin-test')
627 self
.assertRegex(output
, '00:50:56:c0:00:28')
629 def test_match_udev_property(self
):
630 copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network')
632 wait_online(['dummy98:routable'])
634 output
= check_output('networkctl status dummy98')
636 self
.assertRegex(output
, 'Network File: /run/systemd/network/14-match-udev-property')
638 def test_wait_online_any(self
):
639 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
642 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
644 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
645 self
.check_operstate('test1', 'degraded')
647 def test_bridge(self
):
648 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
651 wait_online(['bridge99:no-carrier'])
653 tick
= os
.sysconf('SC_CLK_TCK')
654 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
655 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
656 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
657 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
658 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
659 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
660 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
661 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
664 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
667 wait_online(['bond99:off', 'bond98:off'])
669 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
670 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
671 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
672 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
673 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
674 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
675 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
676 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
677 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
678 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
679 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
681 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
682 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
685 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
686 '21-vlan.network', '21-vlan-test1.network')
689 wait_online(['test1:degraded', 'vlan99:routable'])
691 output
= check_output('ip -d link show test1')
693 self
.assertRegex(output
, ' mtu 2000 ')
695 output
= check_output('ip -d link show vlan99')
697 self
.assertRegex(output
, ' mtu 2000 ')
698 self
.assertRegex(output
, 'REORDER_HDR')
699 self
.assertRegex(output
, 'LOOSE_BINDING')
700 self
.assertRegex(output
, 'GVRP')
701 self
.assertRegex(output
, 'MVRP')
702 self
.assertRegex(output
, ' id 99 ')
704 output
= check_output('ip -4 address show dev test1')
706 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
707 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
709 output
= check_output('ip -4 address show dev vlan99')
711 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
713 def test_macvtap(self
):
714 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
715 with self
.subTest(mode
=mode
):
716 if mode
!= 'private':
718 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
719 '11-dummy.netdev', 'macvtap.network')
720 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
721 f
.write('[MACVTAP]\nMode=' + mode
)
724 wait_online(['macvtap99:degraded', 'test1:degraded'])
726 output
= check_output('ip -d link show macvtap99')
728 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
730 def test_macvlan(self
):
731 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
732 with self
.subTest(mode
=mode
):
733 if mode
!= 'private':
735 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
736 '11-dummy.netdev', 'macvlan.network')
737 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
738 f
.write('[MACVLAN]\nMode=' + mode
)
741 wait_online(['macvlan99:degraded', 'test1:degraded'])
743 output
= check_output('ip -d link show test1')
745 self
.assertRegex(output
, ' mtu 2000 ')
747 output
= check_output('ip -d link show macvlan99')
749 self
.assertRegex(output
, ' mtu 2000 ')
750 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
752 @expectedFailureIfModuleIsNotAvailable('ipvlan')
753 def test_ipvlan(self
):
754 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
755 with self
.subTest(mode
=mode
, flag
=flag
):
758 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
759 '11-dummy.netdev', 'ipvlan.network')
760 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
761 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
764 wait_online(['ipvlan99:degraded', 'test1:degraded'])
766 output
= check_output('ip -d link show ipvlan99')
768 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
770 @expectedFailureIfModuleIsNotAvailable('ipvtap')
771 def test_ipvtap(self
):
772 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
773 with self
.subTest(mode
=mode
, flag
=flag
):
776 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
777 '11-dummy.netdev', 'ipvtap.network')
778 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
779 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
782 wait_online(['ipvtap99:degraded', 'test1:degraded'])
784 output
= check_output('ip -d link show ipvtap99')
786 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
789 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
792 wait_online(['veth99:degraded', 'veth-peer:degraded'])
794 output
= check_output('ip -d link show veth99')
796 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
797 output
= check_output('ip -d link show veth-peer')
799 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
802 copy_unit_to_networkd_unit_path('25-tun.netdev')
805 wait_online(['tun99:off'])
807 output
= check_output('ip -d link show tun99')
809 # Old ip command does not support IFF_ flags
810 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
813 copy_unit_to_networkd_unit_path('25-tap.netdev')
816 wait_online(['tap99:off'])
818 output
= check_output('ip -d link show tap99')
820 # Old ip command does not support IFF_ flags
821 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
823 @expectedFailureIfModuleIsNotAvailable('vrf')
825 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
828 wait_online(['vrf99:carrier'])
830 @expectedFailureIfModuleIsNotAvailable('vcan')
832 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
835 wait_online(['vcan99:carrier'])
837 @expectedFailureIfModuleIsNotAvailable('vxcan')
838 def test_vxcan(self
):
839 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
842 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
844 @expectedFailureIfModuleIsNotAvailable('wireguard')
845 def test_wireguard(self
):
846 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
847 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
848 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
850 wait_online(['wg99:carrier', 'wg98:routable'])
852 if shutil
.which('wg'):
855 output
= check_output('wg show wg99 listen-port')
856 self
.assertRegex(output
, '51820')
857 output
= check_output('wg show wg99 fwmark')
858 self
.assertRegex(output
, '0x4d2')
859 output
= check_output('wg show wg99 allowed-ips')
860 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
861 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
862 output
= check_output('wg show wg99 persistent-keepalive')
863 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
864 output
= check_output('wg show wg99 endpoints')
865 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
866 output
= check_output('wg show wg99 private-key')
867 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
868 output
= check_output('wg show wg99 preshared-keys')
869 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
870 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
872 output
= check_output('wg show wg98 private-key')
873 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
875 def test_geneve(self
):
876 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
879 wait_online(['geneve99:degraded'])
881 output
= check_output('ip -d link show geneve99')
883 self
.assertRegex(output
, '192.168.22.1')
884 self
.assertRegex(output
, '6082')
885 self
.assertRegex(output
, 'udpcsum')
886 self
.assertRegex(output
, 'udp6zerocsumrx')
888 def test_ipip_tunnel(self
):
889 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
890 '25-ipip-tunnel.netdev', '25-tunnel.network',
891 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
892 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
894 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
896 output
= check_output('ip -d link show ipiptun99')
898 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
899 output
= check_output('ip -d link show ipiptun98')
901 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
902 output
= check_output('ip -d link show ipiptun97')
904 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
906 def test_gre_tunnel(self
):
907 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
908 '25-gre-tunnel.netdev', '25-tunnel.network',
909 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
910 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
912 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
914 output
= check_output('ip -d link show gretun99')
916 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
917 self
.assertRegex(output
, 'ikey 1.2.3.103')
918 self
.assertRegex(output
, 'okey 1.2.4.103')
919 self
.assertRegex(output
, 'iseq')
920 self
.assertRegex(output
, 'oseq')
921 output
= check_output('ip -d link show gretun98')
923 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
924 self
.assertRegex(output
, 'ikey 0.0.0.104')
925 self
.assertRegex(output
, 'okey 0.0.0.104')
926 self
.assertNotRegex(output
, 'iseq')
927 self
.assertNotRegex(output
, 'oseq')
928 output
= check_output('ip -d link show gretun97')
930 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
931 self
.assertRegex(output
, 'ikey 0.0.0.105')
932 self
.assertRegex(output
, 'okey 0.0.0.105')
933 self
.assertNotRegex(output
, 'iseq')
934 self
.assertNotRegex(output
, 'oseq')
936 def test_ip6gre_tunnel(self
):
937 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
938 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
939 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
940 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
943 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
945 self
.check_link_exists('dummy98')
946 self
.check_link_exists('ip6gretun99')
947 self
.check_link_exists('ip6gretun98')
948 self
.check_link_exists('ip6gretun97')
950 output
= check_output('ip -d link show ip6gretun99')
952 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
953 output
= check_output('ip -d link show ip6gretun98')
955 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
956 output
= check_output('ip -d link show ip6gretun97')
958 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
960 def test_gretap_tunnel(self
):
961 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
962 '25-gretap-tunnel.netdev', '25-tunnel.network',
963 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
965 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
967 output
= check_output('ip -d link show gretap99')
969 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
970 self
.assertRegex(output
, 'ikey 0.0.0.106')
971 self
.assertRegex(output
, 'okey 0.0.0.106')
972 self
.assertRegex(output
, 'iseq')
973 self
.assertRegex(output
, 'oseq')
974 output
= check_output('ip -d link show gretap98')
976 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
977 self
.assertRegex(output
, 'ikey 0.0.0.107')
978 self
.assertRegex(output
, 'okey 0.0.0.107')
979 self
.assertRegex(output
, 'iseq')
980 self
.assertRegex(output
, 'oseq')
982 def test_ip6gretap_tunnel(self
):
983 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
984 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
985 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
987 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
989 output
= check_output('ip -d link show ip6gretap99')
991 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
992 output
= check_output('ip -d link show ip6gretap98')
994 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
996 def test_vti_tunnel(self
):
997 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
998 '25-vti-tunnel.netdev', '25-tunnel.network',
999 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1000 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1002 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
1004 output
= check_output('ip -d link show vtitun99')
1006 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
1007 output
= check_output('ip -d link show vtitun98')
1009 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
1010 output
= check_output('ip -d link show vtitun97')
1012 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
1014 def test_vti6_tunnel(self
):
1015 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
1016 '25-vti6-tunnel.netdev', '25-tunnel.network',
1017 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1018 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1020 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
1022 output
= check_output('ip -d link show vti6tun99')
1024 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1025 output
= check_output('ip -d link show vti6tun98')
1027 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1028 output
= check_output('ip -d link show vti6tun97')
1030 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1032 def test_ip6tnl_tunnel(self
):
1033 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
1034 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
1035 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1036 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1038 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
1040 output
= check_output('ip -d link show ip6tnl99')
1042 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
1043 output
= check_output('ip -d link show ip6tnl98')
1045 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
1046 output
= check_output('ip -d link show ip6tnl97')
1048 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
1050 def test_sit_tunnel(self
):
1051 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
1052 '25-sit-tunnel.netdev', '25-tunnel.network',
1053 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
1054 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
1056 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1058 output
= check_output('ip -d link show sittun99')
1060 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1061 output
= check_output('ip -d link show sittun98')
1063 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1064 output
= check_output('ip -d link show sittun97')
1066 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1068 def test_isatap_tunnel(self
):
1069 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1070 '25-isatap-tunnel.netdev', '25-tunnel.network')
1072 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1074 output
= check_output('ip -d link show isataptun99')
1076 self
.assertRegex(output
, "isatap ")
1078 def test_6rd_tunnel(self
):
1079 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1080 '25-6rd-tunnel.netdev', '25-tunnel.network')
1082 wait_online(['sittun99:routable', 'dummy98:degraded'])
1084 output
= check_output('ip -d link show sittun99')
1086 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1088 @expectedFailureIfERSPANModuleIsNotAvailable()
1089 def test_erspan_tunnel(self
):
1090 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1091 '25-erspan-tunnel.netdev', '25-tunnel.network',
1092 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1094 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1096 output
= check_output('ip -d link show erspan99')
1098 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1099 self
.assertRegex(output
, 'ikey 0.0.0.101')
1100 self
.assertRegex(output
, 'okey 0.0.0.101')
1101 self
.assertRegex(output
, 'iseq')
1102 self
.assertRegex(output
, 'oseq')
1103 output
= check_output('ip -d link show erspan98')
1105 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1106 self
.assertRegex(output
, '102')
1107 self
.assertRegex(output
, 'ikey 0.0.0.102')
1108 self
.assertRegex(output
, 'okey 0.0.0.102')
1109 self
.assertRegex(output
, 'iseq')
1110 self
.assertRegex(output
, 'oseq')
1112 def test_tunnel_independent(self
):
1113 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1116 wait_online(['ipiptun99:carrier'])
1118 @expectedFailureIfModuleIsNotAvailable('fou')
1120 # The following redundant check is necessary for CentOS CI.
1121 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1122 self
.assertTrue(is_module_available('fou'))
1124 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1125 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1126 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1129 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1131 output
= check_output('ip fou show')
1133 self
.assertRegex(output
, 'port 55555 ipproto 4')
1134 self
.assertRegex(output
, 'port 55556 ipproto 47')
1136 output
= check_output('ip -d link show ipiptun96')
1138 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1139 output
= check_output('ip -d link show sittun96')
1141 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1142 output
= check_output('ip -d link show gretun96')
1144 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1145 output
= check_output('ip -d link show gretap96')
1147 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1149 def test_vxlan(self
):
1150 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1151 '11-dummy.netdev', 'vxlan-test1.network')
1154 wait_online(['test1:degraded', 'vxlan99:degraded'])
1156 output
= check_output('ip -d link show vxlan99')
1158 self
.assertRegex(output
, '999')
1159 self
.assertRegex(output
, '5555')
1160 self
.assertRegex(output
, 'l2miss')
1161 self
.assertRegex(output
, 'l3miss')
1162 self
.assertRegex(output
, 'udpcsum')
1163 self
.assertRegex(output
, 'udp6zerocsumtx')
1164 self
.assertRegex(output
, 'udp6zerocsumrx')
1165 self
.assertRegex(output
, 'remcsumtx')
1166 self
.assertRegex(output
, 'remcsumrx')
1167 self
.assertRegex(output
, 'gbp')
1169 output
= check_output('bridge fdb show dev vxlan99')
1171 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1172 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1173 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1175 def test_macsec(self
):
1176 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1177 'macsec.network', '12-dummy.netdev')
1180 wait_online(['dummy98:degraded', 'macsec99:routable'])
1182 output
= check_output('ip -d link show macsec99')
1184 self
.assertRegex(output
, 'macsec99@dummy98')
1185 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1186 self
.assertRegex(output
, 'encrypt on')
1188 output
= check_output('ip macsec show macsec99')
1190 self
.assertRegex(output
, 'encrypt on')
1191 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1192 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1193 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1194 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1195 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1196 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1197 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1198 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1199 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1200 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1201 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1203 def test_nlmon(self
):
1204 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1207 wait_online(['nlmon99:carrier'])
1209 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1220 '25-l2tp-dummy.network',
1221 '25-l2tp-ip.netdev',
1222 '25-l2tp-udp.netdev']
1224 l2tp_tunnel_ids
= [ '10' ]
1227 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1228 remove_links(self
.links
)
1231 remove_l2tp_tunnels(self
.l2tp_tunnel_ids
)
1232 remove_links(self
.links
)
1233 remove_unit_from_networkd_path(self
.units
)
1235 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1236 def test_l2tp_udp(self
):
1237 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1240 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1242 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1244 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1245 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1246 self
.assertRegex(output
, "Peer tunnel 11")
1247 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1248 self
.assertRegex(output
, "UDP checksum: enabled")
1250 output
= check_output('ip l2tp show session tid 10 session_id 15')
1252 self
.assertRegex(output
, "Session 15 in tunnel 10")
1253 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1254 self
.assertRegex(output
, "interface name: l2tp-ses1")
1256 output
= check_output('ip l2tp show session tid 10 session_id 17')
1258 self
.assertRegex(output
, "Session 17 in tunnel 10")
1259 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1260 self
.assertRegex(output
, "interface name: l2tp-ses2")
1262 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1263 def test_l2tp_ip(self
):
1264 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1267 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1269 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1271 self
.assertRegex(output
, "Tunnel 10, encap IP")
1272 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1273 self
.assertRegex(output
, "Peer tunnel 12")
1275 output
= check_output('ip l2tp show session tid 10 session_id 25')
1277 self
.assertRegex(output
, "Session 25 in tunnel 10")
1278 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1279 self
.assertRegex(output
, "interface name: l2tp-ses3")
1281 output
= check_output('ip l2tp show session tid 10 session_id 27')
1283 self
.assertRegex(output
, "Session 27 in tunnel 10")
1284 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1285 self
.assertRegex(output
, "interface name: l2tp-ses4")
1287 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1297 '23-active-slave.network',
1298 '24-keep-configuration-static.network',
1299 '24-search-domain.network',
1300 '25-address-link-section.network',
1301 '25-address-preferred-lifetime-zero-ipv6.network',
1302 '25-address-static.network',
1303 '25-bind-carrier.network',
1304 '25-bond-active-backup-slave.netdev',
1305 '25-fibrule-invert.network',
1306 '25-fibrule-port-range.network',
1307 '25-ipv6-address-label-section.network',
1308 '25-neighbor-section.network',
1309 '25-link-local-addressing-no.network',
1310 '25-link-local-addressing-yes.network',
1311 '25-link-section-unmanaged.network',
1312 '25-route-ipv6-src.network',
1313 '25-route-static.network',
1314 '25-sysctl-disable-ipv6.network',
1315 '25-sysctl.network',
1316 'configure-without-carrier.network',
1317 'routing-policy-rule-dummy98.network',
1318 'routing-policy-rule-test1.network']
1320 routing_policy_rule_tables
= ['7', '8']
1321 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1324 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1325 remove_routes(self
.routes
)
1326 remove_links(self
.links
)
1329 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1330 remove_routes(self
.routes
)
1331 remove_links(self
.links
)
1332 remove_unit_from_networkd_path(self
.units
)
1334 def test_address_static(self
):
1335 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1338 wait_online(['dummy98:routable'])
1340 output
= check_output('ip -4 address show dev dummy98')
1342 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1343 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1344 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1347 self
.assertNotRegex(output
, '10.10.0.1/16')
1348 self
.assertNotRegex(output
, '10.10.0.2/16')
1350 output
= check_output('ip -4 address show dev dummy98 label 32')
1351 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1353 output
= check_output('ip -4 address show dev dummy98 label 33')
1354 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1356 output
= check_output('ip -4 address show dev dummy98 label 34')
1357 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1359 output
= check_output('ip -4 address show dev dummy98 label 35')
1360 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1362 output
= check_output('ip -6 address show dev dummy98')
1364 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1365 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1366 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1367 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1368 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1369 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1371 def test_address_preferred_lifetime_zero_ipv6(self
):
1372 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1375 self
.check_link_exists('dummy98')
1376 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1378 output
= check_output('ip address show dummy98')
1380 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1381 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1383 def test_configure_without_carrier(self
):
1384 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1386 wait_online(['test1:routable'])
1388 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1390 self
.assertRegex(output
, '192.168.0.15')
1391 self
.assertRegex(output
, '192.168.0.1')
1392 self
.assertRegex(output
, 'routable')
1394 def test_routing_policy_rule(self
):
1395 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1397 wait_online(['test1:degraded'])
1399 output
= check_output('ip rule')
1401 self
.assertRegex(output
, '111')
1402 self
.assertRegex(output
, 'from 192.168.100.18')
1403 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1404 self
.assertRegex(output
, 'iif test1')
1405 self
.assertRegex(output
, 'oif test1')
1406 self
.assertRegex(output
, 'lookup 7')
1408 def test_routing_policy_rule_issue_11280(self
):
1409 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1410 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1412 for trial
in range(3):
1413 # Remove state files only first time
1414 start_networkd(0, remove_state_files
=(trial
== 0))
1415 wait_online(['test1:degraded', 'dummy98:degraded'])
1418 output
= check_output('ip rule list table 7')
1420 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1422 output
= check_output('ip rule list table 8')
1424 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1426 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1427 def test_routing_policy_rule_port_range(self
):
1428 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1430 wait_online(['test1:degraded'])
1432 output
= check_output('ip rule')
1434 self
.assertRegex(output
, '111')
1435 self
.assertRegex(output
, 'from 192.168.100.18')
1436 self
.assertRegex(output
, '1123-1150')
1437 self
.assertRegex(output
, '3224-3290')
1438 self
.assertRegex(output
, 'tcp')
1439 self
.assertRegex(output
, 'lookup 7')
1441 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1442 def test_routing_policy_rule_invert(self
):
1443 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1445 wait_online(['test1:degraded'])
1447 output
= check_output('ip rule')
1449 self
.assertRegex(output
, '111')
1450 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1451 self
.assertRegex(output
, 'tcp')
1452 self
.assertRegex(output
, 'lookup 7')
1454 def test_route_static(self
):
1455 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1457 wait_online(['dummy98:routable'])
1459 output
= check_output('ip -6 route show dev dummy98')
1461 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1462 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1464 output
= check_output('ip -6 route show dev dummy98 default')
1465 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1467 output
= check_output('ip -4 route show dev dummy98')
1469 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1470 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1471 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1472 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1473 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1475 output
= check_output('ip -4 route show dev dummy98 default')
1476 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1477 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1478 self
.assertRegex(output
, 'default proto static')
1480 output
= check_output('ip route show type blackhole')
1482 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1484 output
= check_output('ip route show type unreachable')
1486 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1488 output
= check_output('ip route show type prohibit')
1490 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1492 def test_ip_route_ipv6_src_route(self
):
1493 # a dummy device does not make the addresses go through tentative state, so we
1494 # reuse a bond from an earlier test, which does make the addresses go through
1495 # tentative state, and do our test on that
1496 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1498 wait_online(['dummy98:enslaved', 'bond199:routable'])
1500 output
= check_output('ip -6 route list dev bond199')
1502 self
.assertRegex(output
, 'abcd::/16')
1503 self
.assertRegex(output
, 'src')
1504 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1506 def test_ip_link_mac_address(self
):
1507 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1509 wait_online(['dummy98:degraded'])
1511 output
= check_output('ip link show dummy98')
1513 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1515 def test_ip_link_unmanaged(self
):
1516 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1519 self
.check_link_exists('dummy98')
1521 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1523 def test_ipv6_address_label(self
):
1524 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1526 wait_online(['dummy98:degraded'])
1528 output
= check_output('ip addrlabel list')
1530 self
.assertRegex(output
, '2004:da8:1::/64')
1532 def test_ipv6_neighbor(self
):
1533 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1535 wait_online(['dummy98:degraded'], timeout
='40s')
1537 output
= check_output('ip neigh list dev dummy98')
1539 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1540 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1542 def test_link_local_addressing(self
):
1543 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1544 '25-link-local-addressing-no.network', '12-dummy.netdev')
1546 wait_online(['test1:degraded', 'dummy98:carrier'])
1548 output
= check_output('ip address show dev test1')
1550 self
.assertRegex(output
, 'inet .* scope link')
1551 self
.assertRegex(output
, 'inet6 .* scope link')
1553 output
= check_output('ip address show dev dummy98')
1555 self
.assertNotRegex(output
, 'inet6* .* scope link')
1558 Documentation/networking/ip-sysctl.txt
1560 addr_gen_mode - INTEGER
1561 Defines how link-local and autoconf addresses are generated.
1563 0: generate address based on EUI64 (default)
1564 1: do no generate a link-local address, use EUI64 for addresses generated
1566 2: generate stable privacy addresses, using the secret from
1567 stable_secret (RFC7217)
1568 3: generate stable privacy addresses, using a random secret if unset
1571 test1_addr_gen_mode
= ''
1572 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1573 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1577 # if stable_secret is unset, then EIO is returned
1578 test1_addr_gen_mode
= '0'
1580 test1_addr_gen_mode
= '2'
1582 test1_addr_gen_mode
= '0'
1584 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1585 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1587 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1588 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1590 def test_sysctl(self
):
1591 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1593 wait_online(['dummy98:degraded'])
1595 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1596 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1597 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1598 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1599 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1600 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1601 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1603 def test_sysctl_disable_ipv6(self
):
1604 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1606 print('## Disable ipv6')
1607 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1608 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1611 wait_online(['dummy98:routable'])
1613 output
= check_output('ip -4 address show dummy98')
1615 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1616 output
= check_output('ip -6 address show dummy98')
1618 self
.assertEqual(output
, '')
1619 output
= check_output('ip -4 route show dev dummy98')
1621 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1622 output
= check_output('ip -6 route show dev dummy98')
1624 self
.assertEqual(output
, '')
1626 check_output('ip link del dummy98')
1628 print('## Enable ipv6')
1629 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1630 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1633 wait_online(['dummy98:routable'])
1635 output
= check_output('ip -4 address show dummy98')
1637 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1638 output
= check_output('ip -6 address show dummy98')
1640 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1641 self
.assertRegex(output
, 'inet6 .* scope link')
1642 output
= check_output('ip -4 route show dev dummy98')
1644 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1645 output
= check_output('ip -6 route show dev dummy98')
1647 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1649 def test_bind_carrier(self
):
1650 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1652 wait_online(['test1:routable'])
1654 check_output('ip link add dummy98 type dummy')
1655 check_output('ip link set dummy98 up')
1657 output
= check_output('ip address show test1')
1659 self
.assertRegex(output
, 'UP,LOWER_UP')
1660 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1661 self
.check_operstate('test1', 'routable')
1663 check_output('ip link add dummy99 type dummy')
1664 check_output('ip link set dummy99 up')
1666 output
= check_output('ip address show test1')
1668 self
.assertRegex(output
, 'UP,LOWER_UP')
1669 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1670 self
.check_operstate('test1', 'routable')
1672 check_output('ip link del dummy98')
1674 output
= check_output('ip address show test1')
1676 self
.assertRegex(output
, 'UP,LOWER_UP')
1677 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1678 self
.check_operstate('test1', 'routable')
1680 check_output('ip link del dummy99')
1682 output
= check_output('ip address show test1')
1684 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1685 self
.assertRegex(output
, 'DOWN')
1686 self
.assertNotRegex(output
, '192.168.10')
1687 self
.check_operstate('test1', 'off')
1689 check_output('ip link add dummy98 type dummy')
1690 check_output('ip link set dummy98 up')
1692 output
= check_output('ip address show test1')
1694 self
.assertRegex(output
, 'UP,LOWER_UP')
1695 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1696 self
.check_operstate('test1', 'routable')
1698 def test_domain(self
):
1699 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1701 wait_online(['dummy98:routable'])
1703 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1705 self
.assertRegex(output
, 'Address: 192.168.42.100')
1706 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1707 self
.assertRegex(output
, 'Search Domains: one')
1709 def test_keep_configuration_static(self
):
1710 check_output('systemctl stop systemd-networkd')
1712 check_output('ip link add name dummy98 type dummy')
1713 check_output('ip address add 10.1.2.3/16 dev dummy98')
1714 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1715 output
= check_output('ip address show dummy98')
1717 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1718 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1719 output
= check_output('ip route show dev dummy98')
1722 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1724 wait_online(['dummy98:routable'])
1726 output
= check_output('ip address show dummy98')
1728 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1729 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1731 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1741 '23-active-slave.network',
1742 '23-bond199.network',
1743 '23-primary-slave.network',
1744 '25-bond-active-backup-slave.netdev',
1747 'bond-slave.network']
1750 remove_links(self
.links
)
1753 remove_links(self
.links
)
1754 remove_unit_from_networkd_path(self
.units
)
1756 def test_bond_active_slave(self
):
1757 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1759 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1761 output
= check_output('ip -d link show bond199')
1763 self
.assertRegex(output
, 'active_slave dummy98')
1765 def test_bond_primary_slave(self
):
1766 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1768 wait_online(['dummy98:enslaved', 'bond199:degraded'])
1770 output
= check_output('ip -d link show bond199')
1772 self
.assertRegex(output
, 'primary dummy98')
1774 def test_bond_operstate(self
):
1775 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1776 'bond99.network','bond-slave.network')
1778 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bond99:routable'])
1780 output
= check_output('ip -d link show dummy98')
1782 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1784 output
= check_output('ip -d link show test1')
1786 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1788 output
= check_output('ip -d link show bond99')
1790 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1792 self
.check_operstate('dummy98', 'enslaved')
1793 self
.check_operstate('test1', 'enslaved')
1794 self
.check_operstate('bond99', 'routable')
1796 check_output('ip link set dummy98 down')
1799 self
.check_operstate('dummy98', 'off')
1800 self
.check_operstate('test1', 'enslaved')
1801 self
.check_operstate('bond99', 'degraded-carrier')
1803 check_output('ip link set dummy98 up')
1806 self
.check_operstate('dummy98', 'enslaved')
1807 self
.check_operstate('test1', 'enslaved')
1808 self
.check_operstate('bond99', 'routable')
1810 check_output('ip link set dummy98 down')
1811 check_output('ip link set test1 down')
1814 self
.check_operstate('dummy98', 'off')
1815 self
.check_operstate('test1', 'off')
1817 for trial
in range(30):
1820 output
= check_output('ip address show bond99')
1822 if get_operstate('bond99') == 'no-carrier':
1825 # Huh? Kernel does not recognize that all slave interfaces are down?
1826 # Let's confirm that networkd's operstate is consistent with ip's result.
1827 self
.assertNotRegex(output
, 'NO-CARRIER')
1829 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1839 '26-bridge-slave-interface-1.network',
1840 '26-bridge-slave-interface-2.network',
1841 'bridge99-ignore-carrier-loss.network',
1844 routing_policy_rule_tables
= ['100']
1847 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1848 remove_links(self
.links
)
1851 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1852 remove_links(self
.links
)
1853 remove_unit_from_networkd_path(self
.units
)
1855 def test_bridge_property(self
):
1856 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1857 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1860 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1862 output
= check_output('ip -d link show test1')
1864 self
.assertRegex(output
, 'master')
1865 self
.assertRegex(output
, 'bridge')
1867 output
= check_output('ip -d link show dummy98')
1869 self
.assertRegex(output
, 'master')
1870 self
.assertRegex(output
, 'bridge')
1872 output
= check_output('ip addr show bridge99')
1874 self
.assertRegex(output
, '192.168.0.15/24')
1876 output
= check_output('bridge -d link show dummy98')
1878 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1879 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1880 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1881 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1882 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1883 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1884 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1885 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1887 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1888 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1889 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1891 check_output('ip address add 192.168.0.16/24 dev bridge99')
1894 output
= check_output('ip addr show bridge99')
1896 self
.assertRegex(output
, '192.168.0.16/24')
1898 self
.assertEqual(call('ip link del test1'), 0)
1901 self
.check_operstate('bridge99', 'degraded-carrier')
1903 check_output('ip link del dummy98')
1906 self
.check_operstate('bridge99', 'no-carrier')
1908 output
= check_output('ip address show bridge99')
1910 self
.assertRegex(output
, 'NO-CARRIER')
1911 self
.assertNotRegex(output
, '192.168.0.15/24')
1912 self
.assertNotRegex(output
, '192.168.0.16/24')
1914 def test_bridge_ignore_carrier_loss(self
):
1915 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1916 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1917 'bridge99-ignore-carrier-loss.network')
1919 wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
1921 check_output('ip address add 192.168.0.16/24 dev bridge99')
1924 check_output('ip link del test1')
1925 check_output('ip link del dummy98')
1928 output
= check_output('ip address show bridge99')
1930 self
.assertRegex(output
, 'NO-CARRIER')
1931 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1932 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1934 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1935 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1936 'bridge99-ignore-carrier-loss.network')
1938 wait_online(['bridge99:no-carrier'])
1940 for trial
in range(4):
1941 check_output('ip link add dummy98 type dummy')
1942 check_output('ip link set dummy98 up')
1944 check_output('ip link del dummy98')
1946 wait_online(['bridge99:routable', 'dummy98:enslaved'])
1948 output
= check_output('ip address show bridge99')
1950 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1952 output
= check_output('ip rule list table 100')
1954 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
1956 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
1960 '23-emit-lldp.network',
1965 remove_links(self
.links
)
1968 remove_links(self
.links
)
1969 remove_unit_from_networkd_path(self
.units
)
1971 def test_lldp(self
):
1972 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1974 wait_online(['veth99:degraded', 'veth-peer:degraded'])
1976 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
1978 self
.assertRegex(output
, 'veth-peer')
1979 self
.assertRegex(output
, 'veth99')
1981 class NetworkdRATests(unittest
.TestCase
, Utilities
):
1986 'ipv6-prefix.network',
1987 'ipv6-prefix-veth.network']
1990 remove_links(self
.links
)
1993 remove_links(self
.links
)
1994 remove_unit_from_networkd_path(self
.units
)
1996 def test_ipv6_prefix_delegation(self
):
1997 warn_about_firewalld()
1998 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2000 wait_online(['veth99:routable', 'veth-peer:degraded'])
2002 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2004 self
.assertRegex(output
, '2002:da8:1:0')
2006 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2011 'dhcp-client.network',
2012 'dhcp-client-timezone-router.network',
2013 'dhcp-server.network',
2014 'dhcp-server-timezone-router.network']
2017 remove_links(self
.links
)
2020 remove_links(self
.links
)
2021 remove_unit_from_networkd_path(self
.units
)
2023 def test_dhcp_server(self
):
2024 warn_about_firewalld()
2025 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2027 wait_online(['veth99:routable', 'veth-peer:routable'])
2029 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2031 self
.assertRegex(output
, '192.168.5.*')
2032 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2033 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2034 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2036 def test_emit_router_timezone(self
):
2037 warn_about_firewalld()
2038 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2040 wait_online(['veth99:routable', 'veth-peer:routable'])
2042 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2044 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2045 self
.assertRegex(output
, '192.168.5.*')
2046 self
.assertRegex(output
, 'Europe/Berlin')
2048 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2057 'dhcp-client-anonymize.network',
2058 'dhcp-client-gateway-onlink-implicit.network',
2059 'dhcp-client-ipv4-dhcp-settings.network',
2060 'dhcp-client-ipv4-only-ipv6-disabled.network',
2061 'dhcp-client-ipv4-only.network',
2062 'dhcp-client-ipv6-only.network',
2063 'dhcp-client-ipv6-rapid-commit.network',
2064 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2065 'dhcp-client-keep-configuration-dhcp.network',
2066 'dhcp-client-listen-port.network',
2067 'dhcp-client-route-metric.network',
2068 'dhcp-client-route-table.network',
2069 'dhcp-client-vrf.network',
2070 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2071 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2072 'dhcp-client.network',
2073 'dhcp-server-veth-peer.network',
2074 'dhcp-v4-server-veth-peer.network',
2078 stop_dnsmasq(dnsmasq_pid_file
)
2079 remove_links(self
.links
)
2082 stop_dnsmasq(dnsmasq_pid_file
)
2085 remove_links(self
.links
)
2086 remove_unit_from_networkd_path(self
.units
)
2088 def test_dhcp_client_ipv6_only(self
):
2089 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2092 wait_online(['veth-peer:carrier'])
2094 wait_online(['veth99:routable', 'veth-peer:routable'])
2096 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2098 self
.assertRegex(output
, '2600::')
2099 self
.assertNotRegex(output
, '192.168.5')
2101 # Confirm that ipv6 token is not set in the kernel
2102 output
= check_output('ip token show dev veth99')
2104 self
.assertRegex(output
, 'token :: dev veth99')
2106 def test_dhcp_client_ipv4_only(self
):
2107 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2110 wait_online(['veth-peer:carrier'])
2112 wait_online(['veth99:routable', 'veth-peer:routable'])
2114 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2116 self
.assertNotRegex(output
, '2600::')
2117 self
.assertRegex(output
, '192.168.5')
2119 def test_dhcp_client_ipv4_ipv6(self
):
2120 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2121 'dhcp-client-ipv4-only.network')
2123 wait_online(['veth-peer:carrier'])
2125 wait_online(['veth99:routable', 'veth-peer:routable'])
2127 # link become 'routable' when at least one protocol provide an valid address.
2128 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2129 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2131 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2133 self
.assertRegex(output
, '2600::')
2134 self
.assertRegex(output
, '192.168.5')
2136 def test_dhcp_client_settings(self
):
2137 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2140 wait_online(['veth-peer:carrier'])
2142 wait_online(['veth99:routable', 'veth-peer:routable'])
2144 print('## ip address show dev veth99')
2145 output
= check_output('ip address show dev veth99')
2147 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2148 self
.assertRegex(output
, '192.168.5')
2149 self
.assertRegex(output
, '1492')
2152 print('## ip route show table main dev veth99')
2153 output
= check_output('ip route show table main dev veth99')
2155 self
.assertNotRegex(output
, 'proto dhcp')
2157 print('## ip route show table 211 dev veth99')
2158 output
= check_output('ip route show table 211 dev veth99')
2160 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2161 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2162 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2164 print('## dnsmasq log')
2165 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2166 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2167 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2168 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2170 def test_dhcp6_client_settings_rapidcommit_true(self
):
2171 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2173 wait_online(['veth-peer:carrier'])
2175 wait_online(['veth99:routable', 'veth-peer:routable'])
2177 output
= check_output('ip address show dev veth99')
2179 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2180 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2182 def test_dhcp6_client_settings_rapidcommit_false(self
):
2183 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2185 wait_online(['veth-peer:carrier'])
2187 wait_online(['veth99:routable', 'veth-peer:routable'])
2189 output
= check_output('ip address show dev veth99')
2191 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2192 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2194 def test_dhcp_client_settings_anonymize(self
):
2195 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2197 wait_online(['veth-peer:carrier'])
2199 wait_online(['veth99:routable', 'veth-peer:routable'])
2201 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2202 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2203 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2205 def test_dhcp_client_listen_port(self
):
2206 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2208 wait_online(['veth-peer:carrier'])
2209 start_dnsmasq('--dhcp-alternate-port=67,5555')
2210 wait_online(['veth99:routable', 'veth-peer:routable'])
2212 # link become 'routable' when at least one protocol provide an valid address.
2213 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2214 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2216 output
= check_output('ip -4 address show dev veth99')
2218 self
.assertRegex(output
, '192.168.5.* dynamic')
2220 def test_dhcp_route_table_id(self
):
2221 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2223 wait_online(['veth-peer:carrier'])
2225 wait_online(['veth99:routable', 'veth-peer:routable'])
2227 output
= check_output('ip route show table 12')
2229 self
.assertRegex(output
, 'veth99 proto dhcp')
2230 self
.assertRegex(output
, '192.168.5.1')
2232 def test_dhcp_route_metric(self
):
2233 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2235 wait_online(['veth-peer:carrier'])
2237 wait_online(['veth99:routable', 'veth-peer:routable'])
2239 output
= check_output('ip route show dev veth99')
2241 self
.assertRegex(output
, 'metric 24')
2243 def test_dhcp_keep_configuration_dhcp(self
):
2244 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2246 wait_online(['veth-peer:carrier'])
2247 start_dnsmasq(lease_time
='2m')
2248 wait_online(['veth99:routable', 'veth-peer:routable'])
2250 output
= check_output('ip address show dev veth99 scope global')
2252 self
.assertRegex(output
, r
'192.168.5.*')
2254 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2256 self
.assertRegex(output
, r
'192.168.5.*')
2258 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2259 stop_dnsmasq(dnsmasq_pid_file
)
2261 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2262 print('Wait for the dynamic address to be expired')
2265 print('The lease address should be kept after lease expired')
2266 output
= check_output('ip address show dev veth99 scope global')
2268 self
.assertRegex(output
, r
'192.168.5.*')
2270 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2272 self
.assertRegex(output
, r
'192.168.5.*')
2274 check_output('systemctl stop systemd-networkd')
2276 print('The lease address should be kept after networkd stopped')
2277 output
= check_output('ip address show dev veth99 scope global')
2279 self
.assertRegex(output
, r
'192.168.5.*')
2281 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2283 self
.assertRegex(output
, r
'192.168.5.*')
2285 check_output('systemctl start systemd-networkd')
2286 wait_online(['veth-peer:routable'])
2288 print('Still the lease address should be kept after networkd restarted')
2289 output
= check_output('ip address show dev veth99 scope global')
2291 self
.assertRegex(output
, r
'192.168.5.*')
2293 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2295 self
.assertRegex(output
, r
'192.168.5.*')
2297 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2298 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2300 wait_online(['veth-peer:carrier'])
2301 start_dnsmasq(lease_time
='2m')
2302 wait_online(['veth99:routable', 'veth-peer:routable'])
2304 output
= check_output('ip address show dev veth99 scope global')
2306 self
.assertRegex(output
, r
'192.168.5.*')
2308 stop_dnsmasq(dnsmasq_pid_file
)
2309 check_output('systemctl stop systemd-networkd')
2311 output
= check_output('ip address show dev veth99 scope global')
2313 self
.assertRegex(output
, r
'192.168.5.*')
2316 wait_online(['veth-peer:routable'])
2318 output
= check_output('ip address show dev veth99 scope global')
2320 self
.assertNotRegex(output
, r
'192.168.5.*')
2322 def test_dhcp_client_reuse_address_as_static(self
):
2323 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2325 wait_online(['veth-peer:carrier'])
2327 wait_online(['veth99:routable', 'veth-peer:routable'])
2329 # link become 'routable' when at least one protocol provide an valid address.
2330 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2331 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2333 output
= check_output('ip address show dev veth99 scope global')
2335 self
.assertRegex(output
, '192.168.5')
2336 self
.assertRegex(output
, '2600::')
2338 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2339 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2340 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2341 print(static_network
)
2343 remove_unit_from_networkd_path(['dhcp-client.network'])
2345 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2346 f
.write(static_network
)
2348 # When networkd started, the links are already configured, so let's wait for 5 seconds
2349 # the links to be re-configured.
2351 wait_online(['veth99:routable', 'veth-peer:routable'])
2353 output
= check_output('ip -4 address show dev veth99 scope global')
2355 self
.assertRegex(output
, '192.168.5')
2356 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2358 output
= check_output('ip -6 address show dev veth99 scope global')
2360 self
.assertRegex(output
, '2600::')
2361 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2363 @expectedFailureIfModuleIsNotAvailable('vrf')
2364 def test_dhcp_client_vrf(self
):
2365 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2366 '25-vrf.netdev', '25-vrf.network')
2368 wait_online(['veth-peer:carrier'])
2370 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2372 # link become 'routable' when at least one protocol provide an valid address.
2373 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2374 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2376 print('## ip -d link show dev vrf99')
2377 output
= check_output('ip -d link show dev vrf99')
2379 self
.assertRegex(output
, 'vrf table 42')
2381 print('## ip address show vrf vrf99')
2382 output
= check_output('ip address show vrf vrf99')
2384 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2385 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2386 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2387 self
.assertRegex(output
, 'inet6 .* scope link')
2389 print('## ip address show dev veth99')
2390 output
= check_output('ip address show dev veth99')
2392 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2393 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2394 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2395 self
.assertRegex(output
, 'inet6 .* scope link')
2397 print('## ip route show vrf vrf99')
2398 output
= check_output('ip route show vrf vrf99')
2400 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2401 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2402 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2403 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2404 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2405 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2407 print('## ip route show table main dev veth99')
2408 output
= check_output('ip route show table main dev veth99')
2410 self
.assertEqual(output
, '')
2412 def test_dhcp_client_gateway_onlink_implicit(self
):
2413 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2414 'dhcp-client-gateway-onlink-implicit.network')
2416 wait_online(['veth-peer:carrier'])
2418 wait_online(['veth99:routable', 'veth-peer:routable'])
2420 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2422 self
.assertRegex(output
, '192.168.5')
2424 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2426 self
.assertRegex(output
, 'onlink')
2427 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2429 self
.assertRegex(output
, 'onlink')
2431 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2432 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2433 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2435 wait_online(['veth-peer:carrier'])
2436 start_dnsmasq(lease_time
='2m')
2437 wait_online(['veth99:routable', 'veth-peer:routable'])
2439 output
= check_output('ip address show dev veth99')
2442 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2443 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2444 output
= check_output('ip -6 address show dev veth99 scope link')
2445 self
.assertRegex(output
, 'inet6 .* scope link')
2446 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2447 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2448 output
= check_output('ip -4 address show dev veth99 scope link')
2449 self
.assertNotRegex(output
, 'inet .* scope link')
2451 print('Wait for the dynamic address to be expired')
2454 output
= check_output('ip address show dev veth99')
2457 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2458 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2459 output
= check_output('ip -6 address show dev veth99 scope link')
2460 self
.assertRegex(output
, 'inet6 .* scope link')
2461 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2462 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2463 output
= check_output('ip -4 address show dev veth99 scope link')
2464 self
.assertNotRegex(output
, 'inet .* scope link')
2466 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2468 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2469 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2470 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2472 wait_online(['veth99:degraded', 'veth-peer:routable'])
2474 output
= check_output('ip address show dev veth99')
2477 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2478 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2479 output
= check_output('ip -6 address show dev veth99 scope link')
2480 self
.assertRegex(output
, 'inet6 .* scope link')
2481 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2482 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2483 output
= check_output('ip -4 address show dev veth99 scope link')
2484 self
.assertRegex(output
, 'inet .* scope link')
2486 def test_dhcp_client_route_remove_on_renew(self
):
2487 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2488 'dhcp-client-ipv4-only-ipv6-disabled.network')
2490 wait_online(['veth-peer:carrier'])
2491 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2492 wait_online(['veth99:routable', 'veth-peer:routable'])
2494 # test for issue #12490
2496 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2498 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2500 for line
in output
.splitlines():
2501 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2502 address1
= line
.split()[1].split('/')[0]
2505 output
= check_output('ip -4 route show dev veth99')
2507 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2508 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2510 stop_dnsmasq(dnsmasq_pid_file
)
2511 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2513 print('Wait for the dynamic address to be expired')
2516 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2518 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2520 for line
in output
.splitlines():
2521 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2522 address2
= line
.split()[1].split('/')[0]
2525 self
.assertNotEqual(address1
, address2
)
2527 output
= check_output('ip -4 route show dev veth99')
2529 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2530 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2531 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2532 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2534 if __name__
== '__main__':
2535 parser
= argparse
.ArgumentParser()
2536 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2537 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2538 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2539 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2540 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2541 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2542 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2543 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2544 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2545 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2548 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2549 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2550 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2551 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2552 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2555 networkd_bin
= ns
.networkd_bin
2556 if ns
.wait_online_bin
:
2557 wait_online_bin
= ns
.wait_online_bin
2558 if ns
.networkctl_bin
:
2559 networkctl_bin
= ns
.networkctl_bin
2561 use_valgrind
= ns
.use_valgrind
2562 enable_debug
= ns
.enable_debug
2563 asan_options
= ns
.asan_options
2564 lsan_options
= ns
.lsan_options
2565 ubsan_options
= ns
.ubsan_options
2568 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2569 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2571 networkctl_cmd
= [networkctl_bin
]
2572 wait_online_cmd
= [wait_online_bin
]
2575 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2577 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2579 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2581 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2584 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,