diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2015-08-08 02:51:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-10 17:03:54 -0400 |
commit | 2e15ea390e6f4466655066d97e22ec66870a042c (patch) | |
tree | 68df68ac988e713a34b830bfabe05faaf0d55bf4 | |
parent | a9020fde67a6eb77f8130feff633189f99264db1 (diff) |
ip_gre: Add support to collect tunnel metadata.
Following patch create new tunnel flag which enable
tunnel metadata collection on given device.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip_tunnels.h | 7 | ||||
-rw-r--r-- | include/uapi/linux/if_tunnel.h | 1 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 195 | ||||
-rw-r--r-- | net/ipv4/ip_tunnel.c | 37 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 2 | ||||
-rw-r--r-- | net/ipv6/sit.c | 2 |
6 files changed, 216 insertions, 28 deletions
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 47984415f5d1..984dbfa15e13 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h | |||
@@ -82,6 +82,8 @@ struct ip_tunnel_dst { | |||
82 | __be32 saddr; | 82 | __be32 saddr; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | struct metadata_dst; | ||
86 | |||
85 | struct ip_tunnel { | 87 | struct ip_tunnel { |
86 | struct ip_tunnel __rcu *next; | 88 | struct ip_tunnel __rcu *next; |
87 | struct hlist_node hash_node; | 89 | struct hlist_node hash_node; |
@@ -115,6 +117,7 @@ struct ip_tunnel { | |||
115 | unsigned int prl_count; /* # of entries in PRL */ | 117 | unsigned int prl_count; /* # of entries in PRL */ |
116 | int ip_tnl_net_id; | 118 | int ip_tnl_net_id; |
117 | struct gro_cells gro_cells; | 119 | struct gro_cells gro_cells; |
120 | bool collect_md; | ||
118 | }; | 121 | }; |
119 | 122 | ||
120 | #define TUNNEL_CSUM __cpu_to_be16(0x01) | 123 | #define TUNNEL_CSUM __cpu_to_be16(0x01) |
@@ -149,6 +152,7 @@ struct tnl_ptk_info { | |||
149 | struct ip_tunnel_net { | 152 | struct ip_tunnel_net { |
150 | struct net_device *fb_tunnel_dev; | 153 | struct net_device *fb_tunnel_dev; |
151 | struct hlist_head tunnels[IP_TNL_HASH_SIZE]; | 154 | struct hlist_head tunnels[IP_TNL_HASH_SIZE]; |
155 | struct ip_tunnel __rcu *collect_md_tun; | ||
152 | }; | 156 | }; |
153 | 157 | ||
154 | struct ip_tunnel_encap_ops { | 158 | struct ip_tunnel_encap_ops { |
@@ -235,7 +239,8 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, | |||
235 | __be32 key); | 239 | __be32 key); |
236 | 240 | ||
237 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, | 241 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, |
238 | const struct tnl_ptk_info *tpi, bool log_ecn_error); | 242 | const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, |
243 | bool log_ecn_error); | ||
239 | int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], | 244 | int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], |
240 | struct ip_tunnel_parm *p); | 245 | struct ip_tunnel_parm *p); |
241 | int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], | 246 | int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], |
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h index bd3cc11a431f..af4de90ba27d 100644 --- a/include/uapi/linux/if_tunnel.h +++ b/include/uapi/linux/if_tunnel.h | |||
@@ -112,6 +112,7 @@ enum { | |||
112 | IFLA_GRE_ENCAP_FLAGS, | 112 | IFLA_GRE_ENCAP_FLAGS, |
113 | IFLA_GRE_ENCAP_SPORT, | 113 | IFLA_GRE_ENCAP_SPORT, |
114 | IFLA_GRE_ENCAP_DPORT, | 114 | IFLA_GRE_ENCAP_DPORT, |
115 | IFLA_GRE_COLLECT_METADATA, | ||
115 | __IFLA_GRE_MAX, | 116 | __IFLA_GRE_MAX, |
116 | }; | 117 | }; |
117 | 118 | ||
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5fd706473c73..554a760c2cd0 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/udp.h> | 25 | #include <linux/udp.h> |
26 | #include <linux/if_arp.h> | 26 | #include <linux/if_arp.h> |
27 | #include <linux/mroute.h> | 27 | #include <linux/mroute.h> |
28 | #include <linux/if_vlan.h> | ||
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
29 | #include <linux/in6.h> | 30 | #include <linux/in6.h> |
30 | #include <linux/inetdevice.h> | 31 | #include <linux/inetdevice.h> |
@@ -47,6 +48,7 @@ | |||
47 | #include <net/netns/generic.h> | 48 | #include <net/netns/generic.h> |
48 | #include <net/rtnetlink.h> | 49 | #include <net/rtnetlink.h> |
49 | #include <net/gre.h> | 50 | #include <net/gre.h> |
51 | #include <net/dst_metadata.h> | ||
50 | 52 | ||
51 | #if IS_ENABLED(CONFIG_IPV6) | 53 | #if IS_ENABLED(CONFIG_IPV6) |
52 | #include <net/ipv6.h> | 54 | #include <net/ipv6.h> |
@@ -200,9 +202,29 @@ static int ipgre_err(struct sk_buff *skb, u32 info, | |||
200 | return PACKET_RCVD; | 202 | return PACKET_RCVD; |
201 | } | 203 | } |
202 | 204 | ||
205 | static __be64 key_to_tunnel_id(__be32 key) | ||
206 | { | ||
207 | #ifdef __BIG_ENDIAN | ||
208 | return (__force __be64)((__force u32)key); | ||
209 | #else | ||
210 | return (__force __be64)((__force u64)key << 32); | ||
211 | #endif | ||
212 | } | ||
213 | |||
214 | /* Returns the least-significant 32 bits of a __be64. */ | ||
215 | static __be32 tunnel_id_to_key(__be64 x) | ||
216 | { | ||
217 | #ifdef __BIG_ENDIAN | ||
218 | return (__force __be32)x; | ||
219 | #else | ||
220 | return (__force __be32)((__force u64)x >> 32); | ||
221 | #endif | ||
222 | } | ||
223 | |||
203 | static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) | 224 | static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) |
204 | { | 225 | { |
205 | struct net *net = dev_net(skb->dev); | 226 | struct net *net = dev_net(skb->dev); |
227 | struct metadata_dst *tun_dst = NULL; | ||
206 | struct ip_tunnel_net *itn; | 228 | struct ip_tunnel_net *itn; |
207 | const struct iphdr *iph; | 229 | const struct iphdr *iph; |
208 | struct ip_tunnel *tunnel; | 230 | struct ip_tunnel *tunnel; |
@@ -218,40 +240,162 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) | |||
218 | 240 | ||
219 | if (tunnel) { | 241 | if (tunnel) { |
220 | skb_pop_mac_header(skb); | 242 | skb_pop_mac_header(skb); |
221 | ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error); | 243 | if (tunnel->collect_md) { |
244 | struct ip_tunnel_info *info; | ||
245 | |||
246 | tun_dst = metadata_dst_alloc(0, GFP_ATOMIC); | ||
247 | if (!tun_dst) | ||
248 | return PACKET_REJECT; | ||
249 | |||
250 | info = &tun_dst->u.tun_info; | ||
251 | info->key.ipv4_src = iph->saddr; | ||
252 | info->key.ipv4_dst = iph->daddr; | ||
253 | info->key.ipv4_tos = iph->tos; | ||
254 | info->key.ipv4_ttl = iph->ttl; | ||
255 | |||
256 | info->mode = IP_TUNNEL_INFO_RX; | ||
257 | info->key.tun_flags = tpi->flags & | ||
258 | (TUNNEL_CSUM | TUNNEL_KEY); | ||
259 | info->key.tun_id = key_to_tunnel_id(tpi->key); | ||
260 | |||
261 | info->key.tp_src = 0; | ||
262 | info->key.tp_dst = 0; | ||
263 | } | ||
264 | |||
265 | ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); | ||
222 | return PACKET_RCVD; | 266 | return PACKET_RCVD; |
223 | } | 267 | } |
224 | return PACKET_REJECT; | 268 | return PACKET_REJECT; |
225 | } | 269 | } |
226 | 270 | ||
271 | static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags, | ||
272 | __be16 proto, __be32 key, __be32 seq) | ||
273 | { | ||
274 | struct gre_base_hdr *greh; | ||
275 | |||
276 | skb_push(skb, hdr_len); | ||
277 | |||
278 | skb_reset_transport_header(skb); | ||
279 | greh = (struct gre_base_hdr *)skb->data; | ||
280 | greh->flags = tnl_flags_to_gre_flags(flags); | ||
281 | greh->protocol = proto; | ||
282 | |||
283 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { | ||
284 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); | ||
285 | |||
286 | if (flags & TUNNEL_SEQ) { | ||
287 | *ptr = seq; | ||
288 | ptr--; | ||
289 | } | ||
290 | if (flags & TUNNEL_KEY) { | ||
291 | *ptr = key; | ||
292 | ptr--; | ||
293 | } | ||
294 | if (flags & TUNNEL_CSUM && | ||
295 | !(skb_shinfo(skb)->gso_type & | ||
296 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { | ||
297 | *ptr = 0; | ||
298 | *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, | ||
299 | skb->len, 0)); | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
227 | static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, | 304 | static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, |
228 | const struct iphdr *tnl_params, | 305 | const struct iphdr *tnl_params, |
229 | __be16 proto) | 306 | __be16 proto) |
230 | { | 307 | { |
231 | struct ip_tunnel *tunnel = netdev_priv(dev); | 308 | struct ip_tunnel *tunnel = netdev_priv(dev); |
232 | struct tnl_ptk_info tpi; | ||
233 | 309 | ||
234 | tpi.flags = tunnel->parms.o_flags; | ||
235 | tpi.proto = proto; | ||
236 | tpi.key = tunnel->parms.o_key; | ||
237 | if (tunnel->parms.o_flags & TUNNEL_SEQ) | 310 | if (tunnel->parms.o_flags & TUNNEL_SEQ) |
238 | tunnel->o_seqno++; | 311 | tunnel->o_seqno++; |
239 | tpi.seq = htonl(tunnel->o_seqno); | ||
240 | 312 | ||
241 | /* Push GRE header. */ | 313 | /* Push GRE header. */ |
242 | gre_build_header(skb, &tpi, tunnel->tun_hlen); | 314 | build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags, |
243 | 315 | proto, tunnel->parms.o_key, htonl(tunnel->o_seqno)); | |
244 | skb_set_inner_protocol(skb, tpi.proto); | ||
245 | 316 | ||
317 | skb_set_inner_protocol(skb, proto); | ||
246 | ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); | 318 | ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); |
247 | } | 319 | } |
248 | 320 | ||
321 | static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) | ||
322 | { | ||
323 | struct ip_tunnel_info *tun_info; | ||
324 | struct net *net = dev_net(dev); | ||
325 | const struct ip_tunnel_key *key; | ||
326 | struct flowi4 fl; | ||
327 | struct rtable *rt; | ||
328 | int min_headroom; | ||
329 | int tunnel_hlen; | ||
330 | __be16 df, flags; | ||
331 | int err; | ||
332 | |||
333 | tun_info = skb_tunnel_info(skb, AF_INET); | ||
334 | if (unlikely(!tun_info || tun_info->mode != IP_TUNNEL_INFO_TX)) | ||
335 | goto err_free_skb; | ||
336 | |||
337 | key = &tun_info->key; | ||
338 | memset(&fl, 0, sizeof(fl)); | ||
339 | fl.daddr = key->ipv4_dst; | ||
340 | fl.saddr = key->ipv4_src; | ||
341 | fl.flowi4_tos = RT_TOS(key->ipv4_tos); | ||
342 | fl.flowi4_mark = skb->mark; | ||
343 | fl.flowi4_proto = IPPROTO_GRE; | ||
344 | |||
345 | rt = ip_route_output_key(net, &fl); | ||
346 | if (IS_ERR(rt)) | ||
347 | goto err_free_skb; | ||
348 | |||
349 | tunnel_hlen = ip_gre_calc_hlen(key->tun_flags); | ||
350 | |||
351 | min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len | ||
352 | + tunnel_hlen + sizeof(struct iphdr); | ||
353 | if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { | ||
354 | int head_delta = SKB_DATA_ALIGN(min_headroom - | ||
355 | skb_headroom(skb) + | ||
356 | 16); | ||
357 | err = pskb_expand_head(skb, max_t(int, head_delta, 0), | ||
358 | 0, GFP_ATOMIC); | ||
359 | if (unlikely(err)) | ||
360 | goto err_free_rt; | ||
361 | } | ||
362 | |||
363 | /* Push Tunnel header. */ | ||
364 | skb = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)); | ||
365 | if (IS_ERR(skb)) { | ||
366 | skb = NULL; | ||
367 | goto err_free_rt; | ||
368 | } | ||
369 | |||
370 | flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY); | ||
371 | build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB), | ||
372 | tunnel_id_to_key(tun_info->key.tun_id), 0); | ||
373 | |||
374 | df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; | ||
375 | err = iptunnel_xmit(skb->sk, rt, skb, fl.saddr, | ||
376 | key->ipv4_dst, IPPROTO_GRE, | ||
377 | key->ipv4_tos, key->ipv4_ttl, df, false); | ||
378 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); | ||
379 | return; | ||
380 | |||
381 | err_free_rt: | ||
382 | ip_rt_put(rt); | ||
383 | err_free_skb: | ||
384 | kfree_skb(skb); | ||
385 | dev->stats.tx_dropped++; | ||
386 | } | ||
387 | |||
249 | static netdev_tx_t ipgre_xmit(struct sk_buff *skb, | 388 | static netdev_tx_t ipgre_xmit(struct sk_buff *skb, |
250 | struct net_device *dev) | 389 | struct net_device *dev) |
251 | { | 390 | { |
252 | struct ip_tunnel *tunnel = netdev_priv(dev); | 391 | struct ip_tunnel *tunnel = netdev_priv(dev); |
253 | const struct iphdr *tnl_params; | 392 | const struct iphdr *tnl_params; |
254 | 393 | ||
394 | if (tunnel->collect_md) { | ||
395 | gre_fb_xmit(skb, dev); | ||
396 | return NETDEV_TX_OK; | ||
397 | } | ||
398 | |||
255 | if (dev->header_ops) { | 399 | if (dev->header_ops) { |
256 | /* Need space for new headers */ | 400 | /* Need space for new headers */ |
257 | if (skb_cow_head(skb, dev->needed_headroom - | 401 | if (skb_cow_head(skb, dev->needed_headroom - |
@@ -277,7 +421,6 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb, | |||
277 | goto out; | 421 | goto out; |
278 | 422 | ||
279 | __gre_xmit(skb, dev, tnl_params, skb->protocol); | 423 | __gre_xmit(skb, dev, tnl_params, skb->protocol); |
280 | |||
281 | return NETDEV_TX_OK; | 424 | return NETDEV_TX_OK; |
282 | 425 | ||
283 | free_skb: | 426 | free_skb: |
@@ -292,6 +435,11 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, | |||
292 | { | 435 | { |
293 | struct ip_tunnel *tunnel = netdev_priv(dev); | 436 | struct ip_tunnel *tunnel = netdev_priv(dev); |
294 | 437 | ||
438 | if (tunnel->collect_md) { | ||
439 | gre_fb_xmit(skb, dev); | ||
440 | return NETDEV_TX_OK; | ||
441 | } | ||
442 | |||
295 | skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); | 443 | skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM)); |
296 | if (IS_ERR(skb)) | 444 | if (IS_ERR(skb)) |
297 | goto out; | 445 | goto out; |
@@ -300,7 +448,6 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb, | |||
300 | goto free_skb; | 448 | goto free_skb; |
301 | 449 | ||
302 | __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB)); | 450 | __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB)); |
303 | |||
304 | return NETDEV_TX_OK; | 451 | return NETDEV_TX_OK; |
305 | 452 | ||
306 | free_skb: | 453 | free_skb: |
@@ -596,8 +743,10 @@ out: | |||
596 | return ipgre_tunnel_validate(tb, data); | 743 | return ipgre_tunnel_validate(tb, data); |
597 | } | 744 | } |
598 | 745 | ||
599 | static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[], | 746 | static void ipgre_netlink_parms(struct net_device *dev, |
600 | struct ip_tunnel_parm *parms) | 747 | struct nlattr *data[], |
748 | struct nlattr *tb[], | ||
749 | struct ip_tunnel_parm *parms) | ||
601 | { | 750 | { |
602 | memset(parms, 0, sizeof(*parms)); | 751 | memset(parms, 0, sizeof(*parms)); |
603 | 752 | ||
@@ -635,6 +784,12 @@ static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[], | |||
635 | 784 | ||
636 | if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) | 785 | if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) |
637 | parms->iph.frag_off = htons(IP_DF); | 786 | parms->iph.frag_off = htons(IP_DF); |
787 | |||
788 | if (data[IFLA_GRE_COLLECT_METADATA]) { | ||
789 | struct ip_tunnel *t = netdev_priv(dev); | ||
790 | |||
791 | t->collect_md = true; | ||
792 | } | ||
638 | } | 793 | } |
639 | 794 | ||
640 | /* This function returns true when ENCAP attributes are present in the nl msg */ | 795 | /* This function returns true when ENCAP attributes are present in the nl msg */ |
@@ -712,7 +867,7 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, | |||
712 | return err; | 867 | return err; |
713 | } | 868 | } |
714 | 869 | ||
715 | ipgre_netlink_parms(data, tb, &p); | 870 | ipgre_netlink_parms(dev, data, tb, &p); |
716 | return ip_tunnel_newlink(dev, tb, &p); | 871 | return ip_tunnel_newlink(dev, tb, &p); |
717 | } | 872 | } |
718 | 873 | ||
@@ -730,7 +885,7 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], | |||
730 | return err; | 885 | return err; |
731 | } | 886 | } |
732 | 887 | ||
733 | ipgre_netlink_parms(data, tb, &p); | 888 | ipgre_netlink_parms(dev, data, tb, &p); |
734 | return ip_tunnel_changelink(dev, tb, &p); | 889 | return ip_tunnel_changelink(dev, tb, &p); |
735 | } | 890 | } |
736 | 891 | ||
@@ -765,6 +920,8 @@ static size_t ipgre_get_size(const struct net_device *dev) | |||
765 | nla_total_size(2) + | 920 | nla_total_size(2) + |
766 | /* IFLA_GRE_ENCAP_DPORT */ | 921 | /* IFLA_GRE_ENCAP_DPORT */ |
767 | nla_total_size(2) + | 922 | nla_total_size(2) + |
923 | /* IFLA_GRE_COLLECT_METADATA */ | ||
924 | nla_total_size(0) + | ||
768 | 0; | 925 | 0; |
769 | } | 926 | } |
770 | 927 | ||
@@ -796,6 +953,11 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
796 | t->encap.flags)) | 953 | t->encap.flags)) |
797 | goto nla_put_failure; | 954 | goto nla_put_failure; |
798 | 955 | ||
956 | if (t->collect_md) { | ||
957 | if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA)) | ||
958 | goto nla_put_failure; | ||
959 | } | ||
960 | |||
799 | return 0; | 961 | return 0; |
800 | 962 | ||
801 | nla_put_failure: | 963 | nla_put_failure: |
@@ -817,6 +979,7 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { | |||
817 | [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, | 979 | [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, |
818 | [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, | 980 | [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, |
819 | [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, | 981 | [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, |
982 | [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, | ||
820 | }; | 983 | }; |
821 | 984 | ||
822 | static struct rtnl_link_ops ipgre_link_ops __read_mostly = { | 985 | static struct rtnl_link_ops ipgre_link_ops __read_mostly = { |
@@ -851,7 +1014,7 @@ static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { | |||
851 | 1014 | ||
852 | static int __net_init ipgre_tap_init_net(struct net *net) | 1015 | static int __net_init ipgre_tap_init_net(struct net *net) |
853 | { | 1016 | { |
854 | return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL); | 1017 | return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); |
855 | } | 1018 | } |
856 | 1019 | ||
857 | static void __net_exit ipgre_tap_exit_net(struct net *net) | 1020 | static void __net_exit ipgre_tap_exit_net(struct net *net) |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 626d9e56a6bd..cbb51f3fac06 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -230,10 +230,13 @@ skip_key_lookup: | |||
230 | if (cand) | 230 | if (cand) |
231 | return cand; | 231 | return cand; |
232 | 232 | ||
233 | t = rcu_dereference(itn->collect_md_tun); | ||
234 | if (t) | ||
235 | return t; | ||
236 | |||
233 | if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) | 237 | if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) |
234 | return netdev_priv(itn->fb_tunnel_dev); | 238 | return netdev_priv(itn->fb_tunnel_dev); |
235 | 239 | ||
236 | |||
237 | return NULL; | 240 | return NULL; |
238 | } | 241 | } |
239 | EXPORT_SYMBOL_GPL(ip_tunnel_lookup); | 242 | EXPORT_SYMBOL_GPL(ip_tunnel_lookup); |
@@ -261,11 +264,15 @@ static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t) | |||
261 | { | 264 | { |
262 | struct hlist_head *head = ip_bucket(itn, &t->parms); | 265 | struct hlist_head *head = ip_bucket(itn, &t->parms); |
263 | 266 | ||
267 | if (t->collect_md) | ||
268 | rcu_assign_pointer(itn->collect_md_tun, t); | ||
264 | hlist_add_head_rcu(&t->hash_node, head); | 269 | hlist_add_head_rcu(&t->hash_node, head); |
265 | } | 270 | } |
266 | 271 | ||
267 | static void ip_tunnel_del(struct ip_tunnel *t) | 272 | static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t) |
268 | { | 273 | { |
274 | if (t->collect_md) | ||
275 | rcu_assign_pointer(itn->collect_md_tun, NULL); | ||
269 | hlist_del_init_rcu(&t->hash_node); | 276 | hlist_del_init_rcu(&t->hash_node); |
270 | } | 277 | } |
271 | 278 | ||
@@ -419,7 +426,8 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net, | |||
419 | } | 426 | } |
420 | 427 | ||
421 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, | 428 | int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, |
422 | const struct tnl_ptk_info *tpi, bool log_ecn_error) | 429 | const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, |
430 | bool log_ecn_error) | ||
423 | { | 431 | { |
424 | struct pcpu_sw_netstats *tstats; | 432 | struct pcpu_sw_netstats *tstats; |
425 | const struct iphdr *iph = ip_hdr(skb); | 433 | const struct iphdr *iph = ip_hdr(skb); |
@@ -478,6 +486,9 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, | |||
478 | skb->dev = tunnel->dev; | 486 | skb->dev = tunnel->dev; |
479 | } | 487 | } |
480 | 488 | ||
489 | if (tun_dst) | ||
490 | skb_dst_set(skb, (struct dst_entry *)tun_dst); | ||
491 | |||
481 | gro_cells_receive(&tunnel->gro_cells, skb); | 492 | gro_cells_receive(&tunnel->gro_cells, skb); |
482 | return 0; | 493 | return 0; |
483 | 494 | ||
@@ -806,7 +817,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn, | |||
806 | struct ip_tunnel_parm *p, | 817 | struct ip_tunnel_parm *p, |
807 | bool set_mtu) | 818 | bool set_mtu) |
808 | { | 819 | { |
809 | ip_tunnel_del(t); | 820 | ip_tunnel_del(itn, t); |
810 | t->parms.iph.saddr = p->iph.saddr; | 821 | t->parms.iph.saddr = p->iph.saddr; |
811 | t->parms.iph.daddr = p->iph.daddr; | 822 | t->parms.iph.daddr = p->iph.daddr; |
812 | t->parms.i_key = p->i_key; | 823 | t->parms.i_key = p->i_key; |
@@ -967,7 +978,7 @@ void ip_tunnel_dellink(struct net_device *dev, struct list_head *head) | |||
967 | itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id); | 978 | itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id); |
968 | 979 | ||
969 | if (itn->fb_tunnel_dev != dev) { | 980 | if (itn->fb_tunnel_dev != dev) { |
970 | ip_tunnel_del(netdev_priv(dev)); | 981 | ip_tunnel_del(itn, netdev_priv(dev)); |
971 | unregister_netdevice_queue(dev, head); | 982 | unregister_netdevice_queue(dev, head); |
972 | } | 983 | } |
973 | } | 984 | } |
@@ -1072,8 +1083,13 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], | |||
1072 | nt = netdev_priv(dev); | 1083 | nt = netdev_priv(dev); |
1073 | itn = net_generic(net, nt->ip_tnl_net_id); | 1084 | itn = net_generic(net, nt->ip_tnl_net_id); |
1074 | 1085 | ||
1075 | if (ip_tunnel_find(itn, p, dev->type)) | 1086 | if (nt->collect_md) { |
1076 | return -EEXIST; | 1087 | if (rtnl_dereference(itn->collect_md_tun)) |
1088 | return -EEXIST; | ||
1089 | } else { | ||
1090 | if (ip_tunnel_find(itn, p, dev->type)) | ||
1091 | return -EEXIST; | ||
1092 | } | ||
1077 | 1093 | ||
1078 | nt->net = net; | 1094 | nt->net = net; |
1079 | nt->parms = *p; | 1095 | nt->parms = *p; |
@@ -1089,7 +1105,6 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], | |||
1089 | dev->mtu = mtu; | 1105 | dev->mtu = mtu; |
1090 | 1106 | ||
1091 | ip_tunnel_add(itn, nt); | 1107 | ip_tunnel_add(itn, nt); |
1092 | |||
1093 | out: | 1108 | out: |
1094 | return err; | 1109 | return err; |
1095 | } | 1110 | } |
@@ -1163,6 +1178,10 @@ int ip_tunnel_init(struct net_device *dev) | |||
1163 | iph->version = 4; | 1178 | iph->version = 4; |
1164 | iph->ihl = 5; | 1179 | iph->ihl = 5; |
1165 | 1180 | ||
1181 | if (tunnel->collect_md) { | ||
1182 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
1183 | netif_keep_dst(dev); | ||
1184 | } | ||
1166 | return 0; | 1185 | return 0; |
1167 | } | 1186 | } |
1168 | EXPORT_SYMBOL_GPL(ip_tunnel_init); | 1187 | EXPORT_SYMBOL_GPL(ip_tunnel_init); |
@@ -1176,7 +1195,7 @@ void ip_tunnel_uninit(struct net_device *dev) | |||
1176 | itn = net_generic(net, tunnel->ip_tnl_net_id); | 1195 | itn = net_generic(net, tunnel->ip_tnl_net_id); |
1177 | /* fb_tunnel_dev will be unregisted in net-exit call. */ | 1196 | /* fb_tunnel_dev will be unregisted in net-exit call. */ |
1178 | if (itn->fb_tunnel_dev != dev) | 1197 | if (itn->fb_tunnel_dev != dev) |
1179 | ip_tunnel_del(netdev_priv(dev)); | 1198 | ip_tunnel_del(itn, netdev_priv(dev)); |
1180 | 1199 | ||
1181 | ip_tunnel_dst_reset_all(tunnel); | 1200 | ip_tunnel_dst_reset_all(tunnel); |
1182 | } | 1201 | } |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 254238daf58b..f34c31defafe 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -198,7 +198,7 @@ static int ipip_rcv(struct sk_buff *skb) | |||
198 | goto drop; | 198 | goto drop; |
199 | if (iptunnel_pull_header(skb, 0, tpi.proto)) | 199 | if (iptunnel_pull_header(skb, 0, tpi.proto)) |
200 | goto drop; | 200 | goto drop; |
201 | return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error); | 201 | return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); |
202 | } | 202 | } |
203 | 203 | ||
204 | return -1; | 204 | return -1; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ac35a28599be..94428fd85b2f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -742,7 +742,7 @@ static int ipip_rcv(struct sk_buff *skb) | |||
742 | goto drop; | 742 | goto drop; |
743 | if (iptunnel_pull_header(skb, 0, tpi.proto)) | 743 | if (iptunnel_pull_header(skb, 0, tpi.proto)) |
744 | goto drop; | 744 | goto drop; |
745 | return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error); | 745 | return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); |
746 | } | 746 | } |
747 | 747 | ||
748 | return 1; | 748 | return 1; |