summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/geneve.c97
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}
150EXPORT_SYMBOL_GPL(geneve_xmit_skb); 150EXPORT_SYMBOL_GPL(geneve_xmit_skb);
151 151
152static int geneve_hlen(struct genevehdr *gh)
153{
154 return sizeof(*gh) + gh->opt_len * 4;
155}
156
157static 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
214out_unlock:
215 rcu_read_unlock();
216out:
217 NAPI_GRO_CB(skb)->flush |= flush;
218
219 return pp;
220}
221
222static 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
152static void geneve_notify_add_rx_port(struct geneve_sock *gs) 245static 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));