aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2018-08-08 04:01:30 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-08-10 19:58:46 -0400
commit6bc8529c414f931ce0acef3099b015cf2f5c4291 (patch)
tree303a784ee3ef7c306d57d57ca1f845379bf6cf41 /tools
parent3bd43a8c91cba0493e507ed7baefa9b5613c28a9 (diff)
bpf: test BPF_MAP_TYPE_REUSEPORT_SOCKARRAY
This patch adds tests for the new BPF_MAP_TYPE_REUSEPORT_SOCKARRAY. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/bpf/libbpf.c1
-rw-r--r--tools/testing/selftests/bpf/test_maps.c262
2 files changed, 262 insertions, 1 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 40211b51427a..2abd0f112627 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1501,6 +1501,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)
1501 case BPF_PROG_TYPE_SK_MSG: 1501 case BPF_PROG_TYPE_SK_MSG:
1502 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 1502 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
1503 case BPF_PROG_TYPE_LIRC_MODE2: 1503 case BPF_PROG_TYPE_LIRC_MODE2:
1504 case BPF_PROG_TYPE_SK_REUSEPORT:
1504 return false; 1505 return false;
1505 case BPF_PROG_TYPE_UNSPEC: 1506 case BPF_PROG_TYPE_UNSPEC:
1506 case BPF_PROG_TYPE_KPROBE: 1507 case BPF_PROG_TYPE_KPROBE:
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 6c253343a6f9..4b7c74f5faa7 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -17,7 +17,8 @@
17#include <stdlib.h> 17#include <stdlib.h>
18 18
19#include <sys/wait.h> 19#include <sys/wait.h>
20 20#include <sys/socket.h>
21#include <netinet/in.h>
21#include <linux/bpf.h> 22#include <linux/bpf.h>
22 23
23#include <bpf/bpf.h> 24#include <bpf/bpf.h>
@@ -26,8 +27,21 @@
26#include "bpf_util.h" 27#include "bpf_util.h"
27#include "bpf_rlimit.h" 28#include "bpf_rlimit.h"
28 29
30#ifndef ENOTSUPP
31#define ENOTSUPP 524
32#endif
33
29static int map_flags; 34static int map_flags;
30 35
36#define CHECK(condition, tag, format...) ({ \
37 int __ret = !!(condition); \
38 if (__ret) { \
39 printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \
40 printf(format); \
41 exit(-1); \
42 } \
43})
44
31static void test_hashmap(int task, void *data) 45static void test_hashmap(int task, void *data)
32{ 46{
33 long long key, next_key, first_key, value; 47 long long key, next_key, first_key, value;
@@ -1150,6 +1164,250 @@ static void test_map_wronly(void)
1150 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); 1164 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM);
1151} 1165}
1152 1166
1167static void prepare_reuseport_grp(int type, int map_fd,
1168 __s64 *fds64, __u64 *sk_cookies,
1169 unsigned int n)
1170{
1171 socklen_t optlen, addrlen;
1172 struct sockaddr_in6 s6;
1173 const __u32 index0 = 0;
1174 const int optval = 1;
1175 unsigned int i;
1176 u64 sk_cookie;
1177 __s64 fd64;
1178 int err;
1179
1180 s6.sin6_family = AF_INET6;
1181 s6.sin6_addr = in6addr_any;
1182 s6.sin6_port = 0;
1183 addrlen = sizeof(s6);
1184 optlen = sizeof(sk_cookie);
1185
1186 for (i = 0; i < n; i++) {
1187 fd64 = socket(AF_INET6, type, 0);
1188 CHECK(fd64 == -1, "socket()",
1189 "sock_type:%d fd64:%lld errno:%d\n",
1190 type, fd64, errno);
1191
1192 err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT,
1193 &optval, sizeof(optval));
1194 CHECK(err == -1, "setsockopt(SO_REUSEEPORT)",
1195 "err:%d errno:%d\n", err, errno);
1196
1197 /* reuseport_array does not allow unbound sk */
1198 err = bpf_map_update_elem(map_fd, &index0, &fd64,
1199 BPF_ANY);
1200 CHECK(err != -1 || errno != EINVAL,
1201 "reuseport array update unbound sk",
1202 "sock_type:%d err:%d errno:%d\n",
1203 type, err, errno);
1204
1205 err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6));
1206 CHECK(err == -1, "bind()",
1207 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1208
1209 if (i == 0) {
1210 err = getsockname(fd64, (struct sockaddr *)&s6,
1211 &addrlen);
1212 CHECK(err == -1, "getsockname()",
1213 "sock_type:%d err:%d errno:%d\n",
1214 type, err, errno);
1215 }
1216
1217 err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie,
1218 &optlen);
1219 CHECK(err == -1, "getsockopt(SO_COOKIE)",
1220 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1221
1222 if (type == SOCK_STREAM) {
1223 /*
1224 * reuseport_array does not allow
1225 * non-listening tcp sk.
1226 */
1227 err = bpf_map_update_elem(map_fd, &index0, &fd64,
1228 BPF_ANY);
1229 CHECK(err != -1 || errno != EINVAL,
1230 "reuseport array update non-listening sk",
1231 "sock_type:%d err:%d errno:%d\n",
1232 type, err, errno);
1233 err = listen(fd64, 0);
1234 CHECK(err == -1, "listen()",
1235 "sock_type:%d, err:%d errno:%d\n",
1236 type, err, errno);
1237 }
1238
1239 fds64[i] = fd64;
1240 sk_cookies[i] = sk_cookie;
1241 }
1242}
1243
1244static void test_reuseport_array(void)
1245{
1246#define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; })
1247
1248 const __u32 array_size = 4, index0 = 0, index3 = 3;
1249 int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type;
1250 __u64 grpa_cookies[2], sk_cookie, map_cookie;
1251 __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1;
1252 const __u32 bad_index = array_size;
1253 int map_fd, err, t, f;
1254 __u32 fds_idx = 0;
1255 int fd;
1256
1257 map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
1258 sizeof(__u32), sizeof(__u64), array_size, 0);
1259 CHECK(map_fd == -1, "reuseport array create",
1260 "map_fd:%d, errno:%d\n", map_fd, errno);
1261
1262 /* Test lookup/update/delete with invalid index */
1263 err = bpf_map_delete_elem(map_fd, &bad_index);
1264 CHECK(err != -1 || errno != E2BIG, "reuseport array del >=max_entries",
1265 "err:%d errno:%d\n", err, errno);
1266
1267 err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY);
1268 CHECK(err != -1 || errno != E2BIG,
1269 "reuseport array update >=max_entries",
1270 "err:%d errno:%d\n", err, errno);
1271
1272 err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie);
1273 CHECK(err != -1 || errno != ENOENT,
1274 "reuseport array update >=max_entries",
1275 "err:%d errno:%d\n", err, errno);
1276
1277 /* Test lookup/delete non existence elem */
1278 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1279 CHECK(err != -1 || errno != ENOENT,
1280 "reuseport array lookup not-exist elem",
1281 "err:%d errno:%d\n", err, errno);
1282 err = bpf_map_delete_elem(map_fd, &index3);
1283 CHECK(err != -1 || errno != ENOENT,
1284 "reuseport array del not-exist elem",
1285 "err:%d errno:%d\n", err, errno);
1286
1287 for (t = 0; t < ARRAY_SIZE(types); t++) {
1288 type = types[t];
1289
1290 prepare_reuseport_grp(type, map_fd, grpa_fds64,
1291 grpa_cookies, ARRAY_SIZE(grpa_fds64));
1292
1293 /* Test BPF_* update flags */
1294 /* BPF_EXIST failure case */
1295 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1296 BPF_EXIST);
1297 CHECK(err != -1 || errno != ENOENT,
1298 "reuseport array update empty elem BPF_EXIST",
1299 "sock_type:%d err:%d errno:%d\n",
1300 type, err, errno);
1301 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1302
1303 /* BPF_NOEXIST success case */
1304 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1305 BPF_NOEXIST);
1306 CHECK(err == -1,
1307 "reuseport array update empty elem BPF_NOEXIST",
1308 "sock_type:%d err:%d errno:%d\n",
1309 type, err, errno);
1310 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1311
1312 /* BPF_EXIST success case. */
1313 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1314 BPF_EXIST);
1315 CHECK(err == -1,
1316 "reuseport array update same elem BPF_EXIST",
1317 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1318 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1319
1320 /* BPF_NOEXIST failure case */
1321 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1322 BPF_NOEXIST);
1323 CHECK(err != -1 || errno != EEXIST,
1324 "reuseport array update non-empty elem BPF_NOEXIST",
1325 "sock_type:%d err:%d errno:%d\n",
1326 type, err, errno);
1327 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1328
1329 /* BPF_ANY case (always succeed) */
1330 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1331 BPF_ANY);
1332 CHECK(err == -1,
1333 "reuseport array update same sk with BPF_ANY",
1334 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1335
1336 fd64 = grpa_fds64[fds_idx];
1337 sk_cookie = grpa_cookies[fds_idx];
1338
1339 /* The same sk cannot be added to reuseport_array twice */
1340 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY);
1341 CHECK(err != -1 || errno != EBUSY,
1342 "reuseport array update same sk with same index",
1343 "sock_type:%d err:%d errno:%d\n",
1344 type, err, errno);
1345
1346 err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY);
1347 CHECK(err != -1 || errno != EBUSY,
1348 "reuseport array update same sk with different index",
1349 "sock_type:%d err:%d errno:%d\n",
1350 type, err, errno);
1351
1352 /* Test delete elem */
1353 err = bpf_map_delete_elem(map_fd, &index3);
1354 CHECK(err == -1, "reuseport array delete sk",
1355 "sock_type:%d err:%d errno:%d\n",
1356 type, err, errno);
1357
1358 /* Add it back with BPF_NOEXIST */
1359 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1360 CHECK(err == -1,
1361 "reuseport array re-add with BPF_NOEXIST after del",
1362 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1363
1364 /* Test cookie */
1365 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1366 CHECK(err == -1 || sk_cookie != map_cookie,
1367 "reuseport array lookup re-added sk",
1368 "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn",
1369 type, err, errno, sk_cookie, map_cookie);
1370
1371 /* Test elem removed by close() */
1372 for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++)
1373 close(grpa_fds64[f]);
1374 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1375 CHECK(err != -1 || errno != ENOENT,
1376 "reuseport array lookup after close()",
1377 "sock_type:%d err:%d errno:%d\n",
1378 type, err, errno);
1379 }
1380
1381 /* Test SOCK_RAW */
1382 fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
1383 CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n",
1384 err, errno);
1385 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1386 CHECK(err != -1 || errno != ENOTSUPP, "reuseport array update SOCK_RAW",
1387 "err:%d errno:%d\n", err, errno);
1388 close(fd64);
1389
1390 /* Close the 64 bit value map */
1391 close(map_fd);
1392
1393 /* Test 32 bit fd */
1394 map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
1395 sizeof(__u32), sizeof(__u32), array_size, 0);
1396 CHECK(map_fd == -1, "reuseport array create",
1397 "map_fd:%d, errno:%d\n", map_fd, errno);
1398 prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1);
1399 fd = fd64;
1400 err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
1401 CHECK(err == -1, "reuseport array update 32 bit fd",
1402 "err:%d errno:%d\n", err, errno);
1403 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1404 CHECK(err != -1 || errno != ENOSPC,
1405 "reuseport array lookup 32 bit fd",
1406 "err:%d errno:%d\n", err, errno);
1407 close(fd);
1408 close(map_fd);
1409}
1410
1153static void run_all_tests(void) 1411static void run_all_tests(void)
1154{ 1412{
1155 test_hashmap(0, NULL); 1413 test_hashmap(0, NULL);
@@ -1170,6 +1428,8 @@ static void run_all_tests(void)
1170 1428
1171 test_map_rdonly(); 1429 test_map_rdonly();
1172 test_map_wronly(); 1430 test_map_wronly();
1431
1432 test_reuseport_array();
1173} 1433}
1174 1434
1175int main(void) 1435int main(void)