- if (key->dl_type != htons(ETH_P_IP))
- return skb;
-
- skb = make_writable(skb, 0, gfp);
- if (skb) {
- struct iphdr *nh = ip_hdr(skb);
- u8 *f = &nh->tos;
- u8 old = *f;
- u8 new;
-
- /* Set the DSCP bits and preserve the ECN bits. */
- new = a->nw_tos | (nh->tos & INET_ECN_MASK);
- update_csum(&nh->check, skb, htons((uint16_t)old),
- htons((uint16_t)new), 0);
- *f = new;
- key->nw_tos = a->nw_tos;
+ csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8));
+ nh->ttl = new_ttl;
+}
+
+static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
+{
+ struct iphdr *nh;
+ int err;
+
+ err = make_writable(skb, skb_network_offset(skb) +
+ sizeof(struct iphdr));
+ if (unlikely(err))
+ return err;
+
+ nh = ip_hdr(skb);
+
+ if (ipv4_key->ipv4_src != nh->saddr)
+ set_ip_addr(skb, nh, &nh->saddr, ipv4_key->ipv4_src);
+
+ if (ipv4_key->ipv4_dst != nh->daddr)
+ set_ip_addr(skb, nh, &nh->daddr, ipv4_key->ipv4_dst);
+
+ if (ipv4_key->ipv4_tos != nh->tos)
+ ipv4_change_dsfield(nh, 0, ipv4_key->ipv4_tos);
+
+ if (ipv4_key->ipv4_ttl != nh->ttl)
+ set_ip_ttl(skb, nh, ipv4_key->ipv4_ttl);
+
+ return 0;
+}
+
+static int set_ipv6(struct sk_buff *skb, const struct ovs_key_ipv6 *ipv6_key)
+{
+ struct ipv6hdr *nh;
+ int err;
+ __be32 *saddr;
+ __be32 *daddr;
+
+ err = make_writable(skb, skb_network_offset(skb) +
+ sizeof(struct ipv6hdr));
+ if (unlikely(err))
+ return err;
+
+ nh = ipv6_hdr(skb);
+ saddr = (__be32 *)&nh->saddr;
+ daddr = (__be32 *)&nh->daddr;
+
+ if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src)))
+ set_ipv6_addr(skb, ipv6_key->ipv6_proto, saddr,
+ ipv6_key->ipv6_src, true);
+
+ if (memcmp(ipv6_key->ipv6_dst, daddr, sizeof(ipv6_key->ipv6_dst))) {
+ unsigned int offset = 0;
+ int flags = OVS_IP6T_FH_F_SKIP_RH;
+ bool recalc_csum = true;
+
+ if (ipv6_ext_hdr(nh->nexthdr))
+ recalc_csum = ipv6_find_hdr(skb, &offset,
+ NEXTHDR_ROUTING, NULL,
+ &flags) != NEXTHDR_ROUTING;
+
+ set_ipv6_addr(skb, ipv6_key->ipv6_proto, daddr,
+ ipv6_key->ipv6_dst, recalc_csum);