mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-04-18 11:33:36 -04:00
selftests/net: Add env for container based tests
Add an env NetDrvContEnv for container based selftests. This automates the setup of a netns, netkit pair with one inside the netns, and a BPF program that forwards skbs from the NETIF host inside the container. Currently only netkit is used, but other virtual netdevs e.g. veth can be used too. Expect netkit container datapath selftests to have a publicly routable IP prefix to assign to netkit in a container, such that packets will land on eth0. The BPF skb forward program will then forward such packets from the host netns to the container netns. Signed-off-by: David Wei <dw@davidwei.uk> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Link: https://patch.msgid.link/20260115082603.219152-15-daniel@iogearbox.net Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import ipaddress
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from pathlib import Path
|
||||
from lib.py import KsftSkipEx, KsftXfailEx
|
||||
@@ -8,6 +10,7 @@ from lib.py import ksft_setup, wait_file
|
||||
from lib.py import cmd, ethtool, ip, CmdExitFailure
|
||||
from lib.py import NetNS, NetdevSimDev
|
||||
from .remote import Remote
|
||||
from . import bpftool
|
||||
|
||||
|
||||
class NetDrvEnvBase:
|
||||
@@ -289,3 +292,112 @@ class NetDrvEpEnv(NetDrvEnvBase):
|
||||
data.get('stats-block-usecs', 0) / 1000 / 1000
|
||||
|
||||
time.sleep(self._stats_settle_time)
|
||||
|
||||
|
||||
class NetDrvContEnv(NetDrvEpEnv):
|
||||
"""
|
||||
Class for an environment with a netkit pair setup for forwarding traffic
|
||||
between the physical interface and a network namespace.
|
||||
"""
|
||||
|
||||
def __init__(self, src_path, nk_rxqueues=1, **kwargs):
|
||||
super().__init__(src_path, **kwargs)
|
||||
|
||||
self.require_ipver("6")
|
||||
local_prefix = self.env.get("LOCAL_PREFIX_V6")
|
||||
if not local_prefix:
|
||||
raise KsftSkipEx("LOCAL_PREFIX_V6 required")
|
||||
|
||||
local_prefix = local_prefix.rstrip("/64").rstrip("::").rstrip(":")
|
||||
self.ipv6_prefix = f"{local_prefix}::"
|
||||
self.nk_host_ipv6 = f"{local_prefix}::2:1"
|
||||
self.nk_guest_ipv6 = f"{local_prefix}::2:2"
|
||||
|
||||
self.netns = None
|
||||
self._nk_host_ifname = None
|
||||
self._nk_guest_ifname = None
|
||||
self._tc_attached = False
|
||||
self._bpf_prog_pref = None
|
||||
self._bpf_prog_id = None
|
||||
|
||||
ip(f"link add type netkit mode l2 forward peer forward numrxqueues {nk_rxqueues}")
|
||||
|
||||
all_links = ip("-d link show", json=True)
|
||||
netkit_links = [link for link in all_links
|
||||
if link.get('linkinfo', {}).get('info_kind') == 'netkit'
|
||||
and 'UP' not in link.get('flags', [])]
|
||||
|
||||
if len(netkit_links) != 2:
|
||||
raise KsftSkipEx("Failed to create netkit pair")
|
||||
|
||||
netkit_links.sort(key=lambda x: x['ifindex'])
|
||||
self._nk_host_ifname = netkit_links[1]['ifname']
|
||||
self._nk_guest_ifname = netkit_links[0]['ifname']
|
||||
self.nk_host_ifindex = netkit_links[1]['ifindex']
|
||||
self.nk_guest_ifindex = netkit_links[0]['ifindex']
|
||||
|
||||
self._setup_ns()
|
||||
self._attach_bpf()
|
||||
|
||||
def __del__(self):
|
||||
if self._tc_attached:
|
||||
cmd(f"tc filter del dev {self.ifname} ingress pref {self._bpf_prog_pref}")
|
||||
self._tc_attached = False
|
||||
|
||||
if self._nk_host_ifname:
|
||||
cmd(f"ip link del dev {self._nk_host_ifname}")
|
||||
self._nk_host_ifname = None
|
||||
self._nk_guest_ifname = None
|
||||
|
||||
if self.netns:
|
||||
del self.netns
|
||||
self.netns = None
|
||||
|
||||
super().__del__()
|
||||
|
||||
def _setup_ns(self):
|
||||
self.netns = NetNS()
|
||||
ip(f"link set dev {self._nk_guest_ifname} netns {self.netns.name}")
|
||||
ip(f"link set dev {self._nk_host_ifname} up")
|
||||
ip(f"-6 addr add fe80::1/64 dev {self._nk_host_ifname} nodad")
|
||||
ip(f"-6 route add {self.nk_guest_ipv6}/128 via fe80::2 dev {self._nk_host_ifname}")
|
||||
|
||||
ip("link set lo up", ns=self.netns)
|
||||
ip(f"link set dev {self._nk_guest_ifname} up", ns=self.netns)
|
||||
ip(f"-6 addr add fe80::2/64 dev {self._nk_guest_ifname}", ns=self.netns)
|
||||
ip(f"-6 addr add {self.nk_guest_ipv6}/64 dev {self._nk_guest_ifname} nodad", ns=self.netns)
|
||||
ip(f"-6 route add default via fe80::1 dev {self._nk_guest_ifname}", ns=self.netns)
|
||||
|
||||
def _attach_bpf(self):
|
||||
bpf_obj = self.test_dir / "nk_forward.bpf.o"
|
||||
if not bpf_obj.exists():
|
||||
raise KsftSkipEx("BPF prog not found")
|
||||
|
||||
cmd(f"tc filter add dev {self.ifname} ingress bpf obj {bpf_obj} sec tc/ingress direct-action")
|
||||
self._tc_attached = True
|
||||
|
||||
tc_info = cmd(f"tc filter show dev {self.ifname} ingress").stdout
|
||||
match = re.search(r'pref (\d+).*nk_forward\.bpf.*id (\d+)', tc_info)
|
||||
if not match:
|
||||
raise Exception("Failed to get BPF prog ID")
|
||||
self._bpf_prog_pref = int(match.group(1))
|
||||
self._bpf_prog_id = int(match.group(2))
|
||||
|
||||
prog_info = bpftool(f"prog show id {self._bpf_prog_id}", json=True)
|
||||
map_ids = prog_info.get("map_ids", [])
|
||||
|
||||
bss_map_id = None
|
||||
for map_id in map_ids:
|
||||
map_info = bpftool(f"map show id {map_id}", json=True)
|
||||
if map_info.get("name").endswith("bss"):
|
||||
bss_map_id = map_id
|
||||
|
||||
if bss_map_id is None:
|
||||
raise Exception("Failed to find .bss map")
|
||||
|
||||
ipv6_addr = ipaddress.IPv6Address(self.ipv6_prefix)
|
||||
ipv6_bytes = ipv6_addr.packed
|
||||
ifindex_bytes = self.nk_host_ifindex.to_bytes(4, byteorder='little')
|
||||
value = ipv6_bytes + ifindex_bytes
|
||||
value_hex = ' '.join(f'{b:02x}' for b in value)
|
||||
bpftool(f"map update id {bss_map_id} key hex 00 00 00 00 value hex {value_hex}")
|
||||
|
||||
Reference in New Issue
Block a user