diff options
author | Tom Herbert <therbert@google.com> | 2014-09-17 15:25:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-19 17:15:31 -0400 |
commit | afe93325bc02a5b2dea0cd7d78225de692265e6e (patch) | |
tree | 685a28ca9b3d961e64bb2a08d6ced2d92e33329a /net/ipv4/fou.c | |
parent | 23461551c00628c3f3fe9cf837bf53cf8f212b63 (diff) |
fou: Add GRO support
Implement fou_gro_receive and fou_gro_complete, and populate these
in the correponsing udp_offloads for the socket. Added ipproto to
udp_offloads and pass this from UDP to the fou GRO routine in proto
field of napi_gro_cb structure.
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fou.c')
-rw-r--r-- | net/ipv4/fou.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index d44f97b79418..dced89fbe480 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | #include <net/genetlink.h> | 9 | #include <net/genetlink.h> |
10 | #include <net/ip.h> | 10 | #include <net/ip.h> |
11 | #include <net/protocol.h> | ||
11 | #include <net/udp.h> | 12 | #include <net/udp.h> |
12 | #include <net/udp_tunnel.h> | 13 | #include <net/udp_tunnel.h> |
13 | #include <net/xfrm.h> | 14 | #include <net/xfrm.h> |
@@ -21,6 +22,7 @@ struct fou { | |||
21 | struct socket *sock; | 22 | struct socket *sock; |
22 | u8 protocol; | 23 | u8 protocol; |
23 | u16 port; | 24 | u16 port; |
25 | struct udp_offload udp_offloads; | ||
24 | struct list_head list; | 26 | struct list_head list; |
25 | }; | 27 | }; |
26 | 28 | ||
@@ -62,6 +64,69 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb) | |||
62 | sizeof(struct udphdr)); | 64 | sizeof(struct udphdr)); |
63 | } | 65 | } |
64 | 66 | ||
67 | static struct sk_buff **fou_gro_receive(struct sk_buff **head, | ||
68 | struct sk_buff *skb, | ||
69 | const struct net_offload **offloads) | ||
70 | { | ||
71 | const struct net_offload *ops; | ||
72 | struct sk_buff **pp = NULL; | ||
73 | u8 proto = NAPI_GRO_CB(skb)->proto; | ||
74 | |||
75 | rcu_read_lock(); | ||
76 | ops = rcu_dereference(offloads[proto]); | ||
77 | if (!ops || !ops->callbacks.gro_receive) | ||
78 | goto out_unlock; | ||
79 | |||
80 | pp = ops->callbacks.gro_receive(head, skb); | ||
81 | |||
82 | out_unlock: | ||
83 | rcu_read_unlock(); | ||
84 | |||
85 | return pp; | ||
86 | } | ||
87 | |||
88 | static int fou_gro_complete(struct sk_buff *skb, int nhoff, | ||
89 | const struct net_offload **offloads) | ||
90 | { | ||
91 | const struct net_offload *ops; | ||
92 | u8 proto = NAPI_GRO_CB(skb)->proto; | ||
93 | int err = -ENOSYS; | ||
94 | |||
95 | rcu_read_lock(); | ||
96 | ops = rcu_dereference(offloads[proto]); | ||
97 | if (WARN_ON(!ops || !ops->callbacks.gro_complete)) | ||
98 | goto out_unlock; | ||
99 | |||
100 | err = ops->callbacks.gro_complete(skb, nhoff); | ||
101 | |||
102 | out_unlock: | ||
103 | rcu_read_unlock(); | ||
104 | |||
105 | return err; | ||
106 | } | ||
107 | |||
108 | static struct sk_buff **fou4_gro_receive(struct sk_buff **head, | ||
109 | struct sk_buff *skb) | ||
110 | { | ||
111 | return fou_gro_receive(head, skb, inet_offloads); | ||
112 | } | ||
113 | |||
114 | static int fou4_gro_complete(struct sk_buff *skb, int nhoff) | ||
115 | { | ||
116 | return fou_gro_complete(skb, nhoff, inet_offloads); | ||
117 | } | ||
118 | |||
119 | static struct sk_buff **fou6_gro_receive(struct sk_buff **head, | ||
120 | struct sk_buff *skb) | ||
121 | { | ||
122 | return fou_gro_receive(head, skb, inet6_offloads); | ||
123 | } | ||
124 | |||
125 | static int fou6_gro_complete(struct sk_buff *skb, int nhoff) | ||
126 | { | ||
127 | return fou_gro_complete(skb, nhoff, inet6_offloads); | ||
128 | } | ||
129 | |||
65 | static int fou_add_to_port_list(struct fou *fou) | 130 | static int fou_add_to_port_list(struct fou *fou) |
66 | { | 131 | { |
67 | struct fou *fout; | 132 | struct fou *fout; |
@@ -134,6 +199,29 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, | |||
134 | 199 | ||
135 | sk->sk_allocation = GFP_ATOMIC; | 200 | sk->sk_allocation = GFP_ATOMIC; |
136 | 201 | ||
202 | switch (cfg->udp_config.family) { | ||
203 | case AF_INET: | ||
204 | fou->udp_offloads.callbacks.gro_receive = fou4_gro_receive; | ||
205 | fou->udp_offloads.callbacks.gro_complete = fou4_gro_complete; | ||
206 | break; | ||
207 | case AF_INET6: | ||
208 | fou->udp_offloads.callbacks.gro_receive = fou6_gro_receive; | ||
209 | fou->udp_offloads.callbacks.gro_complete = fou6_gro_complete; | ||
210 | break; | ||
211 | default: | ||
212 | err = -EPFNOSUPPORT; | ||
213 | goto error; | ||
214 | } | ||
215 | |||
216 | fou->udp_offloads.port = cfg->udp_config.local_udp_port; | ||
217 | fou->udp_offloads.ipproto = cfg->protocol; | ||
218 | |||
219 | if (cfg->udp_config.family == AF_INET) { | ||
220 | err = udp_add_offload(&fou->udp_offloads); | ||
221 | if (err) | ||
222 | goto error; | ||
223 | } | ||
224 | |||
137 | err = fou_add_to_port_list(fou); | 225 | err = fou_add_to_port_list(fou); |
138 | if (err) | 226 | if (err) |
139 | goto error; | 227 | goto error; |
@@ -160,6 +248,7 @@ static int fou_destroy(struct net *net, struct fou_cfg *cfg) | |||
160 | spin_lock(&fou_lock); | 248 | spin_lock(&fou_lock); |
161 | list_for_each_entry(fou, &fou_list, list) { | 249 | list_for_each_entry(fou, &fou_list, list) { |
162 | if (fou->port == port) { | 250 | if (fou->port == port) { |
251 | udp_del_offload(&fou->udp_offloads); | ||
163 | fou_release(fou); | 252 | fou_release(fou); |
164 | err = 0; | 253 | err = 0; |
165 | break; | 254 | break; |