diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2013-06-08 06:56:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-12 03:47:25 -0400 |
commit | da5bab079f9b7d90ba234965a14914ace55e45e9 (patch) | |
tree | 868de978a44f6a59ccc7a2f4f9c096707c5bf044 /net | |
parent | 946d3bd7231be3b6202759ea0bea59989ae28c4a (diff) |
net: udp4: move GSO functions to udp_offload
Similarly to TCP offloading and UDPv6 offloading, move all related
UDPv4 functions to udp_offload.c to make things more explicit. Also,
by this, we can make those functions static.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/Makefile | 2 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 9 | ||||
-rw-r--r-- | net/ipv4/udp.c | 75 | ||||
-rw-r--r-- | net/ipv4/udp_offload.c | 100 |
4 files changed, 104 insertions, 82 deletions
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 4d3e138c564f..7fcf8101d85f 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -9,7 +9,7 @@ obj-y := route.o inetpeer.o protocol.o \ | |||
9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ | 9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ |
10 | tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \ | 10 | tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \ |
11 | tcp_offload.o datagram.o raw.o udp.o udplite.o \ | 11 | tcp_offload.o datagram.o raw.o udp.o udplite.o \ |
12 | arp.o icmp.o devinet.o af_inet.o igmp.o \ | 12 | udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ |
13 | fib_frontend.o fib_semantics.o fib_trie.o \ | 13 | fib_frontend.o fib_semantics.o fib_trie.o \ |
14 | inet_fragment.o ping.o | 14 | inet_fragment.o ping.o |
15 | 15 | ||
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7b514290efc6..5598b06d62db 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1566,13 +1566,6 @@ static const struct net_protocol udp_protocol = { | |||
1566 | .netns_ok = 1, | 1566 | .netns_ok = 1, |
1567 | }; | 1567 | }; |
1568 | 1568 | ||
1569 | static const struct net_offload udp_offload = { | ||
1570 | .callbacks = { | ||
1571 | .gso_send_check = udp4_ufo_send_check, | ||
1572 | .gso_segment = udp4_ufo_fragment, | ||
1573 | }, | ||
1574 | }; | ||
1575 | |||
1576 | static const struct net_protocol icmp_protocol = { | 1569 | static const struct net_protocol icmp_protocol = { |
1577 | .handler = icmp_rcv, | 1570 | .handler = icmp_rcv, |
1578 | .err_handler = icmp_err, | 1571 | .err_handler = icmp_err, |
@@ -1672,7 +1665,7 @@ static int __init ipv4_offload_init(void) | |||
1672 | /* | 1665 | /* |
1673 | * Add offloads | 1666 | * Add offloads |
1674 | */ | 1667 | */ |
1675 | if (inet_add_offload(&udp_offload, IPPROTO_UDP) < 0) | 1668 | if (udpv4_offload_init() < 0) |
1676 | pr_crit("%s: Cannot add UDP protocol offload\n", __func__); | 1669 | pr_crit("%s: Cannot add UDP protocol offload\n", __func__); |
1677 | if (tcpv4_offload_init() < 0) | 1670 | if (tcpv4_offload_init() < 0) |
1678 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); | 1671 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 2955b25aee6d..f65bc32c0266 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -2290,29 +2290,8 @@ void __init udp_init(void) | |||
2290 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; | 2290 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; |
2291 | } | 2291 | } |
2292 | 2292 | ||
2293 | int udp4_ufo_send_check(struct sk_buff *skb) | 2293 | struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, |
2294 | { | 2294 | netdev_features_t features) |
2295 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | ||
2296 | return -EINVAL; | ||
2297 | |||
2298 | if (likely(!skb->encapsulation)) { | ||
2299 | const struct iphdr *iph; | ||
2300 | struct udphdr *uh; | ||
2301 | |||
2302 | iph = ip_hdr(skb); | ||
2303 | uh = udp_hdr(skb); | ||
2304 | |||
2305 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, | ||
2306 | IPPROTO_UDP, 0); | ||
2307 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
2308 | skb->csum_offset = offsetof(struct udphdr, check); | ||
2309 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
2310 | } | ||
2311 | return 0; | ||
2312 | } | ||
2313 | |||
2314 | static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | ||
2315 | netdev_features_t features) | ||
2316 | { | 2295 | { |
2317 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 2296 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
2318 | int mac_len = skb->mac_len; | 2297 | int mac_len = skb->mac_len; |
@@ -2371,53 +2350,3 @@ static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | |||
2371 | out: | 2350 | out: |
2372 | return segs; | 2351 | return segs; |
2373 | } | 2352 | } |
2374 | |||
2375 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | ||
2376 | netdev_features_t features) | ||
2377 | { | ||
2378 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
2379 | unsigned int mss; | ||
2380 | mss = skb_shinfo(skb)->gso_size; | ||
2381 | if (unlikely(skb->len <= mss)) | ||
2382 | goto out; | ||
2383 | |||
2384 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { | ||
2385 | /* Packet is from an untrusted source, reset gso_segs. */ | ||
2386 | int type = skb_shinfo(skb)->gso_type; | ||
2387 | |||
2388 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | ||
2389 | SKB_GSO_UDP_TUNNEL | | ||
2390 | SKB_GSO_GRE | SKB_GSO_MPLS) || | ||
2391 | !(type & (SKB_GSO_UDP)))) | ||
2392 | goto out; | ||
2393 | |||
2394 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | ||
2395 | |||
2396 | segs = NULL; | ||
2397 | goto out; | ||
2398 | } | ||
2399 | |||
2400 | /* Fragment the skb. IP headers of the fragments are updated in | ||
2401 | * inet_gso_segment() | ||
2402 | */ | ||
2403 | if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) | ||
2404 | segs = skb_udp_tunnel_segment(skb, features); | ||
2405 | else { | ||
2406 | int offset; | ||
2407 | __wsum csum; | ||
2408 | |||
2409 | /* Do software UFO. Complete and fill in the UDP checksum as | ||
2410 | * HW cannot do checksum of UDP packets sent as multiple | ||
2411 | * IP fragments. | ||
2412 | */ | ||
2413 | offset = skb_checksum_start_offset(skb); | ||
2414 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
2415 | offset += skb->csum_offset; | ||
2416 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
2417 | skb->ip_summed = CHECKSUM_NONE; | ||
2418 | |||
2419 | segs = skb_segment(skb, features); | ||
2420 | } | ||
2421 | out: | ||
2422 | return segs; | ||
2423 | } | ||
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c new file mode 100644 index 000000000000..f35eccaa855e --- /dev/null +++ b/net/ipv4/udp_offload.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * IPV4 GSO/GRO offload support | ||
3 | * Linux INET implementation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * UDPv4 GSO support | ||
11 | */ | ||
12 | |||
13 | #include <linux/skbuff.h> | ||
14 | #include <net/udp.h> | ||
15 | #include <net/protocol.h> | ||
16 | |||
17 | static int udp4_ufo_send_check(struct sk_buff *skb) | ||
18 | { | ||
19 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | ||
20 | return -EINVAL; | ||
21 | |||
22 | if (likely(!skb->encapsulation)) { | ||
23 | const struct iphdr *iph; | ||
24 | struct udphdr *uh; | ||
25 | |||
26 | iph = ip_hdr(skb); | ||
27 | uh = udp_hdr(skb); | ||
28 | |||
29 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, | ||
30 | IPPROTO_UDP, 0); | ||
31 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
32 | skb->csum_offset = offsetof(struct udphdr, check); | ||
33 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
34 | } | ||
35 | |||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | ||
40 | netdev_features_t features) | ||
41 | { | ||
42 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
43 | unsigned int mss; | ||
44 | |||
45 | mss = skb_shinfo(skb)->gso_size; | ||
46 | if (unlikely(skb->len <= mss)) | ||
47 | goto out; | ||
48 | |||
49 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { | ||
50 | /* Packet is from an untrusted source, reset gso_segs. */ | ||
51 | int type = skb_shinfo(skb)->gso_type; | ||
52 | |||
53 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | ||
54 | SKB_GSO_UDP_TUNNEL | | ||
55 | SKB_GSO_GRE | SKB_GSO_MPLS) || | ||
56 | !(type & (SKB_GSO_UDP)))) | ||
57 | goto out; | ||
58 | |||
59 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | ||
60 | |||
61 | segs = NULL; | ||
62 | goto out; | ||
63 | } | ||
64 | |||
65 | /* Fragment the skb. IP headers of the fragments are updated in | ||
66 | * inet_gso_segment() | ||
67 | */ | ||
68 | if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) | ||
69 | segs = skb_udp_tunnel_segment(skb, features); | ||
70 | else { | ||
71 | int offset; | ||
72 | __wsum csum; | ||
73 | |||
74 | /* Do software UFO. Complete and fill in the UDP checksum as | ||
75 | * HW cannot do checksum of UDP packets sent as multiple | ||
76 | * IP fragments. | ||
77 | */ | ||
78 | offset = skb_checksum_start_offset(skb); | ||
79 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
80 | offset += skb->csum_offset; | ||
81 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
82 | skb->ip_summed = CHECKSUM_NONE; | ||
83 | |||
84 | segs = skb_segment(skb, features); | ||
85 | } | ||
86 | out: | ||
87 | return segs; | ||
88 | } | ||
89 | |||
90 | static const struct net_offload udpv4_offload = { | ||
91 | .callbacks = { | ||
92 | .gso_send_check = udp4_ufo_send_check, | ||
93 | .gso_segment = udp4_ufo_fragment, | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | int __init udpv4_offload_init(void) | ||
98 | { | ||
99 | return inet_add_offload(&udpv4_offload, IPPROTO_UDP); | ||
100 | } | ||