Skip to content

Commit 3ddaed6

Browse files
committed
Merge branch 'pmtu-esp'
Vadim Fedorenko ays: ==================== Fix PMTU for ESP-in-UDP encapsulation Bug 213669 uncovered regression in PMTU discovery for UDP-encapsulated routes and some incorrect usage in udp tunnel fields. This series fixes problems and also adds such case for selftests v3: - update checking logic to account SCTP use case v2: - remove refactor code that was in first patch - move checking logic to __udp{4,6}_lib_err_encap - add more tests, especially routed configuration ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 58acd10 + ece1278 commit 3ddaed6

File tree

4 files changed

+298
-19
lines changed

4 files changed

+298
-19
lines changed

net/ipv4/udp.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,12 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
645645
const struct iphdr *iph,
646646
struct udphdr *uh,
647647
struct udp_table *udptable,
648+
struct sock *sk,
648649
struct sk_buff *skb, u32 info)
649650
{
651+
int (*lookup)(struct sock *sk, struct sk_buff *skb);
650652
int network_offset, transport_offset;
651-
struct sock *sk;
653+
struct udp_sock *up;
652654

653655
network_offset = skb_network_offset(skb);
654656
transport_offset = skb_transport_offset(skb);
@@ -659,18 +661,28 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
659661
/* Transport header needs to point to the UDP header */
660662
skb_set_transport_header(skb, iph->ihl << 2);
661663

664+
if (sk) {
665+
up = udp_sk(sk);
666+
667+
lookup = READ_ONCE(up->encap_err_lookup);
668+
if (lookup && lookup(sk, skb))
669+
sk = NULL;
670+
671+
goto out;
672+
}
673+
662674
sk = __udp4_lib_lookup(net, iph->daddr, uh->source,
663675
iph->saddr, uh->dest, skb->dev->ifindex, 0,
664676
udptable, NULL);
665677
if (sk) {
666-
int (*lookup)(struct sock *sk, struct sk_buff *skb);
667-
struct udp_sock *up = udp_sk(sk);
678+
up = udp_sk(sk);
668679

669680
lookup = READ_ONCE(up->encap_err_lookup);
670681
if (!lookup || lookup(sk, skb))
671682
sk = NULL;
672683
}
673684

685+
out:
674686
if (!sk)
675687
sk = ERR_PTR(__udp4_lib_err_encap_no_sk(skb, info));
676688

@@ -707,15 +719,16 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
707719
sk = __udp4_lib_lookup(net, iph->daddr, uh->dest,
708720
iph->saddr, uh->source, skb->dev->ifindex,
709721
inet_sdif(skb), udptable, NULL);
722+
710723
if (!sk || udp_sk(sk)->encap_type) {
711724
/* No socket for error: try tunnels before discarding */
712-
sk = ERR_PTR(-ENOENT);
713725
if (static_branch_unlikely(&udp_encap_needed_key)) {
714-
sk = __udp4_lib_err_encap(net, iph, uh, udptable, skb,
726+
sk = __udp4_lib_err_encap(net, iph, uh, udptable, sk, skb,
715727
info);
716728
if (!sk)
717729
return 0;
718-
}
730+
} else
731+
sk = ERR_PTR(-ENOENT);
719732

720733
if (IS_ERR(sk)) {
721734
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);

net/ipv6/udp.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,14 @@ static struct sock *__udp6_lib_err_encap(struct net *net,
502502
const struct ipv6hdr *hdr, int offset,
503503
struct udphdr *uh,
504504
struct udp_table *udptable,
505+
struct sock *sk,
505506
struct sk_buff *skb,
506507
struct inet6_skb_parm *opt,
507508
u8 type, u8 code, __be32 info)
508509
{
510+
int (*lookup)(struct sock *sk, struct sk_buff *skb);
509511
int network_offset, transport_offset;
510-
struct sock *sk;
512+
struct udp_sock *up;
511513

512514
network_offset = skb_network_offset(skb);
513515
transport_offset = skb_transport_offset(skb);
@@ -518,18 +520,28 @@ static struct sock *__udp6_lib_err_encap(struct net *net,
518520
/* Transport header needs to point to the UDP header */
519521
skb_set_transport_header(skb, offset);
520522

523+
if (sk) {
524+
up = udp_sk(sk);
525+
526+
lookup = READ_ONCE(up->encap_err_lookup);
527+
if (lookup && lookup(sk, skb))
528+
sk = NULL;
529+
530+
goto out;
531+
}
532+
521533
sk = __udp6_lib_lookup(net, &hdr->daddr, uh->source,
522534
&hdr->saddr, uh->dest,
523535
inet6_iif(skb), 0, udptable, skb);
524536
if (sk) {
525-
int (*lookup)(struct sock *sk, struct sk_buff *skb);
526-
struct udp_sock *up = udp_sk(sk);
537+
up = udp_sk(sk);
527538

528539
lookup = READ_ONCE(up->encap_err_lookup);
529540
if (!lookup || lookup(sk, skb))
530541
sk = NULL;
531542
}
532543

544+
out:
533545
if (!sk) {
534546
sk = ERR_PTR(__udp6_lib_err_encap_no_sk(skb, opt, type, code,
535547
offset, info));
@@ -558,16 +570,17 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
558570

559571
sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
560572
inet6_iif(skb), inet6_sdif(skb), udptable, NULL);
573+
561574
if (!sk || udp_sk(sk)->encap_type) {
562575
/* No socket for error: try tunnels before discarding */
563-
sk = ERR_PTR(-ENOENT);
564576
if (static_branch_unlikely(&udpv6_encap_needed_key)) {
565577
sk = __udp6_lib_err_encap(net, hdr, offset, uh,
566-
udptable, skb,
578+
udptable, sk, skb,
567579
opt, type, code, info);
568580
if (!sk)
569581
return 0;
570-
}
582+
} else
583+
sk = ERR_PTR(-ENOENT);
571584

572585
if (IS_ERR(sk)) {
573586
__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),

tools/testing/selftests/net/nettest.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
#include <sys/socket.h>
1212
#include <sys/wait.h>
1313
#include <linux/tcp.h>
14+
#include <linux/udp.h>
1415
#include <arpa/inet.h>
1516
#include <net/if.h>
1617
#include <netinet/in.h>
18+
#include <netinet/ip.h>
1719
#include <netdb.h>
1820
#include <fcntl.h>
1921
#include <libgen.h>
@@ -27,6 +29,10 @@
2729
#include <time.h>
2830
#include <errno.h>
2931

32+
#include <linux/xfrm.h>
33+
#include <linux/ipsec.h>
34+
#include <linux/pfkeyv2.h>
35+
3036
#ifndef IPV6_UNICAST_IF
3137
#define IPV6_UNICAST_IF 76
3238
#endif
@@ -114,6 +120,9 @@ struct sock_args {
114120
struct in_addr in;
115121
struct in6_addr in6;
116122
} expected_raddr;
123+
124+
/* ESP in UDP encap test */
125+
int use_xfrm;
117126
};
118127

119128
static int server_mode;
@@ -1346,6 +1355,41 @@ static int bind_socket(int sd, struct sock_args *args)
13461355
return 0;
13471356
}
13481357

1358+
static int config_xfrm_policy(int sd, struct sock_args *args)
1359+
{
1360+
struct xfrm_userpolicy_info policy = {};
1361+
int type = UDP_ENCAP_ESPINUDP;
1362+
int xfrm_af = IP_XFRM_POLICY;
1363+
int level = SOL_IP;
1364+
1365+
if (args->type != SOCK_DGRAM) {
1366+
log_error("Invalid socket type. Only DGRAM could be used for XFRM\n");
1367+
return 1;
1368+
}
1369+
1370+
policy.action = XFRM_POLICY_ALLOW;
1371+
policy.sel.family = args->version;
1372+
if (args->version == AF_INET6) {
1373+
xfrm_af = IPV6_XFRM_POLICY;
1374+
level = SOL_IPV6;
1375+
}
1376+
1377+
policy.dir = XFRM_POLICY_OUT;
1378+
if (setsockopt(sd, level, xfrm_af, &policy, sizeof(policy)) < 0)
1379+
return 1;
1380+
1381+
policy.dir = XFRM_POLICY_IN;
1382+
if (setsockopt(sd, level, xfrm_af, &policy, sizeof(policy)) < 0)
1383+
return 1;
1384+
1385+
if (setsockopt(sd, IPPROTO_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) {
1386+
log_err_errno("Failed to set xfrm encap");
1387+
return 1;
1388+
}
1389+
1390+
return 0;
1391+
}
1392+
13491393
static int lsock_init(struct sock_args *args)
13501394
{
13511395
long flags;
@@ -1389,6 +1433,11 @@ static int lsock_init(struct sock_args *args)
13891433
if (fcntl(sd, F_SETFD, FD_CLOEXEC) < 0)
13901434
log_err_errno("Failed to set close-on-exec flag");
13911435

1436+
if (args->use_xfrm && config_xfrm_policy(sd, args)) {
1437+
log_err_errno("Failed to set xfrm policy");
1438+
goto err;
1439+
}
1440+
13921441
out:
13931442
return sd;
13941443

@@ -1772,7 +1821,7 @@ static int ipc_parent(int cpid, int fd, struct sock_args *args)
17721821
return client_status;
17731822
}
17741823

1775-
#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:M:X:m:d:I:BN:O:SCi6L:0:1:2:3:Fbq"
1824+
#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:M:X:m:d:I:BN:O:SCi6xL:0:1:2:3:Fbq"
17761825

17771826
static void print_usage(char *prog)
17781827
{
@@ -1795,6 +1844,7 @@ static void print_usage(char *prog)
17951844
" -D|R datagram (D) / raw (R) socket (default stream)\n"
17961845
" -l addr local address to bind to in server mode\n"
17971846
" -c addr local address to bind to in client mode\n"
1847+
" -x configure XFRM policy on socket\n"
17981848
"\n"
17991849
" -d dev bind socket to given device name\n"
18001850
" -I dev bind socket to given device name - server mode\n"
@@ -1966,6 +2016,9 @@ int main(int argc, char *argv[])
19662016
case 'q':
19672017
quiet = 1;
19682018
break;
2019+
case 'x':
2020+
args.use_xfrm = 1;
2021+
break;
19692022
default:
19702023
print_usage(argv[0]);
19712024
return 1;

0 commit comments

Comments
 (0)