diff options
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | net/ipv4/fou.c | 89 | ||||
-rw-r--r-- | net/ipv4/udp_offload.c | 5 |
3 files changed, 95 insertions, 2 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 28d4378615e5..4354b4307e37 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1874,7 +1874,7 @@ struct napi_gro_cb { | |||
1874 | /* jiffies when first packet was created/queued */ | 1874 | /* jiffies when first packet was created/queued */ |
1875 | unsigned long age; | 1875 | unsigned long age; |
1876 | 1876 | ||
1877 | /* Used in ipv6_gro_receive() */ | 1877 | /* Used in ipv6_gro_receive() and foo-over-udp */ |
1878 | u16 proto; | 1878 | u16 proto; |
1879 | 1879 | ||
1880 | /* Used in udp_gro_receive */ | 1880 | /* Used in udp_gro_receive */ |
@@ -1925,6 +1925,7 @@ struct packet_offload { | |||
1925 | 1925 | ||
1926 | struct udp_offload { | 1926 | struct udp_offload { |
1927 | __be16 port; | 1927 | __be16 port; |
1928 | u8 ipproto; | ||
1928 | struct offload_callbacks callbacks; | 1929 | struct offload_callbacks callbacks; |
1929 | }; | 1930 | }; |
1930 | 1931 | ||
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; |
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index adab393b2fe5..d7c43f764c71 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
@@ -276,6 +276,7 @@ unflush: | |||
276 | 276 | ||
277 | skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ | 277 | skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ |
278 | skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); | 278 | skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); |
279 | NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; | ||
279 | pp = uo_priv->offload->callbacks.gro_receive(head, skb); | 280 | pp = uo_priv->offload->callbacks.gro_receive(head, skb); |
280 | 281 | ||
281 | out_unlock: | 282 | out_unlock: |
@@ -329,8 +330,10 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff) | |||
329 | break; | 330 | break; |
330 | } | 331 | } |
331 | 332 | ||
332 | if (uo_priv != NULL) | 333 | if (uo_priv != NULL) { |
334 | NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; | ||
333 | err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr)); | 335 | err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr)); |
336 | } | ||
334 | 337 | ||
335 | rcu_read_unlock(); | 338 | rcu_read_unlock(); |
336 | return err; | 339 | return err; |