Commit 42240901 authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller

ipv6: Implement different admin modes for automatic flow labels

Change the meaning of net.ipv6.auto_flowlabels to provide a mode for
automatic flow labels generation. There are four modes:

0: flow labels are disabled
1: flow labels are enabled, sockets can opt-out
2: flow labels are allowed, sockets can opt-in
3: flow labels are enabled and enforced, no opt-out for sockets

np->autoflowlabel is initialized according to the sysctl value.
Signed-off-by: default avatarTom Herbert <tom@herbertland.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 67800f9b
...@@ -1215,14 +1215,20 @@ flowlabel_consistency - BOOLEAN ...@@ -1215,14 +1215,20 @@ flowlabel_consistency - BOOLEAN
FALSE: disabled FALSE: disabled
Default: TRUE Default: TRUE
auto_flowlabels - BOOLEAN auto_flowlabels - INTEGER
Automatically generate flow labels based based on a flow hash Automatically generate flow labels based on a flow hash of the
of the packet. This allows intermediate devices, such as routers, packet. This allows intermediate devices, such as routers, to
to idenfify packet flows for mechanisms like Equal Cost Multipath identify packet flows for mechanisms like Equal Cost Multipath
Routing (see RFC 6438). Routing (see RFC 6438).
TRUE: enabled 0: automatic flow labels are completely disabled
FALSE: disabled 1: automatic flow labels are enabled by default, they can be
Default: false disabled on a per socket basis using the IPV6_AUTOFLOWLABEL
socket option
2: automatic flow labels are allowed, they may be enabled on a
per socket basis using the IPV6_AUTOFLOWLABEL socket option
3: automatic flow labels are enabled and enforced, they cannot
be disabled by the socket option
Default: 0
flowlabel_state_ranges - BOOLEAN flowlabel_state_ranges - BOOLEAN
Split the flow label number space into two ranges. 0-0x7FFFF is Split the flow label number space into two ranges. 0-0x7FFFF is
......
...@@ -707,36 +707,69 @@ static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow, ...@@ -707,36 +707,69 @@ static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
/* Sysctl settings for net ipv6.auto_flowlabels */
#define IP6_AUTO_FLOW_LABEL_OFF 0
#define IP6_AUTO_FLOW_LABEL_OPTOUT 1
#define IP6_AUTO_FLOW_LABEL_OPTIN 2
#define IP6_AUTO_FLOW_LABEL_FORCED 3
#define IP6_AUTO_FLOW_LABEL_MAX IP6_AUTO_FLOW_LABEL_FORCED
#define IP6_DEFAULT_AUTO_FLOW_LABELS IP6_AUTO_FLOW_LABEL_OFF
static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
__be32 flowlabel, bool autolabel, __be32 flowlabel, bool autolabel,
struct flowi6 *fl6) struct flowi6 *fl6)
{ {
if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) { u32 hash;
u32 hash;
hash = skb_get_hash_flowi6(skb, fl6); if (flowlabel ||
net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
(!autolabel &&
net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED))
return flowlabel;
/* Since this is being sent on the wire obfuscate hash a bit hash = skb_get_hash_flowi6(skb, fl6);
* to minimize possbility that any useful information to an
* attacker is leaked. Only lower 20 bits are relevant.
*/
hash ^= hash >> 12;
flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; /* Since this is being sent on the wire obfuscate hash a bit
* to minimize possbility that any useful information to an
* attacker is leaked. Only lower 20 bits are relevant.
*/
rol32(hash, 16);
if (net->ipv6.sysctl.flowlabel_state_ranges) flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
} if (net->ipv6.sysctl.flowlabel_state_ranges)
flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
return flowlabel; return flowlabel;
} }
static inline int ip6_default_np_autolabel(struct net *net)
{
switch (net->ipv6.sysctl.auto_flowlabels) {
case IP6_AUTO_FLOW_LABEL_OFF:
case IP6_AUTO_FLOW_LABEL_OPTIN:
default:
return 0;
case IP6_AUTO_FLOW_LABEL_OPTOUT:
case IP6_AUTO_FLOW_LABEL_FORCED:
return 1;
}
}
#else #else
static inline void ip6_set_txhash(struct sock *sk) { } static inline void ip6_set_txhash(struct sock *sk) { }
static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
__be32 flowlabel, bool autolabel) __be32 flowlabel, bool autolabel,
struct flowi6 *fl6)
{ {
return flowlabel; return flowlabel;
} }
static inline int ip6_default_np_autolabel(struct net *net)
{
return 0;
}
#endif #endif
......
...@@ -197,6 +197,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, ...@@ -197,6 +197,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
np->mc_loop = 1; np->mc_loop = 1;
np->pmtudisc = IPV6_PMTUDISC_WANT; np->pmtudisc = IPV6_PMTUDISC_WANT;
np->autoflowlabel = ip6_default_np_autolabel(sock_net(sk));
sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
/* Init the ipv4 part of the socket since we can have sockets /* Init the ipv4 part of the socket since we can have sockets
...@@ -767,7 +768,7 @@ static int __net_init inet6_net_init(struct net *net) ...@@ -767,7 +768,7 @@ static int __net_init inet6_net_init(struct net *net)
net->ipv6.sysctl.bindv6only = 0; net->ipv6.sysctl.bindv6only = 0;
net->ipv6.sysctl.icmpv6_time = 1*HZ; net->ipv6.sysctl.icmpv6_time = 1*HZ;
net->ipv6.sysctl.flowlabel_consistency = 1; net->ipv6.sysctl.flowlabel_consistency = 1;
net->ipv6.sysctl.auto_flowlabels = 0; net->ipv6.sysctl.auto_flowlabels = IP6_DEFAULT_AUTO_FLOW_LABELS;
net->ipv6.sysctl.idgen_retries = 3; net->ipv6.sysctl.idgen_retries = 3;
net->ipv6.sysctl.idgen_delay = 1 * HZ; net->ipv6.sysctl.idgen_delay = 1 * HZ;
net->ipv6.sysctl.flowlabel_state_ranges = 1; net->ipv6.sysctl.flowlabel_state_ranges = 1;
......
...@@ -728,7 +728,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, ...@@ -728,7 +728,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
*/ */
ipv6h = ipv6_hdr(skb); ipv6h = ipv6_hdr(skb);
ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
ip6_make_flowlabel(net, skb, fl6->flowlabel, false, fl6)); ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
ipv6h->hop_limit = tunnel->parms.hop_limit; ipv6h->hop_limit = tunnel->parms.hop_limit;
ipv6h->nexthdr = proto; ipv6h->nexthdr = proto;
ipv6h->saddr = fl6->saddr; ipv6h->saddr = fl6->saddr;
...@@ -1182,7 +1182,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, ...@@ -1182,7 +1182,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
ip6_flow_hdr(ipv6h, 0, ip6_flow_hdr(ipv6h, 0,
ip6_make_flowlabel(dev_net(dev), skb, ip6_make_flowlabel(dev_net(dev), skb,
t->fl.u.ip6.flowlabel, false, t->fl.u.ip6.flowlabel, true,
&t->fl.u.ip6)); &t->fl.u.ip6));
ipv6h->hop_limit = t->parms.hop_limit; ipv6h->hop_limit = t->parms.hop_limit;
ipv6h->nexthdr = NEXTHDR_GRE; ipv6h->nexthdr = NEXTHDR_GRE;
......
...@@ -1095,7 +1095,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ...@@ -1095,7 +1095,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
skb_reset_network_header(skb); skb_reset_network_header(skb);
ipv6h = ipv6_hdr(skb); ipv6h = ipv6_hdr(skb);
ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
ip6_make_flowlabel(net, skb, fl6->flowlabel, false, fl6)); ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
ipv6h->hop_limit = t->parms.hop_limit; ipv6h->hop_limit = t->parms.hop_limit;
ipv6h->nexthdr = proto; ipv6h->nexthdr = proto;
ipv6h->saddr = fl6->saddr; ipv6h->saddr = fl6->saddr;
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
#include <net/inet_frag.h> #include <net/inet_frag.h>
static int one = 1; static int one = 1;
static int auto_flowlabels_min;
static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
static struct ctl_table ipv6_table_template[] = { static struct ctl_table ipv6_table_template[] = {
{ {
...@@ -45,7 +48,9 @@ static struct ctl_table ipv6_table_template[] = { ...@@ -45,7 +48,9 @@ static struct ctl_table ipv6_table_template[] = {
.data = &init_net.ipv6.sysctl.auto_flowlabels, .data = &init_net.ipv6.sysctl.auto_flowlabels,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec .proc_handler = proc_dointvec_minmax,
.extra1 = &auto_flowlabels_min,
.extra2 = &auto_flowlabels_max
}, },
{ {
.procname = "fwmark_reflect", .procname = "fwmark_reflect",
......
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