Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Martin KaFai Lau and committed by
Daniel Borkmann
6bc8529c 3bd43a8c

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