diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 9 | ||||
-rw-r--r-- | include/linux/ipv6.h | 3 | ||||
-rw-r--r-- | include/net/ipv6.h | 20 | ||||
-rw-r--r-- | include/net/netns/ipv6.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/in6.h | 1 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 7 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 7 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 3 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 8 | ||||
-rw-r--r-- | net/ipv6/sysctl_net_ipv6.c | 8 |
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 | ||
1135 | auto_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 | |||
1135 | anycast_src_echo_reply - BOOLEAN | 1144 | anycast_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 | ||
702 | static 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) |