|
@@ -91,6 +91,24 @@ static void set_tun_src(struct net *net, struct net_device *dev,
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Compute flowlabel for outer IPv6 header */
|
|
|
|
+static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,
|
|
|
|
+ struct ipv6hdr *inner_hdr)
|
|
|
|
+{
|
|
|
|
+ int do_flowlabel = net->ipv6.sysctl.seg6_flowlabel;
|
|
|
|
+ __be32 flowlabel = 0;
|
|
|
|
+ u32 hash;
|
|
|
|
+
|
|
|
|
+ if (do_flowlabel > 0) {
|
|
|
|
+ hash = skb_get_hash(skb);
|
|
|
|
+ rol32(hash, 16);
|
|
|
|
+ flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
|
|
|
|
+ } else if (!do_flowlabel && skb->protocol == htons(ETH_P_IPV6)) {
|
|
|
|
+ flowlabel = ip6_flowlabel(inner_hdr);
|
|
|
|
+ }
|
|
|
|
+ return flowlabel;
|
|
|
|
+}
|
|
|
|
+
|
|
/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
|
|
/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
|
|
int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
|
|
int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
|
|
{
|
|
{
|
|
@@ -99,6 +117,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
|
|
struct ipv6hdr *hdr, *inner_hdr;
|
|
struct ipv6hdr *hdr, *inner_hdr;
|
|
struct ipv6_sr_hdr *isrh;
|
|
struct ipv6_sr_hdr *isrh;
|
|
int hdrlen, tot_len, err;
|
|
int hdrlen, tot_len, err;
|
|
|
|
+ __be32 flowlabel;
|
|
|
|
|
|
hdrlen = (osrh->hdrlen + 1) << 3;
|
|
hdrlen = (osrh->hdrlen + 1) << 3;
|
|
tot_len = hdrlen + sizeof(*hdr);
|
|
tot_len = hdrlen + sizeof(*hdr);
|
|
@@ -119,12 +138,13 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
|
|
* decapsulation will overwrite inner hlim with outer hlim
|
|
* decapsulation will overwrite inner hlim with outer hlim
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+ flowlabel = seg6_make_flowlabel(net, skb, inner_hdr);
|
|
if (skb->protocol == htons(ETH_P_IPV6)) {
|
|
if (skb->protocol == htons(ETH_P_IPV6)) {
|
|
ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
|
|
ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
|
|
- ip6_flowlabel(inner_hdr));
|
|
|
|
|
|
+ flowlabel);
|
|
hdr->hop_limit = inner_hdr->hop_limit;
|
|
hdr->hop_limit = inner_hdr->hop_limit;
|
|
} else {
|
|
} else {
|
|
- ip6_flow_hdr(hdr, 0, 0);
|
|
|
|
|
|
+ ip6_flow_hdr(hdr, 0, flowlabel);
|
|
hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
|
|
hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
|
|
}
|
|
}
|
|
|
|
|