Commit 8eb3b995 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller

geneve: support setting IPv6 flow label

This work adds support for setting the IPv6 flow label for geneve per
device and through collect metadata (ip_tunnel_key) frontends. Also here,
the geneve dst cache does not need any special considerations, for the
cases where caches can be used, the label is static per cache.
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e7f70af1
...@@ -68,6 +68,7 @@ struct geneve_dev { ...@@ -68,6 +68,7 @@ struct geneve_dev {
u8 tos; /* TOS override */ u8 tos; /* TOS override */
union geneve_addr remote; /* IP address for link partner */ union geneve_addr remote; /* IP address for link partner */
struct list_head next; /* geneve's per namespace list */ struct list_head next; /* geneve's per namespace list */
__be32 label; /* IPv6 flowlabel override */
__be16 dst_port; __be16 dst_port;
bool collect_md; bool collect_md;
struct gro_cells gro_cells; struct gro_cells gro_cells;
...@@ -846,6 +847,7 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, ...@@ -846,6 +847,7 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
fl6->daddr = info->key.u.ipv6.dst; fl6->daddr = info->key.u.ipv6.dst;
fl6->saddr = info->key.u.ipv6.src; fl6->saddr = info->key.u.ipv6.src;
fl6->flowi6_tos = RT_TOS(info->key.tos); fl6->flowi6_tos = RT_TOS(info->key.tos);
fl6->flowlabel = info->key.label;
dst_cache = &info->dst_cache; dst_cache = &info->dst_cache;
} else { } else {
prio = geneve->tos; prio = geneve->tos;
...@@ -857,6 +859,7 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, ...@@ -857,6 +859,7 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
} }
fl6->flowi6_tos = RT_TOS(prio); fl6->flowi6_tos = RT_TOS(prio);
fl6->flowlabel = geneve->label;
fl6->daddr = geneve->remote.sin6.sin6_addr; fl6->daddr = geneve->remote.sin6.sin6_addr;
dst_cache = &geneve->dst_cache; dst_cache = &geneve->dst_cache;
} }
...@@ -998,6 +1001,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -998,6 +1001,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
struct flowi6 fl6; struct flowi6 fl6;
__u8 prio, ttl; __u8 prio, ttl;
__be16 sport; __be16 sport;
__be32 label;
bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
u32 flags = geneve->flags; u32 flags = geneve->flags;
...@@ -1041,6 +1045,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -1041,6 +1045,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
prio = ip_tunnel_ecn_encap(key->tos, iip, skb); prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
ttl = key->ttl; ttl = key->ttl;
label = info->key.label;
} else { } else {
err = geneve6_build_skb(dst, skb, 0, geneve->vni, err = geneve6_build_skb(dst, skb, 0, geneve->vni,
0, NULL, flags, xnet); 0, NULL, flags, xnet);
...@@ -1052,9 +1057,11 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -1052,9 +1057,11 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (!ttl && ipv6_addr_is_multicast(&fl6.daddr)) if (!ttl && ipv6_addr_is_multicast(&fl6.daddr))
ttl = 1; ttl = 1;
ttl = ttl ? : ip6_dst_hoplimit(dst); ttl = ttl ? : ip6_dst_hoplimit(dst);
label = geneve->label;
} }
udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev, udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
&fl6.saddr, &fl6.daddr, prio, ttl, 0, &fl6.saddr, &fl6.daddr, prio, ttl, label,
sport, geneve->dst_port, sport, geneve->dst_port,
!!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX)); !!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX));
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -1238,6 +1245,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { ...@@ -1238,6 +1245,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
[IFLA_GENEVE_REMOTE6] = { .len = sizeof(struct in6_addr) }, [IFLA_GENEVE_REMOTE6] = { .len = sizeof(struct in6_addr) },
[IFLA_GENEVE_TTL] = { .type = NLA_U8 }, [IFLA_GENEVE_TTL] = { .type = NLA_U8 },
[IFLA_GENEVE_TOS] = { .type = NLA_U8 }, [IFLA_GENEVE_TOS] = { .type = NLA_U8 },
[IFLA_GENEVE_LABEL] = { .type = NLA_U32 },
[IFLA_GENEVE_PORT] = { .type = NLA_U16 }, [IFLA_GENEVE_PORT] = { .type = NLA_U16 },
[IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG },
[IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 },
...@@ -1295,8 +1303,8 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn, ...@@ -1295,8 +1303,8 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
static int geneve_configure(struct net *net, struct net_device *dev, static int geneve_configure(struct net *net, struct net_device *dev,
union geneve_addr *remote, union geneve_addr *remote,
__u32 vni, __u8 ttl, __u8 tos, __be16 dst_port, __u32 vni, __u8 ttl, __u8 tos, __be32 label,
bool metadata, u32 flags) __be16 dst_port, bool metadata, u32 flags)
{ {
struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_net *gn = net_generic(net, geneve_net_id);
struct geneve_dev *t, *geneve = netdev_priv(dev); struct geneve_dev *t, *geneve = netdev_priv(dev);
...@@ -1306,7 +1314,7 @@ static int geneve_configure(struct net *net, struct net_device *dev, ...@@ -1306,7 +1314,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
if (!remote) if (!remote)
return -EINVAL; return -EINVAL;
if (metadata && if (metadata &&
(remote->sa.sa_family != AF_UNSPEC || vni || tos || ttl)) (remote->sa.sa_family != AF_UNSPEC || vni || tos || ttl || label))
return -EINVAL; return -EINVAL;
geneve->net = net; geneve->net = net;
...@@ -1321,10 +1329,14 @@ static int geneve_configure(struct net *net, struct net_device *dev, ...@@ -1321,10 +1329,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
(remote->sa.sa_family == AF_INET6 && (remote->sa.sa_family == AF_INET6 &&
ipv6_addr_is_multicast(&remote->sin6.sin6_addr))) ipv6_addr_is_multicast(&remote->sin6.sin6_addr)))
return -EINVAL; return -EINVAL;
if (label && remote->sa.sa_family != AF_INET6)
return -EINVAL;
geneve->remote = *remote; geneve->remote = *remote;
geneve->ttl = ttl; geneve->ttl = ttl;
geneve->tos = tos; geneve->tos = tos;
geneve->label = label;
geneve->dst_port = dst_port; geneve->dst_port = dst_port;
geneve->collect_md = metadata; geneve->collect_md = metadata;
geneve->flags = flags; geneve->flags = flags;
...@@ -1367,6 +1379,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev, ...@@ -1367,6 +1379,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
__u8 ttl = 0, tos = 0; __u8 ttl = 0, tos = 0;
bool metadata = false; bool metadata = false;
union geneve_addr remote = geneve_remote_unspec; union geneve_addr remote = geneve_remote_unspec;
__be32 label = 0;
__u32 vni = 0; __u32 vni = 0;
u32 flags = 0; u32 flags = 0;
...@@ -1403,6 +1416,10 @@ static int geneve_newlink(struct net *net, struct net_device *dev, ...@@ -1403,6 +1416,10 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
if (data[IFLA_GENEVE_TOS]) if (data[IFLA_GENEVE_TOS])
tos = nla_get_u8(data[IFLA_GENEVE_TOS]); tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
if (data[IFLA_GENEVE_LABEL])
label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
IPV6_FLOWLABEL_MASK;
if (data[IFLA_GENEVE_PORT]) if (data[IFLA_GENEVE_PORT])
dst_port = nla_get_be16(data[IFLA_GENEVE_PORT]); dst_port = nla_get_be16(data[IFLA_GENEVE_PORT]);
...@@ -1421,8 +1438,8 @@ static int geneve_newlink(struct net *net, struct net_device *dev, ...@@ -1421,8 +1438,8 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])) nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
flags |= GENEVE_F_UDP_ZERO_CSUM6_RX; flags |= GENEVE_F_UDP_ZERO_CSUM6_RX;
return geneve_configure(net, dev, &remote, vni, ttl, tos, dst_port, return geneve_configure(net, dev, &remote, vni, ttl, tos, label,
metadata, flags); dst_port, metadata, flags);
} }
static void geneve_dellink(struct net_device *dev, struct list_head *head) static void geneve_dellink(struct net_device *dev, struct list_head *head)
...@@ -1439,6 +1456,7 @@ static size_t geneve_get_size(const struct net_device *dev) ...@@ -1439,6 +1456,7 @@ static size_t geneve_get_size(const struct net_device *dev)
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */ nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
nla_total_size(sizeof(__be32)) + /* IFLA_GENEVE_LABEL */
nla_total_size(sizeof(__be16)) + /* IFLA_GENEVE_PORT */ nla_total_size(sizeof(__be16)) + /* IFLA_GENEVE_PORT */
nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */ nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
...@@ -1469,7 +1487,8 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -1469,7 +1487,8 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
} }
if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) || if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) ||
nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos)) nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos) ||
nla_put_be32(skb, IFLA_GENEVE_LABEL, geneve->label))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be16(skb, IFLA_GENEVE_PORT, geneve->dst_port)) if (nla_put_be16(skb, IFLA_GENEVE_PORT, geneve->dst_port))
...@@ -1521,7 +1540,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name, ...@@ -1521,7 +1540,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
return dev; return dev;
err = geneve_configure(net, dev, &geneve_remote_unspec, err = geneve_configure(net, dev, &geneve_remote_unspec,
0, 0, 0, htons(dst_port), true, 0, 0, 0, 0, htons(dst_port), true,
GENEVE_F_UDP_ZERO_CSUM6_RX); GENEVE_F_UDP_ZERO_CSUM6_RX);
if (err) if (err)
goto err; goto err;
......
...@@ -479,6 +479,7 @@ enum { ...@@ -479,6 +479,7 @@ enum {
IFLA_GENEVE_UDP_CSUM, IFLA_GENEVE_UDP_CSUM,
IFLA_GENEVE_UDP_ZERO_CSUM6_TX, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
IFLA_GENEVE_UDP_ZERO_CSUM6_RX, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
IFLA_GENEVE_LABEL,
__IFLA_GENEVE_MAX __IFLA_GENEVE_MAX
}; };
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment