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
)
189 def remove_routing_policy_rule_tables(tables
):
191 call('ip rule del table', table
)
193 def remove_routes(routes
):
194 for route_type
, addr
in routes
:
195 call('ip route del', route_type
, addr
)
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',
474 '25-bridge-configure-without-carrier.network',
476 '25-erspan-tunnel-local-any.netdev',
477 '25-erspan-tunnel.netdev',
478 '25-fou-gretap.netdev',
480 '25-fou-ipip.netdev',
481 '25-fou-ipproto-gre.netdev',
482 '25-fou-ipproto-ipip.netdev',
485 '25-gretap-tunnel-local-any.netdev',
486 '25-gretap-tunnel.netdev',
487 '25-gre-tunnel-local-any.netdev',
488 '25-gre-tunnel-remote-any.netdev',
489 '25-gre-tunnel.netdev',
490 '25-ip6gretap-tunnel-local-any.netdev',
491 '25-ip6gretap-tunnel.netdev',
492 '25-ip6gre-tunnel-local-any.netdev',
493 '25-ip6gre-tunnel-remote-any.netdev',
494 '25-ip6gre-tunnel.netdev',
495 '25-ip6tnl-tunnel-remote-any.netdev',
496 '25-ip6tnl-tunnel-local-any.netdev',
497 '25-ip6tnl-tunnel.netdev',
498 '25-ipip-tunnel-independent.netdev',
499 '25-ipip-tunnel-local-any.netdev',
500 '25-ipip-tunnel-remote-any.netdev',
501 '25-ipip-tunnel.netdev',
504 '25-isatap-tunnel.netdev',
509 '25-sit-tunnel-local-any.netdev',
510 '25-sit-tunnel-remote-any.netdev',
511 '25-sit-tunnel.netdev',
514 '25-tunnel-local-any.network',
515 '25-tunnel-remote-any.network',
520 '25-vti6-tunnel-local-any.netdev',
521 '25-vti6-tunnel-remote-any.netdev',
522 '25-vti6-tunnel.netdev',
523 '25-vti-tunnel-local-any.netdev',
524 '25-vti-tunnel-remote-any.netdev',
525 '25-vti-tunnel.netdev',
528 '25-wireguard-23-peers.netdev',
529 '25-wireguard-23-peers.network',
530 '25-wireguard-preshared-key.txt',
531 '25-wireguard-private-key.txt',
532 '25-wireguard.netdev',
533 '25-wireguard.network',
549 'netdev-link-local-addressing-yes.network',
553 'vxlan-test1.network',
561 remove_fou_ports(self
.fou_ports
)
562 remove_links(self
.links
)
565 remove_fou_ports(self
.fou_ports
)
566 remove_links(self
.links
)
567 remove_unit_from_networkd_path(self
.units
)
569 def test_dropin_and_name_conflict(self
):
570 copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
573 wait_online(['dropin-test:off'])
575 output
= check_output('ip link show dropin-test')
577 self
.assertRegex(output
, '00:50:56:c0:00:28')
579 def test_wait_online_any(self
):
580 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
583 wait_online(['bridge99', 'test1:degraded'], bool_any
=True)
585 self
.check_operstate('bridge99', '(?:off|no-carrier)', setup_state
='configuring')
586 self
.check_operstate('test1', 'degraded')
588 def test_bridge(self
):
589 copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network')
592 wait_online(['bridge99:no-carrier'])
594 tick
= os
.sysconf('SC_CLK_TCK')
595 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'hello_time')) / tick
))
596 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge', 'max_age')) / tick
))
597 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','forward_delay')) / tick
))
598 self
.assertEqual(9, round(float(read_link_attr('bridge99', 'bridge','ageing_time')) / tick
))
599 self
.assertEqual(9, int(read_link_attr('bridge99', 'bridge','priority')))
600 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_querier')))
601 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','multicast_snooping')))
602 self
.assertEqual(1, int(read_link_attr('bridge99', 'bridge','stp_state')))
605 copy_unit_to_networkd_unit_path('25-bond.netdev', '25-bond-balanced-tlb.netdev')
608 wait_online(['bond99:off', 'bond98:off'])
610 self
.assertEqual('802.3ad 4', read_link_attr('bond99', 'bonding', 'mode'))
611 self
.assertEqual('layer3+4 1', read_link_attr('bond99', 'bonding', 'xmit_hash_policy'))
612 self
.assertEqual('1000', read_link_attr('bond99', 'bonding', 'miimon'))
613 self
.assertEqual('fast 1', read_link_attr('bond99', 'bonding', 'lacp_rate'))
614 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'updelay'))
615 self
.assertEqual('2000', read_link_attr('bond99', 'bonding', 'downdelay'))
616 self
.assertEqual('4', read_link_attr('bond99', 'bonding', 'resend_igmp'))
617 self
.assertEqual('1', read_link_attr('bond99', 'bonding', 'min_links'))
618 self
.assertEqual('1218', read_link_attr('bond99', 'bonding', 'ad_actor_sys_prio'))
619 self
.assertEqual('811', read_link_attr('bond99', 'bonding', 'ad_user_port_key'))
620 self
.assertEqual('00:11:22:33:44:55', read_link_attr('bond99', 'bonding', 'ad_actor_system'))
622 self
.assertEqual('balance-tlb 5', read_link_attr('bond98', 'bonding', 'mode'))
623 self
.assertEqual('1', read_link_attr('bond98', 'bonding', 'tlb_dynamic_lb'))
626 copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
627 '21-vlan.network', '21-vlan-test1.network')
630 wait_online(['test1:degraded', 'vlan99:routable'])
632 output
= check_output('ip -d link show test1')
634 self
.assertRegex(output
, ' mtu 2000 ')
636 output
= check_output('ip -d link show vlan99')
638 self
.assertRegex(output
, ' mtu 2000 ')
639 self
.assertRegex(output
, 'REORDER_HDR')
640 self
.assertRegex(output
, 'LOOSE_BINDING')
641 self
.assertRegex(output
, 'GVRP')
642 self
.assertRegex(output
, 'MVRP')
643 self
.assertRegex(output
, ' id 99 ')
645 output
= check_output('ip -4 address show dev test1')
647 self
.assertRegex(output
, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
648 self
.assertRegex(output
, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
650 output
= check_output('ip -4 address show dev vlan99')
652 self
.assertRegex(output
, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
654 def test_macvtap(self
):
655 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
656 with self
.subTest(mode
=mode
):
657 if mode
!= 'private':
659 copy_unit_to_networkd_unit_path('21-macvtap.netdev', 'netdev-link-local-addressing-yes.network',
660 '11-dummy.netdev', 'macvtap.network')
661 with
open(os
.path
.join(network_unit_file_path
, '21-macvtap.netdev'), mode
='a') as f
:
662 f
.write('[MACVTAP]\nMode=' + mode
)
665 wait_online(['macvtap99:degraded', 'test1:degraded'])
667 output
= check_output('ip -d link show macvtap99')
669 self
.assertRegex(output
, 'macvtap mode ' + mode
+ ' ')
671 def test_macvlan(self
):
672 for mode
in ['private', 'vepa', 'bridge', 'passthru']:
673 with self
.subTest(mode
=mode
):
674 if mode
!= 'private':
676 copy_unit_to_networkd_unit_path('21-macvlan.netdev', 'netdev-link-local-addressing-yes.network',
677 '11-dummy.netdev', 'macvlan.network')
678 with
open(os
.path
.join(network_unit_file_path
, '21-macvlan.netdev'), mode
='a') as f
:
679 f
.write('[MACVLAN]\nMode=' + mode
)
682 wait_online(['macvlan99:degraded', 'test1:degraded'])
684 output
= check_output('ip -d link show test1')
686 self
.assertRegex(output
, ' mtu 2000 ')
688 output
= check_output('ip -d link show macvlan99')
690 self
.assertRegex(output
, ' mtu 2000 ')
691 self
.assertRegex(output
, 'macvlan mode ' + mode
+ ' ')
693 @expectedFailureIfModuleIsNotAvailable('ipvlan')
694 def test_ipvlan(self
):
695 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
696 with self
.subTest(mode
=mode
, flag
=flag
):
699 copy_unit_to_networkd_unit_path('25-ipvlan.netdev', 'netdev-link-local-addressing-yes.network',
700 '11-dummy.netdev', 'ipvlan.network')
701 with
open(os
.path
.join(network_unit_file_path
, '25-ipvlan.netdev'), mode
='a') as f
:
702 f
.write('[IPVLAN]\nMode=' + mode
+ '\nFlags=' + flag
)
705 wait_online(['ipvlan99:degraded', 'test1:degraded'])
707 output
= check_output('ip -d link show ipvlan99')
709 self
.assertRegex(output
, 'ipvlan *mode ' + mode
.lower() + ' ' + flag
)
711 @expectedFailureIfModuleIsNotAvailable('ipvtap')
712 def test_ipvtap(self
):
713 for mode
, flag
in [['L2', 'private'], ['L3', 'vepa'], ['L3S', 'bridge']]:
714 with self
.subTest(mode
=mode
, flag
=flag
):
717 copy_unit_to_networkd_unit_path('25-ipvtap.netdev', 'netdev-link-local-addressing-yes.network',
718 '11-dummy.netdev', 'ipvtap.network')
719 with
open(os
.path
.join(network_unit_file_path
, '25-ipvtap.netdev'), mode
='a') as f
:
720 f
.write('[IPVTAP]\nMode=' + mode
+ '\nFlags=' + flag
)
723 wait_online(['ipvtap99:degraded', 'test1:degraded'])
725 output
= check_output('ip -d link show ipvtap99')
727 self
.assertRegex(output
, 'ipvtap *mode ' + mode
.lower() + ' ' + flag
)
730 copy_unit_to_networkd_unit_path('25-veth.netdev', 'netdev-link-local-addressing-yes.network')
733 wait_online(['veth99:degraded', 'veth-peer:degraded'])
735 output
= check_output('ip -d link show veth99')
737 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bc')
738 output
= check_output('ip -d link show veth-peer')
740 self
.assertRegex(output
, 'link/ether 12:34:56:78:9a:bd')
743 copy_unit_to_networkd_unit_path('25-tun.netdev')
746 wait_online(['tun99:off'])
748 output
= check_output('ip -d link show tun99')
750 # Old ip command does not support IFF_ flags
751 self
.assertRegex(output
, 'tun (?:type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
754 copy_unit_to_networkd_unit_path('25-tap.netdev')
757 wait_online(['tap99:off'])
759 output
= check_output('ip -d link show tap99')
761 # Old ip command does not support IFF_ flags
762 self
.assertRegex(output
, 'tun (?:type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
764 @expectedFailureIfModuleIsNotAvailable('vrf')
766 copy_unit_to_networkd_unit_path('25-vrf.netdev', 'netdev-link-local-addressing-yes.network')
769 wait_online(['vrf99:carrier'])
771 @expectedFailureIfModuleIsNotAvailable('vcan')
773 copy_unit_to_networkd_unit_path('25-vcan.netdev', 'netdev-link-local-addressing-yes.network')
776 wait_online(['vcan99:carrier'])
778 @expectedFailureIfModuleIsNotAvailable('vxcan')
779 def test_vxcan(self
):
780 copy_unit_to_networkd_unit_path('25-vxcan.netdev', 'netdev-link-local-addressing-yes.network')
783 wait_online(['vxcan99:carrier', 'vxcan-peer:carrier'])
785 @expectedFailureIfModuleIsNotAvailable('wireguard')
786 def test_wireguard(self
):
787 copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
788 '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
789 '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
791 wait_online(['wg99:carrier', 'wg98:routable'])
793 if shutil
.which('wg'):
796 output
= check_output('wg show wg99 listen-port')
797 self
.assertRegex(output
, '51820')
798 output
= check_output('wg show wg99 fwmark')
799 self
.assertRegex(output
, '0x4d2')
800 output
= check_output('wg show wg99 allowed-ips')
801 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
802 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
803 output
= check_output('wg show wg99 persistent-keepalive')
804 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
805 output
= check_output('wg show wg99 endpoints')
806 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
807 output
= check_output('wg show wg99 private-key')
808 self
.assertRegex(output
, r
'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
809 output
= check_output('wg show wg99 preshared-keys')
810 self
.assertRegex(output
, r
'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
811 self
.assertRegex(output
, r
'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
813 output
= check_output('wg show wg98 private-key')
814 self
.assertRegex(output
, r
'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
816 def test_geneve(self
):
817 copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network')
820 wait_online(['geneve99:degraded'])
822 output
= check_output('ip -d link show geneve99')
824 self
.assertRegex(output
, '192.168.22.1')
825 self
.assertRegex(output
, '6082')
826 self
.assertRegex(output
, 'udpcsum')
827 self
.assertRegex(output
, 'udp6zerocsumrx')
829 def test_ipip_tunnel(self
):
830 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ipip.network',
831 '25-ipip-tunnel.netdev', '25-tunnel.network',
832 '25-ipip-tunnel-local-any.netdev', '25-tunnel-local-any.network',
833 '25-ipip-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
835 wait_online(['ipiptun99:routable', 'ipiptun98:routable', 'ipiptun97:routable', 'dummy98:degraded'])
837 output
= check_output('ip -d link show ipiptun99')
839 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
840 output
= check_output('ip -d link show ipiptun98')
842 self
.assertRegex(output
, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
843 output
= check_output('ip -d link show ipiptun97')
845 self
.assertRegex(output
, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
847 def test_gre_tunnel(self
):
848 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretun.network',
849 '25-gre-tunnel.netdev', '25-tunnel.network',
850 '25-gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
851 '25-gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
853 wait_online(['gretun99:routable', 'gretun98:routable', 'gretun97:routable', 'dummy98:degraded'])
855 output
= check_output('ip -d link show gretun99')
857 self
.assertRegex(output
, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
858 self
.assertRegex(output
, 'ikey 1.2.3.103')
859 self
.assertRegex(output
, 'okey 1.2.4.103')
860 self
.assertRegex(output
, 'iseq')
861 self
.assertRegex(output
, 'oseq')
862 output
= check_output('ip -d link show gretun98')
864 self
.assertRegex(output
, 'gre remote 10.65.223.239 local any dev dummy98')
865 self
.assertRegex(output
, 'ikey 0.0.0.104')
866 self
.assertRegex(output
, 'okey 0.0.0.104')
867 self
.assertNotRegex(output
, 'iseq')
868 self
.assertNotRegex(output
, 'oseq')
869 output
= check_output('ip -d link show gretun97')
871 self
.assertRegex(output
, 'gre remote any local 10.65.223.238 dev dummy98')
872 self
.assertRegex(output
, 'ikey 0.0.0.105')
873 self
.assertRegex(output
, 'okey 0.0.0.105')
874 self
.assertNotRegex(output
, 'iseq')
875 self
.assertNotRegex(output
, 'oseq')
877 def test_ip6gre_tunnel(self
):
878 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretun.network',
879 '25-ip6gre-tunnel.netdev', '25-tunnel.network',
880 '25-ip6gre-tunnel-local-any.netdev', '25-tunnel-local-any.network',
881 '25-ip6gre-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
884 # Old kernels seem not to support IPv6LL address on ip6gre tunnel, So please do not use wait_online() here.
886 self
.check_link_exists('dummy98')
887 self
.check_link_exists('ip6gretun99')
888 self
.check_link_exists('ip6gretun98')
889 self
.check_link_exists('ip6gretun97')
891 output
= check_output('ip -d link show ip6gretun99')
893 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
894 output
= check_output('ip -d link show ip6gretun98')
896 self
.assertRegex(output
, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
897 output
= check_output('ip -d link show ip6gretun97')
899 self
.assertRegex(output
, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
901 def test_gretap_tunnel(self
):
902 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'gretap.network',
903 '25-gretap-tunnel.netdev', '25-tunnel.network',
904 '25-gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
906 wait_online(['gretap99:routable', 'gretap98:routable', 'dummy98:degraded'])
908 output
= check_output('ip -d link show gretap99')
910 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
911 self
.assertRegex(output
, 'ikey 0.0.0.106')
912 self
.assertRegex(output
, 'okey 0.0.0.106')
913 self
.assertRegex(output
, 'iseq')
914 self
.assertRegex(output
, 'oseq')
915 output
= check_output('ip -d link show gretap98')
917 self
.assertRegex(output
, 'gretap remote 10.65.223.239 local any dev dummy98')
918 self
.assertRegex(output
, 'ikey 0.0.0.107')
919 self
.assertRegex(output
, 'okey 0.0.0.107')
920 self
.assertRegex(output
, 'iseq')
921 self
.assertRegex(output
, 'oseq')
923 def test_ip6gretap_tunnel(self
):
924 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6gretap.network',
925 '25-ip6gretap-tunnel.netdev', '25-tunnel.network',
926 '25-ip6gretap-tunnel-local-any.netdev', '25-tunnel-local-any.network')
928 wait_online(['ip6gretap99:routable', 'ip6gretap98:routable', 'dummy98:degraded'])
930 output
= check_output('ip -d link show ip6gretap99')
932 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
933 output
= check_output('ip -d link show ip6gretap98')
935 self
.assertRegex(output
, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
937 def test_vti_tunnel(self
):
938 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti.network',
939 '25-vti-tunnel.netdev', '25-tunnel.network',
940 '25-vti-tunnel-local-any.netdev', '25-tunnel-local-any.network',
941 '25-vti-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
943 wait_online(['vtitun99:routable', 'vtitun98:routable', 'vtitun97:routable', 'dummy98:degraded'])
945 output
= check_output('ip -d link show vtitun99')
947 self
.assertRegex(output
, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
948 output
= check_output('ip -d link show vtitun98')
950 self
.assertRegex(output
, 'vti remote 10.65.223.239 local any dev dummy98')
951 output
= check_output('ip -d link show vtitun97')
953 self
.assertRegex(output
, 'vti remote any local 10.65.223.238 dev dummy98')
955 def test_vti6_tunnel(self
):
956 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'vti6.network',
957 '25-vti6-tunnel.netdev', '25-tunnel.network',
958 '25-vti6-tunnel-local-any.netdev', '25-tunnel-local-any.network',
959 '25-vti6-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
961 wait_online(['vti6tun99:routable', 'vti6tun98:routable', 'vti6tun97:routable', 'dummy98:degraded'])
963 output
= check_output('ip -d link show vti6tun99')
965 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
966 output
= check_output('ip -d link show vti6tun98')
968 self
.assertRegex(output
, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
969 output
= check_output('ip -d link show vti6tun97')
971 self
.assertRegex(output
, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
973 def test_ip6tnl_tunnel(self
):
974 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
975 '25-ip6tnl-tunnel.netdev', '25-tunnel.network',
976 '25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
977 '25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
979 wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
981 output
= check_output('ip -d link show ip6tnl99')
983 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
984 output
= check_output('ip -d link show ip6tnl98')
986 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
987 output
= check_output('ip -d link show ip6tnl97')
989 self
.assertRegex(output
, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
991 def test_sit_tunnel(self
):
992 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
993 '25-sit-tunnel.netdev', '25-tunnel.network',
994 '25-sit-tunnel-local-any.netdev', '25-tunnel-local-any.network',
995 '25-sit-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
997 wait_online(['sittun99:routable', 'sittun98:routable', 'sittun97:routable', 'dummy98:degraded'])
999 output
= check_output('ip -d link show sittun99')
1001 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
1002 output
= check_output('ip -d link show sittun98')
1004 self
.assertRegex(output
, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
1005 output
= check_output('ip -d link show sittun97')
1007 self
.assertRegex(output
, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
1009 def test_isatap_tunnel(self
):
1010 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'isatap.network',
1011 '25-isatap-tunnel.netdev', '25-tunnel.network')
1013 wait_online(['isataptun99:routable', 'dummy98:degraded'])
1015 output
= check_output('ip -d link show isataptun99')
1017 self
.assertRegex(output
, "isatap ")
1019 def test_6rd_tunnel(self
):
1020 copy_unit_to_networkd_unit_path('12-dummy.netdev', '6rd.network',
1021 '25-6rd-tunnel.netdev', '25-tunnel.network')
1023 wait_online(['sittun99:routable', 'dummy98:degraded'])
1025 output
= check_output('ip -d link show sittun99')
1027 self
.assertRegex(output
, '6rd-prefix 2602::/24')
1029 @expectedFailureIfERSPANModuleIsNotAvailable()
1030 def test_erspan_tunnel(self
):
1031 copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
1032 '25-erspan-tunnel.netdev', '25-tunnel.network',
1033 '25-erspan-tunnel-local-any.netdev', '25-tunnel-local-any.network')
1035 wait_online(['erspan99:routable', 'erspan98:routable', 'dummy98:degraded'])
1037 output
= check_output('ip -d link show erspan99')
1039 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local 172.16.1.200')
1040 self
.assertRegex(output
, 'ikey 0.0.0.101')
1041 self
.assertRegex(output
, 'okey 0.0.0.101')
1042 self
.assertRegex(output
, 'iseq')
1043 self
.assertRegex(output
, 'oseq')
1044 output
= check_output('ip -d link show erspan98')
1046 self
.assertRegex(output
, 'erspan remote 172.16.1.100 local any')
1047 self
.assertRegex(output
, '102')
1048 self
.assertRegex(output
, 'ikey 0.0.0.102')
1049 self
.assertRegex(output
, 'okey 0.0.0.102')
1050 self
.assertRegex(output
, 'iseq')
1051 self
.assertRegex(output
, 'oseq')
1053 def test_tunnel_independent(self
):
1054 copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev', 'netdev-link-local-addressing-yes.network')
1057 wait_online(['ipiptun99:carrier'])
1059 @expectedFailureIfModuleIsNotAvailable('fou')
1061 # The following redundant check is necessary for CentOS CI.
1062 # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
1063 self
.assertTrue(is_module_available('fou'))
1065 copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
1066 '25-fou-ipip.netdev', '25-fou-sit.netdev',
1067 '25-fou-gre.netdev', '25-fou-gretap.netdev')
1070 wait_online(['ipiptun96:off', 'sittun96:off', 'gretun96:off', 'gretap96:off'])
1072 output
= check_output('ip fou show')
1074 self
.assertRegex(output
, 'port 55555 ipproto 4')
1075 self
.assertRegex(output
, 'port 55556 ipproto 47')
1077 output
= check_output('ip -d link show ipiptun96')
1079 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1080 output
= check_output('ip -d link show sittun96')
1082 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55555')
1083 output
= check_output('ip -d link show gretun96')
1085 self
.assertRegex(output
, 'encap fou encap-sport 1001 encap-dport 55556')
1086 output
= check_output('ip -d link show gretap96')
1088 self
.assertRegex(output
, 'encap fou encap-sport auto encap-dport 55556')
1090 def test_vxlan(self
):
1091 copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network',
1092 '11-dummy.netdev', 'vxlan-test1.network')
1095 wait_online(['test1:degraded', 'vxlan99:degraded'])
1097 output
= check_output('ip -d link show vxlan99')
1099 self
.assertRegex(output
, '999')
1100 self
.assertRegex(output
, '5555')
1101 self
.assertRegex(output
, 'l2miss')
1102 self
.assertRegex(output
, 'l3miss')
1103 self
.assertRegex(output
, 'udpcsum')
1104 self
.assertRegex(output
, 'udp6zerocsumtx')
1105 self
.assertRegex(output
, 'udp6zerocsumrx')
1106 self
.assertRegex(output
, 'remcsumtx')
1107 self
.assertRegex(output
, 'remcsumrx')
1108 self
.assertRegex(output
, 'gbp')
1110 output
= check_output('bridge fdb show dev vxlan99')
1112 self
.assertRegex(output
, '00:11:22:33:44:55 dst 10.0.0.5 self permanent')
1113 self
.assertRegex(output
, '00:11:22:33:44:66 dst 10.0.0.6 self permanent')
1114 self
.assertRegex(output
, '00:11:22:33:44:77 dst 10.0.0.7 self permanent')
1116 def test_macsec(self
):
1117 copy_unit_to_networkd_unit_path('25-macsec.netdev', '25-macsec.network', '25-macsec.key',
1118 'macsec.network', '12-dummy.netdev')
1121 wait_online(['dummy98:degraded', 'macsec99:routable'])
1123 output
= check_output('ip -d link show macsec99')
1125 self
.assertRegex(output
, 'macsec99@dummy98')
1126 self
.assertRegex(output
, 'macsec sci [0-9a-f]*000b')
1127 self
.assertRegex(output
, 'encrypt on')
1129 output
= check_output('ip macsec show macsec99')
1131 self
.assertRegex(output
, 'encrypt on')
1132 self
.assertRegex(output
, 'TXSC: [0-9a-f]*000b on SA 1')
1133 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 01000000000000000000000000000000')
1134 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030000000000000000000000000000')
1135 self
.assertRegex(output
, 'RXSC: c619528fe6a00100, state on')
1136 self
.assertRegex(output
, '0: PN [0-9]*, state on, key 02030405000000000000000000000000')
1137 self
.assertRegex(output
, '1: PN [0-9]*, state on, key 02030405060000000000000000000000')
1138 self
.assertRegex(output
, '2: PN [0-9]*, state off, key 02030405060700000000000000000000')
1139 self
.assertRegex(output
, '3: PN [0-9]*, state off, key 02030405060708000000000000000000')
1140 self
.assertNotRegex(output
, 'key 02030405067080900000000000000000')
1141 self
.assertRegex(output
, 'RXSC: 8c16456c83a90002, state on')
1142 self
.assertRegex(output
, '0: PN [0-9]*, state off, key 02030400000000000000000000000000')
1144 def test_nlmon(self
):
1145 copy_unit_to_networkd_unit_path('25-nlmon.netdev', 'netdev-link-local-addressing-yes.network')
1148 wait_online(['nlmon99:carrier'])
1150 class NetworkdL2TPTests(unittest
.TestCase
, Utilities
):
1161 '25-l2tp-dummy.network',
1162 '25-l2tp-ip.netdev',
1163 '25-l2tp-udp.netdev']
1165 l2tp_tunnel_ids
= [ '10' ]
1168 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1169 remove_links(self
.links
)
1172 l2tp_tunnel_remove(self
.l2tp_tunnel_ids
)
1173 remove_links(self
.links
)
1174 remove_unit_from_networkd_path(self
.units
)
1176 @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
1177 def test_l2tp_udp(self
):
1178 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
1181 wait_online(['test1:routable', 'l2tp-ses1:off', 'l2tp-ses2:off'])
1183 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1185 self
.assertRegex(output
, "Tunnel 10, encap UDP")
1186 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1187 self
.assertRegex(output
, "Peer tunnel 11")
1188 self
.assertRegex(output
, "UDP source / dest ports: 3000/4000")
1189 self
.assertRegex(output
, "UDP checksum: enabled")
1191 output
= check_output('ip l2tp show session tid 10 session_id 15')
1193 self
.assertRegex(output
, "Session 15 in tunnel 10")
1194 self
.assertRegex(output
, "Peer session 16, tunnel 11")
1195 self
.assertRegex(output
, "interface name: l2tp-ses1")
1197 output
= check_output('ip l2tp show session tid 10 session_id 17')
1199 self
.assertRegex(output
, "Session 17 in tunnel 10")
1200 self
.assertRegex(output
, "Peer session 18, tunnel 11")
1201 self
.assertRegex(output
, "interface name: l2tp-ses2")
1203 @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
1204 def test_l2tp_ip(self
):
1205 copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
1208 wait_online(['test1:routable', 'l2tp-ses3:off', 'l2tp-ses4:off'])
1210 output
= check_output('ip l2tp show tunnel tunnel_id 10')
1212 self
.assertRegex(output
, "Tunnel 10, encap IP")
1213 self
.assertRegex(output
, "From 192.168.30.100 to 192.168.30.101")
1214 self
.assertRegex(output
, "Peer tunnel 12")
1216 output
= check_output('ip l2tp show session tid 10 session_id 25')
1218 self
.assertRegex(output
, "Session 25 in tunnel 10")
1219 self
.assertRegex(output
, "Peer session 26, tunnel 12")
1220 self
.assertRegex(output
, "interface name: l2tp-ses3")
1222 output
= check_output('ip l2tp show session tid 10 session_id 27')
1224 self
.assertRegex(output
, "Session 27 in tunnel 10")
1225 self
.assertRegex(output
, "Peer session 28, tunnel 12")
1226 self
.assertRegex(output
, "interface name: l2tp-ses4")
1228 class NetworkdNetworkTests(unittest
.TestCase
, Utilities
):
1238 '23-active-slave.network',
1239 '24-keep-configuration-static.network',
1240 '24-search-domain.network',
1241 '25-address-link-section.network',
1242 '25-address-preferred-lifetime-zero-ipv6.network',
1243 '25-address-static.network',
1244 '25-bind-carrier.network',
1245 '25-bond-active-backup-slave.netdev',
1246 '25-fibrule-invert.network',
1247 '25-fibrule-port-range.network',
1248 '25-ipv6-address-label-section.network',
1249 '25-neighbor-section.network',
1250 '25-link-local-addressing-no.network',
1251 '25-link-local-addressing-yes.network',
1252 '25-link-section-unmanaged.network',
1253 '25-route-ipv6-src.network',
1254 '25-route-static.network',
1255 '25-sysctl-disable-ipv6.network',
1256 '25-sysctl.network',
1257 'configure-without-carrier.network',
1258 'routing-policy-rule-dummy98.network',
1259 'routing-policy-rule-test1.network']
1261 routing_policy_rule_tables
= ['7', '8']
1262 routes
= [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
1265 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1266 remove_routes(self
.routes
)
1267 remove_links(self
.links
)
1270 remove_routing_policy_rule_tables(self
.routing_policy_rule_tables
)
1271 remove_routes(self
.routes
)
1272 remove_links(self
.links
)
1273 remove_unit_from_networkd_path(self
.units
)
1275 def test_address_static(self
):
1276 copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
1279 wait_online(['dummy98:routable'])
1281 output
= check_output('ip -4 address show dev dummy98')
1283 self
.assertRegex(output
, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
1284 self
.assertRegex(output
, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
1285 self
.assertRegex(output
, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
1288 self
.assertNotRegex(output
, '10.10.0.1/16')
1289 self
.assertNotRegex(output
, '10.10.0.2/16')
1291 output
= check_output('ip -4 address show dev dummy98 label 32')
1292 self
.assertRegex(output
, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
1294 output
= check_output('ip -4 address show dev dummy98 label 33')
1295 self
.assertRegex(output
, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
1297 output
= check_output('ip -4 address show dev dummy98 label 34')
1298 self
.assertRegex(output
, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
1300 output
= check_output('ip -4 address show dev dummy98 label 35')
1301 self
.assertRegex(output
, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
1303 output
= check_output('ip -6 address show dev dummy98')
1305 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::15/64 scope global')
1306 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::16/64 scope global')
1307 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::15/64 scope global')
1308 self
.assertRegex(output
, 'inet6 2001:db8:0:f102::16/64 scope global')
1309 self
.assertRegex(output
, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
1310 self
.assertRegex(output
, 'inet6 fd[0-9a-f:]*1/64 scope global')
1312 def test_address_preferred_lifetime_zero_ipv6(self
):
1313 copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
1316 self
.check_link_exists('dummy98')
1318 self
.check_operstate('dummy98', 'routable', setup_state
='configuring')
1320 output
= check_output('ip address show dummy98')
1322 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
1323 self
.assertRegex(output
, 'inet6 2001:db8:0:f101::1/64 scope global')
1325 def test_configure_without_carrier(self
):
1326 copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
1329 self
.check_link_exists('test1')
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')
1342 self
.check_link_exists('test1')
1344 output
= check_output('ip rule')
1346 self
.assertRegex(output
, '111')
1347 self
.assertRegex(output
, 'from 192.168.100.18')
1348 self
.assertRegex(output
, r
'tos (?:0x08|throughput)\s')
1349 self
.assertRegex(output
, 'iif test1')
1350 self
.assertRegex(output
, 'oif test1')
1351 self
.assertRegex(output
, 'lookup 7')
1353 def test_routing_policy_rule_issue_11280(self
):
1354 copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
1355 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
1357 for trial
in range(3):
1358 # Remove state files only first time
1359 start_networkd(remove_state_files
=(trial
== 0))
1361 self
.check_link_exists('test1')
1362 self
.check_link_exists('dummy98')
1364 output
= check_output('ip rule list table 7')
1366 self
.assertRegex(output
, '111: from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
1368 output
= check_output('ip rule list table 8')
1370 self
.assertRegex(output
, '112: from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
1372 @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
1373 def test_routing_policy_rule_port_range(self
):
1374 copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
1378 self
.check_link_exists('test1')
1380 output
= check_output('ip rule')
1382 self
.assertRegex(output
, '111')
1383 self
.assertRegex(output
, 'from 192.168.100.18')
1384 self
.assertRegex(output
, '1123-1150')
1385 self
.assertRegex(output
, '3224-3290')
1386 self
.assertRegex(output
, 'tcp')
1387 self
.assertRegex(output
, 'lookup 7')
1389 @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
1390 def test_routing_policy_rule_invert(self
):
1391 copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
1395 self
.check_link_exists('test1')
1397 output
= check_output('ip rule')
1399 self
.assertRegex(output
, '111')
1400 self
.assertRegex(output
, 'not.*?from.*?192.168.100.18')
1401 self
.assertRegex(output
, 'tcp')
1402 self
.assertRegex(output
, 'lookup 7')
1404 def test_route_static(self
):
1405 copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
1408 wait_online(['dummy98:routable'])
1410 output
= check_output('ip -6 route show dev dummy98')
1412 self
.assertRegex(output
, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
1413 self
.assertRegex(output
, '2001:1234:5:8f63::1 proto kernel')
1415 output
= check_output('ip -6 route show dev dummy98 default')
1416 self
.assertRegex(output
, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
1418 output
= check_output('ip -4 route show dev dummy98')
1420 self
.assertRegex(output
, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
1421 self
.assertRegex(output
, '149.10.124.64 proto static scope link')
1422 self
.assertRegex(output
, '169.254.0.0/16 proto static scope link metric 2048')
1423 self
.assertRegex(output
, '192.168.1.1 proto static initcwnd 20')
1424 self
.assertRegex(output
, '192.168.1.2 proto static initrwnd 30')
1426 output
= check_output('ip -4 route show dev dummy98 default')
1427 self
.assertRegex(output
, 'default via 149.10.125.65 proto static onlink')
1428 self
.assertRegex(output
, 'default via 149.10.124.64 proto static')
1429 self
.assertRegex(output
, 'default proto static')
1431 output
= check_output('ip route show type blackhole')
1433 self
.assertRegex(output
, 'blackhole 202.54.1.2 proto static')
1435 output
= check_output('ip route show type unreachable')
1437 self
.assertRegex(output
, 'unreachable 202.54.1.3 proto static')
1439 output
= check_output('ip route show type prohibit')
1441 self
.assertRegex(output
, 'prohibit 202.54.1.4 proto static')
1443 def test_ip_route_ipv6_src_route(self
):
1444 # a dummy device does not make the addresses go through tentative state, so we
1445 # reuse a bond from an earlier test, which does make the addresses go through
1446 # tentative state, and do our test on that
1447 copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1450 self
.check_link_exists('dummy98')
1451 self
.check_link_exists('bond199')
1453 output
= check_output('ip -6 route list dev bond199')
1455 self
.assertRegex(output
, 'abcd::/16')
1456 self
.assertRegex(output
, 'src')
1457 self
.assertRegex(output
, '2001:1234:56:8f63::2')
1459 def test_ip_link_mac_address(self
):
1460 copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
1463 self
.check_link_exists('dummy98')
1465 output
= check_output('ip link show dummy98')
1467 self
.assertRegex(output
, '00:01:02:aa:bb:cc')
1469 def test_ip_link_unmanaged(self
):
1470 copy_unit_to_networkd_unit_path('25-link-section-unmanaged.network', '12-dummy.netdev')
1473 self
.check_link_exists('dummy98')
1475 output
= check_output(*networkctl_cmd
, 'status', 'dummy98')
1477 self
.assertRegex(output
, 'unmanaged')
1479 def test_ipv6_address_label(self
):
1480 copy_unit_to_networkd_unit_path('25-ipv6-address-label-section.network', '12-dummy.netdev')
1483 self
.check_link_exists('dummy98')
1485 output
= check_output('ip addrlabel list')
1487 self
.assertRegex(output
, '2004:da8:1::/64')
1489 def test_ipv6_neighbor(self
):
1490 copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev')
1493 self
.check_link_exists('dummy98')
1495 output
= check_output('ip neigh list')
1497 self
.assertRegex(output
, '192.168.10.1.*00:00:5e:00:02:65.*PERMANENT')
1498 self
.assertRegex(output
, '2004:da8:1::1.*00:00:5e:00:02:66.*PERMANENT')
1500 def test_link_local_addressing(self
):
1501 copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
1502 '25-link-local-addressing-no.network', '12-dummy.netdev')
1504 wait_online(['test1:degraded', 'dummy98:carrier'])
1506 self
.check_link_exists('test1')
1507 self
.check_link_exists('dummy98')
1509 output
= check_output('ip address show dev test1')
1511 self
.assertRegex(output
, 'inet .* scope link')
1512 self
.assertRegex(output
, 'inet6 .* scope link')
1514 output
= check_output('ip address show dev dummy98')
1516 self
.assertNotRegex(output
, 'inet6* .* scope link')
1518 self
.check_operstate('test1', 'degraded')
1519 self
.check_operstate('dummy98', 'carrier')
1522 Documentation/networking/ip-sysctl.txt
1524 addr_gen_mode - INTEGER
1525 Defines how link-local and autoconf addresses are generated.
1527 0: generate address based on EUI64 (default)
1528 1: do no generate a link-local address, use EUI64 for addresses generated
1530 2: generate stable privacy addresses, using the secret from
1531 stable_secret (RFC7217)
1532 3: generate stable privacy addresses, using a random secret if unset
1535 test1_addr_gen_mode
= ''
1536 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')):
1537 with
open(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'stable_secret')) as f
:
1541 # if stable_secret is unset, then EIO is returned
1542 test1_addr_gen_mode
= '0'
1544 test1_addr_gen_mode
= '2'
1546 test1_addr_gen_mode
= '0'
1548 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'test1'), 'addr_gen_mode')):
1549 self
.assertEqual(read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode
)
1551 if os
.path
.exists(os
.path
.join(os
.path
.join(network_sysctl_ipv6_path
, 'dummy98'), 'addr_gen_mode')):
1552 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
1554 def test_sysctl(self
):
1555 copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
1557 wait_online(['dummy98:degraded'])
1559 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'forwarding'), '1')
1560 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'use_tempaddr'), '2')
1561 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'dad_transmits'), '3')
1562 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'hop_limit'), '5')
1563 self
.assertEqual(read_ipv6_sysctl_attr('dummy98', 'proxy_ndp'), '1')
1564 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
1565 self
.assertEqual(read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
1567 def test_sysctl_disable_ipv6(self
):
1568 copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
1570 print('## Disable ipv6')
1571 check_output('sysctl net.ipv6.conf.all.disable_ipv6=1')
1572 check_output('sysctl net.ipv6.conf.default.disable_ipv6=1')
1575 wait_online(['dummy98:routable'])
1577 output
= check_output('ip -4 address show dummy98')
1579 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1580 output
= check_output('ip -6 address show dummy98')
1582 self
.assertEqual(output
, '')
1583 output
= check_output('ip -4 route show dev dummy98')
1585 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1586 output
= check_output('ip -6 route show dev dummy98')
1588 self
.assertEqual(output
, '')
1590 check_output('ip link del dummy98')
1592 print('## Enable ipv6')
1593 check_output('sysctl net.ipv6.conf.all.disable_ipv6=0')
1594 check_output('sysctl net.ipv6.conf.default.disable_ipv6=0')
1597 wait_online(['dummy98:routable'])
1599 output
= check_output('ip -4 address show dummy98')
1601 self
.assertRegex(output
, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
1602 output
= check_output('ip -6 address show dummy98')
1604 self
.assertRegex(output
, 'inet6 2607:5300:203:3906::/64 scope global')
1605 self
.assertRegex(output
, 'inet6 .* scope link')
1606 output
= check_output('ip -4 route show dev dummy98')
1608 self
.assertEqual(output
, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
1609 output
= check_output('ip -6 route show dev dummy98')
1611 self
.assertRegex(output
, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
1613 def test_bind_carrier(self
):
1614 copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
1617 self
.check_link_exists('test1')
1619 check_output('ip link add dummy98 type dummy')
1620 check_output('ip link set dummy98 up')
1622 output
= check_output('ip address show test1')
1624 self
.assertRegex(output
, 'UP,LOWER_UP')
1625 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1626 self
.check_operstate('test1', 'routable')
1628 check_output('ip link add dummy99 type dummy')
1629 check_output('ip link set dummy99 up')
1631 output
= check_output('ip address show test1')
1633 self
.assertRegex(output
, 'UP,LOWER_UP')
1634 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1635 self
.check_operstate('test1', 'routable')
1637 check_output('ip link del dummy98')
1639 output
= check_output('ip address show test1')
1641 self
.assertRegex(output
, 'UP,LOWER_UP')
1642 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1643 self
.check_operstate('test1', 'routable')
1645 check_output('ip link del dummy99')
1647 output
= check_output('ip address show test1')
1649 self
.assertNotRegex(output
, 'UP,LOWER_UP')
1650 self
.assertRegex(output
, 'DOWN')
1651 self
.assertNotRegex(output
, '192.168.10')
1652 self
.check_operstate('test1', 'off')
1654 check_output('ip link add dummy98 type dummy')
1655 check_output('ip link set dummy98 up')
1657 output
= check_output('ip address show test1')
1659 self
.assertRegex(output
, 'UP,LOWER_UP')
1660 self
.assertRegex(output
, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
1661 self
.check_operstate('test1', 'routable')
1663 def test_domain(self
):
1664 copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network')
1666 wait_online(['dummy98:routable'])
1668 output
= check_output(*networkctl_cmd
, 'status', 'dummy98', env
=env
)
1670 self
.assertRegex(output
, 'Address: 192.168.42.100')
1671 self
.assertRegex(output
, 'DNS: 192.168.42.1')
1672 self
.assertRegex(output
, 'Search Domains: one')
1674 def test_keep_configuration_static(self
):
1675 check_output('systemctl stop systemd-networkd')
1677 check_output('ip link add name dummy98 type dummy')
1678 check_output('ip address add 10.1.2.3/16 dev dummy98')
1679 check_output('ip address add 10.2.3.4/16 dev dummy98 valid_lft 600 preferred_lft 500')
1680 output
= check_output('ip address show dummy98')
1682 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1683 self
.assertRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1684 output
= check_output('ip route show dev dummy98')
1687 copy_unit_to_networkd_unit_path('24-keep-configuration-static.network')
1689 wait_online(['dummy98:routable'])
1691 output
= check_output('ip address show dummy98')
1693 self
.assertRegex(output
, 'inet 10.1.2.3/16 scope global dummy98')
1694 self
.assertNotRegex(output
, 'inet 10.2.3.4/16 scope global dynamic dummy98')
1696 class NetworkdBondTests(unittest
.TestCase
, Utilities
):
1706 '23-active-slave.network',
1707 '23-bond199.network',
1708 '23-primary-slave.network',
1709 '23-test1-bond199.network',
1710 '25-bond-active-backup-slave.netdev',
1713 'bond-slave.network']
1716 remove_links(self
.links
)
1719 remove_links(self
.links
)
1720 remove_unit_from_networkd_path(self
.units
)
1722 def test_bond_active_slave(self
):
1723 copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
1726 self
.check_link_exists('dummy98')
1727 self
.check_link_exists('bond199')
1729 output
= check_output('ip -d link show bond199')
1731 self
.assertRegex(output
, 'active_slave dummy98')
1733 def test_bond_primary_slave(self
):
1734 copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
1737 self
.check_link_exists('test1')
1738 self
.check_link_exists('bond199')
1740 output
= check_output('ip -d link show bond199')
1742 self
.assertRegex(output
, 'primary test1')
1744 def test_bond_operstate(self
):
1745 copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
1746 'bond99.network','bond-slave.network')
1749 self
.check_link_exists('bond99')
1750 self
.check_link_exists('dummy98')
1751 self
.check_link_exists('test1')
1753 output
= check_output('ip -d link show dummy98')
1755 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1757 output
= check_output('ip -d link show test1')
1759 self
.assertRegex(output
, 'SLAVE,UP,LOWER_UP')
1761 output
= check_output('ip -d link show bond99')
1763 self
.assertRegex(output
, 'MASTER,UP,LOWER_UP')
1765 self
.check_operstate('dummy98', 'enslaved')
1766 self
.check_operstate('test1', 'enslaved')
1767 self
.check_operstate('bond99', 'routable')
1769 check_output('ip link set dummy98 down')
1772 self
.check_operstate('dummy98', 'off')
1773 self
.check_operstate('test1', 'enslaved')
1774 self
.check_operstate('bond99', 'degraded-carrier')
1776 check_output('ip link set dummy98 up')
1779 self
.check_operstate('dummy98', 'enslaved')
1780 self
.check_operstate('test1', 'enslaved')
1781 self
.check_operstate('bond99', 'routable')
1783 check_output('ip link set dummy98 down')
1784 check_output('ip link set test1 down')
1787 self
.check_operstate('dummy98', 'off')
1788 self
.check_operstate('test1', 'off')
1790 for trial
in range(30):
1793 output
= check_output('ip address show bond99')
1795 if get_operstate('bond99') == 'no-carrier':
1798 # Huh? Kernel does not recognize that all slave interfaces are down?
1799 # Let's confirm that networkd's operstate is consistent with ip's result.
1800 self
.assertNotRegex(output
, 'NO-CARRIER')
1802 class NetworkdBridgeTests(unittest
.TestCase
, Utilities
):
1812 '26-bridge-slave-interface-1.network',
1813 '26-bridge-slave-interface-2.network',
1814 'bridge99-ignore-carrier-loss.network',
1818 remove_links(self
.links
)
1821 remove_links(self
.links
)
1822 remove_unit_from_networkd_path(self
.units
)
1824 def test_bridge_property(self
):
1825 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1826 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1830 self
.check_link_exists('dummy98')
1831 self
.check_link_exists('test1')
1832 self
.check_link_exists('bridge99')
1834 output
= check_output('ip -d link show test1')
1836 self
.assertRegex(output
, 'master')
1837 self
.assertRegex(output
, 'bridge')
1839 output
= check_output('ip -d link show dummy98')
1841 self
.assertRegex(output
, 'master')
1842 self
.assertRegex(output
, 'bridge')
1844 output
= check_output('ip addr show bridge99')
1846 self
.assertRegex(output
, '192.168.0.15/24')
1848 output
= check_output('bridge -d link show dummy98')
1850 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
1851 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
1852 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
1853 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
1854 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
1855 if (os
.path
.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
1856 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
1857 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
1859 # CONFIG_BRIDGE_IGMP_SNOOPING=y
1860 if (os
.path
.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
1861 self
.assertEqual(read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
1863 self
.check_operstate('test1', 'enslaved')
1864 self
.check_operstate('dummy98', 'enslaved')
1865 self
.check_operstate('bridge99', 'routable')
1867 check_output('ip address add 192.168.0.16/24 dev bridge99')
1870 output
= check_output('ip addr show bridge99')
1872 self
.assertRegex(output
, '192.168.0.16/24')
1874 self
.check_operstate('bridge99', 'routable')
1876 self
.assertEqual(call('ip link del test1'), 0)
1879 self
.check_operstate('bridge99', 'degraded-carrier')
1881 check_output('ip link del dummy98')
1884 self
.check_operstate('bridge99', 'no-carrier')
1886 output
= check_output('ip address show bridge99')
1888 self
.assertRegex(output
, 'NO-CARRIER')
1889 self
.assertNotRegex(output
, '192.168.0.15/24')
1890 self
.assertNotRegex(output
, '192.168.0.16/24')
1892 def test_bridge_ignore_carrier_loss(self
):
1893 copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
1894 '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
1895 'bridge99-ignore-carrier-loss.network')
1896 call('ip rule del table 100')
1900 self
.check_link_exists('dummy98')
1901 self
.check_link_exists('test1')
1902 self
.check_link_exists('bridge99')
1904 check_output('ip address add 192.168.0.16/24 dev bridge99')
1907 check_output('ip link del test1')
1908 check_output('ip link del dummy98')
1911 output
= check_output('ip address show bridge99')
1913 self
.assertRegex(output
, 'NO-CARRIER')
1914 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1915 self
.assertRegex(output
, 'inet 192.168.0.16/24 scope global secondary bridge99')
1917 call('ip rule del table 100')
1919 def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self
):
1920 copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
1921 'bridge99-ignore-carrier-loss.network')
1923 call('ip rule del table 100')
1927 self
.check_link_exists('bridge99')
1929 check_output('ip link add dummy98 type dummy')
1930 check_output('ip link set dummy98 up')
1931 check_output('ip link del dummy98')
1933 check_output('ip link add dummy98 type dummy')
1934 check_output('ip link set dummy98 up')
1935 check_output('ip link del dummy98')
1937 check_output('ip link add dummy98 type dummy')
1938 check_output('ip link set dummy98 up')
1939 check_output('ip link del dummy98')
1941 check_output('ip link add dummy98 type dummy')
1942 check_output('ip link set dummy98 up')
1944 for trial
in range(30):
1947 if get_operstate('bridge99') == 'routable' and get_operstate('dummy98') == 'enslaved':
1950 self
.assertTrue(False)
1952 output
= check_output('ip address show bridge99')
1954 self
.assertRegex(output
, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
1956 output
= check_output('ip rule list table 100')
1958 self
.assertEqual(output
, '0: from all to 8.8.8.8 lookup 100')
1960 call('ip rule del table 100')
1962 class NetworkdLLDPTests(unittest
.TestCase
, Utilities
):
1966 '23-emit-lldp.network',
1971 remove_links(self
.links
)
1974 remove_links(self
.links
)
1975 remove_unit_from_networkd_path(self
.units
)
1977 def test_lldp(self
):
1978 copy_unit_to_networkd_unit_path('23-emit-lldp.network', '24-lldp.network', '25-veth.netdev')
1980 wait_online(['veth99:degraded', 'veth-peer:degraded'])
1982 output
= check_output(*networkctl_cmd
, 'lldp', env
=env
)
1984 self
.assertRegex(output
, 'veth-peer')
1985 self
.assertRegex(output
, 'veth99')
1987 class NetworkdRATests(unittest
.TestCase
, Utilities
):
1992 'ipv6-prefix.network',
1993 'ipv6-prefix-veth.network']
1996 remove_links(self
.links
)
1999 remove_links(self
.links
)
2000 remove_unit_from_networkd_path(self
.units
)
2002 def test_ipv6_prefix_delegation(self
):
2003 warn_about_firewalld()
2004 copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6-prefix.network', 'ipv6-prefix-veth.network')
2006 wait_online(['veth99:routable', 'veth-peer:degraded'])
2008 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2010 self
.assertRegex(output
, '2002:da8:1:0')
2012 class NetworkdDHCPServerTests(unittest
.TestCase
, Utilities
):
2017 'dhcp-client.network',
2018 'dhcp-client-timezone-router.network',
2019 'dhcp-server.network',
2020 'dhcp-server-timezone-router.network']
2023 remove_links(self
.links
)
2026 remove_links(self
.links
)
2027 remove_unit_from_networkd_path(self
.units
)
2029 def test_dhcp_server(self
):
2030 warn_about_firewalld()
2031 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client.network', 'dhcp-server.network')
2033 wait_online(['veth99:routable', 'veth-peer:routable'])
2035 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2037 self
.assertRegex(output
, '192.168.5.*')
2038 self
.assertRegex(output
, 'Gateway: 192.168.5.1')
2039 self
.assertRegex(output
, 'DNS: 192.168.5.1')
2040 self
.assertRegex(output
, 'NTP: 192.168.5.1')
2042 def test_emit_router_timezone(self
):
2043 warn_about_firewalld()
2044 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-client-timezone-router.network', 'dhcp-server-timezone-router.network')
2046 wait_online(['veth99:routable', 'veth-peer:routable'])
2048 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2050 self
.assertRegex(output
, 'Gateway: 192.168.5.*')
2051 self
.assertRegex(output
, '192.168.5.*')
2052 self
.assertRegex(output
, 'Europe/Berlin')
2054 class NetworkdDHCPClientTests(unittest
.TestCase
, Utilities
):
2063 'dhcp-client-anonymize.network',
2064 'dhcp-client-gateway-onlink-implicit.network',
2065 'dhcp-client-ipv4-dhcp-settings.network',
2066 'dhcp-client-ipv4-only-ipv6-disabled.network',
2067 'dhcp-client-ipv4-only.network',
2068 'dhcp-client-ipv6-only.network',
2069 'dhcp-client-ipv6-rapid-commit.network',
2070 'dhcp-client-keep-configuration-dhcp-on-stop.network',
2071 'dhcp-client-keep-configuration-dhcp.network',
2072 'dhcp-client-listen-port.network',
2073 'dhcp-client-route-metric.network',
2074 'dhcp-client-route-table.network',
2075 'dhcp-client-vrf.network',
2076 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
2077 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
2078 'dhcp-client.network',
2079 'dhcp-server-veth-peer.network',
2080 'dhcp-v4-server-veth-peer.network',
2084 stop_dnsmasq(dnsmasq_pid_file
)
2085 remove_links(self
.links
)
2088 stop_dnsmasq(dnsmasq_pid_file
)
2091 remove_links(self
.links
)
2092 remove_unit_from_networkd_path(self
.units
)
2094 def test_dhcp_client_ipv6_only(self
):
2095 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2098 wait_online(['veth-peer:carrier'])
2100 wait_online(['veth99:routable', 'veth-peer:routable'])
2102 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2104 self
.assertRegex(output
, '2600::')
2105 self
.assertNotRegex(output
, '192.168.5')
2107 # Confirm that ipv6 token is not set in the kernel
2108 output
= check_output('ip token show dev veth99')
2110 self
.assertRegex(output
, 'token :: dev veth99')
2112 def test_dhcp_client_ipv4_only(self
):
2113 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-only-ipv6-disabled.network')
2116 wait_online(['veth-peer:carrier'])
2118 wait_online(['veth99:routable', 'veth-peer:routable'])
2120 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2122 self
.assertNotRegex(output
, '2600::')
2123 self
.assertRegex(output
, '192.168.5')
2125 def test_dhcp_client_ipv4_ipv6(self
):
2126 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network',
2127 'dhcp-client-ipv4-only.network')
2129 wait_online(['veth-peer:carrier'])
2131 wait_online(['veth99:routable', 'veth-peer:routable'])
2133 # link become 'routable' when at least one protocol provide an valid address.
2134 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2135 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2137 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2139 self
.assertRegex(output
, '2600::')
2140 self
.assertRegex(output
, '192.168.5')
2142 def test_dhcp_client_settings(self
):
2143 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv4-dhcp-settings.network')
2146 wait_online(['veth-peer:carrier'])
2148 wait_online(['veth99:routable', 'veth-peer:routable'])
2150 print('## ip address show dev veth99')
2151 output
= check_output('ip address show dev veth99')
2153 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2154 self
.assertRegex(output
, '192.168.5')
2155 self
.assertRegex(output
, '1492')
2158 print('## ip route show table main dev veth99')
2159 output
= check_output('ip route show table main dev veth99')
2161 self
.assertNotRegex(output
, 'proto dhcp')
2163 print('## ip route show table 211 dev veth99')
2164 output
= check_output('ip route show table 211 dev veth99')
2166 self
.assertRegex(output
, 'default via 192.168.5.1 proto dhcp')
2167 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
2168 self
.assertRegex(output
, '192.168.5.1 proto dhcp scope link')
2170 print('## dnsmasq log')
2171 self
.assertTrue(search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
2172 self
.assertTrue(search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
2173 self
.assertTrue(search_words_in_dnsmasq_log('client provides name: test-hostname'))
2174 self
.assertTrue(search_words_in_dnsmasq_log('26:mtu'))
2176 def test_dhcp6_client_settings_rapidcommit_true(self
):
2177 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-only.network')
2179 wait_online(['veth-peer:carrier'])
2181 wait_online(['veth99:routable', 'veth-peer:routable'])
2183 output
= check_output('ip address show dev veth99')
2185 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2186 self
.assertTrue(search_words_in_dnsmasq_log('14:rapid-commit', True))
2188 def test_dhcp6_client_settings_rapidcommit_false(self
):
2189 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-ipv6-rapid-commit.network')
2191 wait_online(['veth-peer:carrier'])
2193 wait_online(['veth99:routable', 'veth-peer:routable'])
2195 output
= check_output('ip address show dev veth99')
2197 self
.assertRegex(output
, '12:34:56:78:9a:bc')
2198 self
.assertFalse(search_words_in_dnsmasq_log('14:rapid-commit', True))
2200 def test_dhcp_client_settings_anonymize(self
):
2201 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-anonymize.network')
2203 wait_online(['veth-peer:carrier'])
2205 wait_online(['veth99:routable', 'veth-peer:routable'])
2207 self
.assertFalse(search_words_in_dnsmasq_log('VendorClassIdentifier=SusantVendorTest', True))
2208 self
.assertFalse(search_words_in_dnsmasq_log('test-hostname'))
2209 self
.assertFalse(search_words_in_dnsmasq_log('26:mtu'))
2211 def test_dhcp_client_listen_port(self
):
2212 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-listen-port.network')
2214 wait_online(['veth-peer:carrier'])
2215 start_dnsmasq('--dhcp-alternate-port=67,5555')
2216 wait_online(['veth99:routable', 'veth-peer:routable'])
2218 # link become 'routable' when at least one protocol provide an valid address.
2219 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2220 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2222 output
= check_output('ip -4 address show dev veth99')
2224 self
.assertRegex(output
, '192.168.5.* dynamic')
2226 def test_dhcp_route_table_id(self
):
2227 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-table.network')
2229 wait_online(['veth-peer:carrier'])
2231 wait_online(['veth99:routable', 'veth-peer:routable'])
2233 output
= check_output('ip route show table 12')
2235 self
.assertRegex(output
, 'veth99 proto dhcp')
2236 self
.assertRegex(output
, '192.168.5.1')
2238 def test_dhcp_route_metric(self
):
2239 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-route-metric.network')
2241 wait_online(['veth-peer:carrier'])
2243 wait_online(['veth99:routable', 'veth-peer:routable'])
2245 output
= check_output('ip route show dev veth99')
2247 self
.assertRegex(output
, 'metric 24')
2249 def test_dhcp_keep_configuration_dhcp(self
):
2250 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp.network')
2252 wait_online(['veth-peer:carrier'])
2253 start_dnsmasq(lease_time
='2m')
2254 wait_online(['veth99:routable', 'veth-peer:routable'])
2256 output
= check_output('ip address show dev veth99 scope global')
2258 self
.assertRegex(output
, r
'192.168.5.*')
2260 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2262 self
.assertRegex(output
, r
'192.168.5.*')
2264 # Stopping dnsmasq as networkd won't be allowed to renew the DHCP lease.
2265 stop_dnsmasq(dnsmasq_pid_file
)
2267 # Sleep for 120 sec as the dnsmasq minimum lease time can only be set to 120
2268 print('Wait for the dynamic address to be expired')
2271 print('The lease address should be kept after lease expired')
2272 output
= check_output('ip address show dev veth99 scope global')
2274 self
.assertRegex(output
, r
'192.168.5.*')
2276 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2278 self
.assertRegex(output
, r
'192.168.5.*')
2280 check_output('systemctl stop systemd-networkd')
2282 print('The lease address should be kept after networkd stopped')
2283 output
= check_output('ip address show dev veth99 scope global')
2285 self
.assertRegex(output
, r
'192.168.5.*')
2287 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2289 self
.assertRegex(output
, r
'192.168.5.*')
2291 check_output('systemctl start systemd-networkd')
2292 wait_online(['veth-peer:routable'])
2294 print('Still the lease address should be kept after networkd restarted')
2295 output
= check_output('ip address show dev veth99 scope global')
2297 self
.assertRegex(output
, r
'192.168.5.*')
2299 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2301 self
.assertRegex(output
, r
'192.168.5.*')
2303 def test_dhcp_keep_configuration_dhcp_on_stop(self
):
2304 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-v4-server-veth-peer.network', 'dhcp-client-keep-configuration-dhcp-on-stop.network')
2306 wait_online(['veth-peer:carrier'])
2307 start_dnsmasq(lease_time
='2m')
2308 wait_online(['veth99:routable', 'veth-peer:routable'])
2310 output
= check_output('ip address show dev veth99 scope global')
2312 self
.assertRegex(output
, r
'192.168.5.*')
2314 stop_dnsmasq(dnsmasq_pid_file
)
2315 check_output('systemctl stop systemd-networkd')
2317 output
= check_output('ip address show dev veth99 scope global')
2319 self
.assertRegex(output
, r
'192.168.5.*')
2322 wait_online(['veth-peer:routable'])
2324 output
= check_output('ip address show dev veth99 scope global')
2326 self
.assertNotRegex(output
, r
'192.168.5.*')
2328 def test_dhcp_client_reuse_address_as_static(self
):
2329 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client.network')
2331 wait_online(['veth-peer:carrier'])
2333 wait_online(['veth99:routable', 'veth-peer:routable'])
2335 # link become 'routable' when at least one protocol provide an valid address.
2336 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2337 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2339 output
= check_output('ip address show dev veth99 scope global')
2341 self
.assertRegex(output
, '192.168.5')
2342 self
.assertRegex(output
, '2600::')
2344 ipv4_address
= re
.search(r
'192.168.5.[0-9]*/24', output
)
2345 ipv6_address
= re
.search(r
'2600::[0-9a-f:]*/128', output
)
2346 static_network
= '\n'.join(['[Match]', 'Name=veth99', '[Network]', 'IPv6AcceptRA=no', 'Address=' + ipv4_address
.group(), 'Address=' + ipv6_address
.group()])
2347 print(static_network
)
2349 remove_unit_from_networkd_path(['dhcp-client.network'])
2351 with
open(os
.path
.join(network_unit_file_path
, 'static.network'), mode
='w') as f
:
2352 f
.write(static_network
)
2354 # When networkd started, the links are already configured, so let's wait for 5 seconds
2355 # the links to be re-configured.
2357 wait_online(['veth99:routable', 'veth-peer:routable'])
2359 output
= check_output('ip -4 address show dev veth99 scope global')
2361 self
.assertRegex(output
, '192.168.5')
2362 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2364 output
= check_output('ip -6 address show dev veth99 scope global')
2366 self
.assertRegex(output
, '2600::')
2367 self
.assertRegex(output
, 'valid_lft forever preferred_lft forever')
2369 @expectedFailureIfModuleIsNotAvailable('vrf')
2370 def test_dhcp_client_vrf(self
):
2371 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
2372 '25-vrf.netdev', '25-vrf.network')
2374 wait_online(['veth-peer:carrier'])
2376 wait_online(['veth99:routable', 'veth-peer:routable', 'vrf99:carrier'])
2378 # link become 'routable' when at least one protocol provide an valid address.
2379 self
.wait_address('veth99', r
'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic', ipv
='-4')
2380 self
.wait_address('veth99', r
'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)', ipv
='-6')
2382 print('## ip -d link show dev vrf99')
2383 output
= check_output('ip -d link show dev vrf99')
2385 self
.assertRegex(output
, 'vrf table 42')
2387 print('## ip address show vrf vrf99')
2388 output
= check_output('ip address show vrf vrf99')
2390 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2391 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2392 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2393 self
.assertRegex(output
, 'inet6 .* scope link')
2395 print('## ip address show dev veth99')
2396 output
= check_output('ip address show dev veth99')
2398 self
.assertRegex(output
, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
2399 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2400 self
.assertRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global (?:dynamic noprefixroute|noprefixroute dynamic)')
2401 self
.assertRegex(output
, 'inet6 .* scope link')
2403 print('## ip route show vrf vrf99')
2404 output
= check_output('ip route show vrf vrf99')
2406 self
.assertRegex(output
, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
2407 self
.assertRegex(output
, 'default dev veth99 proto static scope link')
2408 self
.assertRegex(output
, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
2409 self
.assertRegex(output
, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
2410 self
.assertRegex(output
, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
2411 self
.assertRegex(output
, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
2413 print('## ip route show table main dev veth99')
2414 output
= check_output('ip route show table main dev veth99')
2416 self
.assertEqual(output
, '')
2418 self
.check_operstate('vrf99', 'carrier')
2419 self
.check_operstate('veth99', 'routable')
2421 def test_dhcp_client_gateway_onlink_implicit(self
):
2422 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2423 'dhcp-client-gateway-onlink-implicit.network')
2425 wait_online(['veth-peer:carrier'])
2427 wait_online(['veth99:routable', 'veth-peer:routable'])
2429 output
= check_output(*networkctl_cmd
, 'status', 'veth99', env
=env
)
2431 self
.assertRegex(output
, '192.168.5')
2433 output
= check_output('ip route list dev veth99 10.0.0.0/8')
2435 self
.assertRegex(output
, 'onlink')
2436 output
= check_output('ip route list dev veth99 192.168.100.0/24')
2438 self
.assertRegex(output
, 'onlink')
2440 def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self
):
2441 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2442 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
2444 wait_online(['veth-peer:carrier'])
2445 start_dnsmasq(lease_time
='2m')
2446 wait_online(['veth99:routable', 'veth-peer:routable'])
2448 output
= check_output('ip address show dev veth99')
2451 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2452 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2453 output
= check_output('ip -6 address show dev veth99 scope link')
2454 self
.assertRegex(output
, 'inet6 .* scope link')
2455 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2456 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2457 output
= check_output('ip -4 address show dev veth99 scope link')
2458 self
.assertNotRegex(output
, 'inet .* scope link')
2460 print('Wait for the dynamic address to be expired')
2463 output
= check_output('ip address show dev veth99')
2466 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2467 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2468 output
= check_output('ip -6 address show dev veth99 scope link')
2469 self
.assertRegex(output
, 'inet6 .* scope link')
2470 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2471 self
.assertRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2472 output
= check_output('ip -4 address show dev veth99 scope link')
2473 self
.assertNotRegex(output
, 'inet .* scope link')
2475 search_words_in_dnsmasq_log('DHCPOFFER', show_all
=True)
2477 def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self
):
2478 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2479 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
2481 wait_online(['veth99:degraded', 'veth-peer:routable'])
2483 output
= check_output('ip address show dev veth99')
2486 output
= check_output('ip -6 address show dev veth99 scope global dynamic')
2487 self
.assertNotRegex(output
, 'inet6 2600::[0-9a-f]*/128 scope global dynamic')
2488 output
= check_output('ip -6 address show dev veth99 scope link')
2489 self
.assertRegex(output
, 'inet6 .* scope link')
2490 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2491 self
.assertNotRegex(output
, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2492 output
= check_output('ip -4 address show dev veth99 scope link')
2493 self
.assertRegex(output
, 'inet .* scope link')
2495 def test_dhcp_client_route_remove_on_renew(self
):
2496 copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
2497 'dhcp-client-ipv4-only-ipv6-disabled.network')
2499 wait_online(['veth-peer:carrier'])
2500 start_dnsmasq(ipv4_range
='192.168.5.100,192.168.5.199', lease_time
='2m')
2501 wait_online(['veth99:routable', 'veth-peer:routable'])
2503 # test for issue #12490
2505 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2507 self
.assertRegex(output
, 'inet 192.168.5.1[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2509 for line
in output
.splitlines():
2510 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2511 address1
= line
.split()[1].split('/')[0]
2514 output
= check_output('ip -4 route show dev veth99')
2516 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2517 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2519 stop_dnsmasq(dnsmasq_pid_file
)
2520 start_dnsmasq(ipv4_range
='192.168.5.200,192.168.5.250', lease_time
='2m')
2522 print('Wait for the dynamic address to be expired')
2525 output
= check_output('ip -4 address show dev veth99 scope global dynamic')
2527 self
.assertRegex(output
, 'inet 192.168.5.2[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
2529 for line
in output
.splitlines():
2530 if 'brd 192.168.5.255 scope global dynamic veth99' in line
:
2531 address2
= line
.split()[1].split('/')[0]
2534 self
.assertNotEqual(address1
, address2
)
2536 output
= check_output('ip -4 route show dev veth99')
2538 self
.assertNotRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address1} metric 1024')
2539 self
.assertNotRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address1} metric 1024')
2540 self
.assertRegex(output
, f
'default via 192.168.5.1 proto dhcp src {address2} metric 1024')
2541 self
.assertRegex(output
, f
'192.168.5.1 proto dhcp scope link src {address2} metric 1024')
2543 if __name__
== '__main__':
2544 parser
= argparse
.ArgumentParser()
2545 parser
.add_argument('--build-dir', help='Path to build dir', dest
='build_dir')
2546 parser
.add_argument('--networkd', help='Path to systemd-networkd', dest
='networkd_bin')
2547 parser
.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest
='wait_online_bin')
2548 parser
.add_argument('--networkctl', help='Path to networkctl', dest
='networkctl_bin')
2549 parser
.add_argument('--valgrind', help='Enable valgrind', dest
='use_valgrind', type=bool, nargs
='?', const
=True, default
=use_valgrind
)
2550 parser
.add_argument('--debug', help='Generate debugging logs', dest
='enable_debug', type=bool, nargs
='?', const
=True, default
=enable_debug
)
2551 parser
.add_argument('--asan-options', help='ASAN options', dest
='asan_options')
2552 parser
.add_argument('--lsan-options', help='LSAN options', dest
='lsan_options')
2553 parser
.add_argument('--ubsan-options', help='UBSAN options', dest
='ubsan_options')
2554 ns
, args
= parser
.parse_known_args(namespace
=unittest
)
2557 if ns
.networkd_bin
or ns
.wait_online_bin
or ns
.networkctl_bin
:
2558 print('WARNING: --networkd, --wait-online, or --networkctl options are ignored when --build-dir is specified.')
2559 networkd_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd')
2560 wait_online_bin
= os
.path
.join(ns
.build_dir
, 'systemd-networkd-wait-online')
2561 networkctl_bin
= os
.path
.join(ns
.build_dir
, 'networkctl')
2564 networkd_bin
= ns
.networkd_bin
2565 if ns
.wait_online_bin
:
2566 wait_online_bin
= ns
.wait_online_bin
2567 if ns
.networkctl_bin
:
2568 networkctl_bin
= ns
.networkctl_bin
2570 use_valgrind
= ns
.use_valgrind
2571 enable_debug
= ns
.enable_debug
2572 asan_options
= ns
.asan_options
2573 lsan_options
= ns
.lsan_options
2574 ubsan_options
= ns
.ubsan_options
2577 networkctl_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin
]
2578 wait_online_cmd
= ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin
]
2580 networkctl_cmd
= [networkctl_bin
]
2581 wait_online_cmd
= [wait_online_bin
]
2584 env
.update({ 'SYSTEMD_LOG_LEVEL' : 'debug' })
2586 env
.update({ 'ASAN_OPTIONS' : asan_options
})
2588 env
.update({ 'LSAN_OPTIONS' : lsan_options
})
2590 env
.update({ 'UBSAN_OPTIONS' : ubsan_options
})
2593 unittest
.main(testRunner
=unittest
.TextTestRunner(stream
=sys
.stdout
,