xref: /linux/tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c (revision cf4cebcec619d963fa7496018f03cb0ff00dc257)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <network_helpers.h>
4 #include <bpf/btf.h>
5 #include <linux/if_link.h>
6 #include <linux/udp.h>
7 #include <net/if.h>
8 #include <unistd.h>
9 
10 #include "xdp_flowtable.skel.h"
11 
12 #define TX_NETNS_NAME	"ns0"
13 #define RX_NETNS_NAME	"ns1"
14 
15 #define TX_NAME		"v0"
16 #define FORWARD_NAME	"v1"
17 #define RX_NAME		"d0"
18 
19 #define TX_MAC		"00:00:00:00:00:01"
20 #define FORWARD_MAC	"00:00:00:00:00:02"
21 #define RX_MAC		"00:00:00:00:00:03"
22 #define DST_MAC		"00:00:00:00:00:04"
23 
24 #define TX_ADDR		"10.0.0.1"
25 #define FORWARD_ADDR	"10.0.0.2"
26 #define RX_ADDR		"20.0.0.1"
27 #define DST_ADDR	"20.0.0.2"
28 
29 #define PREFIX_LEN	"8"
30 #define N_PACKETS	10
31 #define UDP_PORT	12345
32 #define UDP_PORT_STR	"12345"
33 
34 static int send_udp_traffic(void)
35 {
36 	struct sockaddr_storage addr;
37 	int i, sock;
38 
39 	if (make_sockaddr(AF_INET, DST_ADDR, UDP_PORT, &addr, NULL))
40 		return -EINVAL;
41 
42 	sock = socket(AF_INET, SOCK_DGRAM, 0);
43 	if (sock < 0)
44 		return sock;
45 
46 	for (i = 0; i < N_PACKETS; i++) {
47 		unsigned char buf[] = { 0xaa, 0xbb, 0xcc };
48 		int n;
49 
50 		n = sendto(sock, buf, sizeof(buf), MSG_NOSIGNAL | MSG_CONFIRM,
51 			   (struct sockaddr *)&addr, sizeof(addr));
52 		if (n != sizeof(buf)) {
53 			close(sock);
54 			return -EINVAL;
55 		}
56 
57 		usleep(50000); /* 50ms */
58 	}
59 	close(sock);
60 
61 	return 0;
62 }
63 
64 void test_xdp_flowtable(void)
65 {
66 	struct xdp_flowtable *skel = NULL;
67 	struct nstoken *tok = NULL;
68 	int iifindex, stats_fd;
69 	__u32 value, key = 0;
70 	struct bpf_link *link;
71 
72 	if (SYS_NOFAIL("nft -v")) {
73 		fprintf(stdout, "Missing required nft tool\n");
74 		test__skip();
75 		return;
76 	}
77 
78 	SYS(out, "ip netns add " TX_NETNS_NAME);
79 	SYS(out, "ip netns add " RX_NETNS_NAME);
80 
81 	tok = open_netns(RX_NETNS_NAME);
82 	if (!ASSERT_OK_PTR(tok, "setns"))
83 		goto out;
84 
85 	SYS(out, "sysctl -qw net.ipv4.conf.all.forwarding=1");
86 
87 	SYS(out, "ip link add " TX_NAME " type veth peer " FORWARD_NAME);
88 	SYS(out, "ip link set " TX_NAME " netns " TX_NETNS_NAME);
89 	SYS(out, "ip link set dev " FORWARD_NAME " address " FORWARD_MAC);
90 	SYS(out,
91 	    "ip addr add " FORWARD_ADDR "/" PREFIX_LEN " dev " FORWARD_NAME);
92 	SYS(out, "ip link set dev " FORWARD_NAME " up");
93 
94 	SYS(out, "ip link add " RX_NAME " type dummy");
95 	SYS(out, "ip link set dev " RX_NAME " address " RX_MAC);
96 	SYS(out, "ip addr add " RX_ADDR "/" PREFIX_LEN " dev " RX_NAME);
97 	SYS(out, "ip link set dev " RX_NAME " up");
98 
99 	/* configure the flowtable */
100 	SYS(out, "nft add table ip filter");
101 	SYS(out,
102 	    "nft add flowtable ip filter f { hook ingress priority 0\\; "
103 	    "devices = { " FORWARD_NAME ", " RX_NAME " }\\; }");
104 	SYS(out,
105 	    "nft add chain ip filter forward "
106 	    "{ type filter hook forward priority 0\\; }");
107 	SYS(out,
108 	    "nft add rule ip filter forward ip protocol udp th dport "
109 	    UDP_PORT_STR " flow add @f");
110 
111 	/* Avoid ARP calls */
112 	SYS(out,
113 	    "ip -4 neigh add " DST_ADDR " lladdr " DST_MAC " dev " RX_NAME);
114 
115 	close_netns(tok);
116 	tok = open_netns(TX_NETNS_NAME);
117 	if (!ASSERT_OK_PTR(tok, "setns"))
118 		goto out;
119 
120 	SYS(out, "ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME);
121 	SYS(out, "ip link set dev " TX_NAME " address " TX_MAC);
122 	SYS(out, "ip link set dev " TX_NAME " up");
123 	SYS(out, "ip route add default via " FORWARD_ADDR);
124 
125 	close_netns(tok);
126 	tok = open_netns(RX_NETNS_NAME);
127 	if (!ASSERT_OK_PTR(tok, "setns"))
128 		goto out;
129 
130 	iifindex = if_nametoindex(FORWARD_NAME);
131 	if (!ASSERT_NEQ(iifindex, 0, "iifindex"))
132 		goto out;
133 
134 	skel = xdp_flowtable__open_and_load();
135 	if (!ASSERT_OK_PTR(skel, "skel"))
136 		goto out;
137 
138 	link = bpf_program__attach_xdp(skel->progs.xdp_flowtable_do_lookup,
139 				       iifindex);
140 	if (!ASSERT_OK_PTR(link, "prog_attach"))
141 		goto out;
142 
143 	close_netns(tok);
144 	tok = open_netns(TX_NETNS_NAME);
145 	if (!ASSERT_OK_PTR(tok, "setns"))
146 		goto out;
147 
148 	if (!ASSERT_OK(send_udp_traffic(), "send udp"))
149 		goto out;
150 
151 	close_netns(tok);
152 	tok = open_netns(RX_NETNS_NAME);
153 	if (!ASSERT_OK_PTR(tok, "setns"))
154 		goto out;
155 
156 	stats_fd = bpf_map__fd(skel->maps.stats);
157 	if (!ASSERT_OK(bpf_map_lookup_elem(stats_fd, &key, &value),
158 		       "bpf_map_update_elem stats"))
159 		goto out;
160 
161 	ASSERT_GE(value, N_PACKETS - 2, "bpf_xdp_flow_lookup failed");
162 out:
163 	xdp_flowtable__destroy(skel);
164 	if (tok)
165 		close_netns(tok);
166 	SYS_NOFAIL("ip netns del " TX_NETNS_NAME);
167 	SYS_NOFAIL("ip netns del " RX_NETNS_NAME);
168 }
169