diff options
author | Tom Herbert <therbert@google.com> | 2014-09-17 15:25:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-19 17:15:32 -0400 |
commit | 56328486539ddd07cbaafec7a542a2c8a3043623 (patch) | |
tree | fbfbf2ae1b1aa35fe2fc537d4f8f3fdcceb1f5c8 /net/ipv4/ip_tunnel.c | |
parent | afe93325bc02a5b2dea0cd7d78225de692265e6e (diff) |
net: Changes to ip_tunnel to support foo-over-udp encapsulation
This patch changes IP tunnel to support (secondary) encapsulation,
Foo-over-UDP. Changes include:
1) Adding tun_hlen as the tunnel header length, encap_hlen as the
encapsulation header length, and hlen becomes the grand total
of these.
2) Added common netlink define to support FOU encapsulation.
3) Routines to perform FOU encapsulation.
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_tunnel.c')
-rw-r--r-- | net/ipv4/ip_tunnel.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index afed1aac2638..e3a3dc91e49c 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <net/net_namespace.h> | 55 | #include <net/net_namespace.h> |
56 | #include <net/netns/generic.h> | 56 | #include <net/netns/generic.h> |
57 | #include <net/rtnetlink.h> | 57 | #include <net/rtnetlink.h> |
58 | #include <net/udp.h> | ||
58 | 59 | ||
59 | #if IS_ENABLED(CONFIG_IPV6) | 60 | #if IS_ENABLED(CONFIG_IPV6) |
60 | #include <net/ipv6.h> | 61 | #include <net/ipv6.h> |
@@ -487,6 +488,91 @@ drop: | |||
487 | } | 488 | } |
488 | EXPORT_SYMBOL_GPL(ip_tunnel_rcv); | 489 | EXPORT_SYMBOL_GPL(ip_tunnel_rcv); |
489 | 490 | ||
491 | static int ip_encap_hlen(struct ip_tunnel_encap *e) | ||
492 | { | ||
493 | switch (e->type) { | ||
494 | case TUNNEL_ENCAP_NONE: | ||
495 | return 0; | ||
496 | case TUNNEL_ENCAP_FOU: | ||
497 | return sizeof(struct udphdr); | ||
498 | default: | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | int ip_tunnel_encap_setup(struct ip_tunnel *t, | ||
504 | struct ip_tunnel_encap *ipencap) | ||
505 | { | ||
506 | int hlen; | ||
507 | |||
508 | memset(&t->encap, 0, sizeof(t->encap)); | ||
509 | |||
510 | hlen = ip_encap_hlen(ipencap); | ||
511 | if (hlen < 0) | ||
512 | return hlen; | ||
513 | |||
514 | t->encap.type = ipencap->type; | ||
515 | t->encap.sport = ipencap->sport; | ||
516 | t->encap.dport = ipencap->dport; | ||
517 | t->encap.flags = ipencap->flags; | ||
518 | |||
519 | t->encap_hlen = hlen; | ||
520 | t->hlen = t->encap_hlen + t->tun_hlen; | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup); | ||
525 | |||
526 | static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
527 | size_t hdr_len, u8 *protocol, struct flowi4 *fl4) | ||
528 | { | ||
529 | struct udphdr *uh; | ||
530 | __be16 sport; | ||
531 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); | ||
532 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
533 | |||
534 | skb = iptunnel_handle_offloads(skb, csum, type); | ||
535 | |||
536 | if (IS_ERR(skb)) | ||
537 | return PTR_ERR(skb); | ||
538 | |||
539 | /* Get length and hash before making space in skb */ | ||
540 | |||
541 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), | ||
542 | skb, 0, 0, false); | ||
543 | |||
544 | skb_push(skb, hdr_len); | ||
545 | |||
546 | skb_reset_transport_header(skb); | ||
547 | uh = udp_hdr(skb); | ||
548 | |||
549 | uh->dest = e->dport; | ||
550 | uh->source = sport; | ||
551 | uh->len = htons(skb->len); | ||
552 | uh->check = 0; | ||
553 | udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb, | ||
554 | fl4->saddr, fl4->daddr, skb->len); | ||
555 | |||
556 | *protocol = IPPROTO_UDP; | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, | ||
562 | u8 *protocol, struct flowi4 *fl4) | ||
563 | { | ||
564 | switch (t->encap.type) { | ||
565 | case TUNNEL_ENCAP_NONE: | ||
566 | return 0; | ||
567 | case TUNNEL_ENCAP_FOU: | ||
568 | return fou_build_header(skb, &t->encap, t->encap_hlen, | ||
569 | protocol, fl4); | ||
570 | default: | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | } | ||
574 | EXPORT_SYMBOL(ip_tunnel_encap); | ||
575 | |||
490 | static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, | 576 | static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, |
491 | struct rtable *rt, __be16 df) | 577 | struct rtable *rt, __be16 df) |
492 | { | 578 | { |
@@ -536,7 +622,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, | |||
536 | } | 622 | } |
537 | 623 | ||
538 | void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | 624 | void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, |
539 | const struct iphdr *tnl_params, const u8 protocol) | 625 | const struct iphdr *tnl_params, u8 protocol) |
540 | { | 626 | { |
541 | struct ip_tunnel *tunnel = netdev_priv(dev); | 627 | struct ip_tunnel *tunnel = netdev_priv(dev); |
542 | const struct iphdr *inner_iph; | 628 | const struct iphdr *inner_iph; |
@@ -617,6 +703,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
617 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, | 703 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, |
618 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); | 704 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); |
619 | 705 | ||
706 | if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) | ||
707 | goto tx_error; | ||
708 | |||
620 | rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL; | 709 | rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL; |
621 | 710 | ||
622 | if (!rt) { | 711 | if (!rt) { |