aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/ip-sysctl.txt9
-rw-r--r--include/linux/ipv6.h3
-rw-r--r--include/net/ipv6.h20
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--include/uapi/linux/in6.h1
-rw-r--r--net/ipv6/af_inet6.c1
-rw-r--r--net/ipv6/ip6_gre.c7
-rw-r--r--net/ipv6/ip6_output.c7
-rw-r--r--net/ipv6/ip6_tunnel.c3
-rw-r--r--net/ipv6/ipv6_sockglue.c8
-rw-r--r--net/ipv6/sysctl_net_ipv6.c8
11 files changed, 62 insertions, 6 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 10e216c6e05e..f35bfe43bf7a 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1132,6 +1132,15 @@ flowlabel_consistency - BOOLEAN
1132 FALSE: disabled 1132 FALSE: disabled
1133 Default: TRUE 1133 Default: TRUE
1134 1134
1135auto_flowlabels - BOOLEAN
1136 Automatically generate flow labels based based on a flow hash
1137 of the packet. This allows intermediate devices, such as routers,
1138 to idenfify packet flows for mechanisms like Equal Cost Multipath
1139 Routing (see RFC 6438).
1140 TRUE: enabled
1141 FALSE: disabled
1142 Default: false
1143
1135anycast_src_echo_reply - BOOLEAN 1144anycast_src_echo_reply - BOOLEAN
1136 Controls the use of anycast addresses as source addresses for ICMPv6 1145 Controls the use of anycast addresses as source addresses for ICMPv6
1137 echo reply 1146 echo reply
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 5dc68c3ebcbd..ff560537dd61 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -199,7 +199,8 @@ struct ipv6_pinfo {
199 * 010: prefer public address 199 * 010: prefer public address
200 * 100: prefer care-of address 200 * 100: prefer care-of address
201 */ 201 */
202 dontfrag:1; 202 dontfrag:1,
203 autoflowlabel:1;
203 __u8 min_hopcount; 204 __u8 min_hopcount;
204 __u8 tclass; 205 __u8 tclass;
205 __be32 rcv_flowinfo; 206 __be32 rcv_flowinfo;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 2aa86e1135a1..4308f2ada8b3 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -699,6 +699,26 @@ static inline void ip6_set_txhash(struct sock *sk)
699 sk->sk_txhash = flow_hash_from_keys(&keys); 699 sk->sk_txhash = flow_hash_from_keys(&keys);
700} 700}
701 701
702static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
703 __be32 flowlabel, bool autolabel)
704{
705 if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) {
706 __be32 hash;
707
708 hash = skb_get_hash(skb);
709
710 /* Since this is being sent on the wire obfuscate hash a bit
711 * to minimize possbility that any useful information to an
712 * attacker is leaked. Only lower 20 bits are relevant.
713 */
714 hash ^= hash >> 12;
715
716 flowlabel = hash & IPV6_FLOWLABEL_MASK;
717 }
718
719 return flowlabel;
720}
721
702/* 722/*
703 * Header manipulation 723 * Header manipulation
704 */ 724 */
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 19d3446e59d2..eade27adecf3 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -28,6 +28,7 @@ struct netns_sysctl_ipv6 {
28 int ip6_rt_mtu_expires; 28 int ip6_rt_mtu_expires;
29 int ip6_rt_min_advmss; 29 int ip6_rt_min_advmss;
30 int flowlabel_consistency; 30 int flowlabel_consistency;
31 int auto_flowlabels;
31 int icmpv6_time; 32 int icmpv6_time;
32 int anycast_src_echo_reply; 33 int anycast_src_echo_reply;
33 int fwmark_reflect; 34 int fwmark_reflect;
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 0d8e0f0342dc..22b7a69619d8 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -233,6 +233,7 @@ struct in6_flowlabel_req {
233#if 0 /* not yet */ 233#if 0 /* not yet */
234#define IPV6_USE_MIN_MTU 63 234#define IPV6_USE_MIN_MTU 63
235#endif 235#endif
236#define IPV6_AUTOFLOWLABEL 64
236 237
237/* 238/*
238 * Netfilter (1) 239 * Netfilter (1)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index a426cd7099bb..2daa3a133e49 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -765,6 +765,7 @@ static int __net_init inet6_net_init(struct net *net)
765 net->ipv6.sysctl.bindv6only = 0; 765 net->ipv6.sysctl.bindv6only = 0;
766 net->ipv6.sysctl.icmpv6_time = 1*HZ; 766 net->ipv6.sysctl.icmpv6_time = 1*HZ;
767 net->ipv6.sysctl.flowlabel_consistency = 1; 767 net->ipv6.sysctl.flowlabel_consistency = 1;
768 net->ipv6.sysctl.auto_flowlabels = 0;
768 atomic_set(&net->ipv6.rt_genid, 0); 769 atomic_set(&net->ipv6.rt_genid, 0);
769 770
770 err = ipv6_init_mibs(net); 771 err = ipv6_init_mibs(net);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 3873181ed856..365b2b6f3942 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -723,7 +723,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
723 * Push down and install the IP header. 723 * Push down and install the IP header.
724 */ 724 */
725 ipv6h = ipv6_hdr(skb); 725 ipv6h = ipv6_hdr(skb);
726 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); 726 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
727 ip6_make_flowlabel(net, skb, fl6->flowlabel, false));
727 ipv6h->hop_limit = tunnel->parms.hop_limit; 728 ipv6h->hop_limit = tunnel->parms.hop_limit;
728 ipv6h->nexthdr = proto; 729 ipv6h->nexthdr = proto;
729 ipv6h->saddr = fl6->saddr; 730 ipv6h->saddr = fl6->saddr;
@@ -1174,7 +1175,9 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
1174 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); 1175 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen);
1175 __be16 *p = (__be16 *)(ipv6h+1); 1176 __be16 *p = (__be16 *)(ipv6h+1);
1176 1177
1177 ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel); 1178 ip6_flow_hdr(ipv6h, 0,
1179 ip6_make_flowlabel(dev_net(dev), skb,
1180 t->fl.u.ip6.flowlabel, false));
1178 ipv6h->hop_limit = t->parms.hop_limit; 1181 ipv6h->hop_limit = t->parms.hop_limit;
1179 ipv6h->nexthdr = NEXTHDR_GRE; 1182 ipv6h->nexthdr = NEXTHDR_GRE;
1180 ipv6h->saddr = t->parms.laddr; 1183 ipv6h->saddr = t->parms.laddr;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index cb9df0eb4023..fa83bdd4c3dd 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -205,7 +205,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
205 if (hlimit < 0) 205 if (hlimit < 0)
206 hlimit = ip6_dst_hoplimit(dst); 206 hlimit = ip6_dst_hoplimit(dst);
207 207
208 ip6_flow_hdr(hdr, tclass, fl6->flowlabel); 208 ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel,
209 np->autoflowlabel));
209 210
210 hdr->payload_len = htons(seg_len); 211 hdr->payload_len = htons(seg_len);
211 hdr->nexthdr = proto; 212 hdr->nexthdr = proto;
@@ -1569,7 +1570,9 @@ int ip6_push_pending_frames(struct sock *sk)
1569 skb_reset_network_header(skb); 1570 skb_reset_network_header(skb);
1570 hdr = ipv6_hdr(skb); 1571 hdr = ipv6_hdr(skb);
1571 1572
1572 ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); 1573 ip6_flow_hdr(hdr, np->cork.tclass,
1574 ip6_make_flowlabel(net, skb, fl6->flowlabel,
1575 np->autoflowlabel));
1573 hdr->hop_limit = np->cork.hop_limit; 1576 hdr->hop_limit = np->cork.hop_limit;
1574 hdr->nexthdr = proto; 1577 hdr->nexthdr = proto;
1575 hdr->saddr = fl6->saddr; 1578 hdr->saddr = fl6->saddr;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index afa082458360..51a1eb185ea7 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1046,7 +1046,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
1046 skb_push(skb, sizeof(struct ipv6hdr)); 1046 skb_push(skb, sizeof(struct ipv6hdr));
1047 skb_reset_network_header(skb); 1047 skb_reset_network_header(skb);
1048 ipv6h = ipv6_hdr(skb); 1048 ipv6h = ipv6_hdr(skb);
1049 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); 1049 ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
1050 ip6_make_flowlabel(net, skb, fl6->flowlabel, false));
1050 ipv6h->hop_limit = t->parms.hop_limit; 1051 ipv6h->hop_limit = t->parms.hop_limit;
1051 ipv6h->nexthdr = proto; 1052 ipv6h->nexthdr = proto;
1052 ipv6h->saddr = fl6->saddr; 1053 ipv6h->saddr = fl6->saddr;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index cc34f65179e4..b50b9e54cf53 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -834,6 +834,10 @@ pref_skip_coa:
834 np->dontfrag = valbool; 834 np->dontfrag = valbool;
835 retv = 0; 835 retv = 0;
836 break; 836 break;
837 case IPV6_AUTOFLOWLABEL:
838 np->autoflowlabel = valbool;
839 retv = 0;
840 break;
837 } 841 }
838 842
839 release_sock(sk); 843 release_sock(sk);
@@ -1273,6 +1277,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1273 val = np->dontfrag; 1277 val = np->dontfrag;
1274 break; 1278 break;
1275 1279
1280 case IPV6_AUTOFLOWLABEL:
1281 val = np->autoflowlabel;
1282 break;
1283
1276 default: 1284 default:
1277 return -ENOPROTOOPT; 1285 return -ENOPROTOOPT;
1278 } 1286 }
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 058f3eca2e53..5bf7b61f8ae8 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -39,6 +39,13 @@ static struct ctl_table ipv6_table_template[] = {
39 .proc_handler = proc_dointvec 39 .proc_handler = proc_dointvec
40 }, 40 },
41 { 41 {
42 .procname = "auto_flowlabels",
43 .data = &init_net.ipv6.sysctl.auto_flowlabels,
44 .maxlen = sizeof(int),
45 .mode = 0644,
46 .proc_handler = proc_dointvec
47 },
48 {
42 .procname = "fwmark_reflect", 49 .procname = "fwmark_reflect",
43 .data = &init_net.ipv6.sysctl.fwmark_reflect, 50 .data = &init_net.ipv6.sysctl.fwmark_reflect,
44 .maxlen = sizeof(int), 51 .maxlen = sizeof(int),
@@ -74,6 +81,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net)
74 ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; 81 ipv6_table[0].data = &net->ipv6.sysctl.bindv6only;
75 ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; 82 ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply;
76 ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; 83 ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency;
84 ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels;
77 85
78 ipv6_route_table = ipv6_route_sysctl_init(net); 86 ipv6_route_table = ipv6_route_sysctl_init(net);
79 if (!ipv6_route_table) 87 if (!ipv6_route_table)