Skip to content

Commit

Permalink
gre: Setup and TX path for gre/UDP foo-over-udp encapsulation
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Tom Herbert authored and davem330 committed Sep 19, 2014
1 parent 473ab82 commit 4565e99
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 5 deletions.
4 changes: 4 additions & 0 deletions include/uapi/linux/if_tunnel.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ enum {
IFLA_GRE_ENCAP_LIMIT,
IFLA_GRE_FLOWINFO,
IFLA_GRE_FLAGS,
IFLA_GRE_ENCAP_TYPE,
IFLA_GRE_ENCAP_FLAGS,
IFLA_GRE_ENCAP_SPORT,
IFLA_GRE_ENCAP_DPORT,
__IFLA_GRE_MAX,
};

Expand Down
90 changes: 85 additions & 5 deletions net/ipv4/ip_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
tpi.seq = htonl(tunnel->o_seqno);

/* 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);
}
Expand Down Expand Up @@ -310,7 +310,7 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
static int ipgre_tunnel_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
{
int err = 0;
int err;
struct ip_tunnel_parm p;

if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
Expand Down Expand Up @@ -470,13 +470,18 @@ static void ipgre_tunnel_setup(struct net_device *dev)
static void __gre_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel;
int t_hlen;

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;

dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;

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->hw_features |= GRE_FEATURES;
Expand Down Expand Up @@ -628,6 +633,40 @@ static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
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)
{
__gre_tunnel_init(dev);
Expand Down Expand Up @@ -657,6 +696,15 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
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);
return ip_tunnel_newlink(dev, tb, &p);
Expand All @@ -666,6 +714,15 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
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);
return ip_tunnel_changelink(dev, tb, &p);
Expand Down Expand Up @@ -694,6 +751,14 @@ static size_t ipgre_get_size(const struct net_device *dev)
nla_total_size(1) +
/* IFLA_GRE_PMTUDISC */
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;
}

Expand All @@ -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,
!!(p->iph.frag_off & htons(IP_DF))))
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;

nla_put_failure:
Expand All @@ -731,6 +807,10 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
[IFLA_GRE_TTL] = { .type = NLA_U8 },
[IFLA_GRE_TOS] = { .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 = {
Expand Down

0 comments on commit 4565e99

Please sign in to comment.