diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/geneve.c | 97 |
1 files changed, 95 insertions, 2 deletions
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 394a200f93c1..19e256e1dd92 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c | |||
@@ -149,6 +149,99 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, | |||
149 | } | 149 | } |
150 | EXPORT_SYMBOL_GPL(geneve_xmit_skb); | 150 | EXPORT_SYMBOL_GPL(geneve_xmit_skb); |
151 | 151 | ||
152 | static int geneve_hlen(struct genevehdr *gh) | ||
153 | { | ||
154 | return sizeof(*gh) + gh->opt_len * 4; | ||
155 | } | ||
156 | |||
157 | static struct sk_buff **geneve_gro_receive(struct sk_buff **head, | ||
158 | struct sk_buff *skb) | ||
159 | { | ||
160 | struct sk_buff *p, **pp = NULL; | ||
161 | struct genevehdr *gh, *gh2; | ||
162 | unsigned int hlen, gh_len, off_gnv; | ||
163 | const struct packet_offload *ptype; | ||
164 | __be16 type; | ||
165 | int flush = 1; | ||
166 | |||
167 | off_gnv = skb_gro_offset(skb); | ||
168 | hlen = off_gnv + sizeof(*gh); | ||
169 | gh = skb_gro_header_fast(skb, off_gnv); | ||
170 | if (skb_gro_header_hard(skb, hlen)) { | ||
171 | gh = skb_gro_header_slow(skb, hlen, off_gnv); | ||
172 | if (unlikely(!gh)) | ||
173 | goto out; | ||
174 | } | ||
175 | |||
176 | if (gh->ver != GENEVE_VER || gh->oam) | ||
177 | goto out; | ||
178 | gh_len = geneve_hlen(gh); | ||
179 | |||
180 | hlen = off_gnv + gh_len; | ||
181 | if (skb_gro_header_hard(skb, hlen)) { | ||
182 | gh = skb_gro_header_slow(skb, hlen, off_gnv); | ||
183 | if (unlikely(!gh)) | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | flush = 0; | ||
188 | |||
189 | for (p = *head; p; p = p->next) { | ||
190 | if (!NAPI_GRO_CB(p)->same_flow) | ||
191 | continue; | ||
192 | |||
193 | gh2 = (struct genevehdr *)(p->data + off_gnv); | ||
194 | if (gh->opt_len != gh2->opt_len || | ||
195 | memcmp(gh, gh2, gh_len)) { | ||
196 | NAPI_GRO_CB(p)->same_flow = 0; | ||
197 | continue; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | type = gh->proto_type; | ||
202 | |||
203 | rcu_read_lock(); | ||
204 | ptype = gro_find_receive_by_type(type); | ||
205 | if (ptype == NULL) { | ||
206 | flush = 1; | ||
207 | goto out_unlock; | ||
208 | } | ||
209 | |||
210 | skb_gro_pull(skb, gh_len); | ||
211 | skb_gro_postpull_rcsum(skb, gh, gh_len); | ||
212 | pp = ptype->callbacks.gro_receive(head, skb); | ||
213 | |||
214 | out_unlock: | ||
215 | rcu_read_unlock(); | ||
216 | out: | ||
217 | NAPI_GRO_CB(skb)->flush |= flush; | ||
218 | |||
219 | return pp; | ||
220 | } | ||
221 | |||
222 | static int geneve_gro_complete(struct sk_buff *skb, int nhoff) | ||
223 | { | ||
224 | struct genevehdr *gh; | ||
225 | struct packet_offload *ptype; | ||
226 | __be16 type; | ||
227 | int gh_len; | ||
228 | int err = -ENOSYS; | ||
229 | |||
230 | udp_tunnel_gro_complete(skb, nhoff); | ||
231 | |||
232 | gh = (struct genevehdr *)(skb->data + nhoff); | ||
233 | gh_len = geneve_hlen(gh); | ||
234 | type = gh->proto_type; | ||
235 | |||
236 | rcu_read_lock(); | ||
237 | ptype = gro_find_complete_by_type(type); | ||
238 | if (ptype != NULL) | ||
239 | err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); | ||
240 | |||
241 | rcu_read_unlock(); | ||
242 | return err; | ||
243 | } | ||
244 | |||
152 | static void geneve_notify_add_rx_port(struct geneve_sock *gs) | 245 | static void geneve_notify_add_rx_port(struct geneve_sock *gs) |
153 | { | 246 | { |
154 | struct sock *sk = gs->sock->sk; | 247 | struct sock *sk = gs->sock->sk; |
@@ -278,8 +371,8 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, | |||
278 | 371 | ||
279 | /* Initialize the geneve udp offloads structure */ | 372 | /* Initialize the geneve udp offloads structure */ |
280 | gs->udp_offloads.port = port; | 373 | gs->udp_offloads.port = port; |
281 | gs->udp_offloads.callbacks.gro_receive = NULL; | 374 | gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive; |
282 | gs->udp_offloads.callbacks.gro_complete = NULL; | 375 | gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete; |
283 | 376 | ||
284 | spin_lock(&gn->sock_lock); | 377 | spin_lock(&gn->sock_lock); |
285 | hlist_add_head_rcu(&gs->hlist, gs_head(net, port)); | 378 | hlist_add_head_rcu(&gs->hlist, gs_head(net, port)); |