gre: Setup and TX path for gre/UDP foo-over-udp encapsulation
Added netlink attrs to configure FOU encapsulation for GRE, netlink handling of these flags, and properly adjust MTU for encapsulation. ip_tunnel_encap is called from ip_tunnel_xmit to actually 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
473ab820dd
commit
4565e9919c
@@ -106,6 +106,10 @@ enum {
|
|||||||
IFLA_GRE_ENCAP_LIMIT,
|
IFLA_GRE_ENCAP_LIMIT,
|
||||||
IFLA_GRE_FLOWINFO,
|
IFLA_GRE_FLOWINFO,
|
||||||
IFLA_GRE_FLAGS,
|
IFLA_GRE_FLAGS,
|
||||||
|
IFLA_GRE_ENCAP_TYPE,
|
||||||
|
IFLA_GRE_ENCAP_FLAGS,
|
||||||
|
IFLA_GRE_ENCAP_SPORT,
|
||||||
|
IFLA_GRE_ENCAP_DPORT,
|
||||||
__IFLA_GRE_MAX,
|
__IFLA_GRE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -239,7 +239,7 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
|
|||||||
tpi.seq = htonl(tunnel->o_seqno);
|
tpi.seq = htonl(tunnel->o_seqno);
|
||||||
|
|
||||||
/* Push GRE header. */
|
/* Push GRE header. */
|
||||||
gre_build_header(skb, &tpi, tunnel->hlen);
|
gre_build_header(skb, &tpi, tunnel->tun_hlen);
|
||||||
|
|
||||||
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
|
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
|
||||||
}
|
}
|
||||||
@@ -310,7 +310,7 @@ out:
|
|||||||
static int ipgre_tunnel_ioctl(struct net_device *dev,
|
static int ipgre_tunnel_ioctl(struct net_device *dev,
|
||||||
struct ifreq *ifr, int cmd)
|
struct ifreq *ifr, int cmd)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err;
|
||||||
struct ip_tunnel_parm p;
|
struct ip_tunnel_parm p;
|
||||||
|
|
||||||
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
|
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
|
||||||
@@ -470,13 +470,18 @@ static void ipgre_tunnel_setup(struct net_device *dev)
|
|||||||
static void __gre_tunnel_init(struct net_device *dev)
|
static void __gre_tunnel_init(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct ip_tunnel *tunnel;
|
struct ip_tunnel *tunnel;
|
||||||
|
int t_hlen;
|
||||||
|
|
||||||
tunnel = netdev_priv(dev);
|
tunnel = netdev_priv(dev);
|
||||||
tunnel->hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
|
tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
|
||||||
tunnel->parms.iph.protocol = IPPROTO_GRE;
|
tunnel->parms.iph.protocol = IPPROTO_GRE;
|
||||||
|
|
||||||
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
|
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
|
||||||
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
|
|
||||||
|
t_hlen = tunnel->hlen + sizeof(struct iphdr);
|
||||||
|
|
||||||
|
dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
|
||||||
|
dev->mtu = ETH_DATA_LEN - t_hlen - 4;
|
||||||
|
|
||||||
dev->features |= GRE_FEATURES;
|
dev->features |= GRE_FEATURES;
|
||||||
dev->hw_features |= GRE_FEATURES;
|
dev->hw_features |= GRE_FEATURES;
|
||||||
@@ -628,6 +633,40 @@ static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
|
|||||||
parms->iph.frag_off = htons(IP_DF);
|
parms->iph.frag_off = htons(IP_DF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function returns true when ENCAP attributes are present in the nl msg */
|
||||||
|
static bool ipgre_netlink_encap_parms(struct nlattr *data[],
|
||||||
|
struct ip_tunnel_encap *ipencap)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
memset(ipencap, 0, sizeof(*ipencap));
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ENCAP_TYPE]) {
|
||||||
|
ret = true;
|
||||||
|
ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ENCAP_FLAGS]) {
|
||||||
|
ret = true;
|
||||||
|
ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ENCAP_SPORT]) {
|
||||||
|
ret = true;
|
||||||
|
ipencap->sport = nla_get_u16(data[IFLA_GRE_ENCAP_SPORT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ENCAP_DPORT]) {
|
||||||
|
ret = true;
|
||||||
|
ipencap->dport = nla_get_u16(data[IFLA_GRE_ENCAP_DPORT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int gre_tap_init(struct net_device *dev)
|
static int gre_tap_init(struct net_device *dev)
|
||||||
{
|
{
|
||||||
__gre_tunnel_init(dev);
|
__gre_tunnel_init(dev);
|
||||||
@@ -657,6 +696,15 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
|
|||||||
struct nlattr *tb[], struct nlattr *data[])
|
struct nlattr *tb[], struct nlattr *data[])
|
||||||
{
|
{
|
||||||
struct ip_tunnel_parm p;
|
struct ip_tunnel_parm p;
|
||||||
|
struct ip_tunnel_encap ipencap;
|
||||||
|
|
||||||
|
if (ipgre_netlink_encap_parms(data, &ipencap)) {
|
||||||
|
struct ip_tunnel *t = netdev_priv(dev);
|
||||||
|
int err = ip_tunnel_encap_setup(t, &ipencap);
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
ipgre_netlink_parms(data, tb, &p);
|
ipgre_netlink_parms(data, tb, &p);
|
||||||
return ip_tunnel_newlink(dev, tb, &p);
|
return ip_tunnel_newlink(dev, tb, &p);
|
||||||
@@ -666,6 +714,15 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||||||
struct nlattr *data[])
|
struct nlattr *data[])
|
||||||
{
|
{
|
||||||
struct ip_tunnel_parm p;
|
struct ip_tunnel_parm p;
|
||||||
|
struct ip_tunnel_encap ipencap;
|
||||||
|
|
||||||
|
if (ipgre_netlink_encap_parms(data, &ipencap)) {
|
||||||
|
struct ip_tunnel *t = netdev_priv(dev);
|
||||||
|
int err = ip_tunnel_encap_setup(t, &ipencap);
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
ipgre_netlink_parms(data, tb, &p);
|
ipgre_netlink_parms(data, tb, &p);
|
||||||
return ip_tunnel_changelink(dev, tb, &p);
|
return ip_tunnel_changelink(dev, tb, &p);
|
||||||
@@ -694,6 +751,14 @@ static size_t ipgre_get_size(const struct net_device *dev)
|
|||||||
nla_total_size(1) +
|
nla_total_size(1) +
|
||||||
/* IFLA_GRE_PMTUDISC */
|
/* IFLA_GRE_PMTUDISC */
|
||||||
nla_total_size(1) +
|
nla_total_size(1) +
|
||||||
|
/* IFLA_GRE_ENCAP_TYPE */
|
||||||
|
nla_total_size(2) +
|
||||||
|
/* IFLA_GRE_ENCAP_FLAGS */
|
||||||
|
nla_total_size(2) +
|
||||||
|
/* IFLA_GRE_ENCAP_SPORT */
|
||||||
|
nla_total_size(2) +
|
||||||
|
/* IFLA_GRE_ENCAP_DPORT */
|
||||||
|
nla_total_size(2) +
|
||||||
0;
|
0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,6 +779,17 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||||||
nla_put_u8(skb, IFLA_GRE_PMTUDISC,
|
nla_put_u8(skb, IFLA_GRE_PMTUDISC,
|
||||||
!!(p->iph.frag_off & htons(IP_DF))))
|
!!(p->iph.frag_off & htons(IP_DF))))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE,
|
||||||
|
t->encap.type) ||
|
||||||
|
nla_put_u16(skb, IFLA_GRE_ENCAP_SPORT,
|
||||||
|
t->encap.sport) ||
|
||||||
|
nla_put_u16(skb, IFLA_GRE_ENCAP_DPORT,
|
||||||
|
t->encap.dport) ||
|
||||||
|
nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS,
|
||||||
|
t->encap.dport))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
@@ -731,6 +807,10 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
|
|||||||
[IFLA_GRE_TTL] = { .type = NLA_U8 },
|
[IFLA_GRE_TTL] = { .type = NLA_U8 },
|
||||||
[IFLA_GRE_TOS] = { .type = NLA_U8 },
|
[IFLA_GRE_TOS] = { .type = NLA_U8 },
|
||||||
[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
|
[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
|
||||||
|
[IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 },
|
||||||
|
[IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
|
||||||
|
[IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
|
||||||
|
[IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
|
static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
|
||||||
|
Reference in New Issue
Block a user