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 <netinet/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
send_udp_traffic(void)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
test_xdp_flowtable(void)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