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
):
191 call('ip rule del table', table
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
193 def remove_routes(routes
):
194 for route_type
, addr
in routes
:
195 call('ip route del', route_type
, addr
, stdout
=subprocess
.DEVNULL
, stderr
=subprocess
.DEVNULL
)
197 def l2tp_tunnel_remove(tunnel_ids
):
198 output
= check_output('ip l2tp show tunnel')
199 for tid
in tunnel_ids
:
200 words
='Tunnel ' + tid
+ ', encap'
202 call('ip l2tp del tunnel tid', tid
)
205 def read_ipv6_sysctl_attr(link
, attribute
):
206 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, link
), attribute
)) as f
:
207 return f
.readline().strip()
209 def read_ipv4_sysctl_attr(link
, attribute
):
210 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv4_path
, link
), attribute
)) as f
:
211 return f
.readline().strip()
213 def copy_unit_to_networkd_unit_path(*units
):
216 shutil
.copy(os
.path
.join(networkd_ci_path
, unit
), network_unit_file_path
)
217 if (os
.path
.exists(os
.path
.join(networkd_ci_path
, unit
+ '.d'))):
218 copytree(os
.path
.join(networkd_ci_path
, unit
+ '.d'), os
.path
.join(network_unit_file_path
, unit
+ '.d'))
220 def remove_unit_from_networkd_path(units
):
222 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
))):
223 os
.remove(os
.path
.join(network_unit_file_path
, unit
))
224 if (os
.path
.exists(os
.path
.join(network_unit_file_path
, unit
+ '.d'))):
225 shutil
.rmtree(os
.path
.join(network_unit_file_path
, unit
+ '.d'))
227 def warn_about_firewalld():
228 rc
= call('systemctl -q is-active firewalld.service')
230 print('\nWARNING: firewalld.service is active. The test may fail.')
232 def start_dnsmasq(additional_options
='', ipv4_range
='192.168.5.10,192.168.5.200', ipv6_range
='2600::10,2600::20', lease_time
='1h'):
233 warn_about_firewalld()
234 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
235 check_output(dnsmasq_command
)
237 def stop_dnsmasq(pid_file
):
238 if os
.path
.exists(pid_file
):
239 with
open(pid_file
, 'r') as f
:
240 pid
= f
.read().rstrip(' \t\r\n\0')
241 os
.kill(int(pid
), signal
.SIGTERM
)
245 def search_words_in_dnsmasq_log(words
, show_all
=False):
246 if os
.path
.exists(dnsmasq_log_file
):
247 with
open (dnsmasq_log_file
) as in_file
:
248 contents
= in_file
.read()
251 for line
in contents
.splitlines():
254 print("%s, %s" % (words
, line
))
258 def remove_lease_file():
259 if os
.path
.exists(os
.path
.join(networkd_ci_path
, 'lease')):
260 os
.remove(os
.path
.join(networkd_ci_path
, 'lease'))
262 def remove_log_file():
263 if os
.path
.exists(dnsmasq_log_file
):
264 os
.remove(dnsmasq_log_file
)
266 def start_networkd(sleep_sec
=5, remove_state_files
=True):
267 if (remove_state_files
and
268 os
.path
.exists(os
.path
.join(networkd_runtime_directory
, 'state'))):
269 check_output('systemctl stop systemd-networkd')
270 os
.remove(os
.path
.join(networkd_runtime_directory
, 'state'))
271 check_output('systemctl start systemd-networkd')
273 check_output('systemctl restart systemd-networkd')
275 time
.sleep(sleep_sec
)
277 def wait_online(links_with_operstate
, timeout
='20s', bool_any
=False):
278 args
= wait_online_cmd
+ [f
'--timeout={timeout}'] + [f
'--interface={link}' for link
in links_with_operstate
]
282 check_output(*args
, env
=env
)
283 except subprocess
.CalledProcessError
:
284 for link
in links_with_operstate
:
285 output
= check_output(*networkctl_cmd
, 'status', link
.split(':')[0], env
=env
)
289 def get_operstate(link
, show_status
=True, setup_state
='configured'):
290 output
= check_output(*networkctl_cmd
, 'status', link
, env
=env
)
293 for line
in output
.splitlines():
294 if 'State:' in line
and (not setup_state
or setup_state
in line
):
295 return line
.split()[1]
299 def check_link_exists(self
, link
):
300 self
.assertTrue(link_exists(link
))
302 def check_operstate(self
, link
, expected
, show_status
=True, setup_state
='configured'):
303 self
.assertRegex(get_operstate(link
, show_status
, setup_state
), expected
)
305 def wait_address(self
, link
, address_regex
, scope
='global', ipv
='', timeout_sec
=100):
306 for i
in range(timeout_sec
):
309 output
= check_output(f
'ip {ipv} address show dev {link} scope {scope}')
310 if re
.search(address_regex
, output
):
313 self
.assertRegex(output
, address_regex
)
315 class NetworkctlTests(unittest
.TestCase
, Utilities
):
324 '11-dummy-mtu.netdev',
327 'netdev-link-local-addressing-yes.network',
331 remove_links(self
.links
)
334 remove_links(self
.links
)
335 remove_unit_from_networkd_path(self
.units
)
338 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network')
341 wait_online(['test1:degraded'])
343 output
= check_output(*networkctl_cmd
, 'list', env
=env
)
344 self
.assertRegex(output
, '1 lo ')
345 self
.assertRegex(output
, 'test1')
347 output
= check_output(*networkctl_cmd
, 'list', 'test1', env
=env
)
348 self
.assertNotRegex(output
, '1 lo ')
349 self
.assertRegex(output
, 'test1')
351 output
= check_output(*networkctl_cmd
, 'list', 'te*', env
=env
)
352 self
.assertNotRegex(output
, '1 lo ')
353 self
.assertRegex(output
, 'test1')
355 output
= check_output(*networkctl_cmd
, 'status', 'te*', env
=env
)
356 self
.assertNotRegex(output
, '1: lo ')
357 self
.assertRegex(output
, 'test1')
359 output
= check_output(*networkctl_cmd
, 'status', 'tes[a-z][0-9]', env
=env
)
360 self
.assertNotRegex(output
, '1: lo ')
361 self
.assertRegex(output
, 'test1')
364 copy_unit_to_networkd_unit_path('11-dummy-mtu.netdev', '11-dummy.network')
367 wait_online(['test1:degraded'])
369 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
370 self
.assertRegex(output
, 'MTU: 1600')
372 @expectedFailureIfEthtoolDoesNotSupportDriver()
373 def test_udev_driver(self
):
374 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
375 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
378 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
380 output
= check_output(*networkctl_cmd
, 'status', 'test1', env
=env
)
381 self
.assertRegex(output
, 'Driver: dummy')
383 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
384 self
.assertRegex(output
, 'Driver: veth')
386 output
= check_output(*networkctl_cmd
, 'status', 'veth-peer', env
=env
)
387 self
.assertRegex(output
, 'Driver: veth')
389 def test_delete_links(self
):
390 copy_unit_to_networkd_unit_path('11-dummy.netdev', '11-dummy.network',
391 '25-veth.netdev', 'netdev-link-local-addressing-yes.network')
394 wait_online(['test1:degraded', 'veth99:degraded', 'veth-peer:degraded'])
396 check_output(*networkctl_cmd
, 'delete', 'test1', 'veth99')
397 self
.assertFalse(link_exists('test1'))
398 self
.assertFalse(link_exists('veth99'))
399 self
.assertFalse(link_exists('veth-peer'))
401 class NetworkdNetDevTests(unittest
.TestCase
, Utilities
):
460 '10-dropin-test.netdev',
464 '15-name-conflict-test.netdev',
467 '21-vlan-test1.network',
470 '25-6rd-tunnel.netdev',
472 '25-bond-balanced-tlb.netdev',
475 '25-erspan-tunnel-local-any.netdev',
476 '25-erspan-tunnel.netdev',
477 '25-fou-gretap.netdev',
479 '25-fou-ipip.netdev',
480 '25-fou-ipproto-gre.netdev',
481 '25-fou-ipproto-ipip.netdev',
484 '25-gretap-tunnel-local-any.netdev',
485 '25-gretap-tunnel.netdev',
486 '25-gre-tunnel-local-any.netdev',
487 '25-gre-tunnel-remote-any.netdev',
488 '25-gre-tunnel.netdev',
489 '25-ip6gretap-tunnel-local-any.netdev',
490 '25-ip6gretap-tunnel.netdev',
491 '25-ip6gre-tunnel-local-any.netdev',
492 '25-ip6gre-tunnel-remote-any.netdev',
493 '25-ip6gre-tunnel.netdev',
494 '25-ip6tnl-tunnel-remote-any.netdev',
495 '25-ip6tnl-tunnel-local-any.netdev',
496 '25-ip6tnl-tunnel.netdev',
497 '25-ipip-tunnel-independent.netdev',
498 '25-ipip-tunnel-local-any.netdev',
499 '25-ipip-tunnel-remote-any.netdev',
500 '25-ipip-tunnel.netdev',
503 '25-isatap-tunnel.netdev',
508 '25-sit-tunnel-local-any.netdev',
509 '25-sit-tunnel-remote-any.netdev',
510 '25-sit-tunnel.netdev',
513 '25-tunnel-local-any.network',
514 '25-tunnel-remote-any.network',
519 '25-vti6-tunnel-local-any.netdev',
520 '25-vti6-tunnel-remote-any.netdev',
521 '25-vti6-tunnel.netdev',
522 '25-vti-tunnel-local-any.netdev',
523 '25-vti-tunnel-remote-any.netdev',
524 '25-vti-tunnel.netdev',
527 '25-wireguard-23-peers.netdev',
528 '25-wireguard-23-peers.network',
529 '25-wireguard-preshared-key.txt',
530 '25-wireguard-private-key.txt',
531 '25-wireguard.netdev',
532 '25-wireguard.network',
548 'netdev-link-local-addressing-yes.network',
552 'vxlan-test1.network',
560 remove_fou_ports(self
.fou_ports
)
561 remove_links(self
.links
)
564 remove_fou_ports(self
.fou_ports
)
565 remove_links(self
.links
)
566 remove_unit_from_networkd_path(self
.units
)
568 def test_dropin_and_name_conflict(self
):
569 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
572 wait_online(['dropin-test:off'])
574 output
= check_output('ip link show dropin-test')
576 self
.assertRegex(output
, '00:50:56:c0:00:28')
578 def test_wait_online_any(self
):
579 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
582 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
584 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
585 self
.check_operstate('test1', 'degraded')
587 def test_bridge(self
):
588 copy_unit_to_networkd_unit_path('25-bridge.netdev')
591 wait_online(['bridge99:off'])
593 tick
= os
.sysconf('SC_CLK_TCK')
594 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
595 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
596 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
597 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
598 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
599 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
600 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
601 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
604 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
607 wait_online(['bond99:off', 'bond98:off'])
609 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
610 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
611 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
612 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
613 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
614 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
615 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
616 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
617 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
618 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
619 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
621 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
622 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
625 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
626 '21-vlan.network', '21-vlan-test1.network')
629 wait_online(['test1:degraded', 'vlan99:routable'])
631 output
= check_output('ip -d link show test1')
633 self
.assertRegex(output
, ' mtu 2000 ')
635 output
= check_output('ip -d link show vlan99')
637 self
.assertRegex(output
, ' mtu 2000 ')
638 self
.assertRegex(output
, 'REORDER_HDR')
639 self
.assertRegex(output
, 'LOOSE_BINDING')
640 self
.assertRegex(output
, 'GVRP')
641 self
.assertRegex(output
, 'MVRP')
642 self
.assertRegex(output
, ' id 99 ')
644 output
= check_output('ip -4 address show dev test1')
646 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
647 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
649 output
= check_output('ip -4 address show dev vlan99')
651 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
653 def test_macvtap(self
):
654 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
655 with self
.subTest(mode
=mode
):
656 if mode
!= 'private':
658 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
659 '11-dummy.netdev', 'macvtap.network')
660 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
661 f
.write('[MACVTAP]\nMode=' + mode
)
664 wait_online(['macvtap99:degraded', 'test1:degraded'])
666 output
= check_output('ip -d link show macvtap99')
668 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
670 def test_macvlan(self
):
671 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
672 with self
.subTest(mode
=mode
):
673 if mode
!= 'private':
675 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
676 '11-dummy.netdev', 'macvlan.network')
677 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
678 f
.write('[MACVLAN]\nMode=' + mode
)
681 wait_online(['macvlan99:degraded', 'test1:degraded'])
683 output
= check_output('ip -d link show test1')
685 self
.assertRegex(output
, ' mtu 2000 ')
687 output
= check_output('ip -d link show macvlan99')
689 self
.assertRegex(output
, ' mtu 2000 ')
690 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
692 @expectedFailureIfModuleIsNotAvailable('ipvlan')
693 def test_ipvlan(self
):
694 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
695 with self
.subTest(mode
=mode
, flag
=flag
):
698 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
699 '11-dummy.netdev', 'ipvlan.network')
700 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
701 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
704 wait_online(['ipvlan99:degraded', 'test1:degraded'])
706 output
= check_output('ip -d link show ipvlan99')
708 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
710 @expectedFailureIfModuleIsNotAvailable('ipvtap')
711 def test_ipvtap(self
):
712 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
713 with self
.subTest(mode
=mode
, flag
=flag
):
716 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
717 '11-dummy.netdev', 'ipvtap.network')
718 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
719 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
722 wait_online(['ipvtap99:degraded', 'test1:degraded'])
724 output
= check_output('ip -d link show ipvtap99')
726 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
729 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
732 wait_online(['veth99:degraded', 'veth-peer:degraded'])
734 output
= check_output('ip -d link show veth99')
736 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
737 output
= check_output('ip -d link show veth-peer')
739 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
742 copy_unit_to_networkd_unit_path('25-tun.netdev')
745 wait_online(['tun99:off'])
747 output
= check_output('ip -d link show tun99')
749 # Old ip command does not support IFF_ flags
750 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
753 copy_unit_to_networkd_unit_path('25-tap.netdev')
756 wait_online(['tap99:off'])
758 output
= check_output('ip -d link show tap99')
760 # Old ip command does not support IFF_ flags
761 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
763 @expectedFailureIfModuleIsNotAvailable('vrf')
765 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
768 wait_online(['vrf99:carrier'])
770 @expectedFailureIfModuleIsNotAvailable('vcan')
772 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
775 wait_online(['vcan99:carrier'])
777 @expectedFailureIfModuleIsNotAvailable('vxcan')
778 def test_vxcan(self
):
779 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
782 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
784 @expectedFailureIfModuleIsNotAvailable('wireguard')
785 def test_wireguard(self
):
786 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
787 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
788 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
790 wait_online(['wg99:carrier', 'wg98:routable'])
792 if shutil
.which('wg'):
795 output
= check_output('wg show wg99 listen-port')
796 self
.assertRegex(output
, '51820')
797 output
= check_output('wg show wg99 fwmark')
798 self
.assertRegex(output
, '0x4d2')
799 output
= check_output('wg show wg99 allowed-ips')
800 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
801 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
802 output
= check_output('wg show wg99 persistent-keepalive')
803 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
804 output
= check_output('wg show wg99 endpoints')
805 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
806 output
= check_output('wg show wg99 private-key')
807 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
808 output
= check_output('wg show wg99 preshared-keys')
809 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
810 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
812 output
= check_output('wg show wg98 private-key')
813 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
815 def test_geneve(self
):
816 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
819 wait_online(['geneve99:degraded'])
821 output
= check_output('ip -d link show geneve99')
823 self
.assertRegex(output
, '192.168.22.1')
824 self
.assertRegex(output
, '6082')
825 self
.assertRegex(output
, 'udpcsum')
826 self
.assertRegex(output
, 'udp6zerocsumrx')
828 def test_ipip_tunnel(self
):
829 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
830 '25-ipip-tunnel.netdev', '25-tunnel.network',
831 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
832 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
834 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
836 output
= check_output('ip -d link show ipiptun99')
838 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
839 output
= check_output('ip -d link show ipiptun98')
841 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
842 output
= check_output('ip -d link show ipiptun97')
844 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
846 def test_gre_tunnel(self
):
847 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
848 '25-gre-tunnel.netdev', '25-tunnel.network',
849 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
850 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
852 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
854 output
= check_output('ip -d link show gretun99')
856 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
857 self
.assertRegex(output
, 'ikey 1.2.3.103')
858 self
.assertRegex(output
, 'okey 1.2.4.103')
859 self
.assertRegex(output
, 'iseq')
860 self
.assertRegex(output
, 'oseq')
861 output
= check_output('ip -d link show gretun98')
863 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
864 self
.assertRegex(output
, 'ikey 0.0.0.104')
865 self
.assertRegex(output
, 'okey 0.0.0.104')
866 self
.assertNotRegex(output
, 'iseq')
867 self
.assertNotRegex(output
, 'oseq')
868 output
= check_output('ip -d link show gretun97')
870 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
871 self
.assertRegex(output
, 'ikey 0.0.0.105')
872 self
.assertRegex(output
, 'okey 0.0.0.105')
873 self
.assertNotRegex(output
, 'iseq')
874 self
.assertNotRegex(output
, 'oseq')
876 def test_ip6gre_tunnel(self
):
877 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
878 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
879 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
880 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
883 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
885 self
.check_link_exists('dummy98')
886 self
.check_link_exists('ip6gretun99')
887 self
.check_link_exists('ip6gretun98')
888 self
.check_link_exists('ip6gretun97')
890 output
= check_output('ip -d link show ip6gretun99')
892 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
893 output
= check_output('ip -d link show ip6gretun98')
895 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
896 output
= check_output('ip -d link show ip6gretun97')
898 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
900 def test_gretap_tunnel(self
):
901 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
902 '25-gretap-tunnel.netdev', '25-tunnel.network',
903 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
905 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
907 output
= check_output('ip -d link show gretap99')
909 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
910 self
.assertRegex(output
, 'ikey 0.0.0.106')
911 self
.assertRegex(output
, 'okey 0.0.0.106')
912 self
.assertRegex(output
, 'iseq')
913 self
.assertRegex(output
, 'oseq')
914 output
= check_output('ip -d link show gretap98')
916 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
917 self
.assertRegex(output
, 'ikey 0.0.0.107')
918 self
.assertRegex(output
, 'okey 0.0.0.107')
919 self
.assertRegex(output
, 'iseq')
920 self
.assertRegex(output
, 'oseq')
922 def test_ip6gretap_tunnel(self
):
923 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
924 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
925 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
927 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
929 output
= check_output('ip -d link show ip6gretap99')
931 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
932 output
= check_output('ip -d link show ip6gretap98')
934 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
936 def test_vti_tunnel(self
):
937 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
938 '25-vti-tunnel.netdev', '25-tunnel.network',
939 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
940 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
942 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
944 output
= check_output('ip -d link show vtitun99')
946 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
947 output
= check_output('ip -d link show vtitun98')
949 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
950 output
= check_output('ip -d link show vtitun97')
952 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
954 def test_vti6_tunnel(self
):
955 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
956 '25-vti6-tunnel.netdev', '25-tunnel.network',
957 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
958 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
960 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
962 output
= check_output('ip -d link show vti6tun99')
964 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
965 output
= check_output('ip -d link show vti6tun98')
967 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
968 output
= check_output('ip -d link show vti6tun97')
970 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
972 def test_ip6tnl_tunnel(self
):
973 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
974 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
975 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
976 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
978 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
980 output
= check_output('ip -d link show ip6tnl99')
982 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
983 output
= check_output('ip -d link show ip6tnl98')
985 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
986 output
= check_output('ip -d link show ip6tnl97')
988 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
990 def test_sit_tunnel(self
):
991 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
992 '25-sit-tunnel.netdev', '25-tunnel.network',
993 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
994 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
996 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
998 output
= check_output('ip -d link show sittun99')
1000 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1001 output
= check_output('ip -d link show sittun98')
1003 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1004 output
= check_output('ip -d link show sittun97')
1006 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1008 def test_isatap_tunnel(self
):
1009 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1010 '25-isatap-tunnel.netdev', '25-tunnel.network')
1012 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1014 output
= check_output('ip -d link show isataptun99')
1016 self
.assertRegex(output
, "isatap ")
1018 def test_6rd_tunnel(self
):
1019 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1020 '25-6rd-tunnel.netdev', '25-tunnel.network')
1022 wait_online(['sittun99:routable', 'dummy98:degraded'])
1024 output
= check_output('ip -d link show sittun99')
1026 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1028 @expectedFailureIfERSPANModuleIsNotAvailable()
1029 def test_erspan_tunnel(self
):
1030 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1031 '25-erspan-tunnel.netdev', '25-tunnel.network',
1032 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1034 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1036 output
= check_output('ip -d link show erspan99')
1038 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1039 self
.assertRegex(output
, 'ikey 0.0.0.101')
1040 self
.assertRegex(output
, 'okey 0.0.0.101')
1041 self
.assertRegex(output
, 'iseq')
1042 self
.assertRegex(output
, 'oseq')
1043 output
= check_output('ip -d link show erspan98')
1045 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1046 self
.assertRegex(output
, '102')
1047 self
.assertRegex(output
, 'ikey 0.0.0.102')
1048 self
.assertRegex(output
, 'okey 0.0.0.102')
1049 self
.assertRegex(output
, 'iseq')
1050 self
.assertRegex(output
, 'oseq')
1052 def test_tunnel_independent(self
):
1053 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1056 wait_online(['ipiptun99:carrier'])
1058 @expectedFailureIfModuleIsNotAvailable('fou')
1060 # The following redundant check is necessary for CentOS CI.
1061 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1062 self
.assertTrue(is_module_available('fou'))
1064 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1065 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1066 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1069 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1071 output
= check_output('ip fou show')
1073 self
.assertRegex(output
, 'port 55555 ipproto 4')
1074 self
.assertRegex(output
, 'port 55556 ipproto 47')
1076 output
= check_output('ip -d link show ipiptun96')
1078 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1079 output
= check_output('ip -d link show sittun96')
1081 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1082 output
= check_output('ip -d link show gretun96')
1084 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1085 output
= check_output('ip -d link show gretap96')
1087 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1089 def test_vxlan(self
):
1090 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1091 '11-dummy.netdev', 'vxlan-test1.network')
1094 wait_online(['test1:degraded', 'vxlan99:degraded'])
1096 output
= check_output('ip -d link show vxlan99')
1098 self
.assertRegex(output
, '999')
1099 self
.assertRegex(output
, '5555')
1100 self
.assertRegex(output
, 'l2miss')
1101 self
.assertRegex(output
, 'l3miss')
1102 self
.assertRegex(output
, 'udpcsum')
1103 self
.assertRegex(output
, 'udp6zerocsumtx')
1104 self
.assertRegex(output
, 'udp6zerocsumrx')
1105 self
.assertRegex(output
, 'remcsumtx')
1106 self
.assertRegex(output
, 'remcsumrx')
1107 self
.assertRegex(output
, 'gbp')
1109 output
= check_output('bridge fdb show dev vxlan99')
1111 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1112 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1113 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1115 def test_macsec(self
):
1116 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1117 'macsec.network', '12-dummy.netdev')
1120 wait_online(['dummy98:degraded', 'macsec99:routable'])
1122 output
= check_output('ip -d link show macsec99')
1124 self
.assertRegex(output
, 'macsec99@dummy98')
1125 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1126 self
.assertRegex(output
, 'encrypt on')
1128 output
= check_output('ip macsec show macsec99')
1130 self
.assertRegex(output
, 'encrypt on')
1131 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1132 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1133 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1134 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1135 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1136 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1137 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1138 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1139 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1140 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1141 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1143 def test_nlmon(self
):
1144 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1147 wait_online(['nlmon99:carrier'])
1149 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1160 '25-l2tp-dummy.network',
1161 '25-l2tp-ip.netdev',
1162 '25-l2tp-udp.netdev']
1164 l2tp_tunnel_ids
= [ '10' ]
1167 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1168 remove_links(self
.links
)
1171 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1172 remove_links(self
.links
)
1173 remove_unit_from_networkd_path(self
.units
)
1175 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1176 def test_l2tp_udp(self
):
1177 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1180 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1182 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1184 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1185 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1186 self
.assertRegex(output
, "Peer tunnel 11")
1187 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1188 self
.assertRegex(output
, "UDP checksum: enabled")
1190 output
= check_output('ip l2tp show session tid 10 session_id 15')
1192 self
.assertRegex(output
, "Session 15 in tunnel 10")
1193 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1194 self
.assertRegex(output
, "interface name: l2tp-ses1")
1196 output
= check_output('ip l2tp show session tid 10 session_id 17')
1198 self
.assertRegex(output
, "Session 17 in tunnel 10")
1199 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1200 self
.assertRegex(output
, "interface name: l2tp-ses2")
1202 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1203 def test_l2tp_ip(self
):
1204 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1207 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1209 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1211 self
.assertRegex(output
, "Tunnel 10, encap IP")
1212 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1213 self
.assertRegex(output
, "Peer tunnel 12")
1215 output
= check_output('ip l2tp show session tid 10 session_id 25')
1217 self
.assertRegex(output
, "Session 25 in tunnel 10")
1218 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1219 self
.assertRegex(output
, "interface name: l2tp-ses3")
1221 output
= check_output('ip l2tp show session tid 10 session_id 27')
1223 self
.assertRegex(output
, "Session 27 in tunnel 10")
1224 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1225 self
.assertRegex(output
, "interface name: l2tp-ses4")
1227 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1237 '23-active-slave.network',
1238 '24-keep-configuration-static.network',
1239 '24-search-domain.network',
1240 '25-address-link-section.network',
1241 '25-address-preferred-lifetime-zero-ipv6.network',
1242 '25-address-static.network',
1243 '25-bind-carrier.network',
1244 '25-bond-active-backup-slave.netdev',
1245 '25-fibrule-invert.network',
1246 '25-fibrule-port-range.network',
1247 '25-ipv6-address-label-section.network',
1248 '25-neighbor-section.network',
1249 '25-link-local-addressing-no.network',
1250 '25-link-local-addressing-yes.network',
1251 '25-link-section-unmanaged.network',
1252 '25-route-ipv6-src.network',
1253 '25-route-static.network',
1254 '25-sysctl-disable-ipv6.network',
1255 '25-sysctl.network',
1256 'configure-without-carrier.network',
1257 'routing-policy-rule-dummy98.network',
1258 'routing-policy-rule-test1.network']
1260 routing_policy_rule_tables
= ['7', '8']
1261 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1264 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1265 remove_routes(self
.routes
)
1266 remove_links(self
.links
)
1269 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1270 remove_routes(self
.routes
)
1271 remove_links(self
.links
)
1272 remove_unit_from_networkd_path(self
.units
)
1274 def test_address_static(self
):
1275 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1278 wait_online(['dummy98:routable'])
1280 output
= check_output('ip -4 address show dev dummy98')
1282 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1283 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1284 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1287 self
.assertNotRegex(output
, '10.10.0.1/16')
1288 self
.assertNotRegex(output
, '10.10.0.2/16')
1290 output
= check_output('ip -4 address show dev dummy98 label 32')
1291 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1293 output
= check_output('ip -4 address show dev dummy98 label 33')
1294 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1296 output
= check_output('ip -4 address show dev dummy98 label 34')
1297 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1299 output
= check_output('ip -4 address show dev dummy98 label 35')
1300 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1302 output
= check_output('ip -6 address show dev dummy98')
1304 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1305 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1306 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1307 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1308 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1309 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1311 def test_address_preferred_lifetime_zero_ipv6(self
):
1312 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1315 self
.check_link_exists('dummy98')
1316 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1318 output
= check_output('ip address show dummy98')
1320 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1321 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1323 def test_configure_without_carrier(self
):
1324 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1326 wait_online(['test1:routable'])
1328 output
= check_output(*networkctl_cmd
, 'status', 'test1')
1330 self
.assertRegex(output
, '192.168.0.15')
1331 self
.assertRegex(output
, '192.168.0.1')
1332 self
.assertRegex(output
, 'routable')
1334 def test_routing_policy_rule(self
):
1335 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
1337 wait_online(['test1:degraded'])
1339 output
= check_output('ip rule')
1341 self
.assertRegex(output
, '111')
1342 self
.assertRegex(output
, 'from 192.168.100.18')
1343 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1344 self
.assertRegex(output
, 'iif test1')
1345 self
.assertRegex(output
, 'oif test1')
1346 self
.assertRegex(output
, 'lookup 7')
1348 def test_routing_policy_rule_issue_11280(self
):
1349 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1350 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1352 for trial
in range(3):
1353 # Remove state files only first time
1354 start_networkd(0, remove_state_files
=(trial
== 0))
1355 wait_online(['test1:degraded', 'dummy98:degraded'])
1358 output
= check_output('ip rule list table 7')
1360 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1362 output
= check_output('ip rule list table 8')
1364 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1366 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1367 def test_routing_policy_rule_port_range(self
):
1368 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1370 wait_online(['test1:degraded'])
1372 output
= check_output('ip rule')
1374 self
.assertRegex(output
, '111')
1375 self
.assertRegex(output
, 'from 192.168.100.18')
1376 self
.assertRegex(output
, '1123-1150')
1377 self
.assertRegex(output
, '3224-3290')
1378 self
.assertRegex(output
, 'tcp')
1379 self
.assertRegex(output
, 'lookup 7')
1381 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1382 def test_routing_policy_rule_invert(self
):
1383 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1385 wait_online(['test1:degraded'])
1387 output
= check_output('ip rule')
1389 self
.assertRegex(output
, '111')
1390 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1391 self
.assertRegex(output
, 'tcp')
1392 self
.assertRegex(output
, 'lookup 7')
1394 def test_route_static(self
):
1395 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1397 wait_online(['dummy98:routable'])
1399 output
= check_output('ip -6 route show dev dummy98')
1401 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1402 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1404 output
= check_output('ip -6 route show dev dummy98 default')
1405 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1407 output
= check_output('ip -4 route show dev dummy98')
1409 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1410 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1411 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1412 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1413 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1415 output
= check_output('ip -4 route show dev dummy98 default')
1416 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1417 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1418 self
.assertRegex(output
, 'default proto static')
1420 output
= check_output('ip route show type blackhole')
1422 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1424 output
= check_output('ip route show type unreachable')
1426 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1428 output
= check_output('ip route show type prohibit')
1430 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1432 def test_ip_route_ipv6_src_route(self
):
1433 # a dummy device does not make the addresses go through tentative state, so we
1434 # reuse a bond from an earlier test, which does make the addresses go through
1435 # tentative state, and do our test on that
1436 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1438 wait_online(['dummy98:enslaved', 'bond199:routable'])
1440 output
= check_output('ip -6 route list dev bond199')
1442 self
.assertRegex(output
, 'abcd::/16')
1443 self
.assertRegex(output
, 'src')
1444 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1446 def test_ip_link_mac_address(self
):
1447 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1449 wait_online(['dummy98:degraded'])
1451 output
= check_output('ip link show dummy98')
1453 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1455 def test_ip_link_unmanaged(self
):
1456 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1459 self
.check_link_exists('dummy98')
1461 self
.check_operstate('dummy98', 'off', setup_state
='unmanaged')
1463 def test_ipv6_address_label(self
):
1464 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1466 wait_online(['dummy98:degraded'])
1468 output
= check_output('ip addrlabel list')
1470 self
.assertRegex(output
, '2004:da8:1::/64')
1472 def test_ipv6_neighbor(self
):
1473 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1475 wait_online(['dummy98:degraded'], timeout
='40s')
1477 output
= check_output('ip neigh list dev dummy98')
1479 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1480 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1482 def test_link_local_addressing(self
):
1483 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1484 '25-link-local-addressing-no.network', '12-dummy.netdev')
1486 wait_online(['test1:degraded', 'dummy98:carrier'])
1488 self
.check_link_exists('test1')
1489 self
.check_link_exists('dummy98')
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')
1500 self
.check_operstate('test1', 'degraded')
1501 self
.check_operstate('dummy98', 'carrier')
1504 Documentation/networking/ip-sysctl.txt
1506 addr_gen_mode - INTEGER
1507 Defines how link-local and autoconf addresses are generated.
1509 0: generate address based on EUI64 (default)
1510 1: do no generate a link-local address, use EUI64 for addresses generated
1512 2: generate stable privacy addresses, using the secret from
1513 stable_secret (RFC7217)
1514 3: generate stable privacy addresses, using a random secret if unset
1517 test1_addr_gen_mode
= ''
1518 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1519 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1523 # if stable_secret is unset, then EIO is returned
1524 test1_addr_gen_mode
= '0'
1526 test1_addr_gen_mode
= '2'
1528 test1_addr_gen_mode
= '0'
1530 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1531 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1533 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1534 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1536 def test_sysctl(self
):
1537 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1539 wait_online(['dummy98:degraded'])
1541 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1542 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1543 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1544 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1545 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1546 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1547 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1549 def test_sysctl_disable_ipv6(self
):
1550 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1552 print('## Disable ipv6')
1553 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1554 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1557 wait_online(['dummy98:routable'])
1559 output
= check_output('ip -4 address show dummy98')
1561 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1562 output
= check_output('ip -6 address show dummy98')
1564 self
.assertEqual(output
, '')
1565 output
= check_output('ip -4 route show dev dummy98')
1567 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1568 output
= check_output('ip -6 route show dev dummy98')
1570 self
.assertEqual(output
, '')
1572 check_output('ip link del dummy98')
1574 print('## Enable ipv6')
1575 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1576 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1579 wait_online(['dummy98:routable'])
1581 output
= check_output('ip -4 address show dummy98')
1583 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1584 output
= check_output('ip -6 address show dummy98')
1586 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1587 self
.assertRegex(output
, 'inet6 .* scope link')
1588 output
= check_output('ip -4 route show dev dummy98')
1590 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1591 output
= check_output('ip -6 route show dev dummy98')
1593 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1595 def test_bind_carrier(self
):
1596 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1598 wait_online(['test1:routable'])
1600 check_output('ip link add dummy98 type dummy')
1601 check_output('ip link set dummy98 up')
1603 output
= check_output('ip address show test1')
1605 self
.assertRegex(output
, 'UP,LOWER_UP')
1606 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1607 self
.check_operstate('test1', 'routable')
1609 check_output('ip link add dummy99 type dummy')
1610 check_output('ip link set dummy99 up')
1612 output
= check_output('ip address show test1')
1614 self
.assertRegex(output
, 'UP,LOWER_UP')
1615 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1616 self
.check_operstate('test1', 'routable')
1618 check_output('ip link del dummy98')
1620 output
= check_output('ip address show test1')
1622 self
.assertRegex(output
, 'UP,LOWER_UP')
1623 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1624 self
.check_operstate('test1', 'routable')
1626 check_output('ip link del dummy99')
1628 output
= check_output('ip address show test1')
1630 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1631 self
.assertRegex(output
, 'DOWN')
1632 self
.assertNotRegex(output
, '192.168.10')
1633 self
.check_operstate('test1', 'off')
1635 check_output('ip link add dummy98 type dummy')
1636 check_output('ip link set dummy98 up')
1638 output
= check_output('ip address show test1')
1640 self
.assertRegex(output
, 'UP,LOWER_UP')
1641 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1642 self
.check_operstate('test1', 'routable')
1644 def test_domain(self
):
1645 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1647 wait_online(['dummy98:routable'])
1649 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1651 self
.assertRegex(output
, 'Address: 192.168.42.100')
1652 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1653 self
.assertRegex(output
, 'Search Domains: one')
1655 def test_keep_configuration_static(self
):
1656 check_output('systemctl stop systemd-networkd')
1658 check_output('ip link add name dummy98 type dummy')
1659 check_output('ip address add 10.1.2.3/16 dev dummy98')
1660 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1661 output
= check_output('ip address show dummy98')
1663 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1664 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1665 output
= check_output('ip route show dev dummy98')
1668 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1670 wait_online(['dummy98:routable'])
1672 output
= check_output('ip address show dummy98')
1674 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1675 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1677 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1687 '23-active-slave.network',
1688 '23-bond199.network',
1689 '23-primary-slave.network',
1690 '23-test1-bond199.network',
1691 '25-bond-active-backup-slave.netdev',
1694 'bond-slave.network']
1697 remove_links(self
.links
)
1700 remove_links(self
.links
)
1701 remove_unit_from_networkd_path(self
.units
)
1703 def test_bond_active_slave(self
):
1704 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1707 self
.check_link_exists('dummy98')
1708 self
.check_link_exists('bond199')
1710 output
= check_output('ip -d link show bond199')
1712 self
.assertRegex(output
, 'active_slave dummy98')
1714 def test_bond_primary_slave(self
):
1715 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1718 self
.check_link_exists('test1')
1719 self
.check_link_exists('bond199')
1721 output
= check_output('ip -d link show bond199')
1723 self
.assertRegex(output
, 'primary test1')
1725 def test_bond_operstate(self
):
1726 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1727 'bond99.network','bond-slave.network')
1730 self
.check_link_exists('bond99')
1731 self
.check_link_exists('dummy98')
1732 self
.check_link_exists('test1')
1734 output
= check_output('ip -d link show dummy98')
1736 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1738 output
= check_output('ip -d link show test1')
1740 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1742 output
= check_output('ip -d link show bond99')
1744 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1746 self
.check_operstate('dummy98', 'enslaved')
1747 self
.check_operstate('test1', 'enslaved')
1748 self
.check_operstate('bond99', 'routable')
1750 check_output('ip link set dummy98 down')
1753 self
.check_operstate('dummy98', 'off')
1754 self
.check_operstate('test1', 'enslaved')
1755 self
.check_operstate('bond99', 'degraded-carrier')
1757 check_output('ip link set dummy98 up')
1760 self
.check_operstate('dummy98', 'enslaved')
1761 self
.check_operstate('test1', 'enslaved')
1762 self
.check_operstate('bond99', 'routable')
1764 check_output('ip link set dummy98 down')
1765 check_output('ip link set test1 down')
1768 self
.check_operstate('dummy98', 'off')
1769 self
.check_operstate('test1', 'off')
1771 for trial
in range(30):
1774 output
= check_output('ip address show bond99')
1776 if get_operstate('bond99') == 'no-carrier':
1779 # Huh? Kernel does not recognize that all slave interfaces are down?
1780 # Let's confirm that networkd's operstate is consistent with ip's result.
1781 self
.assertNotRegex(output
, 'NO-CARRIER')
1783 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1793 '26-bridge-slave-interface-1.network',
1794 '26-bridge-slave-interface-2.network',
1795 'bridge99-ignore-carrier-loss.network',
1799 remove_links(self
.links
)
1802 remove_links(self
.links
)
1803 remove_unit_from_networkd_path(self
.units
)
1805 def test_bridge_property(self
):
1806 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1807 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1811 self
.check_link_exists('dummy98')
1812 self
.check_link_exists('test1')
1813 self
.check_link_exists('bridge99')
1815 output
= check_output('ip -d link show test1')
1817 self
.assertRegex(output
, 'master')
1818 self
.assertRegex(output
, 'bridge')
1820 output
= check_output('ip -d link show dummy98')
1822 self
.assertRegex(output
, 'master')
1823 self
.assertRegex(output
, 'bridge')
1825 output
= check_output('ip addr show bridge99')
1827 self
.assertRegex(output
, '192.168.0.15/24')
1829 output
= check_output('bridge -d link show dummy98')
1831 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1832 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1833 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1834 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1835 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1836 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1837 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1838 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1840 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1841 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1842 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1844 self
.check_operstate('test1', 'enslaved')
1845 self
.check_operstate('dummy98', 'enslaved')
1846 self
.check_operstate('bridge99', 'routable')
1848 check_output('ip address add 192.168.0.16/24 dev bridge99')
1851 output
= check_output('ip addr show bridge99')
1853 self
.assertRegex(output
, '192.168.0.16/24')
1855 self
.check_operstate('bridge99', 'routable')
1857 self
.assertEqual(call('ip link del test1'), 0)
1860 self
.check_operstate('bridge99', 'degraded-carrier')
1862 check_output('ip link del dummy98')
1865 self
.check_operstate('bridge99', 'no-carrier')
1867 output
= check_output('ip address show bridge99')
1869 self
.assertRegex(output
, 'NO-CARRIER')
1870 self
.assertNotRegex(output
, '192.168.0.15/24')
1871 self
.assertNotRegex(output
, '192.168.0.16/24')
1873 def test_bridge_ignore_carrier_loss(self
):
1874 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1875 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1876 'bridge99-ignore-carrier-loss.network')
1877 call('ip rule del table 100')
1881 self
.check_link_exists('dummy98')
1882 self
.check_link_exists('test1')
1883 self
.check_link_exists('bridge99')
1885 check_output('ip address add 192.168.0.16/24 dev bridge99')
1888 check_output('ip link del test1')
1889 check_output('ip link del dummy98')
1892 output
= check_output('ip address show bridge99')
1894 self
.assertRegex(output
, 'NO-CARRIER')
1895 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1896 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1898 call('ip rule del table 100')
1900 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1901 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1902 'bridge99-ignore-carrier-loss.network')
1904 call('ip rule del table 100')
1908 self
.check_link_exists('bridge99')
1910 check_output('ip link add dummy98 type dummy')
1911 check_output('ip link set dummy98 up')
1912 check_output('ip link del dummy98')
1914 check_output('ip link add dummy98 type dummy')
1915 check_output('ip link set dummy98 up')
1916 check_output('ip link del dummy98')
1918 check_output('ip link add dummy98 type dummy')
1919 check_output('ip link set dummy98 up')
1920 check_output('ip link del dummy98')
1922 check_output('ip link add dummy98 type dummy')
1923 check_output('ip link set dummy98 up')
1925 for trial
in range(30):
1928 if get_operstate('bridge99') == 'routable' and get_operstate('dummy98') == 'enslaved':
1931 self
.assertTrue(False)
1933 output
= check_output('ip address show bridge99')
1935 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1937 output
= check_output('ip rule list table 100')
1939 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
1941 call('ip rule del table 100')
1943 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
1947 '23-emit-lldp.network',
1952 remove_links(self
.links
)
1955 remove_links(self
.links
)
1956 remove_unit_from_networkd_path(self
.units
)
1958 def test_lldp(self
):
1959 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1961 wait_online(['veth99:degraded', 'veth-peer:degraded'])
1963 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
1965 self
.assertRegex(output
, 'veth-peer')
1966 self
.assertRegex(output
, 'veth99')
1968 class NetworkdRATests(unittest
.TestCase
, Utilities
):
1973 'ipv6-prefix.network',
1974 'ipv6-prefix-veth.network']
1977 remove_links(self
.links
)
1980 remove_links(self
.links
)
1981 remove_unit_from_networkd_path(self
.units
)
1983 def test_ipv6_prefix_delegation(self
):
1984 warn_about_firewalld()
1985 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
1987 wait_online(['veth99:routable', 'veth-peer:degraded'])
1989 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
1991 self
.assertRegex(output
, '2002:da8:1:0')
1993 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
1998 'dhcp-client.network',
1999 'dhcp-client-timezone-router.network',
2000 'dhcp-server.network',
2001 'dhcp-server-timezone-router.network']
2004 remove_links(self
.links
)
2007 remove_links(self
.links
)
2008 remove_unit_from_networkd_path(self
.units
)
2010 def test_dhcp_server(self
):
2011 warn_about_firewalld()
2012 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2014 wait_online(['veth99:routable', 'veth-peer:routable'])
2016 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2018 self
.assertRegex(output
, '192.168.5.*')
2019 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2020 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2021 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2023 def test_emit_router_timezone(self
):
2024 warn_about_firewalld()
2025 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2027 wait_online(['veth99:routable', 'veth-peer:routable'])
2029 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2031 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2032 self
.assertRegex(output
, '192.168.5.*')
2033 self
.assertRegex(output
, 'Europe/Berlin')
2035 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2044 'dhcp-client-anonymize.network',
2045 'dhcp-client-gateway-onlink-implicit.network',
2046 'dhcp-client-ipv4-dhcp-settings.network',
2047 'dhcp-client-ipv4-only-ipv6-disabled.network',
2048 'dhcp-client-ipv4-only.network',
2049 'dhcp-client-ipv6-only.network',
2050 'dhcp-client-ipv6-rapid-commit.network',
2051 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2052 'dhcp-client-keep-configuration-dhcp.network',
2053 'dhcp-client-listen-port.network',
2054 'dhcp-client-route-metric.network',
2055 'dhcp-client-route-table.network',
2056 'dhcp-client-vrf.network',
2057 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2058 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2059 'dhcp-client.network',
2060 'dhcp-server-veth-peer.network',
2061 'dhcp-v4-server-veth-peer.network',
2065 stop_dnsmasq(dnsmasq_pid_file
)
2066 remove_links(self
.links
)
2069 stop_dnsmasq(dnsmasq_pid_file
)
2072 remove_links(self
.links
)
2073 remove_unit_from_networkd_path(self
.units
)
2075 def test_dhcp_client_ipv6_only(self
):
2076 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2079 wait_online(['veth-peer:carrier'])
2081 wait_online(['veth99:routable', 'veth-peer:routable'])
2083 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2085 self
.assertRegex(output
, '2600::')
2086 self
.assertNotRegex(output
, '192.168.5')
2088 # Confirm that ipv6 token is not set in the kernel
2089 output
= check_output('ip token show dev veth99')
2091 self
.assertRegex(output
, 'token :: dev veth99')
2093 def test_dhcp_client_ipv4_only(self
):
2094 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2097 wait_online(['veth-peer:carrier'])
2099 wait_online(['veth99:routable', 'veth-peer:routable'])
2101 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2103 self
.assertNotRegex(output
, '2600::')
2104 self
.assertRegex(output
, '192.168.5')
2106 def test_dhcp_client_ipv4_ipv6(self
):
2107 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2108 'dhcp-client-ipv4-only.network')
2110 wait_online(['veth-peer:carrier'])
2112 wait_online(['veth99:routable', 'veth-peer:routable'])
2114 # link become 'routable' when at least one protocol provide an valid address.
2115 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2116 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2118 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2120 self
.assertRegex(output
, '2600::')
2121 self
.assertRegex(output
, '192.168.5')
2123 def test_dhcp_client_settings(self
):
2124 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2127 wait_online(['veth-peer:carrier'])
2129 wait_online(['veth99:routable', 'veth-peer:routable'])
2131 print('## ip address show dev veth99')
2132 output
= check_output('ip address show dev veth99')
2134 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2135 self
.assertRegex(output
, '192.168.5')
2136 self
.assertRegex(output
, '1492')
2139 print('## ip route show table main dev veth99')
2140 output
= check_output('ip route show table main dev veth99')
2142 self
.assertNotRegex(output
, 'proto dhcp')
2144 print('## ip route show table 211 dev veth99')
2145 output
= check_output('ip route show table 211 dev veth99')
2147 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2148 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2149 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2151 print('## dnsmasq log')
2152 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2153 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2154 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2155 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2157 def test_dhcp6_client_settings_rapidcommit_true(self
):
2158 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2160 wait_online(['veth-peer:carrier'])
2162 wait_online(['veth99:routable', 'veth-peer:routable'])
2164 output
= check_output('ip address show dev veth99')
2166 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2167 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2169 def test_dhcp6_client_settings_rapidcommit_false(self
):
2170 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2172 wait_online(['veth-peer:carrier'])
2174 wait_online(['veth99:routable', 'veth-peer:routable'])
2176 output
= check_output('ip address show dev veth99')
2178 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2179 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2181 def test_dhcp_client_settings_anonymize(self
):
2182 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2184 wait_online(['veth-peer:carrier'])
2186 wait_online(['veth99:routable', 'veth-peer:routable'])
2188 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2189 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2190 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2192 def test_dhcp_client_listen_port(self
):
2193 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2195 wait_online(['veth-peer:carrier'])
2196 start_dnsmasq('--dhcp-alternate-port=67,5555')
2197 wait_online(['veth99:routable', 'veth-peer:routable'])
2199 # link become 'routable' when at least one protocol provide an valid address.
2200 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2201 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2203 output
= check_output('ip -4 address show dev veth99')
2205 self
.assertRegex(output
, '192.168.5.* dynamic')
2207 def test_dhcp_route_table_id(self
):
2208 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2210 wait_online(['veth-peer:carrier'])
2212 wait_online(['veth99:routable', 'veth-peer:routable'])
2214 output
= check_output('ip route show table 12')
2216 self
.assertRegex(output
, 'veth99 proto dhcp')
2217 self
.assertRegex(output
, '192.168.5.1')
2219 def test_dhcp_route_metric(self
):
2220 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2222 wait_online(['veth-peer:carrier'])
2224 wait_online(['veth99:routable', 'veth-peer:routable'])
2226 output
= check_output('ip route show dev veth99')
2228 self
.assertRegex(output
, 'metric 24')
2230 def test_dhcp_keep_configuration_dhcp(self
):
2231 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2233 wait_online(['veth-peer:carrier'])
2234 start_dnsmasq(lease_time
='2m')
2235 wait_online(['veth99:routable', 'veth-peer:routable'])
2237 output
= check_output('ip address show dev veth99 scope global')
2239 self
.assertRegex(output
, r
'192.168.5.*')
2241 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2243 self
.assertRegex(output
, r
'192.168.5.*')
2245 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2246 stop_dnsmasq(dnsmasq_pid_file
)
2248 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2249 print('Wait for the dynamic address to be expired')
2252 print('The lease address should be kept after lease expired')
2253 output
= check_output('ip address show dev veth99 scope global')
2255 self
.assertRegex(output
, r
'192.168.5.*')
2257 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2259 self
.assertRegex(output
, r
'192.168.5.*')
2261 check_output('systemctl stop systemd-networkd')
2263 print('The lease address should be kept after networkd stopped')
2264 output
= check_output('ip address show dev veth99 scope global')
2266 self
.assertRegex(output
, r
'192.168.5.*')
2268 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2270 self
.assertRegex(output
, r
'192.168.5.*')
2272 check_output('systemctl start systemd-networkd')
2273 wait_online(['veth-peer:routable'])
2275 print('Still the lease address should be kept after networkd restarted')
2276 output
= check_output('ip address show dev veth99 scope global')
2278 self
.assertRegex(output
, r
'192.168.5.*')
2280 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2282 self
.assertRegex(output
, r
'192.168.5.*')
2284 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2285 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2287 wait_online(['veth-peer:carrier'])
2288 start_dnsmasq(lease_time
='2m')
2289 wait_online(['veth99:routable', 'veth-peer:routable'])
2291 output
= check_output('ip address show dev veth99 scope global')
2293 self
.assertRegex(output
, r
'192.168.5.*')
2295 stop_dnsmasq(dnsmasq_pid_file
)
2296 check_output('systemctl stop systemd-networkd')
2298 output
= check_output('ip address show dev veth99 scope global')
2300 self
.assertRegex(output
, r
'192.168.5.*')
2303 wait_online(['veth-peer:routable'])
2305 output
= check_output('ip address show dev veth99 scope global')
2307 self
.assertNotRegex(output
, r
'192.168.5.*')
2309 def test_dhcp_client_reuse_address_as_static(self
):
2310 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2312 wait_online(['veth-peer:carrier'])
2314 wait_online(['veth99:routable', 'veth-peer:routable'])
2316 # link become 'routable' when at least one protocol provide an valid address.
2317 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2318 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2320 output
= check_output('ip address show dev veth99 scope global')
2322 self
.assertRegex(output
, '192.168.5')
2323 self
.assertRegex(output
, '2600::')
2325 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2326 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2327 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2328 print(static_network
)
2330 remove_unit_from_networkd_path(['dhcp-client.network'])
2332 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2333 f
.write(static_network
)
2335 # When networkd started, the links are already configured, so let's wait for 5 seconds
2336 # the links to be re-configured.
2338 wait_online(['veth99:routable', 'veth-peer:routable'])
2340 output
= check_output('ip -4 address show dev veth99 scope global')
2342 self
.assertRegex(output
, '192.168.5')
2343 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2345 output
= check_output('ip -6 address show dev veth99 scope global')
2347 self
.assertRegex(output
, '2600::')
2348 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2350 @expectedFailureIfModuleIsNotAvailable('vrf')
2351 def test_dhcp_client_vrf(self
):
2352 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2353 '25-vrf.netdev', '25-vrf.network')
2355 wait_online(['veth-peer:carrier'])
2357 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2359 # link become 'routable' when at least one protocol provide an valid address.
2360 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2361 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2363 print('## ip -d link show dev vrf99')
2364 output
= check_output('ip -d link show dev vrf99')
2366 self
.assertRegex(output
, 'vrf table 42')
2368 print('## ip address show vrf vrf99')
2369 output
= check_output('ip address show vrf vrf99')
2371 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2372 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2373 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2374 self
.assertRegex(output
, 'inet6 .* scope link')
2376 print('## ip address show dev veth99')
2377 output
= check_output('ip address show dev veth99')
2379 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2380 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2381 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2382 self
.assertRegex(output
, 'inet6 .* scope link')
2384 print('## ip route show vrf vrf99')
2385 output
= check_output('ip route show vrf vrf99')
2387 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2388 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2389 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2390 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2391 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2392 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2394 print('## ip route show table main dev veth99')
2395 output
= check_output('ip route show table main dev veth99')
2397 self
.assertEqual(output
, '')
2399 self
.check_operstate('vrf99', 'carrier')
2400 self
.check_operstate('veth99', 'routable')
2402 def test_dhcp_client_gateway_onlink_implicit(self
):
2403 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2404 'dhcp-client-gateway-onlink-implicit.network')
2406 wait_online(['veth-peer:carrier'])
2408 wait_online(['veth99:routable', 'veth-peer:routable'])
2410 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2412 self
.assertRegex(output
, '192.168.5')
2414 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2416 self
.assertRegex(output
, 'onlink')
2417 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2419 self
.assertRegex(output
, 'onlink')
2421 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2422 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2423 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2425 wait_online(['veth-peer:carrier'])
2426 start_dnsmasq(lease_time
='2m')
2427 wait_online(['veth99:routable', 'veth-peer:routable'])
2429 output
= check_output('ip address show dev veth99')
2432 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2433 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2434 output
= check_output('ip -6 address show dev veth99 scope link')
2435 self
.assertRegex(output
, 'inet6 .* scope link')
2436 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2437 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2438 output
= check_output('ip -4 address show dev veth99 scope link')
2439 self
.assertNotRegex(output
, 'inet .* scope link')
2441 print('Wait for the dynamic address to be expired')
2444 output
= check_output('ip address show dev veth99')
2447 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2448 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2449 output
= check_output('ip -6 address show dev veth99 scope link')
2450 self
.assertRegex(output
, 'inet6 .* scope link')
2451 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2452 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2453 output
= check_output('ip -4 address show dev veth99 scope link')
2454 self
.assertNotRegex(output
, 'inet .* scope link')
2456 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2458 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2459 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2460 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2462 wait_online(['veth99:degraded', 'veth-peer:routable'])
2464 output
= check_output('ip address show dev veth99')
2467 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2468 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2469 output
= check_output('ip -6 address show dev veth99 scope link')
2470 self
.assertRegex(output
, 'inet6 .* scope link')
2471 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2472 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2473 output
= check_output('ip -4 address show dev veth99 scope link')
2474 self
.assertRegex(output
, 'inet .* scope link')
2476 def test_dhcp_client_route_remove_on_renew(self
):
2477 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2478 'dhcp-client-ipv4-only-ipv6-disabled.network')
2480 wait_online(['veth-peer:carrier'])
2481 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2482 wait_online(['veth99:routable', 'veth-peer:routable'])
2484 # test for issue #12490
2486 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2488 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2490 for line
in output
.splitlines():
2491 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2492 address1
= line
.split()[1].split('/')[0]
2495 output
= check_output('ip -4 route show dev veth99')
2497 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2498 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2500 stop_dnsmasq(dnsmasq_pid_file
)
2501 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2503 print('Wait for the dynamic address to be expired')
2506 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2508 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2510 for line
in output
.splitlines():
2511 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2512 address2
= line
.split()[1].split('/')[0]
2515 self
.assertNotEqual(address1
, address2
)
2517 output
= check_output('ip -4 route show dev veth99')
2519 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2520 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2521 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2522 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2524 if __name__
== '__main__':
2525 parser
= argparse
.ArgumentParser()
2526 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2527 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2528 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2529 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2530 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2531 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2532 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2533 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2534 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2535 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2538 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2539 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2540 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2541 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2542 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2545 networkd_bin
= ns
.networkd_bin
2546 if ns
.wait_online_bin
:
2547 wait_online_bin
= ns
.wait_online_bin
2548 if ns
.networkctl_bin
:
2549 networkctl_bin
= ns
.networkctl_bin
2551 use_valgrind
= ns
.use_valgrind
2552 enable_debug
= ns
.enable_debug
2553 asan_options
= ns
.asan_options
2554 lsan_options
= ns
.lsan_options
2555 ubsan_options
= ns
.ubsan_options
2558 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2559 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2561 networkctl_cmd
= [networkctl_bin
]
2562 wait_online_cmd
= [wait_online_bin
]
2565 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2567 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2569 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2571 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2574 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,