#include <linux/udp.h>
#include <linux/in6.h>
#include <linux/if_vlan.h>
+#include <net/inet_ecn.h>
#include <net/ip.h>
#include <net/checksum.h>
#include "datapath.h"
mask = VLAN_VID_MASK;
key->dl_vlan = htons(tci & mask);
} else {
- tci = a->vlan_pcp.vlan_pcp << 13;
+ tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
mask = VLAN_PCP_MASK;
}
{
__be32 diff[] = { ~from, to };
-/* On older kernels, CHECKSUM_PARTIAL and CHECKSUM_COMPLETE are both defined
- * as CHECKSUM_HW. However, we can make some inferences so that we can update
- * the checksums appropriately. */
- enum {
- CSUM_PARTIAL, /* Partial checksum, skb->csum undefined. */
- CSUM_PACKET, /* In-packet checksum, skb->csum undefined. */
- CSUM_COMPLETE, /* In-packet checksum, skb->csum valid. */
- } csum_type;
-
- csum_type = CSUM_PACKET;
-#ifndef CHECKSUM_HW
- /* Newer kernel, just map between kernel types and ours. */
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- csum_type = CSUM_PARTIAL;
- else if (skb->ip_summed == CHECKSUM_COMPLETE)
- csum_type = CSUM_COMPLETE;
-#else
- /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
- * However, we should only get CHECKSUM_PARTIAL packets from Xen, which
- * uses some special fields to represent this (see below). Since we
- * can only make one type work, pick the one that actually happens in
- * practice. */
- if (skb->ip_summed == CHECKSUM_HW)
- csum_type = CSUM_COMPLETE;
-#endif
-#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
- /* Xen has a special way of representing CHECKSUM_PARTIAL on older
- * kernels. */
- if (skb->proto_csum_blank)
- csum_type = CSUM_PARTIAL;
-#endif
-
- if (csum_type != CSUM_PARTIAL) {
+ if (OVS_CB(skb)->ip_summed != CSUM_PARTIAL) {
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
~csum_unfold(*sum)));
- if (csum_type == CSUM_COMPLETE && pseudohdr)
+ if (OVS_CB(skb)->ip_summed == CSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
~skb->csum);
} else if (pseudohdr)
return skb;
}
+static struct sk_buff *set_nw_tos(struct sk_buff *skb,
+ struct odp_flow_key *key,
+ const struct odp_action_nw_tos *a,
+ gfp_t gfp)
+{
+ 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 & ~INET_ECN_MASK) | (nh->tos & INET_ECN_MASK);
+ update_csum(&nh->check, skb, htons((uint16_t)old),
+ htons((uint16_t)new), 0);
+ *f = new;
+ }
+ return skb;
+}
+
static struct sk_buff *
set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
const struct odp_action_tp_port *a,
skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
break;
+ case ODPAT_SET_NW_TOS:
+ skb = set_nw_tos(skb, key, &a->nw_tos, gfp);
+ break;
+
case ODPAT_SET_TP_SRC:
case ODPAT_SET_TP_DST:
skb = set_tp_port(skb, key, &a->tp_port, gfp);