diff options
author | Craig Gallek <kraig@google.com> | 2016-01-05 15:08:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-01-06 01:28:04 -0500 |
commit | 1134158ba3d656b8dbc79a23d482129a531ba0ae (patch) | |
tree | 2b88e0dc8ac5cc9a85c22abe6b11ad082300cd9a | |
parent | f0138e2596f2994129451ee320ff8692cb7bc86b (diff) |
soreuseport: pass skb to secondary UDP socket lookup
This socket-lookup path did not pass along the skb in question
in my original BPF-based socket selection patch. The skb in the
udpN_lib_lookup2 path can be used for BPF-based socket selection just
like it is in the 'traditional' udpN_lib_lookup path.
udpN_lib_lookup2 kicks in when there are greater than 10 sockets in
the same hlist slot. Coincidentally, I chose 10 sockets per
reuseport group in my functional test, so the lookup2 path was not
excersised. This adds an additional set of tests with 20 sockets.
Fixes: 538950a1b752 ("soreuseport: setsockopt SO_ATTACH_REUSEPORT_[CE]BPF")
Fixes: 3ca8e4029969 ("soreuseport: BPF selection functional test")
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Craig Gallek <kraig@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/udp.c | 10 | ||||
-rw-r--r-- | net/ipv6/udp.c | 10 | ||||
-rw-r--r-- | tools/testing/selftests/net/reuseport_bpf.c | 47 |
3 files changed, 59 insertions, 8 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 835378365f25..3a66731e3af6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -493,7 +493,8 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr, | |||
493 | static struct sock *udp4_lib_lookup2(struct net *net, | 493 | static struct sock *udp4_lib_lookup2(struct net *net, |
494 | __be32 saddr, __be16 sport, | 494 | __be32 saddr, __be16 sport, |
495 | __be32 daddr, unsigned int hnum, int dif, | 495 | __be32 daddr, unsigned int hnum, int dif, |
496 | struct udp_hslot *hslot2, unsigned int slot2) | 496 | struct udp_hslot *hslot2, unsigned int slot2, |
497 | struct sk_buff *skb) | ||
497 | { | 498 | { |
498 | struct sock *sk, *result; | 499 | struct sock *sk, *result; |
499 | struct hlist_nulls_node *node; | 500 | struct hlist_nulls_node *node; |
@@ -514,7 +515,8 @@ begin: | |||
514 | struct sock *sk2; | 515 | struct sock *sk2; |
515 | hash = udp_ehashfn(net, daddr, hnum, | 516 | hash = udp_ehashfn(net, daddr, hnum, |
516 | saddr, sport); | 517 | saddr, sport); |
517 | sk2 = reuseport_select_sock(sk, hash, NULL, 0); | 518 | sk2 = reuseport_select_sock(sk, hash, skb, |
519 | sizeof(struct udphdr)); | ||
518 | if (sk2) { | 520 | if (sk2) { |
519 | result = sk2; | 521 | result = sk2; |
520 | goto found; | 522 | goto found; |
@@ -573,7 +575,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, | |||
573 | 575 | ||
574 | result = udp4_lib_lookup2(net, saddr, sport, | 576 | result = udp4_lib_lookup2(net, saddr, sport, |
575 | daddr, hnum, dif, | 577 | daddr, hnum, dif, |
576 | hslot2, slot2); | 578 | hslot2, slot2, skb); |
577 | if (!result) { | 579 | if (!result) { |
578 | hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); | 580 | hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); |
579 | slot2 = hash2 & udptable->mask; | 581 | slot2 = hash2 & udptable->mask; |
@@ -583,7 +585,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, | |||
583 | 585 | ||
584 | result = udp4_lib_lookup2(net, saddr, sport, | 586 | result = udp4_lib_lookup2(net, saddr, sport, |
585 | htonl(INADDR_ANY), hnum, dif, | 587 | htonl(INADDR_ANY), hnum, dif, |
586 | hslot2, slot2); | 588 | hslot2, slot2, skb); |
587 | } | 589 | } |
588 | rcu_read_unlock(); | 590 | rcu_read_unlock(); |
589 | return result; | 591 | return result; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 56fcb55fda31..5d2c2afffe7b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -251,7 +251,8 @@ static inline int compute_score2(struct sock *sk, struct net *net, | |||
251 | static struct sock *udp6_lib_lookup2(struct net *net, | 251 | static struct sock *udp6_lib_lookup2(struct net *net, |
252 | const struct in6_addr *saddr, __be16 sport, | 252 | const struct in6_addr *saddr, __be16 sport, |
253 | const struct in6_addr *daddr, unsigned int hnum, int dif, | 253 | const struct in6_addr *daddr, unsigned int hnum, int dif, |
254 | struct udp_hslot *hslot2, unsigned int slot2) | 254 | struct udp_hslot *hslot2, unsigned int slot2, |
255 | struct sk_buff *skb) | ||
255 | { | 256 | { |
256 | struct sock *sk, *result; | 257 | struct sock *sk, *result; |
257 | struct hlist_nulls_node *node; | 258 | struct hlist_nulls_node *node; |
@@ -272,7 +273,8 @@ begin: | |||
272 | struct sock *sk2; | 273 | struct sock *sk2; |
273 | hash = udp6_ehashfn(net, daddr, hnum, | 274 | hash = udp6_ehashfn(net, daddr, hnum, |
274 | saddr, sport); | 275 | saddr, sport); |
275 | sk2 = reuseport_select_sock(sk, hash, NULL, 0); | 276 | sk2 = reuseport_select_sock(sk, hash, skb, |
277 | sizeof(struct udphdr)); | ||
276 | if (sk2) { | 278 | if (sk2) { |
277 | result = sk2; | 279 | result = sk2; |
278 | goto found; | 280 | goto found; |
@@ -331,7 +333,7 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
331 | 333 | ||
332 | result = udp6_lib_lookup2(net, saddr, sport, | 334 | result = udp6_lib_lookup2(net, saddr, sport, |
333 | daddr, hnum, dif, | 335 | daddr, hnum, dif, |
334 | hslot2, slot2); | 336 | hslot2, slot2, skb); |
335 | if (!result) { | 337 | if (!result) { |
336 | hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); | 338 | hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); |
337 | slot2 = hash2 & udptable->mask; | 339 | slot2 = hash2 & udptable->mask; |
@@ -341,7 +343,7 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
341 | 343 | ||
342 | result = udp6_lib_lookup2(net, saddr, sport, | 344 | result = udp6_lib_lookup2(net, saddr, sport, |
343 | &in6addr_any, hnum, dif, | 345 | &in6addr_any, hnum, dif, |
344 | hslot2, slot2); | 346 | hslot2, slot2, skb); |
345 | } | 347 | } |
346 | rcu_read_unlock(); | 348 | rcu_read_unlock(); |
347 | return result; | 349 | return result; |
diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c index 74ff09988958..bec1b5dd2530 100644 --- a/tools/testing/selftests/net/reuseport_bpf.c +++ b/tools/testing/selftests/net/reuseport_bpf.c | |||
@@ -123,6 +123,8 @@ static void attach_ebpf(int fd, uint16_t mod) | |||
123 | if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd, | 123 | if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &bpf_fd, |
124 | sizeof(bpf_fd))) | 124 | sizeof(bpf_fd))) |
125 | error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF"); | 125 | error(1, errno, "failed to set SO_ATTACH_REUSEPORT_EBPF"); |
126 | |||
127 | close(bpf_fd); | ||
126 | } | 128 | } |
127 | 129 | ||
128 | static void attach_cbpf(int fd, uint16_t mod) | 130 | static void attach_cbpf(int fd, uint16_t mod) |
@@ -396,6 +398,9 @@ static void test_filter_without_bind(void) | |||
396 | int main(void) | 398 | int main(void) |
397 | { | 399 | { |
398 | fprintf(stderr, "---- IPv4 UDP ----\n"); | 400 | fprintf(stderr, "---- IPv4 UDP ----\n"); |
401 | /* NOTE: UDP socket lookups traverse a different code path when there | ||
402 | * are > 10 sockets in a group. Run the bpf test through both paths. | ||
403 | */ | ||
399 | test_reuseport_ebpf((struct test_params) { | 404 | test_reuseport_ebpf((struct test_params) { |
400 | .recv_family = AF_INET, | 405 | .recv_family = AF_INET, |
401 | .send_family = AF_INET, | 406 | .send_family = AF_INET, |
@@ -403,6 +408,13 @@ int main(void) | |||
403 | .recv_socks = 10, | 408 | .recv_socks = 10, |
404 | .recv_port = 8000, | 409 | .recv_port = 8000, |
405 | .send_port_min = 9000}); | 410 | .send_port_min = 9000}); |
411 | test_reuseport_ebpf((struct test_params) { | ||
412 | .recv_family = AF_INET, | ||
413 | .send_family = AF_INET, | ||
414 | .protocol = SOCK_DGRAM, | ||
415 | .recv_socks = 20, | ||
416 | .recv_port = 8000, | ||
417 | .send_port_min = 9000}); | ||
406 | test_reuseport_cbpf((struct test_params) { | 418 | test_reuseport_cbpf((struct test_params) { |
407 | .recv_family = AF_INET, | 419 | .recv_family = AF_INET, |
408 | .send_family = AF_INET, | 420 | .send_family = AF_INET, |
@@ -410,6 +422,13 @@ int main(void) | |||
410 | .recv_socks = 10, | 422 | .recv_socks = 10, |
411 | .recv_port = 8001, | 423 | .recv_port = 8001, |
412 | .send_port_min = 9020}); | 424 | .send_port_min = 9020}); |
425 | test_reuseport_cbpf((struct test_params) { | ||
426 | .recv_family = AF_INET, | ||
427 | .send_family = AF_INET, | ||
428 | .protocol = SOCK_DGRAM, | ||
429 | .recv_socks = 20, | ||
430 | .recv_port = 8001, | ||
431 | .send_port_min = 9020}); | ||
413 | test_extra_filter((struct test_params) { | 432 | test_extra_filter((struct test_params) { |
414 | .recv_family = AF_INET, | 433 | .recv_family = AF_INET, |
415 | .protocol = SOCK_DGRAM, | 434 | .protocol = SOCK_DGRAM, |
@@ -427,6 +446,13 @@ int main(void) | |||
427 | .recv_socks = 10, | 446 | .recv_socks = 10, |
428 | .recv_port = 8003, | 447 | .recv_port = 8003, |
429 | .send_port_min = 9040}); | 448 | .send_port_min = 9040}); |
449 | test_reuseport_ebpf((struct test_params) { | ||
450 | .recv_family = AF_INET6, | ||
451 | .send_family = AF_INET6, | ||
452 | .protocol = SOCK_DGRAM, | ||
453 | .recv_socks = 20, | ||
454 | .recv_port = 8003, | ||
455 | .send_port_min = 9040}); | ||
430 | test_reuseport_cbpf((struct test_params) { | 456 | test_reuseport_cbpf((struct test_params) { |
431 | .recv_family = AF_INET6, | 457 | .recv_family = AF_INET6, |
432 | .send_family = AF_INET6, | 458 | .send_family = AF_INET6, |
@@ -434,6 +460,13 @@ int main(void) | |||
434 | .recv_socks = 10, | 460 | .recv_socks = 10, |
435 | .recv_port = 8004, | 461 | .recv_port = 8004, |
436 | .send_port_min = 9060}); | 462 | .send_port_min = 9060}); |
463 | test_reuseport_cbpf((struct test_params) { | ||
464 | .recv_family = AF_INET6, | ||
465 | .send_family = AF_INET6, | ||
466 | .protocol = SOCK_DGRAM, | ||
467 | .recv_socks = 20, | ||
468 | .recv_port = 8004, | ||
469 | .send_port_min = 9060}); | ||
437 | test_extra_filter((struct test_params) { | 470 | test_extra_filter((struct test_params) { |
438 | .recv_family = AF_INET6, | 471 | .recv_family = AF_INET6, |
439 | .protocol = SOCK_DGRAM, | 472 | .protocol = SOCK_DGRAM, |
@@ -448,6 +481,13 @@ int main(void) | |||
448 | .recv_family = AF_INET6, | 481 | .recv_family = AF_INET6, |
449 | .send_family = AF_INET, | 482 | .send_family = AF_INET, |
450 | .protocol = SOCK_DGRAM, | 483 | .protocol = SOCK_DGRAM, |
484 | .recv_socks = 20, | ||
485 | .recv_port = 8006, | ||
486 | .send_port_min = 9080}); | ||
487 | test_reuseport_ebpf((struct test_params) { | ||
488 | .recv_family = AF_INET6, | ||
489 | .send_family = AF_INET, | ||
490 | .protocol = SOCK_DGRAM, | ||
451 | .recv_socks = 10, | 491 | .recv_socks = 10, |
452 | .recv_port = 8006, | 492 | .recv_port = 8006, |
453 | .send_port_min = 9080}); | 493 | .send_port_min = 9080}); |
@@ -458,6 +498,13 @@ int main(void) | |||
458 | .recv_socks = 10, | 498 | .recv_socks = 10, |
459 | .recv_port = 8007, | 499 | .recv_port = 8007, |
460 | .send_port_min = 9100}); | 500 | .send_port_min = 9100}); |
501 | test_reuseport_cbpf((struct test_params) { | ||
502 | .recv_family = AF_INET6, | ||
503 | .send_family = AF_INET, | ||
504 | .protocol = SOCK_DGRAM, | ||
505 | .recv_socks = 20, | ||
506 | .recv_port = 8007, | ||
507 | .send_port_min = 9100}); | ||
461 | 508 | ||
462 | 509 | ||
463 | test_filter_without_bind(); | 510 | test_filter_without_bind(); |