3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-10-04 02:18:49 +02:00

auto-t: In testNetconfig verify routes created

Check that the right set of routes is being added for IPv4 and IPv6.
Chane gateway addresses to differ from the AP or dhcpd addresses.
This commit is contained in:
Andrew Zaborowski 2022-06-16 02:02:27 +02:00 committed by Denis Kenzior
parent c65b2ec317
commit c4fe900a71
4 changed files with 118 additions and 5 deletions

View File

@ -12,7 +12,7 @@ from hostapd import HostapdCLI
import testutil
from config import ctx
import os
import subprocess
import socket
class Test(unittest.TestCase):
@ -54,6 +54,29 @@ class Test(unittest.TestCase):
ctx.non_block_wait(check_addr, 10, device,
exception=Exception("IPv6 address was not set"))
ifname = str(device.name)
router_ll_addr = [addr for addr, _, _ in testutil.get_addrs6(self.hapd.ifname) if addr[0:2] == b'\xfe\x80'][0]
# Since we're in an isolated VM with freshly created interfaces we know any routes
# will have been created by IWD and don't have to allow for pre-existing routes
# in the table.
# Flags: 1=RTF_UP, 2=RTF_GATEWAY
expected_routes4 = {
testutil.RouteInfo(gw=socket.inet_pton(socket.AF_INET, '192.168.1.1'),
flags=3, ifname=ifname),
testutil.RouteInfo(dst=socket.inet_pton(socket.AF_INET, '192.168.0.0'), plen=17,
flags=1, ifname=ifname)
}
expected_routes6 = {
# Default router
testutil.RouteInfo(gw=router_ll_addr, flags=3, ifname=ifname),
# On-link prefix
testutil.RouteInfo(dst=socket.inet_pton(socket.AF_INET6, '3ffe:501:ffff:100::'), plen=72,
flags=1, ifname=ifname),
}
self.maxDiff = None
self.assertEqual(expected_routes4, set(testutil.get_routes4(ifname)))
self.assertEqual(expected_routes6, set(testutil.get_routes6(ifname)))
device.disconnect()
condition = 'not obj.connected'
@ -77,6 +100,7 @@ class Test(unittest.TestCase):
pass
hapd = HostapdCLI()
cls.hapd = hapd
# TODO: This could be moved into test-runner itself if other tests ever
# require this functionality (p2p, FILS, etc.). Since its simple
# enough it can stay here for now.
@ -94,9 +118,18 @@ class Test(unittest.TestCase):
'-lf', '/tmp/dhcpd6.leases',
hapd.ifname], cleanup=remove_lease6)
ctx.start_process(['sysctl', 'net.ipv6.conf.' + hapd.ifname + '.forwarding=1']).wait()
# Tell clients to use DHCPv6
# Send out Router Advertisements telling clients to use DHCPv6.
# Note trying to send the RAs from the router's global IPv6 address by adding a
# "AdvRASrcAddress { 3ffe:501:ffff:100::1; };" line will fail because the client
# and the router interfaces are in the same namespace and Linux won't allow routes
# with a non-link-local gateway address that is present on another interface in the
# same namespace.
config = open('/tmp/radvd.conf', 'w')
config.write('interface ' + hapd.ifname + ' { AdvSendAdvert on; AdvManagedFlag on; };')
config.write('interface ' + hapd.ifname + ''' {
AdvSendAdvert on;
AdvManagedFlag on;
prefix 3ffe:501:ffff:100::/72 { AdvAutonomous off; };
};''')
config.close()
cls.radvd_pid = ctx.start_process(['radvd', '-n', '-d5', '-p', '/tmp/radvd.pid', '-C', '/tmp/radvd.conf'])

View File

@ -3,12 +3,12 @@
# as DHCP would assign us to produce a conflict and test ACD
Address=192.168.1.10
Netmask=255.255.255.128
Gateway=192.168.1.1
Gateway=192.168.1.3
[IPv6]
# Use a different subnet than DHCP on purpose
Address=3ffe:501:ffff:200::10/80
Gateway=3ffe:501:ffff:200::1
Gateway=3ffe:501:ffff:200::3
[Settings]
AutoConnect=false

View File

@ -12,6 +12,7 @@ from hostapd import HostapdCLI
import testutil
from config import ctx
import os
import socket
class Test(unittest.TestCase):
@ -49,6 +50,28 @@ class Test(unittest.TestCase):
testutil.test_ip_address_match(dev1.name, '192.168.1.10', 25)
testutil.test_ip_address_match(dev1.name, '3ffe:501:ffff:200::10', 80)
ifname = str(dev1.name)
# Since we're in an isolated VM with freshly created interfaces we know any routes
# will have been created by IWD and don't have to allow for pre-existing routes
# in the table.
# Flags: 1=RTF_UP, 2=RTF_GATEWAY
expected_routes4 = {
testutil.RouteInfo(gw=socket.inet_pton(socket.AF_INET, '192.168.1.3'),
flags=3, ifname=ifname),
testutil.RouteInfo(dst=socket.inet_pton(socket.AF_INET, '192.168.1.0'), plen=25,
flags=1, ifname=ifname)
}
expected_routes6 = {
testutil.RouteInfo(gw=socket.inet_pton(socket.AF_INET6, '3ffe:501:ffff:200::3'),
flags=3, ifname=ifname),
testutil.RouteInfo(dst=socket.inet_pton(socket.AF_INET6, '3ffe:501:ffff:200::'), plen=80,
flags=1, ifname=ifname),
}
self.maxDiff = None
self.assertEqual(expected_routes4, set(testutil.get_routes4(ifname)))
self.assertEqual(expected_routes6, set(testutil.get_routes6(ifname)))
ordered_network = dev2.get_ordered_network('ssidTKIP')
condition = 'not obj.connected'

View File

@ -5,6 +5,7 @@ import fcntl
import struct
import select
import codecs
import collections
import iwd
from config import ctx
@ -230,3 +231,59 @@ def test_ip_connected(tup0, tup1):
ns1.start_process(['ping', '-c', '5', '-i', '0.2', ip0], check=True)
except:
raise Exception('Could not ping between %s and %s' % (ip0, ip1))
RouteInfo = collections.namedtuple('RouteInfo', 'dst plen gw flags ifname',
defaults=(None, None, None, 0, ''))
def get_routes4(ifname=None):
f = open('/proc/net/route', 'r')
lines = f.readlines()
f.close()
for line in lines[1:]: # Skip header line
route_ifname, dst_str, gw_str, flags, ref_cnt, use_cnt, metric, mask_str, \
mtu = line.strip().split(maxsplit=8)
if ifname is not None and route_ifname != ifname:
continue
dst = codecs.decode(dst_str, 'hex')[::-1]
mask = int(mask_str, 16)
plen = sum([(mask >> bit) & 1 for bit in range(0, 32)]) # count bits
gw = codecs.decode(gw_str, 'hex')[::-1]
if dst == b'\0\0\0\0':
dst = None
plen = None
if gw == b'\0\0\0\0':
gw = None
yield RouteInfo(dst, plen, gw, int(flags, 16), route_ifname)
def get_routes6(ifname=None):
f = open('/proc/net/ipv6_route', 'r')
lines = f.readlines()
f.close()
for line in lines:
dst_str, dst_plen_str, src_str, src_plen_str, gw_str, metric, ref_cnt, \
use_cnt, flags, route_ifname = line.strip().split(maxsplit=9)
if ifname is not None and route_ifname != ifname:
continue
dst = codecs.decode(dst_str, 'hex')
plen = int(dst_plen_str, 16)
gw = codecs.decode(gw_str, 'hex')
if dst[0] == 0xff or dst[:2] == b'\xfe\x80': # Skip link-local and multicast
continue
# Skip RTN_LOCAL-type routes, we don't need to validate them since they're added by
# the kernel and we can't simply add them to the expected list (the list that we
# validate against) because they're added a short time after an address (due to DAD?)
# and would create race conditions
if int(flags, 16) & (1 << 31):
continue
if dst == b'\0' * 16:
dst = None
plen = None
if gw == b'\0' * 16:
gw = None
yield RouteInfo(dst, plen, gw, int(flags, 16) & 0xf, route_ifname)