diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 20 | ||||
-rw-r--r-- | include/net/ipv6.h | 59 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 4 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 2 | ||||
-rw-r--r-- | net/ipv6/sysctl_net_ipv6.c | 7 |
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 | ||
1218 | auto_flowlabels - BOOLEAN | 1218 | auto_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 | ||
1227 | flowlabel_state_ranges - BOOLEAN | 1233 | flowlabel_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 | |||
710 | static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, | 721 | static 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 | |||
749 | static 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 |
734 | static inline void ip6_set_txhash(struct sock *sk) { } | 762 | static inline void ip6_set_txhash(struct sock *sk) { } |
735 | static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, | 763 | static 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 | } |
769 | static 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 | ||
19 | static int one = 1; | 19 | static int one = 1; |
20 | static int auto_flowlabels_min; | ||
21 | static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; | ||
22 | |||
20 | 23 | ||
21 | static struct ctl_table ipv6_table_template[] = { | 24 | static 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", |