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>
This commit is contained in:
committed by
David S. Miller
parent
afe93325bc
commit
5632848653
+90
-1
@@ -55,6 +55,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/udp.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
#include <net/ipv6.h>
|
||||
@@ -487,6 +488,91 @@ drop:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
|
||||
|
||||
static int ip_encap_hlen(struct ip_tunnel_encap *e)
|
||||
{
|
||||
switch (e->type) {
|
||||
case TUNNEL_ENCAP_NONE:
|
||||
return 0;
|
||||
case TUNNEL_ENCAP_FOU:
|
||||
return sizeof(struct udphdr);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int ip_tunnel_encap_setup(struct ip_tunnel *t,
|
||||
struct ip_tunnel_encap *ipencap)
|
||||
{
|
||||
int hlen;
|
||||
|
||||
memset(&t->encap, 0, sizeof(t->encap));
|
||||
|
||||
hlen = ip_encap_hlen(ipencap);
|
||||
if (hlen < 0)
|
||||
return hlen;
|
||||
|
||||
t->encap.type = ipencap->type;
|
||||
t->encap.sport = ipencap->sport;
|
||||
t->encap.dport = ipencap->dport;
|
||||
t->encap.flags = ipencap->flags;
|
||||
|
||||
t->encap_hlen = hlen;
|
||||
t->hlen = t->encap_hlen + t->tun_hlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup);
|
||||
|
||||
static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
|
||||
size_t hdr_len, u8 *protocol, struct flowi4 *fl4)
|
||||
{
|
||||
struct udphdr *uh;
|
||||
__be16 sport;
|
||||
bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM);
|
||||
int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
|
||||
|
||||
skb = iptunnel_handle_offloads(skb, csum, type);
|
||||
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
/* Get length and hash before making space in skb */
|
||||
|
||||
sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev),
|
||||
skb, 0, 0, false);
|
||||
|
||||
skb_push(skb, hdr_len);
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
uh = udp_hdr(skb);
|
||||
|
||||
uh->dest = e->dport;
|
||||
uh->source = sport;
|
||||
uh->len = htons(skb->len);
|
||||
uh->check = 0;
|
||||
udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb,
|
||||
fl4->saddr, fl4->daddr, skb->len);
|
||||
|
||||
*protocol = IPPROTO_UDP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
|
||||
u8 *protocol, struct flowi4 *fl4)
|
||||
{
|
||||
switch (t->encap.type) {
|
||||
case TUNNEL_ENCAP_NONE:
|
||||
return 0;
|
||||
case TUNNEL_ENCAP_FOU:
|
||||
return fou_build_header(skb, &t->encap, t->encap_hlen,
|
||||
protocol, fl4);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ip_tunnel_encap);
|
||||
|
||||
static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
|
||||
struct rtable *rt, __be16 df)
|
||||
{
|
||||
@@ -536,7 +622,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
|
||||
}
|
||||
|
||||
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
const struct iphdr *tnl_params, const u8 protocol)
|
||||
const struct iphdr *tnl_params, u8 protocol)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
const struct iphdr *inner_iph;
|
||||
@@ -617,6 +703,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
|
||||
tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
|
||||
|
||||
if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
|
||||
goto tx_error;
|
||||
|
||||
rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL;
|
||||
|
||||
if (!rt) {
|
||||
|
||||
Reference in New Issue
Block a user