summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-03-02 02:08:02 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-03-02 02:08:02 +0000
commitf60e5bb8ad862139b2c8ffc0033bfa3cf750acf7 (patch)
tree31e26fadf8d6081d6f40ecebbc31ed95731cb3f9
parent5fda9b1cb973e83874d09379f4e04a4011e19c0f (diff)
parentbb7845a38dd19858523405cf7563d000fb5e493c (diff)
downloadtests-f60e5bb8ad862139b2c8ffc0033bfa3cf750acf7.tar.gz
Snap for 7178253 from bb7845a38dd19858523405cf7563d000fb5e493c to sc-release
Change-Id: I396b7791c6443d971f7074a75562a2fe337140c5
-rwxr-xr-xnet/test/bpf.py1
-rwxr-xr-xnet/test/bpf_test.py44
-rwxr-xr-xnet/test/csocket_test.py12
-rwxr-xr-xnet/test/run_net_test.sh1
-rwxr-xr-xnet/test/xfrm.py51
-rwxr-xr-xnet/test/xfrm_tunnel_test.py144
6 files changed, 242 insertions, 11 deletions
diff --git a/net/test/bpf.py b/net/test/bpf.py
index be4c72f..6d22423 100755
--- a/net/test/bpf.py
+++ b/net/test/bpf.py
@@ -163,6 +163,7 @@ BPF_FUNC_map_update_elem = 2
BPF_FUNC_map_delete_elem = 3
BPF_FUNC_ktime_get_ns = 5
BPF_FUNC_get_current_uid_gid = 15
+BPF_FUNC_skb_change_head = 43
BPF_FUNC_get_socket_cookie = 46
BPF_FUNC_get_socket_uid = 47
BPF_FUNC_ktime_get_boot_ns = 125
diff --git a/net/test/bpf_test.py b/net/test/bpf_test.py
index 92bbe50..a014918 100755
--- a/net/test/bpf_test.py
+++ b/net/test/bpf_test.py
@@ -38,6 +38,7 @@ from bpf import BPF_FUNC_ktime_get_boot_ns
from bpf import BPF_FUNC_ktime_get_ns
from bpf import BPF_FUNC_map_lookup_elem
from bpf import BPF_FUNC_map_update_elem
+from bpf import BPF_FUNC_skb_change_head
from bpf import BPF_JNE
from bpf import BPF_MAP_TYPE_HASH
from bpf import BPF_PROG_TYPE_CGROUP_SKB
@@ -330,9 +331,40 @@ class BpfTest(net_test.NetworkTest):
SocketUDPLoopBack(packet_count, 6, self.prog_fd)
self.assertEqual(packet_count * 2, LookupMap(self.map_fd, key).value)
+ ##############################################################################
+ #
+ # Test for presence of kernel patch:
+ #
+ # ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
+ #
+ # 4.14: https://android-review.googlesource.com/c/kernel/common/+/1237789
+ # commit fe82848d9c1c887d2a84d3738c13e644d01b6d6f
+ #
+ # 4.19: https://android-review.googlesource.com/c/kernel/common/+/1237788
+ # commit 6e04d94ab72435b45c413daff63520fd724e260e
+ #
+ # 5.4: https://android-review.googlesource.com/c/kernel/common/+/1237787
+ # commit d730995e7bc5b4c10cc176235b704a274e6ec16f
+ #
+ # Upstream in Linux v5.8:
+ # net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
+ # commit 6f3f65d80dac8f2bafce2213005821fccdce194c
+ #
+ @unittest.skipUnless(bpf.HAVE_EBPF_4_14,
+ "no bpf_skb_change_head() support for pre-4.14 kernels")
+ def testSkbChangeHead(self):
+ # long bpf_skb_change_head(struct sk_buff *skb, u32 len, u64 flags)
+ instructions = [
+ BpfMov64Imm(BPF_REG_2, 14), # u32 len
+ BpfMov64Imm(BPF_REG_3, 0), # u64 flags
+ BpfFuncCall(BPF_FUNC_skb_change_head),
+ ] + INS_BPF_EXIT_BLOCK
+ self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions,
+ b"Apache 2.0")
+ # No exceptions? Good.
+
def testKtimeGetNsGPL(self):
- instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)]
- instructions += INS_BPF_EXIT_BLOCK
+ instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)] + INS_BPF_EXIT_BLOCK
self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions)
# No exceptions? Good.
@@ -354,8 +386,7 @@ class BpfTest(net_test.NetworkTest):
@unittest.skipUnless(HAVE_EBPF_KTIME_GET_NS_APACHE2,
"no bpf_ktime_get_ns() support for non-GPL programs")
def testKtimeGetNsApache2(self):
- instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)]
- instructions += INS_BPF_EXIT_BLOCK
+ instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)] + INS_BPF_EXIT_BLOCK
self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions,
b"Apache 2.0")
# No exceptions? Good.
@@ -378,8 +409,9 @@ class BpfTest(net_test.NetworkTest):
@unittest.skipUnless(HAVE_EBPF_KTIME_GET_BOOT_NS,
"no bpf_ktime_get_boot_ns() support")
def testKtimeGetBootNs(self):
- instructions = [BpfFuncCall(BPF_FUNC_ktime_get_boot_ns)]
- instructions += INS_BPF_EXIT_BLOCK
+ instructions = [
+ BpfFuncCall(BPF_FUNC_ktime_get_boot_ns),
+ ] + INS_BPF_EXIT_BLOCK
self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions,
b"Apache 2.0")
# No exceptions? Good.
diff --git a/net/test/csocket_test.py b/net/test/csocket_test.py
index 2191fec..19760fe 100755
--- a/net/test/csocket_test.py
+++ b/net/test/csocket_test.py
@@ -16,7 +16,15 @@
"""Unit tests for csocket."""
-from socket import * # pylint: disable=wildcard-import
+import socket
+# pylint: disable=g-importing-member
+from socket import AF_INET
+from socket import AF_INET6
+from socket import inet_pton
+from socket import SOCK_DGRAM
+from socket import SOL_IP
+# pylint: enable=g-importing-member
+
import unittest
import csocket
@@ -29,7 +37,7 @@ SOL_IPV6 = 41
class CsocketTest(unittest.TestCase):
def _BuildSocket(self, family, addr):
- s = socket(family, SOCK_DGRAM, 0)
+ s = socket.socket(family, SOCK_DGRAM, 0)
s.bind((addr, 0))
return s
diff --git a/net/test/run_net_test.sh b/net/test/run_net_test.sh
index d65769d..6f32f81 100755
--- a/net/test/run_net_test.sh
+++ b/net/test/run_net_test.sh
@@ -47,6 +47,7 @@ OPTIONS="$OPTIONS DUMMY"
# Kernel version specific options
OPTIONS="$OPTIONS XFRM_INTERFACE" # Various device kernels
+OPTIONS="$OPTIONS XFRM_MIGRATE" # Added in 5.10
OPTIONS="$OPTIONS CGROUP_BPF" # Added in android-4.9
OPTIONS="$OPTIONS NF_SOCKET_IPV4 NF_SOCKET_IPV6" # Added in 4.9
OPTIONS="$OPTIONS INET_SCTP_DIAG" # Added in 4.7
diff --git a/net/test/xfrm.py b/net/test/xfrm.py
index c63d2a2..83437bd 100755
--- a/net/test/xfrm.py
+++ b/net/test/xfrm.py
@@ -140,6 +140,11 @@ XfrmSelector = cstruct.Struct(
"daddr saddr dport dport_mask sport sport_mask "
"family prefixlen_d prefixlen_s proto ifindex user")
+XfrmMigrate = cstruct.Struct(
+ "XfrmMigrate", "=16s16s16s16sBBxxIHH",
+ "old_daddr old_saddr new_daddr new_saddr proto "
+ "mode reqid old_family new_family")
+
XfrmLifetimeCfg = cstruct.Struct(
"XfrmLifetimeCfg", "=QQQQQQQQ",
"soft_byte hard_byte soft_packet hard_packet "
@@ -710,6 +715,52 @@ class Xfrm(netlink.NetlinkSocket):
for selector in selectors:
self.DeletePolicyInfo(selector, direction, mark, xfrm_if_id)
+ def MigrateTunnel(self, direction, selector, old_saddr, old_daddr,
+ new_saddr, new_daddr, spi,
+ encryption, auth_trunc, aead,
+ encap, new_output_mark, xfrm_if_id):
+ """Update addresses and underlying network of Policies and an SA
+
+ Args:
+ direction: XFRM_POLICY_IN or XFRM_POLICY_OUT
+ selector: An XfrmSelector of the tunnel that needs to be updated.
+ If the passed-in selector is None, it means the tunnel is
+ dual-stack and thus both IPv4 and IPv6 policies will be updated.
+ old_saddr: the old (current) source address of the tunnel
+ old_daddr: the old (current) destination address of the tunnel
+ new_saddr: the new source address the IPsec SA will be migrated to
+ new_daddr: the new destination address the tunnel will be migrated to
+ spi: The SPI for the IPsec SA that encapsulates the tunneled packets
+ encryption: A tuple of an XfrmAlgo and raw key bytes, or None.
+ auth_trunc: A tuple of an XfrmAlgoAuth and raw key bytes, or None.
+ aead: A tuple of an XfrmAlgoAead and raw key bytes, or None.
+ encap: An XfrmEncapTmpl structure, or None.
+ new_output_mark: The mark used to select the new underlying network
+ for packets outbound from xfrm. None means unspecified.
+ xfrm_if_id: The XFRM interface ID
+ """
+
+ if selector is None:
+ selectors = [EmptySelector(AF_INET), EmptySelector(AF_INET6)]
+ else:
+ selectors = [selector]
+
+ nlattrs = []
+ xfrmMigrate = XfrmMigrate((PaddedAddress(old_daddr), PaddedAddress(old_saddr),
+ PaddedAddress(new_daddr), PaddedAddress(new_saddr),
+ IPPROTO_ESP, XFRM_MODE_TUNNEL, 0,
+ net_test.GetAddressFamily(net_test.GetAddressVersion(old_saddr)),
+ net_test.GetAddressFamily(net_test.GetAddressVersion(new_saddr))))
+ nlattrs.append((XFRMA_MIGRATE, xfrmMigrate))
+
+ for selector in selectors:
+ self.SendXfrmNlRequest(XFRM_MSG_MIGRATE,
+ XfrmUserpolicyId(sel=selector, dir=direction), nlattrs)
+
+ # UPDSA is called exclusively to update the set_mark=new_output_mark.
+ self.AddSaInfo(new_saddr, new_daddr, spi, XFRM_MODE_TUNNEL, 0, encryption,
+ auth_trunc, aead, encap, None, new_output_mark, True, xfrm_if_id)
+
if __name__ == "__main__":
x = Xfrm()
diff --git a/net/test/xfrm_tunnel_test.py b/net/test/xfrm_tunnel_test.py
index f175c09..7497ea2 100755
--- a/net/test/xfrm_tunnel_test.py
+++ b/net/test/xfrm_tunnel_test.py
@@ -37,9 +37,13 @@ import xfrm_base
_LOOPBACK_IFINDEX = 1
_TEST_XFRM_IFNAME = "ipsec42"
_TEST_XFRM_IF_ID = 42
+_TEST_SPI = 0x1234
# Does the kernel support xfrmi interfaces?
def HaveXfrmInterfaces():
+ if net_test.LINUX_VERSION >= (4, 19, 0):
+ return True
+
try:
i = iproute.IPRoute()
i.CreateXfrmInterface(_TEST_XFRM_IFNAME, _TEST_XFRM_IF_ID,
@@ -56,13 +60,45 @@ def HaveXfrmInterfaces():
HAVE_XFRM_INTERFACES = HaveXfrmInterfaces()
+# Does the kernel support CONFIG_XFRM_MIGRATE?
+def SupportsXfrmMigrate():
+ if net_test.LINUX_VERSION >= (5, 10, 0):
+ return True
+
+ # XFRM_MIGRATE depends on xfrmi interfaces
+ if not HAVE_XFRM_INTERFACES:
+ return False
+
+ try:
+ x = xfrm.Xfrm()
+ wildcard_addr = net_test.GetWildcardAddress(6)
+ selector = xfrm.EmptySelector(AF_INET6)
+
+ # Expect migration to fail with EINVAL because it is trying to migrate a
+ # non-existent SA.
+ x.MigrateTunnel(xfrm.XFRM_POLICY_OUT, selector, wildcard_addr, wildcard_addr,
+ wildcard_addr, wildcard_addr, _TEST_SPI,
+ None, None, None, None, None, None)
+ print("Migration succeeded unexpectedly, assuming XFRM_MIGRATE is enabled")
+ return True
+ except IOError as err:
+ if err.errno == ENOPROTOOPT:
+ return False
+ elif err.errno == EINVAL:
+ return True
+ else:
+ print("Unexpected error, assuming XFRM_MIGRATE is enabled:", err.errno)
+ return True
+
+SUPPORTS_XFRM_MIGRATE = SupportsXfrmMigrate()
+
# Parameters to setup tunnels as special networks
_TUNNEL_NETID_OFFSET = 0xFC00 # Matches reserved netid range for IpSecService
_BASE_TUNNEL_NETID = {4: 40, 6: 60}
_BASE_VTI_OKEY = 2000000100
_BASE_VTI_IKEY = 2000000200
-_TEST_OUT_SPI = 0x1234
+_TEST_OUT_SPI = _TEST_SPI
_TEST_IN_SPI = _TEST_OUT_SPI
_TEST_OKEY = 2000000100
@@ -132,6 +168,7 @@ def InjectTests():
InjectParameterizedTests(XfrmTunnelTest)
InjectParameterizedTests(XfrmInterfaceTest)
InjectParameterizedTests(XfrmVtiTest)
+ InjectParameterizedTests(XfrmInterfaceMigrateTest)
def InjectParameterizedTests(cls):
@@ -334,6 +371,9 @@ class IpSecBaseInterface(object):
else:
auth, crypt = xfrm_base._ALGO_HMAC_SHA1, xfrm_base._ALGO_CBC_AES_256
+ self.auth = auth
+ self.crypt = crypt
+
self._SetupXfrmByType(auth, crypt)
def Rekey(self, outer_family, new_out_sa, new_in_sa):
@@ -448,7 +488,7 @@ class XfrmAddDeleteXfrmInterfaceTest(xfrm_base.XfrmBaseTest):
class XfrmInterface(IpSecBaseInterface):
def __init__(self, iface, netid, underlying_netid, ifindex, local, remote,
- version):
+ version, use_null_crypt=False):
super(XfrmInterface, self).__init__(iface, netid, underlying_netid, local,
remote, version)
@@ -456,7 +496,7 @@ class XfrmInterface(IpSecBaseInterface):
self.xfrm_if_id = netid
self.SetupInterface()
- self.SetupXfrm(False)
+ self.SetupXfrm(use_null_crypt)
def SetupInterface(self):
"""Create an XFRM interface."""
@@ -505,9 +545,30 @@ class XfrmInterface(IpSecBaseInterface):
self.xfrm.DeleteSaInfo(self.remote, old_out_spi, IPPROTO_ESP, None,
self.xfrm_if_id)
+ def Migrate(self, new_underlying_netid, new_local, new_remote):
+ self.xfrm.MigrateTunnel(xfrm.XFRM_POLICY_IN, None, self.remote, self.local,
+ new_remote, new_local, self.in_sa.spi,
+ self.crypt, self.auth, None, None,
+ new_underlying_netid, self.xfrm_if_id)
+
+ self.xfrm.MigrateTunnel(xfrm.XFRM_POLICY_OUT, None, self.local, self.remote,
+ new_local, new_remote, self.out_sa.spi,
+ self.crypt, self.auth, None, None,
+ new_underlying_netid, self.xfrm_if_id)
+
+ self.local = new_local
+ self.remote = new_remote
+ self.underlying_netid = new_underlying_netid
+
class XfrmTunnelBase(xfrm_base.XfrmBaseTest):
+ # Subclass that does not allow multiple tunnels (e.g. XfrmInterfaceMigrateTest)
+ # should override this method.
+ @classmethod
+ def allowMultipleTunnels(cls):
+ return True
+
@classmethod
def setUpClass(cls):
xfrm_base.XfrmBaseTest.setUpClass()
@@ -520,6 +581,10 @@ class XfrmTunnelBase(xfrm_base.XfrmBaseTest):
# IPv6 tunnel
cls.tunnelsV4 = {}
cls.tunnelsV6 = {}
+
+ if not cls.allowMultipleTunnels():
+ return
+
for i, underlying_netid in enumerate(cls.tuns):
for version in 4, 6:
netid = _BASE_TUNNEL_NETID[version] + _TUNNEL_NETID_OFFSET + i
@@ -947,6 +1012,79 @@ class XfrmInterfaceTest(XfrmTunnelBase):
def ParamTestXfrmIntfRekey(self, inner_version, outer_version):
self._TestTunnelRekey(inner_version, outer_version)
+@unittest.skipUnless(SUPPORTS_XFRM_MIGRATE, "XFRM migration unsupported")
+class XfrmInterfaceMigrateTest(XfrmTunnelBase):
+ # TODO: b/172497215 There is a kernel issue that XFRM_MIGRATE cannot work correctly
+ # when there are multiple tunnels with the same selectors. Thus before this issue
+ # is fixed, #allowMultipleTunnels must be overridden to avoid setting up multiple
+ # tunnels. This need to be removed after the kernel issue is fixed.
+ @classmethod
+ def allowMultipleTunnels(cls):
+ return False
+
+ def setUpTunnel(self, outer_version, use_null_crypt):
+ underlying_netid = self.RandomNetid()
+ netid = _BASE_TUNNEL_NETID[outer_version] + _TUNNEL_NETID_OFFSET
+ iface = "ipsec%s" % netid
+ ifindex = self.ifindices[underlying_netid]
+
+ local = self.MyAddress(outer_version, underlying_netid)
+ remote = net_test.IPV4_ADDR if outer_version == 4 else net_test.IPV6_ADDR
+
+ tunnel = XfrmInterface(iface, netid, underlying_netid, ifindex,
+ local, remote, outer_version, use_null_crypt)
+ self._SetInboundMarking(netid, iface, True)
+ self._SetupTunnelNetwork(tunnel, True)
+
+ return tunnel
+
+ def tearDownTunnel(self, tunnel):
+ self._SetInboundMarking(tunnel.netid, tunnel.iface, False)
+ self._SetupTunnelNetwork(tunnel, False)
+ tunnel.Teardown()
+
+ def _TestTunnel(self, inner_version, outer_version, func, use_null_crypt):
+ tunnel = self.setUpTunnel(outer_version, use_null_crypt)
+
+ # Verify functionality before migration
+ local_inner = tunnel.addrs[inner_version]
+ remote_inner = _GetRemoteInnerAddress(inner_version)
+ func(tunnel, inner_version, local_inner, remote_inner)
+
+ # Migrate tunnel
+ # TODO:b/169170981 Add tests that migrate 4 -> 6 and 6 -> 4
+ new_underlying_netid = self.RandomNetid(exclude=tunnel.underlying_netid)
+ new_local = self.MyAddress(outer_version, new_underlying_netid)
+ new_remote = net_test.IPV4_ADDR2 if outer_version == 4 else net_test.IPV6_ADDR2
+
+ tunnel.Migrate(new_underlying_netid, new_local, new_remote)
+
+ # Verify functionality after migration
+ func(tunnel, inner_version, local_inner, remote_inner)
+
+ self.tearDownTunnel(tunnel)
+
+ def ParamTestMigrateXfrmIntfInput(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version, self._CheckTunnelInput, True)
+
+ def ParamTestMigrateXfrmIntfOutput(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version, self._CheckTunnelOutput,
+ True)
+
+ def ParamTestMigrateXfrmIntfInOutEncrypted(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version, self._CheckTunnelEncryption,
+ False)
+
+ def ParamTestMigrateXfrmIntfIcmp(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version, self._CheckTunnelIcmp, False)
+
+ def ParamTestMigrateXfrmIntfEncryptionWithIcmp(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version,
+ self._CheckTunnelEncryptionWithIcmp, False)
+
+ def ParamTestMigrateXfrmIntfRekey(self, inner_version, outer_version):
+ self._TestTunnel(inner_version, outer_version, self._CheckTunnelRekey,
+ True)
if __name__ == "__main__":
InjectTests()