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 expectedFailureIfEthtoolDoesNotSupportDriver():
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_DRIVER=dummy' in ret
.stdout
.rstrip():
102 call('ip link del dummy99')
107 return unittest
.expectedFailure(func
)
112 os
.makedirs(network_unit_file_path
, exist_ok
=True)
113 os
.makedirs(networkd_ci_path
, exist_ok
=True)
115 shutil
.rmtree(networkd_ci_path
)
116 copytree(os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'conf'), networkd_ci_path
)
118 check_output('systemctl stop systemd-networkd.socket')
119 check_output('systemctl stop systemd-networkd.service')
128 'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin
,
132 drop_in
+= ['ExecStart=!!' + networkd_bin
]
134 drop_in
+= ['Environment=SYSTEMD_LOG_LEVEL=debug']
136 drop_in
+= ['Environment=ASAN_OPTIONS="' + asan_options
+ '"']
138 drop_in
+= ['Environment=LSAN_OPTIONS="' + lsan_options
+ '"']
140 drop_in
+= ['Environment=UBSAN_OPTIONS="' + ubsan_options
+ '"']
141 if asan_options
or lsan_options
or ubsan_options
:
142 drop_in
+= ['SystemCallFilter=']
143 if use_valgrind
or asan_options
or lsan_options
or ubsan_options
:
144 drop_in
+= ['MemoryDenyWriteExecute=no']
146 os
.makedirs('/run/systemd/system/systemd-networkd.service.d', exist_ok
=True)
147 with
open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode
='w') as f
:
148 f
.write('\n'.join(drop_in
))
150 check_output('systemctl daemon-reload')
151 print(check_output('systemctl cat systemd-networkd.service'))
153 def tearDownModule():
154 shutil
.rmtree(networkd_ci_path
)
156 check_output('systemctl stop systemd-networkd.service')
158 shutil
.rmtree('/run/systemd/system/systemd-networkd.service.d')
159 check_output('systemctl daemon-reload')
161 check_output('systemctl start systemd-networkd.socket')
162 check_output('systemctl start systemd-networkd.service')
164 def read_link_attr(link
, dev
, attribute
):
165 with
open(os
.path
.join(os
.path
.join(os
.path
.join('/sys/class/net/', link
), dev
), attribute
)) as f
:
166 return f
.readline().strip()
168 def read_bridge_port_attr(bridge
, link
, attribute
):
169 path_bridge
= os
.path
.join('/sys/devices/virtual/net', bridge
)
170 path_port
= 'lower_' + link
+ '/brport'
171 path
= os
.path
.join(path_bridge
, path_port
)
173 with
open(os
.path
.join(path
, attribute
)) as f
:
174 return f
.readline().strip()
176 def link_exists(link
):
177 return os
.path
.exists(os
.path
.join('/sys/class/net', link
))
179 def remove_links(links
):
181 if link_exists(link
):
182 call('ip link del dev', link
)
185 def remove_fou_ports(ports
):
187 call('ip fou del port', port
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
189 def remove_routing_policy_rule_tables(tables
):
193 rc
= call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
195 def remove_routes(routes
):
196 for route_type
, addr
in routes
:
197 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
199 def l2tp_tunnel_remove(tunnel_ids
):
200 output
= check_output('ip l2tp show tunnel')
201 for tid
in tunnel_ids
:
202 words
='Tunnel ' + tid
+ ', encap'
204 call('ip l2tp del tunnel tid', tid
)
207 def read_ipv6_sysctl_attr(link
, attribute
):
208 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
209 return f
.readline().strip()
211 def read_ipv4_sysctl_attr(link
, attribute
):
212 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
213 return f
.readline().strip()
215 def copy_unit_to_networkd_unit_path(*units
):
218 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
219 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
220 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
222 def remove_unit_from_networkd_path(units
):
224 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
225 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
226 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
227 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
229 def warn_about_firewalld():
230 rc
= call('systemctl -q is-active firewalld.service')
232 print('\nWARNING: firewalld.service is active. The test may fail.')
234 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
235 warn_about_firewalld()
236 dnsmasq_command
= f
'dnsmasq -8 /var/run/networkd-ci/test-dnsmasq-log-file --log-queries=extra --log-dhcp --pid-file=/var/run/networkd-ci/test-test-dnsmasq.pid --conf-file=/dev/null --interface=veth-peer --enable-ra --dhcp-range={ipv6_range},{lease_time} --dhcp-range={ipv4_range},{lease_time} -R --dhcp-leasefile=/var/run/networkd-ci/lease --dhcp-option=26,1492 --dhcp-option=option:router,192.168.5.1 --dhcp-option=33,192.168.5.4,192.168.5.5 --port=0 ' + additional_options
237 check_output(dnsmasq_command
)
239 def stop_dnsmasq(pid_file
):
240 if os
.path
.exists(pid_file
):
241 with
open(pid_file
, 'r') as f
:
242 pid
= f
.read().rstrip(' \t\r\n\0')
243 os
.kill(int(pid
), signal
.SIGTERM
)
247 def search_words_in_dnsmasq_log(words
, show_all
=False):
248 if os
.path
.exists(dnsmasq_log_file
):
249 with
open (dnsmasq_log_file
) as in_file
:
250 contents
= in_file
.read()
253 for line
in contents
.splitlines():
256 print("%s, %s" % (words
, line
))
260 def remove_lease_file():
261 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
262 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
264 def remove_log_file():
265 if os
.path
.exists(dnsmasq_log_file
):
266 os
.remove(dnsmasq_log_file
)
268 def start_networkd(sleep_sec
=5, remove_state_files
=True):
269 if (remove_state_files
and
270 os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state'))):
271 check_output('systemctl stop systemd-networkd')
272 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
273 check_output('systemctl start systemd-networkd')
275 check_output('systemctl restart systemd-networkd')
277 time
.sleep(sleep_sec
)
279 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
280 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
284 check_output(*args
, env
=env
)
285 except subprocess
.CalledProcessError
:
286 for link
in links_with_operstate
:
287 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
291 def get_operstate(link
, show_status
=True, setup_state
='configured'):
292 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
295 for line
in output
.splitlines():
296 if 'State:' in line
and (not setup_state
or setup_state
in line
):
297 return line
.split()[1]
301 def check_link_exists(self
, link
):
302 self
.assertTrue(link_exists(link
))
304 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
305 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
307 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
308 for i
in range(timeout_sec
):
311 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
312 if re
.search(address_regex
, output
):
315 self
.assertRegex(output
, address_regex
)
317 class NetworkctlTests(unittest
.TestCase
, Utilities
):
326 '11-dummy-mtu.netdev',
329 'netdev-link-local-addressing-yes.network',
333 remove_links(self
.links
)
336 remove_links(self
.links
)
337 remove_unit_from_networkd_path(self
.units
)
340 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
343 wait_online(['test1:degraded'])
345 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
346 self
.assertRegex(output
, '1 lo ')
347 self
.assertRegex(output
, 'test1')
349 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
350 self
.assertNotRegex(output
, '1 lo ')
351 self
.assertRegex(output
, 'test1')
353 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
354 self
.assertNotRegex(output
, '1 lo ')
355 self
.assertRegex(output
, 'test1')
357 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
358 self
.assertNotRegex(output
, '1: lo ')
359 self
.assertRegex(output
, 'test1')
361 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
362 self
.assertNotRegex(output
, '1: lo ')
363 self
.assertRegex(output
, 'test1')
366 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
369 wait_online(['test1:degraded'])
371 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
372 self
.assertRegex(output
, 'MTU: 1600')
374 @expectedFailureIfEthtoolDoesNotSupportDriver()
375 def test_udev_driver(self
):
376 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
377 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
380 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
382 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
383 self
.assertRegex(output
, 'Driver: dummy')
385 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
386 self
.assertRegex(output
, 'Driver: veth')
388 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
389 self
.assertRegex(output
, 'Driver: veth')
391 def test_delete_links(self
):
392 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
393 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
396 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
398 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
399 self
.assertFalse(link_exists('test1'))
400 self
.assertFalse(link_exists('veth99'))
401 self
.assertFalse(link_exists('veth-peer'))
403 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
462 '10-dropin-test.netdev',
466 '15-name-conflict-test.netdev',
469 '21-vlan-test1.network',
472 '25-6rd-tunnel.netdev',
474 '25-bond-balanced-tlb.netdev',
476 '25-bridge-configure-without-carrier.network',
478 '25-erspan-tunnel-local-any.netdev',
479 '25-erspan-tunnel.netdev',
480 '25-fou-gretap.netdev',
482 '25-fou-ipip.netdev',
483 '25-fou-ipproto-gre.netdev',
484 '25-fou-ipproto-ipip.netdev',
487 '25-gretap-tunnel-local-any.netdev',
488 '25-gretap-tunnel.netdev',
489 '25-gre-tunnel-local-any.netdev',
490 '25-gre-tunnel-remote-any.netdev',
491 '25-gre-tunnel.netdev',
492 '25-ip6gretap-tunnel-local-any.netdev',
493 '25-ip6gretap-tunnel.netdev',
494 '25-ip6gre-tunnel-local-any.netdev',
495 '25-ip6gre-tunnel-remote-any.netdev',
496 '25-ip6gre-tunnel.netdev',
497 '25-ip6tnl-tunnel-remote-any.netdev',
498 '25-ip6tnl-tunnel-local-any.netdev',
499 '25-ip6tnl-tunnel.netdev',
500 '25-ipip-tunnel-independent.netdev',
501 '25-ipip-tunnel-local-any.netdev',
502 '25-ipip-tunnel-remote-any.netdev',
503 '25-ipip-tunnel.netdev',
506 '25-isatap-tunnel.netdev',
511 '25-sit-tunnel-local-any.netdev',
512 '25-sit-tunnel-remote-any.netdev',
513 '25-sit-tunnel.netdev',
516 '25-tunnel-local-any.network',
517 '25-tunnel-remote-any.network',
522 '25-vti6-tunnel-local-any.netdev',
523 '25-vti6-tunnel-remote-any.netdev',
524 '25-vti6-tunnel.netdev',
525 '25-vti-tunnel-local-any.netdev',
526 '25-vti-tunnel-remote-any.netdev',
527 '25-vti-tunnel.netdev',
530 '25-wireguard-23-peers.netdev',
531 '25-wireguard-23-peers.network',
532 '25-wireguard-preshared-key.txt',
533 '25-wireguard-private-key.txt',
534 '25-wireguard.netdev',
535 '25-wireguard.network',
551 'netdev-link-local-addressing-yes.network',
555 'vxlan-test1.network',
563 remove_fou_ports(self
.fou_ports
)
564 remove_links(self
.links
)
567 remove_fou_ports(self
.fou_ports
)
568 remove_links(self
.links
)
569 remove_unit_from_networkd_path(self
.units
)
571 def test_dropin_and_name_conflict(self
):
572 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
575 wait_online(['dropin-test:off'])
577 output
= check_output('ip link show dropin-test')
579 self
.assertRegex(output
, '00:50:56:c0:00:28')
581 def test_wait_online_any(self
):
582 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
585 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
587 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
588 self
.check_operstate('test1', 'degraded')
590 def test_bridge(self
):
591 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
594 wait_online(['bridge99:no-carrier'])
596 tick
= os
.sysconf('SC_CLK_TCK')
597 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
598 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
599 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
600 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
601 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
602 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
603 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
604 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
607 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
610 wait_online(['bond99:off', 'bond98:off'])
612 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
613 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
614 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
615 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
616 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
617 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
618 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
619 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
620 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
621 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
622 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
624 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
625 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
628 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
629 '21-vlan.network', '21-vlan-test1.network')
632 wait_online(['test1:degraded', 'vlan99:routable'])
634 output
= check_output('ip -d link show test1')
636 self
.assertRegex(output
, ' mtu 2000 ')
638 output
= check_output('ip -d link show vlan99')
640 self
.assertRegex(output
, ' mtu 2000 ')
641 self
.assertRegex(output
, 'REORDER_HDR')
642 self
.assertRegex(output
, 'LOOSE_BINDING')
643 self
.assertRegex(output
, 'GVRP')
644 self
.assertRegex(output
, 'MVRP')
645 self
.assertRegex(output
, ' id 99 ')
647 output
= check_output('ip -4 address show dev test1')
649 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
650 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
652 output
= check_output('ip -4 address show dev vlan99')
654 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
656 def test_macvtap(self
):
657 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
658 with self
.subTest(mode
=mode
):
659 if mode
!= 'private':
661 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
662 '11-dummy.netdev', 'macvtap.network')
663 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
664 f
.write('[MACVTAP]\nMode=' + mode
)
667 wait_online(['macvtap99:degraded', 'test1:degraded'])
669 output
= check_output('ip -d link show macvtap99')
671 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
673 def test_macvlan(self
):
674 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
675 with self
.subTest(mode
=mode
):
676 if mode
!= 'private':
678 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
679 '11-dummy.netdev', 'macvlan.network')
680 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
681 f
.write('[MACVLAN]\nMode=' + mode
)
684 wait_online(['macvlan99:degraded', 'test1:degraded'])
686 output
= check_output('ip -d link show test1')
688 self
.assertRegex(output
, ' mtu 2000 ')
690 output
= check_output('ip -d link show macvlan99')
692 self
.assertRegex(output
, ' mtu 2000 ')
693 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
695 @expectedFailureIfModuleIsNotAvailable('ipvlan')
696 def test_ipvlan(self
):
697 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
698 with self
.subTest(mode
=mode
, flag
=flag
):
701 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
702 '11-dummy.netdev', 'ipvlan.network')
703 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
704 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
707 wait_online(['ipvlan99:degraded', 'test1:degraded'])
709 output
= check_output('ip -d link show ipvlan99')
711 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
713 @expectedFailureIfModuleIsNotAvailable('ipvtap')
714 def test_ipvtap(self
):
715 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
716 with self
.subTest(mode
=mode
, flag
=flag
):
719 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
720 '11-dummy.netdev', 'ipvtap.network')
721 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
722 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
725 wait_online(['ipvtap99:degraded', 'test1:degraded'])
727 output
= check_output('ip -d link show ipvtap99')
729 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
732 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
735 wait_online(['veth99:degraded', 'veth-peer:degraded'])
737 output
= check_output('ip -d link show veth99')
739 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
740 output
= check_output('ip -d link show veth-peer')
742 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
745 copy_unit_to_networkd_unit_path('25-tun.netdev')
748 wait_online(['tun99:off'])
750 output
= check_output('ip -d link show tun99')
752 # Old ip command does not support IFF_ flags
753 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
756 copy_unit_to_networkd_unit_path('25-tap.netdev')
759 wait_online(['tap99:off'])
761 output
= check_output('ip -d link show tap99')
763 # Old ip command does not support IFF_ flags
764 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
766 @expectedFailureIfModuleIsNotAvailable('vrf')
768 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
771 wait_online(['vrf99:carrier'])
773 @expectedFailureIfModuleIsNotAvailable('vcan')
775 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
778 wait_online(['vcan99:carrier'])
780 @expectedFailureIfModuleIsNotAvailable('vxcan')
781 def test_vxcan(self
):
782 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
785 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
787 @expectedFailureIfModuleIsNotAvailable('wireguard')
788 def test_wireguard(self
):
789 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
790 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
791 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
793 wait_online(['wg99:carrier', 'wg98:routable'])
795 if shutil
.which('wg'):
798 output
= check_output('wg show wg99 listen-port')
799 self
.assertRegex(output
, '51820')
800 output
= check_output('wg show wg99 fwmark')
801 self
.assertRegex(output
, '0x4d2')
802 output
= check_output('wg show wg99 allowed-ips')
803 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
804 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
805 output
= check_output('wg show wg99 persistent-keepalive')
806 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
807 output
= check_output('wg show wg99 endpoints')
808 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
809 output
= check_output('wg show wg99 private-key')
810 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
811 output
= check_output('wg show wg99 preshared-keys')
812 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
813 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
815 output
= check_output('wg show wg98 private-key')
816 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
818 def test_geneve(self
):
819 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
822 wait_online(['geneve99:degraded'])
824 output
= check_output('ip -d link show geneve99')
826 self
.assertRegex(output
, '192.168.22.1')
827 self
.assertRegex(output
, '6082')
828 self
.assertRegex(output
, 'udpcsum')
829 self
.assertRegex(output
, 'udp6zerocsumrx')
831 def test_ipip_tunnel(self
):
832 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
833 '25-ipip-tunnel.netdev', '25-tunnel.network',
834 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
835 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
837 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
839 output
= check_output('ip -d link show ipiptun99')
841 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
842 output
= check_output('ip -d link show ipiptun98')
844 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
845 output
= check_output('ip -d link show ipiptun97')
847 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
849 def test_gre_tunnel(self
):
850 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
851 '25-gre-tunnel.netdev', '25-tunnel.network',
852 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
853 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
855 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
857 output
= check_output('ip -d link show gretun99')
859 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
860 self
.assertRegex(output
, 'ikey 1.2.3.103')
861 self
.assertRegex(output
, 'okey 1.2.4.103')
862 self
.assertRegex(output
, 'iseq')
863 self
.assertRegex(output
, 'oseq')
864 output
= check_output('ip -d link show gretun98')
866 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
867 self
.assertRegex(output
, 'ikey 0.0.0.104')
868 self
.assertRegex(output
, 'okey 0.0.0.104')
869 self
.assertNotRegex(output
, 'iseq')
870 self
.assertNotRegex(output
, 'oseq')
871 output
= check_output('ip -d link show gretun97')
873 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
874 self
.assertRegex(output
, 'ikey 0.0.0.105')
875 self
.assertRegex(output
, 'okey 0.0.0.105')
876 self
.assertNotRegex(output
, 'iseq')
877 self
.assertNotRegex(output
, 'oseq')
879 def test_ip6gre_tunnel(self
):
880 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
881 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
882 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
883 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
886 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
888 self
.check_link_exists('dummy98')
889 self
.check_link_exists('ip6gretun99')
890 self
.check_link_exists('ip6gretun98')
891 self
.check_link_exists('ip6gretun97')
893 output
= check_output('ip -d link show ip6gretun99')
895 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
896 output
= check_output('ip -d link show ip6gretun98')
898 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
899 output
= check_output('ip -d link show ip6gretun97')
901 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
903 def test_gretap_tunnel(self
):
904 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
905 '25-gretap-tunnel.netdev', '25-tunnel.network',
906 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
908 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
910 output
= check_output('ip -d link show gretap99')
912 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
913 self
.assertRegex(output
, 'ikey 0.0.0.106')
914 self
.assertRegex(output
, 'okey 0.0.0.106')
915 self
.assertRegex(output
, 'iseq')
916 self
.assertRegex(output
, 'oseq')
917 output
= check_output('ip -d link show gretap98')
919 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
920 self
.assertRegex(output
, 'ikey 0.0.0.107')
921 self
.assertRegex(output
, 'okey 0.0.0.107')
922 self
.assertRegex(output
, 'iseq')
923 self
.assertRegex(output
, 'oseq')
925 def test_ip6gretap_tunnel(self
):
926 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
927 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
928 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
930 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
932 output
= check_output('ip -d link show ip6gretap99')
934 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
935 output
= check_output('ip -d link show ip6gretap98')
937 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
939 def test_vti_tunnel(self
):
940 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
941 '25-vti-tunnel.netdev', '25-tunnel.network',
942 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
943 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
945 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
947 output
= check_output('ip -d link show vtitun99')
949 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
950 output
= check_output('ip -d link show vtitun98')
952 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
953 output
= check_output('ip -d link show vtitun97')
955 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
957 def test_vti6_tunnel(self
):
958 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
959 '25-vti6-tunnel.netdev', '25-tunnel.network',
960 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
961 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
963 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
965 output
= check_output('ip -d link show vti6tun99')
967 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
968 output
= check_output('ip -d link show vti6tun98')
970 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
971 output
= check_output('ip -d link show vti6tun97')
973 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
975 def test_ip6tnl_tunnel(self
):
976 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
977 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
978 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
979 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
981 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
983 output
= check_output('ip -d link show ip6tnl99')
985 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
986 output
= check_output('ip -d link show ip6tnl98')
988 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
989 output
= check_output('ip -d link show ip6tnl97')
991 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
993 def test_sit_tunnel(self
):
994 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
995 '25-sit-tunnel.netdev', '25-tunnel.network',
996 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
997 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
999 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
1001 output
= check_output('ip -d link show sittun99')
1003 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1004 output
= check_output('ip -d link show sittun98')
1006 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1007 output
= check_output('ip -d link show sittun97')
1009 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1011 def test_isatap_tunnel(self
):
1012 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1013 '25-isatap-tunnel.netdev', '25-tunnel.network')
1015 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1017 output
= check_output('ip -d link show isataptun99')
1019 self
.assertRegex(output
, "isatap ")
1021 def test_6rd_tunnel(self
):
1022 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1023 '25-6rd-tunnel.netdev', '25-tunnel.network')
1025 wait_online(['sittun99:routable', 'dummy98:degraded'])
1027 output
= check_output('ip -d link show sittun99')
1029 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1031 @expectedFailureIfERSPANModuleIsNotAvailable()
1032 def test_erspan_tunnel(self
):
1033 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1034 '25-erspan-tunnel.netdev', '25-tunnel.network',
1035 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1037 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1039 output
= check_output('ip -d link show erspan99')
1041 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1042 self
.assertRegex(output
, 'ikey 0.0.0.101')
1043 self
.assertRegex(output
, 'okey 0.0.0.101')
1044 self
.assertRegex(output
, 'iseq')
1045 self
.assertRegex(output
, 'oseq')
1046 output
= check_output('ip -d link show erspan98')
1048 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1049 self
.assertRegex(output
, '102')
1050 self
.assertRegex(output
, 'ikey 0.0.0.102')
1051 self
.assertRegex(output
, 'okey 0.0.0.102')
1052 self
.assertRegex(output
, 'iseq')
1053 self
.assertRegex(output
, 'oseq')
1055 def test_tunnel_independent(self
):
1056 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1059 wait_online(['ipiptun99:carrier'])
1061 @expectedFailureIfModuleIsNotAvailable('fou')
1063 # The following redundant check is necessary for CentOS CI.
1064 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1065 self
.assertTrue(is_module_available('fou'))
1067 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1068 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1069 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1072 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1074 output
= check_output('ip fou show')
1076 self
.assertRegex(output
, 'port 55555 ipproto 4')
1077 self
.assertRegex(output
, 'port 55556 ipproto 47')
1079 output
= check_output('ip -d link show ipiptun96')
1081 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1082 output
= check_output('ip -d link show sittun96')
1084 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1085 output
= check_output('ip -d link show gretun96')
1087 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1088 output
= check_output('ip -d link show gretap96')
1090 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1092 def test_vxlan(self
):
1093 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1094 '11-dummy.netdev', 'vxlan-test1.network')
1097 wait_online(['test1:degraded', 'vxlan99:degraded'])
1099 output
= check_output('ip -d link show vxlan99')
1101 self
.assertRegex(output
, '999')
1102 self
.assertRegex(output
, '5555')
1103 self
.assertRegex(output
, 'l2miss')
1104 self
.assertRegex(output
, 'l3miss')
1105 self
.assertRegex(output
, 'udpcsum')
1106 self
.assertRegex(output
, 'udp6zerocsumtx')
1107 self
.assertRegex(output
, 'udp6zerocsumrx')
1108 self
.assertRegex(output
, 'remcsumtx')
1109 self
.assertRegex(output
, 'remcsumrx')
1110 self
.assertRegex(output
, 'gbp')
1112 output
= check_output('bridge fdb show dev vxlan99')
1114 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1115 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1116 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1118 def test_macsec(self
):
1119 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1120 'macsec.network', '12-dummy.netdev')
1123 wait_online(['dummy98:degraded', 'macsec99:routable'])
1125 output
= check_output('ip -d link show macsec99')
1127 self
.assertRegex(output
, 'macsec99@dummy98')
1128 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1129 self
.assertRegex(output
, 'encrypt on')
1131 output
= check_output('ip macsec show macsec99')
1133 self
.assertRegex(output
, 'encrypt on')
1134 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1135 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1136 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1137 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1138 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1139 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1140 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1141 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1142 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1143 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1144 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1146 def test_nlmon(self
):
1147 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1150 wait_online(['nlmon99:carrier'])
1152 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1163 '25-l2tp-dummy.network',
1164 '25-l2tp-ip.netdev',
1165 '25-l2tp-udp.netdev']
1167 l2tp_tunnel_ids
= [ '10' ]
1170 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1171 remove_links(self
.links
)
1174 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1175 remove_links(self
.links
)
1176 remove_unit_from_networkd_path(self
.units
)
1178 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1179 def test_l2tp_udp(self
):
1180 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1183 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1185 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1187 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1188 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1189 self
.assertRegex(output
, "Peer tunnel 11")
1190 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1191 self
.assertRegex(output
, "UDP checksum: enabled")
1193 output
= check_output('ip l2tp show session tid 10 session_id 15')
1195 self
.assertRegex(output
, "Session 15 in tunnel 10")
1196 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1197 self
.assertRegex(output
, "interface name: l2tp-ses1")
1199 output
= check_output('ip l2tp show session tid 10 session_id 17')
1201 self
.assertRegex(output
, "Session 17 in tunnel 10")
1202 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1203 self
.assertRegex(output
, "interface name: l2tp-ses2")
1205 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1206 def test_l2tp_ip(self
):
1207 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1210 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1212 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1214 self
.assertRegex(output
, "Tunnel 10, encap IP")
1215 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1216 self
.assertRegex(output
, "Peer tunnel 12")
1218 output
= check_output('ip l2tp show session tid 10 session_id 25')
1220 self
.assertRegex(output
, "Session 25 in tunnel 10")
1221 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1222 self
.assertRegex(output
, "interface name: l2tp-ses3")
1224 output
= check_output('ip l2tp show session tid 10 session_id 27')
1226 self
.assertRegex(output
, "Session 27 in tunnel 10")
1227 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1228 self
.assertRegex(output
, "interface name: l2tp-ses4")
1230 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1240 '23-active-slave.network',
1241 '24-keep-configuration-static.network',
1242 '24-search-domain.network',
1243 '25-address-link-section.network',
1244 '25-address-preferred-lifetime-zero-ipv6.network',
1245 '25-address-static.network',
1246 '25-bind-carrier.network',
1247 '25-bond-active-backup-slave.netdev',
1248 '25-fibrule-invert.network',
1249 '25-fibrule-port-range.network',
1250 '25-ipv6-address-label-section.network',
1251 '25-neighbor-section.network',
1252 '25-link-local-addressing-no.network',
1253 '25-link-local-addressing-yes.network',
1254 '25-link-section-unmanaged.network',
1255 '25-route-ipv6-src.network',
1256 '25-route-static.network',
1257 '25-sysctl-disable-ipv6.network',
1258 '25-sysctl.network',
1259 'configure-without-carrier.network',
1260 'routing-policy-rule-dummy98.network',
1261 'routing-policy-rule-test1.network']
1263 routing_policy_rule_tables
= ['7', '8']
1264 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1267 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1268 remove_routes(self
.routes
)
1269 remove_links(self
.links
)
1272 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1273 remove_routes(self
.routes
)
1274 remove_links(self
.links
)
1275 remove_unit_from_networkd_path(self
.units
)
1277 def test_address_static(self
):
1278 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1281 wait_online(['dummy98:routable'])
1283 output
= check_output('ip -4 address show dev dummy98')
1285 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1286 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1287 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1290 self
.assertNotRegex(output
, '10.10.0.1/16')
1291 self
.assertNotRegex(output
, '10.10.0.2/16')
1293 output
= check_output('ip -4 address show dev dummy98 label 32')
1294 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1296 output
= check_output('ip -4 address show dev dummy98 label 33')
1297 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1299 output
= check_output('ip -4 address show dev dummy98 label 34')
1300 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1302 output
= check_output('ip -4 address show dev dummy98 label 35')
1303 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1305 output
= check_output('ip -6 address show dev dummy98')
1307 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1308 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1309 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1310 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1311 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1312 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1314 def test_address_preferred_lifetime_zero_ipv6(self
):
1315 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1318 self
.check_link_exists('dummy98')
1319 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1321 output
= check_output('ip address show dummy98')
1323 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1324 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1326 def test_configure_without_carrier(self
):
1327 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1329 wait_online(['test1:routable'])
1331 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1333 self
.assertRegex(output
, '192.168.0.15')
1334 self
.assertRegex(output
, '192.168.0.1')
1335 self
.assertRegex(output
, 'routable')
1337 def test_routing_policy_rule(self
):
1338 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1340 wait_online(['test1:degraded'])
1342 output
= check_output('ip rule')
1344 self
.assertRegex(output
, '111')
1345 self
.assertRegex(output
, 'from 192.168.100.18')
1346 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1347 self
.assertRegex(output
, 'iif test1')
1348 self
.assertRegex(output
, 'oif test1')
1349 self
.assertRegex(output
, 'lookup 7')
1351 def test_routing_policy_rule_issue_11280(self
):
1352 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1353 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1355 for trial
in range(3):
1356 # Remove state files only first time
1357 start_networkd(0, remove_state_files
=(trial
== 0))
1358 wait_online(['test1:degraded', 'dummy98:degraded'])
1361 output
= check_output('ip rule list table 7')
1363 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1365 output
= check_output('ip rule list table 8')
1367 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1369 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1370 def test_routing_policy_rule_port_range(self
):
1371 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1373 wait_online(['test1:degraded'])
1375 output
= check_output('ip rule')
1377 self
.assertRegex(output
, '111')
1378 self
.assertRegex(output
, 'from 192.168.100.18')
1379 self
.assertRegex(output
, '1123-1150')
1380 self
.assertRegex(output
, '3224-3290')
1381 self
.assertRegex(output
, 'tcp')
1382 self
.assertRegex(output
, 'lookup 7')
1384 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1385 def test_routing_policy_rule_invert(self
):
1386 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1388 wait_online(['test1:degraded'])
1390 output
= check_output('ip rule')
1392 self
.assertRegex(output
, '111')
1393 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1394 self
.assertRegex(output
, 'tcp')
1395 self
.assertRegex(output
, 'lookup 7')
1397 def test_route_static(self
):
1398 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1400 wait_online(['dummy98:routable'])
1402 output
= check_output('ip -6 route show dev dummy98')
1404 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1405 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1407 output
= check_output('ip -6 route show dev dummy98 default')
1408 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1410 output
= check_output('ip -4 route show dev dummy98')
1412 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1413 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1414 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1415 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1416 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1418 output
= check_output('ip -4 route show dev dummy98 default')
1419 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1420 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1421 self
.assertRegex(output
, 'default proto static')
1423 output
= check_output('ip route show type blackhole')
1425 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1427 output
= check_output('ip route show type unreachable')
1429 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1431 output
= check_output('ip route show type prohibit')
1433 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1435 def test_ip_route_ipv6_src_route(self
):
1436 # a dummy device does not make the addresses go through tentative state, so we
1437 # reuse a bond from an earlier test, which does make the addresses go through
1438 # tentative state, and do our test on that
1439 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1441 wait_online(['dummy98:enslaved', 'bond199:routable'])
1443 output
= check_output('ip -6 route list dev bond199')
1445 self
.assertRegex(output
, 'abcd::/16')
1446 self
.assertRegex(output
, 'src')
1447 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1449 def test_ip_link_mac_address(self
):
1450 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1452 wait_online(['dummy98:degraded'])
1454 output
= check_output('ip link show dummy98')
1456 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1458 def test_ip_link_unmanaged(self
):
1459 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1462 self
.check_link_exists('dummy98')
1464 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1466 def test_ipv6_address_label(self
):
1467 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1469 wait_online(['dummy98:degraded'])
1471 output
= check_output('ip addrlabel list')
1473 self
.assertRegex(output
, '2004:da8:1::/64')
1475 def test_ipv6_neighbor(self
):
1476 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1478 wait_online(['dummy98:degraded'], timeout
='40s')
1480 output
= check_output('ip neigh list dev dummy98')
1482 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1483 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1485 def test_link_local_addressing(self
):
1486 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1487 '25-link-local-addressing-no.network', '12-dummy.netdev')
1489 wait_online(['test1:degraded', 'dummy98:carrier'])
1491 output
= check_output('ip address show dev test1')
1493 self
.assertRegex(output
, 'inet .* scope link')
1494 self
.assertRegex(output
, 'inet6 .* scope link')
1496 output
= check_output('ip address show dev dummy98')
1498 self
.assertNotRegex(output
, 'inet6* .* scope link')
1501 Documentation/networking/ip-sysctl.txt
1503 addr_gen_mode - INTEGER
1504 Defines how link-local and autoconf addresses are generated.
1506 0: generate address based on EUI64 (default)
1507 1: do no generate a link-local address, use EUI64 for addresses generated
1509 2: generate stable privacy addresses, using the secret from
1510 stable_secret (RFC7217)
1511 3: generate stable privacy addresses, using a random secret if unset
1514 test1_addr_gen_mode
= ''
1515 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1516 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1520 # if stable_secret is unset, then EIO is returned
1521 test1_addr_gen_mode
= '0'
1523 test1_addr_gen_mode
= '2'
1525 test1_addr_gen_mode
= '0'
1527 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1528 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1530 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1531 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1533 def test_sysctl(self
):
1534 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1536 wait_online(['dummy98:degraded'])
1538 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1539 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1540 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1541 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1542 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1543 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1544 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1546 def test_sysctl_disable_ipv6(self
):
1547 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1549 print('## Disable ipv6')
1550 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1551 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1554 wait_online(['dummy98:routable'])
1556 output
= check_output('ip -4 address show dummy98')
1558 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1559 output
= check_output('ip -6 address show dummy98')
1561 self
.assertEqual(output
, '')
1562 output
= check_output('ip -4 route show dev dummy98')
1564 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1565 output
= check_output('ip -6 route show dev dummy98')
1567 self
.assertEqual(output
, '')
1569 check_output('ip link del dummy98')
1571 print('## Enable ipv6')
1572 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1573 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1576 wait_online(['dummy98:routable'])
1578 output
= check_output('ip -4 address show dummy98')
1580 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1581 output
= check_output('ip -6 address show dummy98')
1583 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1584 self
.assertRegex(output
, 'inet6 .* scope link')
1585 output
= check_output('ip -4 route show dev dummy98')
1587 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1588 output
= check_output('ip -6 route show dev dummy98')
1590 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1592 def test_bind_carrier(self
):
1593 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1595 wait_online(['test1:routable'])
1597 check_output('ip link add dummy98 type dummy')
1598 check_output('ip link set dummy98 up')
1600 output
= check_output('ip address show test1')
1602 self
.assertRegex(output
, 'UP,LOWER_UP')
1603 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1604 self
.check_operstate('test1', 'routable')
1606 check_output('ip link add dummy99 type dummy')
1607 check_output('ip link set dummy99 up')
1609 output
= check_output('ip address show test1')
1611 self
.assertRegex(output
, 'UP,LOWER_UP')
1612 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1613 self
.check_operstate('test1', 'routable')
1615 check_output('ip link del dummy98')
1617 output
= check_output('ip address show test1')
1619 self
.assertRegex(output
, 'UP,LOWER_UP')
1620 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1621 self
.check_operstate('test1', 'routable')
1623 check_output('ip link del dummy99')
1625 output
= check_output('ip address show test1')
1627 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1628 self
.assertRegex(output
, 'DOWN')
1629 self
.assertNotRegex(output
, '192.168.10')
1630 self
.check_operstate('test1', 'off')
1632 check_output('ip link add dummy98 type dummy')
1633 check_output('ip link set dummy98 up')
1635 output
= check_output('ip address show test1')
1637 self
.assertRegex(output
, 'UP,LOWER_UP')
1638 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1639 self
.check_operstate('test1', 'routable')
1641 def test_domain(self
):
1642 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1644 wait_online(['dummy98:routable'])
1646 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1648 self
.assertRegex(output
, 'Address: 192.168.42.100')
1649 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1650 self
.assertRegex(output
, 'Search Domains: one')
1652 def test_keep_configuration_static(self
):
1653 check_output('systemctl stop systemd-networkd')
1655 check_output('ip link add name dummy98 type dummy')
1656 check_output('ip address add 10.1.2.3/16 dev dummy98')
1657 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1658 output
= check_output('ip address show dummy98')
1660 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1661 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1662 output
= check_output('ip route show dev dummy98')
1665 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1667 wait_online(['dummy98:routable'])
1669 output
= check_output('ip address show dummy98')
1671 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1672 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1674 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1684 '23-active-slave.network',
1685 '23-bond199.network',
1686 '23-primary-slave.network',
1687 '23-test1-bond199.network',
1688 '25-bond-active-backup-slave.netdev',
1691 'bond-slave.network']
1694 remove_links(self
.links
)
1697 remove_links(self
.links
)
1698 remove_unit_from_networkd_path(self
.units
)
1700 def test_bond_active_slave(self
):
1701 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1704 self
.check_link_exists('dummy98')
1705 self
.check_link_exists('bond199')
1707 output
= check_output('ip -d link show bond199')
1709 self
.assertRegex(output
, 'active_slave dummy98')
1711 def test_bond_primary_slave(self
):
1712 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1715 self
.check_link_exists('test1')
1716 self
.check_link_exists('bond199')
1718 output
= check_output('ip -d link show bond199')
1720 self
.assertRegex(output
, 'primary test1')
1722 def test_bond_operstate(self
):
1723 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1724 'bond99.network','bond-slave.network')
1727 self
.check_link_exists('bond99')
1728 self
.check_link_exists('dummy98')
1729 self
.check_link_exists('test1')
1731 output
= check_output('ip -d link show dummy98')
1733 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1735 output
= check_output('ip -d link show test1')
1737 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1739 output
= check_output('ip -d link show bond99')
1741 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1743 self
.check_operstate('dummy98', 'enslaved')
1744 self
.check_operstate('test1', 'enslaved')
1745 self
.check_operstate('bond99', 'routable')
1747 check_output('ip link set dummy98 down')
1750 self
.check_operstate('dummy98', 'off')
1751 self
.check_operstate('test1', 'enslaved')
1752 self
.check_operstate('bond99', 'degraded-carrier')
1754 check_output('ip link set dummy98 up')
1757 self
.check_operstate('dummy98', 'enslaved')
1758 self
.check_operstate('test1', 'enslaved')
1759 self
.check_operstate('bond99', 'routable')
1761 check_output('ip link set dummy98 down')
1762 check_output('ip link set test1 down')
1765 self
.check_operstate('dummy98', 'off')
1766 self
.check_operstate('test1', 'off')
1768 for trial
in range(30):
1771 output
= check_output('ip address show bond99')
1773 if get_operstate('bond99') == 'no-carrier':
1776 # Huh? Kernel does not recognize that all slave interfaces are down?
1777 # Let's confirm that networkd's operstate is consistent with ip's result.
1778 self
.assertNotRegex(output
, 'NO-CARRIER')
1780 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1790 '26-bridge-slave-interface-1.network',
1791 '26-bridge-slave-interface-2.network',
1792 'bridge99-ignore-carrier-loss.network',
1796 remove_links(self
.links
)
1799 remove_links(self
.links
)
1800 remove_unit_from_networkd_path(self
.units
)
1802 def test_bridge_property(self
):
1803 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1804 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1808 self
.check_link_exists('dummy98')
1809 self
.check_link_exists('test1')
1810 self
.check_link_exists('bridge99')
1812 output
= check_output('ip -d link show test1')
1814 self
.assertRegex(output
, 'master')
1815 self
.assertRegex(output
, 'bridge')
1817 output
= check_output('ip -d link show dummy98')
1819 self
.assertRegex(output
, 'master')
1820 self
.assertRegex(output
, 'bridge')
1822 output
= check_output('ip addr show bridge99')
1824 self
.assertRegex(output
, '192.168.0.15/24')
1826 output
= check_output('bridge -d link show dummy98')
1828 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1829 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1830 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1831 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1832 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1833 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1834 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1835 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1837 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1838 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1839 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1841 self
.check_operstate('test1', 'enslaved')
1842 self
.check_operstate('dummy98', 'enslaved')
1843 self
.check_operstate('bridge99', 'routable')
1845 check_output('ip address add 192.168.0.16/24 dev bridge99')
1848 output
= check_output('ip addr show bridge99')
1850 self
.assertRegex(output
, '192.168.0.16/24')
1852 self
.check_operstate('bridge99', 'routable')
1854 self
.assertEqual(call('ip link del test1'), 0)
1857 self
.check_operstate('bridge99', 'degraded-carrier')
1859 check_output('ip link del dummy98')
1862 self
.check_operstate('bridge99', 'no-carrier')
1864 output
= check_output('ip address show bridge99')
1866 self
.assertRegex(output
, 'NO-CARRIER')
1867 self
.assertNotRegex(output
, '192.168.0.15/24')
1868 self
.assertNotRegex(output
, '192.168.0.16/24')
1870 def test_bridge_ignore_carrier_loss(self
):
1871 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1872 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1873 'bridge99-ignore-carrier-loss.network')
1874 call('ip rule del table 100')
1878 self
.check_link_exists('dummy98')
1879 self
.check_link_exists('test1')
1880 self
.check_link_exists('bridge99')
1882 check_output('ip address add 192.168.0.16/24 dev bridge99')
1885 check_output('ip link del test1')
1886 check_output('ip link del dummy98')
1889 output
= check_output('ip address show bridge99')
1891 self
.assertRegex(output
, 'NO-CARRIER')
1892 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1893 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1895 call('ip rule del table 100')
1897 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1898 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1899 'bridge99-ignore-carrier-loss.network')
1901 call('ip rule del table 100')
1905 self
.check_link_exists('bridge99')
1907 check_output('ip link add dummy98 type dummy')
1908 check_output('ip link set dummy98 up')
1909 check_output('ip link del dummy98')
1911 check_output('ip link add dummy98 type dummy')
1912 check_output('ip link set dummy98 up')
1913 check_output('ip link del dummy98')
1915 check_output('ip link add dummy98 type dummy')
1916 check_output('ip link set dummy98 up')
1917 check_output('ip link del dummy98')
1919 check_output('ip link add dummy98 type dummy')
1920 check_output('ip link set dummy98 up')
1922 for trial
in range(30):
1925 if get_operstate('bridge99') == 'routable' and get_operstate('dummy98') == 'enslaved':
1928 self
.assertTrue(False)
1930 output
= check_output('ip address show bridge99')
1932 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1934 output
= check_output('ip rule list table 100')
1936 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
1938 call('ip rule del table 100')
1940 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
1944 '23-emit-lldp.network',
1949 remove_links(self
.links
)
1952 remove_links(self
.links
)
1953 remove_unit_from_networkd_path(self
.units
)
1955 def test_lldp(self
):
1956 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1958 wait_online(['veth99:degraded', 'veth-peer:degraded'])
1960 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
1962 self
.assertRegex(output
, 'veth-peer')
1963 self
.assertRegex(output
, 'veth99')
1965 class NetworkdRATests(unittest
.TestCase
, Utilities
):
1970 'ipv6-prefix.network',
1971 'ipv6-prefix-veth.network']
1974 remove_links(self
.links
)
1977 remove_links(self
.links
)
1978 remove_unit_from_networkd_path(self
.units
)
1980 def test_ipv6_prefix_delegation(self
):
1981 warn_about_firewalld()
1982 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1984 wait_online(['veth99:routable', 'veth-peer:degraded'])
1986 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
1988 self
.assertRegex(output
, '2002:da8:1:0')
1990 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
1995 'dhcp-client.network',
1996 'dhcp-client-timezone-router.network',
1997 'dhcp-server.network',
1998 'dhcp-server-timezone-router.network']
2001 remove_links(self
.links
)
2004 remove_links(self
.links
)
2005 remove_unit_from_networkd_path(self
.units
)
2007 def test_dhcp_server(self
):
2008 warn_about_firewalld()
2009 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2011 wait_online(['veth99:routable', 'veth-peer:routable'])
2013 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2015 self
.assertRegex(output
, '192.168.5.*')
2016 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2017 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2018 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2020 def test_emit_router_timezone(self
):
2021 warn_about_firewalld()
2022 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2024 wait_online(['veth99:routable', 'veth-peer:routable'])
2026 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2028 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2029 self
.assertRegex(output
, '192.168.5.*')
2030 self
.assertRegex(output
, 'Europe/Berlin')
2032 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2041 'dhcp-client-anonymize.network',
2042 'dhcp-client-gateway-onlink-implicit.network',
2043 'dhcp-client-ipv4-dhcp-settings.network',
2044 'dhcp-client-ipv4-only-ipv6-disabled.network',
2045 'dhcp-client-ipv4-only.network',
2046 'dhcp-client-ipv6-only.network',
2047 'dhcp-client-ipv6-rapid-commit.network',
2048 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2049 'dhcp-client-keep-configuration-dhcp.network',
2050 'dhcp-client-listen-port.network',
2051 'dhcp-client-route-metric.network',
2052 'dhcp-client-route-table.network',
2053 'dhcp-client-vrf.network',
2054 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2055 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2056 'dhcp-client.network',
2057 'dhcp-server-veth-peer.network',
2058 'dhcp-v4-server-veth-peer.network',
2062 stop_dnsmasq(dnsmasq_pid_file
)
2063 remove_links(self
.links
)
2066 stop_dnsmasq(dnsmasq_pid_file
)
2069 remove_links(self
.links
)
2070 remove_unit_from_networkd_path(self
.units
)
2072 def test_dhcp_client_ipv6_only(self
):
2073 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2076 wait_online(['veth-peer:carrier'])
2078 wait_online(['veth99:routable', 'veth-peer:routable'])
2080 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2082 self
.assertRegex(output
, '2600::')
2083 self
.assertNotRegex(output
, '192.168.5')
2085 # Confirm that ipv6 token is not set in the kernel
2086 output
= check_output('ip token show dev veth99')
2088 self
.assertRegex(output
, 'token :: dev veth99')
2090 def test_dhcp_client_ipv4_only(self
):
2091 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2094 wait_online(['veth-peer:carrier'])
2096 wait_online(['veth99:routable', 'veth-peer:routable'])
2098 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2100 self
.assertNotRegex(output
, '2600::')
2101 self
.assertRegex(output
, '192.168.5')
2103 def test_dhcp_client_ipv4_ipv6(self
):
2104 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2105 'dhcp-client-ipv4-only.network')
2107 wait_online(['veth-peer:carrier'])
2109 wait_online(['veth99:routable', 'veth-peer:routable'])
2111 # link become 'routable' when at least one protocol provide an valid address.
2112 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2113 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2115 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2117 self
.assertRegex(output
, '2600::')
2118 self
.assertRegex(output
, '192.168.5')
2120 def test_dhcp_client_settings(self
):
2121 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2124 wait_online(['veth-peer:carrier'])
2126 wait_online(['veth99:routable', 'veth-peer:routable'])
2128 print('## ip address show dev veth99')
2129 output
= check_output('ip address show dev veth99')
2131 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2132 self
.assertRegex(output
, '192.168.5')
2133 self
.assertRegex(output
, '1492')
2136 print('## ip route show table main dev veth99')
2137 output
= check_output('ip route show table main dev veth99')
2139 self
.assertNotRegex(output
, 'proto dhcp')
2141 print('## ip route show table 211 dev veth99')
2142 output
= check_output('ip route show table 211 dev veth99')
2144 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2145 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2146 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2148 print('## dnsmasq log')
2149 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2150 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2151 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2152 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2154 def test_dhcp6_client_settings_rapidcommit_true(self
):
2155 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2157 wait_online(['veth-peer:carrier'])
2159 wait_online(['veth99:routable', 'veth-peer:routable'])
2161 output
= check_output('ip address show dev veth99')
2163 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2164 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2166 def test_dhcp6_client_settings_rapidcommit_false(self
):
2167 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2169 wait_online(['veth-peer:carrier'])
2171 wait_online(['veth99:routable', 'veth-peer:routable'])
2173 output
= check_output('ip address show dev veth99')
2175 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2176 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2178 def test_dhcp_client_settings_anonymize(self
):
2179 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2181 wait_online(['veth-peer:carrier'])
2183 wait_online(['veth99:routable', 'veth-peer:routable'])
2185 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2186 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2187 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2189 def test_dhcp_client_listen_port(self
):
2190 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2192 wait_online(['veth-peer:carrier'])
2193 start_dnsmasq('--dhcp-alternate-port=67,5555')
2194 wait_online(['veth99:routable', 'veth-peer:routable'])
2196 # link become 'routable' when at least one protocol provide an valid address.
2197 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2198 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2200 output
= check_output('ip -4 address show dev veth99')
2202 self
.assertRegex(output
, '192.168.5.* dynamic')
2204 def test_dhcp_route_table_id(self
):
2205 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2207 wait_online(['veth-peer:carrier'])
2209 wait_online(['veth99:routable', 'veth-peer:routable'])
2211 output
= check_output('ip route show table 12')
2213 self
.assertRegex(output
, 'veth99 proto dhcp')
2214 self
.assertRegex(output
, '192.168.5.1')
2216 def test_dhcp_route_metric(self
):
2217 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2219 wait_online(['veth-peer:carrier'])
2221 wait_online(['veth99:routable', 'veth-peer:routable'])
2223 output
= check_output('ip route show dev veth99')
2225 self
.assertRegex(output
, 'metric 24')
2227 def test_dhcp_keep_configuration_dhcp(self
):
2228 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2230 wait_online(['veth-peer:carrier'])
2231 start_dnsmasq(lease_time
='2m')
2232 wait_online(['veth99:routable', 'veth-peer:routable'])
2234 output
= check_output('ip address show dev veth99 scope global')
2236 self
.assertRegex(output
, r
'192.168.5.*')
2238 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2240 self
.assertRegex(output
, r
'192.168.5.*')
2242 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2243 stop_dnsmasq(dnsmasq_pid_file
)
2245 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2246 print('Wait for the dynamic address to be expired')
2249 print('The lease address should be kept after lease expired')
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 check_output('systemctl stop systemd-networkd')
2260 print('The lease address should be kept after networkd stopped')
2261 output
= check_output('ip address show dev veth99 scope global')
2263 self
.assertRegex(output
, r
'192.168.5.*')
2265 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2267 self
.assertRegex(output
, r
'192.168.5.*')
2269 check_output('systemctl start systemd-networkd')
2270 wait_online(['veth-peer:routable'])
2272 print('Still the lease address should be kept after networkd restarted')
2273 output
= check_output('ip address show dev veth99 scope global')
2275 self
.assertRegex(output
, r
'192.168.5.*')
2277 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2279 self
.assertRegex(output
, r
'192.168.5.*')
2281 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2282 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2284 wait_online(['veth-peer:carrier'])
2285 start_dnsmasq(lease_time
='2m')
2286 wait_online(['veth99:routable', 'veth-peer:routable'])
2288 output
= check_output('ip address show dev veth99 scope global')
2290 self
.assertRegex(output
, r
'192.168.5.*')
2292 stop_dnsmasq(dnsmasq_pid_file
)
2293 check_output('systemctl stop systemd-networkd')
2295 output
= check_output('ip address show dev veth99 scope global')
2297 self
.assertRegex(output
, r
'192.168.5.*')
2300 wait_online(['veth-peer:routable'])
2302 output
= check_output('ip address show dev veth99 scope global')
2304 self
.assertNotRegex(output
, r
'192.168.5.*')
2306 def test_dhcp_client_reuse_address_as_static(self
):
2307 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2309 wait_online(['veth-peer:carrier'])
2311 wait_online(['veth99:routable', 'veth-peer:routable'])
2313 # link become 'routable' when at least one protocol provide an valid address.
2314 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2315 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2317 output
= check_output('ip address show dev veth99 scope global')
2319 self
.assertRegex(output
, '192.168.5')
2320 self
.assertRegex(output
, '2600::')
2322 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2323 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2324 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2325 print(static_network
)
2327 remove_unit_from_networkd_path(['dhcp-client.network'])
2329 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2330 f
.write(static_network
)
2332 # When networkd started, the links are already configured, so let's wait for 5 seconds
2333 # the links to be re-configured.
2335 wait_online(['veth99:routable', 'veth-peer:routable'])
2337 output
= check_output('ip -4 address show dev veth99 scope global')
2339 self
.assertRegex(output
, '192.168.5')
2340 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2342 output
= check_output('ip -6 address show dev veth99 scope global')
2344 self
.assertRegex(output
, '2600::')
2345 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2347 @expectedFailureIfModuleIsNotAvailable('vrf')
2348 def test_dhcp_client_vrf(self
):
2349 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2350 '25-vrf.netdev', '25-vrf.network')
2352 wait_online(['veth-peer:carrier'])
2354 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2356 # link become 'routable' when at least one protocol provide an valid address.
2357 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2358 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2360 print('## ip -d link show dev vrf99')
2361 output
= check_output('ip -d link show dev vrf99')
2363 self
.assertRegex(output
, 'vrf table 42')
2365 print('## ip address show vrf vrf99')
2366 output
= check_output('ip address show vrf vrf99')
2368 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2369 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2370 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2371 self
.assertRegex(output
, 'inet6 .* scope link')
2373 print('## ip address show dev veth99')
2374 output
= check_output('ip address show dev veth99')
2376 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2377 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2378 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2379 self
.assertRegex(output
, 'inet6 .* scope link')
2381 print('## ip route show vrf vrf99')
2382 output
= check_output('ip route show vrf vrf99')
2384 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2385 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2386 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2387 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2388 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2389 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2391 print('## ip route show table main dev veth99')
2392 output
= check_output('ip route show table main dev veth99')
2394 self
.assertEqual(output
, '')
2396 def test_dhcp_client_gateway_onlink_implicit(self
):
2397 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2398 'dhcp-client-gateway-onlink-implicit.network')
2400 wait_online(['veth-peer:carrier'])
2402 wait_online(['veth99:routable', 'veth-peer:routable'])
2404 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2406 self
.assertRegex(output
, '192.168.5')
2408 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2410 self
.assertRegex(output
, 'onlink')
2411 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2413 self
.assertRegex(output
, 'onlink')
2415 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2416 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2417 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2419 wait_online(['veth-peer:carrier'])
2420 start_dnsmasq(lease_time
='2m')
2421 wait_online(['veth99:routable', 'veth-peer:routable'])
2423 output
= check_output('ip address show dev veth99')
2426 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2427 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2428 output
= check_output('ip -6 address show dev veth99 scope link')
2429 self
.assertRegex(output
, 'inet6 .* scope link')
2430 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2431 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2432 output
= check_output('ip -4 address show dev veth99 scope link')
2433 self
.assertNotRegex(output
, 'inet .* scope link')
2435 print('Wait for the dynamic address to be expired')
2438 output
= check_output('ip address show dev veth99')
2441 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2442 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2443 output
= check_output('ip -6 address show dev veth99 scope link')
2444 self
.assertRegex(output
, 'inet6 .* scope link')
2445 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2446 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2447 output
= check_output('ip -4 address show dev veth99 scope link')
2448 self
.assertNotRegex(output
, 'inet .* scope link')
2450 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2452 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2453 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2454 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2456 wait_online(['veth99:degraded', 'veth-peer:routable'])
2458 output
= check_output('ip address show dev veth99')
2461 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2462 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2463 output
= check_output('ip -6 address show dev veth99 scope link')
2464 self
.assertRegex(output
, 'inet6 .* scope link')
2465 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2466 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2467 output
= check_output('ip -4 address show dev veth99 scope link')
2468 self
.assertRegex(output
, 'inet .* scope link')
2470 def test_dhcp_client_route_remove_on_renew(self
):
2471 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2472 'dhcp-client-ipv4-only-ipv6-disabled.network')
2474 wait_online(['veth-peer:carrier'])
2475 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2476 wait_online(['veth99:routable', 'veth-peer:routable'])
2478 # test for issue #12490
2480 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2482 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2484 for line
in output
.splitlines():
2485 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2486 address1
= line
.split()[1].split('/')[0]
2489 output
= check_output('ip -4 route show dev veth99')
2491 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2492 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2494 stop_dnsmasq(dnsmasq_pid_file
)
2495 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2497 print('Wait for the dynamic address to be expired')
2500 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2502 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2504 for line
in output
.splitlines():
2505 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2506 address2
= line
.split()[1].split('/')[0]
2509 self
.assertNotEqual(address1
, address2
)
2511 output
= check_output('ip -4 route show dev veth99')
2513 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2514 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2515 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2516 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2518 if __name__
== '__main__':
2519 parser
= argparse
.ArgumentParser()
2520 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2521 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2522 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2523 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2524 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2525 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2526 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2527 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2528 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2529 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2532 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2533 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2534 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2535 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2536 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2539 networkd_bin
= ns
.networkd_bin
2540 if ns
.wait_online_bin
:
2541 wait_online_bin
= ns
.wait_online_bin
2542 if ns
.networkctl_bin
:
2543 networkctl_bin
= ns
.networkctl_bin
2545 use_valgrind
= ns
.use_valgrind
2546 enable_debug
= ns
.enable_debug
2547 asan_options
= ns
.asan_options
2548 lsan_options
= ns
.lsan_options
2549 ubsan_options
= ns
.ubsan_options
2552 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2553 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2555 networkctl_cmd
= [networkctl_bin
]
2556 wait_online_cmd
= [wait_online_bin
]
2559 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2561 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2563 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2565 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2568 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,