mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
selftests: drv-net: Test XDP_TX support
Add test to verify the XDP_TX functionality by generating traffic from a remote node on a specific UDP port and redirecting it back to the sender. ./drivers/net/xdp.py TAP version 13 1..5 ok 1 xdp.test_xdp_native_pass_sb ok 2 xdp.test_xdp_native_pass_mb ok 3 xdp.test_xdp_native_drop_sb ok 4 xdp.test_xdp_native_drop_mb ok 5 xdp.test_xdp_native_tx_mb \# Totals: pass:5 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Mohsin Bashir <mohsin.bashr@gmail.com> Link: https://patch.msgid.link/20250719083059.3209169-4-mohsin.bashr@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
1cbcb1b28b
commit
6713945726
|
|
@ -27,6 +27,7 @@ class XDPAction(Enum):
|
|||
"""Enum for XDP actions."""
|
||||
PASS = 0 # Pass the packet up to the stack
|
||||
DROP = 1 # Drop the packet
|
||||
TX = 2 # Route the packet to the remote host
|
||||
|
||||
|
||||
class XDPStats(Enum):
|
||||
|
|
@ -34,6 +35,7 @@ class XDPStats(Enum):
|
|||
RX = 0 # Count of valid packets received for testing
|
||||
PASS = 1 # Count of packets passed up to the stack
|
||||
DROP = 2 # Count of packets dropped
|
||||
TX = 3 # Count of incoming packets routed to the remote host
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
@ -180,6 +182,8 @@ def _get_stats(xdp_map_id):
|
|||
stats_formatted[XDPStats.PASS.value] = val
|
||||
elif stats_dump[key]["formatted"]["key"] == XDPStats.DROP.value:
|
||||
stats_formatted[XDPStats.DROP.value] = val
|
||||
elif stats_dump[key]["formatted"]["key"] == XDPStats.TX.value:
|
||||
stats_formatted[XDPStats.TX.value] = val
|
||||
|
||||
return stats_formatted
|
||||
|
||||
|
|
@ -278,6 +282,35 @@ def test_xdp_native_drop_mb(cfg):
|
|||
_test_drop(cfg, bpf_info, 8000)
|
||||
|
||||
|
||||
def test_xdp_native_tx_mb(cfg):
|
||||
"""
|
||||
Tests the XDP_TX action for a multi-buff case.
|
||||
|
||||
Args:
|
||||
cfg: Configuration object containing network settings.
|
||||
"""
|
||||
cfg.require_cmd("socat", remote=True)
|
||||
|
||||
bpf_info = BPFProgInfo("xdp_prog_frags", "xdp_native.bpf.o", "xdp.frags", 9000)
|
||||
prog_info = _load_xdp_prog(cfg, bpf_info)
|
||||
port = rand_port()
|
||||
|
||||
_set_xdp_map("map_xdp_setup", TestConfig.MODE.value, XDPAction.TX.value)
|
||||
_set_xdp_map("map_xdp_setup", TestConfig.PORT.value, port)
|
||||
|
||||
test_string = ''.join(random.choice(string.ascii_lowercase) for _ in range(8000))
|
||||
rx_udp = f"socat -{cfg.addr_ipver} -T 2 -u UDP-RECV:{port},reuseport STDOUT"
|
||||
tx_udp = f"echo {test_string} | socat -t 2 -u STDIN UDP:{cfg.baddr}:{port}"
|
||||
|
||||
with bkg(rx_udp, host=cfg.remote, exit_wait=True) as rnc:
|
||||
cmd(tx_udp, host=cfg.remote, shell=True)
|
||||
|
||||
stats = _get_stats(prog_info['maps']['map_xdp_stats'])
|
||||
|
||||
ksft_eq(rnc.stdout.strip(), test_string, "UDP packet exchange failed")
|
||||
ksft_eq(stats[XDPStats.TX.value], 1, "TX stats mismatch")
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to execute the XDP tests.
|
||||
|
|
@ -294,6 +327,7 @@ def main():
|
|||
test_xdp_native_pass_mb,
|
||||
test_xdp_native_drop_sb,
|
||||
test_xdp_native_drop_mb,
|
||||
test_xdp_native_tx_mb,
|
||||
],
|
||||
args=(cfg,))
|
||||
ksft_exit()
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ enum {
|
|||
enum {
|
||||
XDP_MODE_PASS = 0,
|
||||
XDP_MODE_DROP = 1,
|
||||
XDP_MODE_TX = 2,
|
||||
} xdp_map_modes;
|
||||
|
||||
enum {
|
||||
STATS_RX = 0,
|
||||
STATS_PASS = 1,
|
||||
STATS_DROP = 2,
|
||||
STATS_TX = 3,
|
||||
} xdp_stats;
|
||||
|
||||
struct {
|
||||
|
|
@ -117,6 +119,82 @@ static int xdp_mode_drop_handler(struct xdp_md *ctx, __u16 port)
|
|||
return XDP_DROP;
|
||||
}
|
||||
|
||||
static void swap_machdr(void *data)
|
||||
{
|
||||
struct ethhdr *eth = data;
|
||||
__u8 tmp_mac[ETH_ALEN];
|
||||
|
||||
__builtin_memcpy(tmp_mac, eth->h_source, ETH_ALEN);
|
||||
__builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
|
||||
__builtin_memcpy(eth->h_dest, tmp_mac, ETH_ALEN);
|
||||
}
|
||||
|
||||
static int xdp_mode_tx_handler(struct xdp_md *ctx, __u16 port)
|
||||
{
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
struct udphdr *udph = NULL;
|
||||
struct ethhdr *eth = data;
|
||||
|
||||
if (data + sizeof(*eth) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
|
||||
struct iphdr *iph = data + sizeof(*eth);
|
||||
__be32 tmp_ip = iph->saddr;
|
||||
|
||||
if (iph + 1 > (struct iphdr *)data_end ||
|
||||
iph->protocol != IPPROTO_UDP)
|
||||
return XDP_PASS;
|
||||
|
||||
udph = data + sizeof(*iph) + sizeof(*eth);
|
||||
|
||||
if (udph + 1 > (struct udphdr *)data_end)
|
||||
return XDP_PASS;
|
||||
if (udph->dest != bpf_htons(port))
|
||||
return XDP_PASS;
|
||||
|
||||
record_stats(ctx, STATS_RX);
|
||||
swap_machdr((void *)eth);
|
||||
|
||||
iph->saddr = iph->daddr;
|
||||
iph->daddr = tmp_ip;
|
||||
|
||||
record_stats(ctx, STATS_TX);
|
||||
|
||||
return XDP_TX;
|
||||
|
||||
} else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
|
||||
struct ipv6hdr *ipv6h = data + sizeof(*eth);
|
||||
struct in6_addr tmp_ipv6;
|
||||
|
||||
if (ipv6h + 1 > (struct ipv6hdr *)data_end ||
|
||||
ipv6h->nexthdr != IPPROTO_UDP)
|
||||
return XDP_PASS;
|
||||
|
||||
udph = data + sizeof(*ipv6h) + sizeof(*eth);
|
||||
|
||||
if (udph + 1 > (struct udphdr *)data_end)
|
||||
return XDP_PASS;
|
||||
if (udph->dest != bpf_htons(port))
|
||||
return XDP_PASS;
|
||||
|
||||
record_stats(ctx, STATS_RX);
|
||||
swap_machdr((void *)eth);
|
||||
|
||||
__builtin_memcpy(&tmp_ipv6, &ipv6h->saddr, sizeof(tmp_ipv6));
|
||||
__builtin_memcpy(&ipv6h->saddr, &ipv6h->daddr,
|
||||
sizeof(tmp_ipv6));
|
||||
__builtin_memcpy(&ipv6h->daddr, &tmp_ipv6, sizeof(tmp_ipv6));
|
||||
|
||||
record_stats(ctx, STATS_TX);
|
||||
|
||||
return XDP_TX;
|
||||
}
|
||||
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
static int xdp_prog_common(struct xdp_md *ctx)
|
||||
{
|
||||
__u32 key, *port;
|
||||
|
|
@ -137,6 +215,8 @@ static int xdp_prog_common(struct xdp_md *ctx)
|
|||
return xdp_mode_pass(ctx, (__u16)(*port));
|
||||
case XDP_MODE_DROP:
|
||||
return xdp_mode_drop_handler(ctx, (__u16)(*port));
|
||||
case XDP_MODE_TX:
|
||||
return xdp_mode_tx_handler(ctx, (__u16)(*port));
|
||||
}
|
||||
|
||||
/* Default action is to simple pass */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user