aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/ip-sysctl.txt20
-rw-r--r--include/net/ipv6.h59
-rw-r--r--net/ipv6/af_inet6.c3
-rw-r--r--net/ipv6/ip6_gre.c4
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/sysctl_net_ipv6.c7
6 files changed, 70 insertions, 25 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 00d26d919459..9ac3af3ab739 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1215,14 +1215,20 @@ flowlabel_consistency - BOOLEAN
1215 FALSE: disabled 1215 FALSE: disabled
1216 Default: TRUE 1216 Default: TRUE
1217 1217
1218auto_flowlabels - BOOLEAN 1218auto_flowlabels - INTEGER
1219 Automatically generate flow labels based based on a flow hash 1219 Automatically generate flow labels based on a flow hash of the
1220 of the packet. This allows intermediate devices, such as routers, 1220 packet. This allows intermediate devices, such as routers, to
1221 to idenfify packet flows for mechanisms like Equal Cost Multipath 1221 identify packet flows for mechanisms like Equal Cost Multipath
1222 Routing (see RFC 6438). 1222 Routing (see RFC 6438).
1223 TRUE: enabled 1223 0: automatic flow labels are completely disabled
1224 FALSE: disabled 1224 1: automatic flow labels are enabled by default, they can be
1225 Default: false 1225 disabled on a per socket basis using the IPV6_AUTOFLOWLABEL
1226 socket option
1227 2: automatic flow labels are allowed, they may be enabled on a
1228 per socket basis using the IPV6_AUTOFLOWLABEL socket option
1229 3: automatic flow labels are enabled and enforced, they cannot
1230 be disabled by the socket option
1231 Default: 0
1226 1232
1227flowlabel_state_ranges - BOOLEAN 1233flowlabel_state_ranges - BOOLEAN
1228 Split the flow label number space into two ranges. 0-0x7FFFF is 1234 Split the flow label number space into two ranges. 0-0x7FFFF is
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3e334b33ef3a..c02c1c03363a 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -707,36 +707,69 @@ static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
707} 707}
708 708
709#if IS_ENABLED(CONFIG_IPV6) 709#if IS_ENABLED(CONFIG_IPV6)
710
711/* Sysctl settings for net ipv6.auto_flowlabels */
712#define IP6_AUTO_FLOW_LABEL_OFF 0
713#define IP6_AUTO_FLOW_LABEL_OPTOUT 1
714#define IP6_AUTO_FLOW_LABEL_OPTIN 2
715#define IP6_AUTO_FLOW_LABEL_FORCED 3
716
717#define IP6_AUTO_FLOW_LABEL_MAX IP6_AUTO_FLOW_LABEL_FORCED
718
719#define IP6_DEFAULT_AUTO_FLOW_LABELS IP6_AUTO_FLOW_LABEL_OFF
720
710static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, 721static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
711 __be32 flowlabel, bool autolabel, 722 __be32 flowlabel, bool autolabel,
712 struct flowi6 *fl6) 723 struct flowi6 *fl6)
713{ 724{
714 if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) { 725 u32 hash;
715 u32 hash;
716 726
717 hash = skb_get_hash_flowi6(skb, fl6); 727 if (flowlabel ||
728 net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
729 (!autolabel &&
730 net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED))
731 return flowlabel;
718 732
719 /* Since this is being sent on the wire obfuscate hash a bit 733 hash = skb_get_hash_flowi6(skb, fl6);
720 * to minimize possbility that any useful information to an
721 * attacker is leaked. Only lower 20 bits are relevant.
722 */
723 hash ^= hash >> 12;
724 734
725 flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; 735 /* Since this is being sent on the wire obfuscate hash a bit
736 * to minimize possbility that any useful information to an
737 * attacker is leaked. Only lower 20 bits are relevant.
738 */
739 rol32(hash, 16);
726 740
727 if (net->ipv6.sysctl.flowlabel_state_ranges) 741 flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
728 flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG; 742
729 } 743 if (net->ipv6.sysctl.flowlabel_state_ranges)
744 flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG;
730 745
731 return flowlabel; 746 return flowlabel;
732} 747}
748
749static inline int ip6_default_np_autolabel(struct net *net)
750{
751 switch (net->ipv6.sysctl.auto_flowlabels) {
752 case IP6_AUTO_FLOW_LABEL_OFF:
753 case IP6_AUTO_FLOW_LABEL_OPTIN:
754 default:
755 return 0;
756 case IP6_AUTO_FLOW_LABEL_OPTOUT:
757 case IP6_AUTO_FLOW_LABEL_FORCED:
758 return 1;
759 }
760}
733#else 761#else
734static inline void ip6_set_txhash(struct sock *sk) { } 762static inline void ip6_set_txhash(struct sock *sk) { }
735static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, 763static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
736 __be32 flowlabel, bool autolabel) 764 __be32 flowlabel, bool autolabel,
765 struct flowi6 *fl6)
737{ 766{
738 return flowlabel; 767 return flowlabel;
739} 768}
769static inline int ip6_default_np_autolabel(struct net *net)
770{
771 return 0;
772}
740#endif 773#endif
741 774
742 775
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 7bc92ea4ae8f..3f0ae3a7c0b1 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -197,6 +197,7 @@ lookup_protocol:
197 np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; 197 np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
198 np->mc_loop = 1; 198 np->mc_loop = 1;
199 np->pmtudisc = IPV6_PMTUDISC_WANT; 199 np->pmtudisc = IPV6_PMTUDISC_WANT;
200 np->autoflowlabel = ip6_default_np_autolabel(sock_net(sk));
200 sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; 201 sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
201 202
202 /* Init the ipv4 part of the socket since we can have sockets 203 /* 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 net->ipv6.sysctl.bindv6only = 0; 768 net->ipv6.sysctl.bindv6only = 0;
768 net->ipv6.sysctl.icmpv6_time = 1*HZ; 769 net->ipv6.sysctl.icmpv6_time = 1*HZ;
769 net->ipv6.sysctl.flowlabel_consistency = 1; 770 net->ipv6.sysctl.flowlabel_consistency = 1;
770 net->ipv6.sysctl.auto_flowlabels = 0; 771 net->ipv6.sysctl.auto_flowlabels = IP6_DEFAULT_AUTO_FLOW_LABELS;
771 net->ipv6.sysctl.idgen_retries = 3; 772 net->ipv6.sysctl.idgen_retries = 3;
772 net->ipv6.sysctl.idgen_delay = 1 * HZ; 773 net->ipv6.sysctl.idgen_delay = 1 * HZ;
773 net->ipv6.sysctl.flowlabel_state_ranges = 1; 774 net->ipv6.sysctl.flowlabel_state_ranges = 1;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index a7d1ca2337a9..34f121812a14 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -728,7 +728,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
728 */ 728 */
729 ipv6h = ipv6_hdr(skb); 729 ipv6h = ipv6_hdr(skb);
730 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), 730 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
731 ip6_make_flowlabel(net, skb, fl6->flowlabel, false, fl6)); 731 ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
732 ipv6h->hop_limit = tunnel->parms.hop_limit; 732 ipv6h->hop_limit = tunnel->parms.hop_limit;
733 ipv6h->nexthdr = proto; 733 ipv6h->nexthdr = proto;
734 ipv6h->saddr = fl6->saddr; 734 ipv6h->saddr = fl6->saddr;
@@ -1182,7 +1182,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
1182 1182
1183 ip6_flow_hdr(ipv6h, 0, 1183 ip6_flow_hdr(ipv6h, 0,
1184 ip6_make_flowlabel(dev_net(dev), skb, 1184 ip6_make_flowlabel(dev_net(dev), skb,
1185 t->fl.u.ip6.flowlabel, false, 1185 t->fl.u.ip6.flowlabel, true,
1186 &t->fl.u.ip6)); 1186 &t->fl.u.ip6));
1187 ipv6h->hop_limit = t->parms.hop_limit; 1187 ipv6h->hop_limit = t->parms.hop_limit;
1188 ipv6h->nexthdr = NEXTHDR_GRE; 1188 ipv6h->nexthdr = NEXTHDR_GRE;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 54e694c4af0e..b0ab420612bc 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1095,7 +1095,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
1095 skb_reset_network_header(skb); 1095 skb_reset_network_header(skb);
1096 ipv6h = ipv6_hdr(skb); 1096 ipv6h = ipv6_hdr(skb);
1097 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), 1097 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
1098 ip6_make_flowlabel(net, skb, fl6->flowlabel, false, fl6)); 1098 ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
1099 ipv6h->hop_limit = t->parms.hop_limit; 1099 ipv6h->hop_limit = t->parms.hop_limit;
1100 ipv6h->nexthdr = proto; 1100 ipv6h->nexthdr = proto;
1101 ipv6h->saddr = fl6->saddr; 1101 ipv6h->saddr = fl6->saddr;
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index db48aebd9c47..45243bbe5253 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -17,6 +17,9 @@
17#include <net/inet_frag.h> 17#include <net/inet_frag.h>
18 18
19static int one = 1; 19static int one = 1;
20static int auto_flowlabels_min;
21static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
22
20 23
21static struct ctl_table ipv6_table_template[] = { 24static struct ctl_table ipv6_table_template[] = {
22 { 25 {
@@ -45,7 +48,9 @@ static struct ctl_table ipv6_table_template[] = {
45 .data = &init_net.ipv6.sysctl.auto_flowlabels, 48 .data = &init_net.ipv6.sysctl.auto_flowlabels,
46 .maxlen = sizeof(int), 49 .maxlen = sizeof(int),
47 .mode = 0644, 50 .mode = 0644,
48 .proc_handler = proc_dointvec 51 .proc_handler = proc_dointvec_minmax,
52 .extra1 = &auto_flowlabels_min,
53 .extra2 = &auto_flowlabels_max
49 }, 54 },
50 { 55 {
51 .procname = "fwmark_reflect", 56 .procname = "fwmark_reflect",