|
@@ -111,11 +111,24 @@ static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner)
|
|
|
|
|
|
struct ipv6hdr;
|
|
struct ipv6hdr;
|
|
|
|
|
|
-static inline int IP6_ECN_set_ce(struct ipv6hdr *iph)
|
|
|
|
|
|
+/* Note:
|
|
|
|
+ * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE,
|
|
|
|
+ * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE
|
|
|
|
+ * In IPv6 case, no checksum compensates the change in IPv6 header,
|
|
|
|
+ * so we have to update skb->csum.
|
|
|
|
+ */
|
|
|
|
+static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph)
|
|
{
|
|
{
|
|
|
|
+ __be32 from, to;
|
|
|
|
+
|
|
if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
|
|
if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
|
|
return 0;
|
|
return 0;
|
|
- *(__be32*)iph |= htonl(INET_ECN_CE << 20);
|
|
|
|
|
|
+
|
|
|
|
+ from = *(__be32 *)iph;
|
|
|
|
+ to = from | htonl(INET_ECN_CE << 20);
|
|
|
|
+ *(__be32 *)iph = to;
|
|
|
|
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
|
|
|
|
+ skb->csum = csum_add(csum_sub(skb->csum, from), to);
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -142,7 +155,7 @@ static inline int INET_ECN_set_ce(struct sk_buff *skb)
|
|
case cpu_to_be16(ETH_P_IPV6):
|
|
case cpu_to_be16(ETH_P_IPV6):
|
|
if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
|
|
if (skb_network_header(skb) + sizeof(struct ipv6hdr) <=
|
|
skb_tail_pointer(skb))
|
|
skb_tail_pointer(skb))
|
|
- return IP6_ECN_set_ce(ipv6_hdr(skb));
|
|
|
|
|
|
+ return IP6_ECN_set_ce(skb, ipv6_hdr(skb));
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|