[ovs-dev] [netlink 07/16] datapath: Combine dl_vlan and dl_vlan_pcp.

Ben Pfaff blp at nicira.com
Fri Sep 10 15:55:07 PDT 2010


This allows eliminating padding from odp_flow_key, although actually doing
that is postponed until the next commit.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 datapath/actions.c                                 |   21 ++------
 datapath/datapath.c                                |   15 +++---
 datapath/flow.c                                    |    4 +-
 .../linux-2.6/compat-2.6/include/linux/if_vlan.h   |   10 ++++
 include/openvswitch/datapath-protocol.h            |   52 ++++++++------------
 lib/dpif-netdev.c                                  |   44 +++++++----------
 lib/odp-util.c                                     |   39 ++++++++++-----
 lib/packets.h                                      |   20 ++++++++
 ofproto/ofproto-sflow.c                            |   14 +++--
 ofproto/ofproto.c                                  |   11 +++--
 vswitchd/bridge.c                                  |    5 +-
 11 files changed, 127 insertions(+), 108 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index c0b3040..961a0dc 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -75,15 +75,8 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 				       const union odp_action *a, int n_actions,
 				       gfp_t gfp)
 {
-	u16 tci, mask;
-
-	if (a->type == ODPAT_SET_VLAN_VID) {
-		tci = ntohs(a->vlan_vid.vlan_vid);
-		mask = VLAN_VID_MASK;
-	} else {
-		tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
-		mask = VLAN_PCP_MASK;
-	}
+	__be16 mask = a->dl_tci.mask;
+	__be16 tci = a->dl_tci.tci;
 
 	skb = make_writable(skb, VLAN_HLEN, gfp);
 	if (!skb)
@@ -100,7 +93,7 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 		vh = vlan_eth_hdr(skb);
 		old_tci = vh->h_vlan_TCI;
 
-		vh->h_vlan_TCI = htons((ntohs(vh->h_vlan_TCI) & ~mask) | tci);
+		vh->h_vlan_TCI = (vh->h_vlan_TCI & ~mask) | tci;
 
 		if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE) {
 			__be16 diff[] = { ~old_tci, vh->h_vlan_TCI };
@@ -156,7 +149,7 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 				/* GSO can change the checksum type so update.*/
 				compute_ip_summed(segs, true);
 
-				segs = __vlan_put_tag(segs, tci);
+				segs = __vlan_put_tag(segs, ntohs(tci));
 				err = -ENOMEM;
 				if (segs) {
 					err = execute_actions(dp, segs,
@@ -186,7 +179,7 @@ static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 		 * e.g. vconfig(8)), so call the software-only version
 		 * __vlan_put_tag() directly instead.
 		 */
-		skb = __vlan_put_tag(skb, tci);
+		skb = __vlan_put_tag(skb, ntohs(tci));
 		if (!skb)
 			return ERR_PTR(-ENOMEM);
 
@@ -205,7 +198,6 @@ static struct sk_buff *strip_vlan(struct sk_buff *skb, gfp_t gfp)
 	skb = make_writable(skb, 0, gfp);
 	if (skb)
 		vlan_pull_tag(skb);
-
 	return skb;
 }
 
@@ -478,8 +470,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 			OVS_CB(skb)->tun_id = a->tunnel.tun_id;
 			break;
 
-		case ODPAT_SET_VLAN_VID:
-		case ODPAT_SET_VLAN_PCP:
+		case ODPAT_SET_DL_TCI:
 			skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp);
 			if (IS_ERR(skb))
 				return PTR_ERR(skb);
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 3ab302a..5941d26 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -858,6 +858,8 @@ static int validate_actions(const struct sw_flow_actions *actions)
 
 	for (i = 0; i < actions->n_actions; i++) {
 		const union odp_action *a = &actions->actions[i];
+		__be16 mask;
+
 		switch (a->type) {
 		case ODPAT_CONTROLLER:
 		case ODPAT_STRIP_VLAN:
@@ -879,14 +881,13 @@ static int validate_actions(const struct sw_flow_actions *actions)
 				return -EINVAL;
 			break;
 
-		case ODPAT_SET_VLAN_VID:
-			if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK))
+		case ODPAT_SET_DL_TCI:
+			mask = a->dl_tci.mask;
+			if (mask != htons(VLAN_VID_MASK) &&
+			    mask != htons(VLAN_PCP_MASK) &&
+			    mask != htons(VLAN_VID_MASK | VLAN_PCP_MASK))
 				return -EINVAL;
-			break;
-
-		case ODPAT_SET_VLAN_PCP:
-			if (a->vlan_pcp.vlan_pcp
-			    & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT))
+			if (a->dl_tci.tci & ~mask)
 				return -EINVAL;
 			break;
 
diff --git a/datapath/flow.c b/datapath/flow.c
index dbfe5dd..06a2ce3 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -177,8 +177,7 @@ static void parse_vlan(struct sk_buff *skb, struct odp_flow_key *key)
 		return;
 
 	qp = (struct qtag_prefix *) skb->data;
-	key->dl_vlan = qp->tci & htons(VLAN_VID_MASK);
-	key->dl_vlan_pcp = (ntohs(qp->tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
+	key->dl_tci = qp->tci | htons(ODP_TCI_PRESENT);
 	__skb_pull(skb, sizeof(struct qtag_prefix));
 }
 
@@ -246,7 +245,6 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
 	memset(key, 0, sizeof *key);
 	key->tun_id = OVS_CB(skb)->tun_id;
 	key->in_port = in_port;
-	key->dl_vlan = htons(ODP_VLAN_NONE);
 	OVS_CB(skb)->is_frag = false;
 
 	/*
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h b/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h
index 8bc4ac5..f418407 100644
--- a/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h
+++ b/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h
@@ -44,4 +44,14 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 	return skb;
 }
 
+
+/* All of these were introduced in a single commit preceding 2.6.33, so
+ * presumably all of them or none of them are present. */
+#ifndef VLAN_PRIO_MASK
+#define VLAN_PRIO_MASK		0xe000 /* Priority Code Point */
+#define VLAN_PRIO_SHIFT		13
+#define VLAN_CFI_MASK		0x1000 /* Canonical Format Indicator */
+#define VLAN_TAG_PRESENT	VLAN_CFI_MASK
+#endif
+
 #endif	/* linux/if_vlan.h wrapper */
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
index 2186562..3e5bf28 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -204,12 +204,21 @@ struct odp_flow_stats {
     uint16_t error;             /* Used by ODP_FLOW_GET. */
 };
 
+/*
+ * The datapath protocol adopts the Linux convention for TCI fields: if an
+ * 802.1Q header is present then its TCI value is used verbatim except that the
+ * CFI bit (0x1000) is always set to 1, and all-bits-zero indicates no 802.1Q
+ * header.
+ */
+#define ODP_TCI_PRESENT 0x1000  /* CFI bit */
+
 struct odp_flow_key {
     ovs_be32 tun_id;            /* Encapsulating tunnel ID. */
     ovs_be32 nw_src;            /* IP source address. */
     ovs_be32 nw_dst;            /* IP destination address. */
     uint16_t in_port;           /* Input switch port. */
-    ovs_be16 dl_vlan;           /* Input VLAN. */
+    ovs_be16 dl_tci;            /* All zeros if 802.1Q header absent,
+                                  * ODP_TCI_PRESENT set if present. */
     ovs_be16 dl_type;           /* Ethernet frame type. */
     ovs_be16 tp_src;            /* TCP/UDP source port. */
     ovs_be16 tp_dst;            /* TCP/UDP destination port. */
@@ -217,9 +226,8 @@ struct odp_flow_key {
     uint8_t  dl_dst[6];         /* Ethernet destination address. */
     uint8_t  nw_proto;          /* IP protocol or lower 8 bits of
                                    ARP opcode. */
-    uint8_t  dl_vlan_pcp;       /* Input VLAN priority. */
     uint8_t  nw_tos;            /* IP ToS (DSCP field, 6 bits). */
-    uint8_t  reserved[3];       /* Align to 32-bits...must be zeroed. */
+    uint32_t reserved[1];          /* Reserved for later use. */
 };
 
 /* Flags for ODP_FLOW. */
@@ -249,16 +257,10 @@ struct odp_flowvec {
     uint32_t n_flows;
 };
 
-/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate
- * special conditions.  All ones is used to match that no VLAN id was
- * set. */
-#define ODP_VLAN_NONE      0xffff
-
 /* Action types. */
 #define ODPAT_OUTPUT            0    /* Output to switch port. */
 #define ODPAT_CONTROLLER        2    /* Send copy to controller. */
-#define ODPAT_SET_VLAN_VID      3    /* Set the 802.1q VLAN id. */
-#define ODPAT_SET_VLAN_PCP      4    /* Set the 802.1q priority. */
+#define ODPAT_SET_DL_TCI        3    /* Set the 802.1q VLAN VID and/or PCP. */
 #define ODPAT_STRIP_VLAN        5    /* Strip the 802.1q header. */
 #define ODPAT_SET_DL_SRC        6    /* Ethernet source address. */
 #define ODPAT_SET_DL_DST        7    /* Ethernet destination address. */
@@ -292,21 +294,13 @@ struct odp_action_tunnel {
     ovs_be32 tun_id;            /* Tunnel ID. */
 };
 
-/* Action structure for ODPAT_SET_VLAN_VID. */
-struct odp_action_vlan_vid {
-    uint16_t type;              /* ODPAT_SET_VLAN_VID. */
-    ovs_be16 vlan_vid;          /* VLAN id. */
-    uint16_t reserved1;
-    uint16_t reserved2;
-};
-
-/* Action structure for ODPAT_SET_VLAN_PCP. */
-struct odp_action_vlan_pcp {
-    uint16_t type;              /* ODPAT_SET_VLAN_PCP. */
-    uint8_t vlan_pcp;           /* VLAN priority. */
-    uint8_t reserved1;
-    uint16_t reserved2;
-    uint16_t reserved3;
+/* Action structure for ODPAT_SET_DL_TCI. */
+struct odp_action_dl_tci {
+    uint16_t type;              /* ODPAT_SET_DL_TCI. */
+    ovs_be16 tci;               /* New TCI.  Bits not in mask must be zero. */
+    ovs_be16 mask;              /* 0x0fff to set VID, 0xe000 to set PCP,
+                                 * or 0xefff to set both. */
+    uint16_t reserved;
 };
 
 /* Action structure for ODPAT_SET_DL_SRC/DST. */
@@ -350,8 +344,7 @@ union odp_action {
     struct odp_action_output output;
     struct odp_action_controller controller;
     struct odp_action_tunnel tunnel;
-    struct odp_action_vlan_vid vlan_vid;
-    struct odp_action_vlan_pcp vlan_pcp;
+    struct odp_action_dl_tci dl_tci;
     struct odp_action_dl_addr dl_addr;
     struct odp_action_nw_addr nw_addr;
     struct odp_action_nw_tos nw_tos;
@@ -408,9 +401,4 @@ struct odp_vport_mtu {
  */
 #define ODP_DL_TYPE_NOT_ETH_TYPE  0x05ff
 
-/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
- * special conditions.  All ones indicates that no VLAN id was set.
- */
-#define ODP_VLAN_NONE      0xffff
-
 #endif  /* openvswitch/datapath-protocol.h */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index bbc590f..d848995 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -609,6 +609,8 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp,
 {
     struct dp_netdev_flow *flow;
 
+    BUILD_ASSERT_DECL(ARRAY_SIZE(key->reserved) == 1);
+    assert(!key->reserved[0]);
     HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
                              odp_flow_key_hash(key, 0), &dp->flow_table) {
         if (odp_flow_key_equal(&flow->key, key)) {
@@ -680,16 +682,14 @@ dpif_netdev_validate_actions(const union odp_action *actions, int n_actions,
         case ODPAT_CONTROLLER:
             break;
 
-        case ODPAT_SET_VLAN_VID:
+        case ODPAT_SET_DL_TCI:
             *mutates = true;
-            if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK)) {
+            if (a->dl_tci.mask != htons(VLAN_VID_MASK)
+                && a->dl_tci.mask != htons(VLAN_PCP_MASK)
+                && a->dl_tci.mask != htons(VLAN_VID_MASK | VLAN_PCP_MASK)) {
                 return EINVAL;
             }
-            break;
-
-        case ODPAT_SET_VLAN_PCP:
-            *mutates = true;
-            if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
+            if (a->dl_tci.tci & ~a->dl_tci.mask){
                 return EINVAL;
             }
             break;
@@ -1027,16 +1027,16 @@ dp_netdev_wait(void)
 }
 
 
-/* Modify the TCI field of 'packet'.  If a VLAN tag is not present, one
- * is added with the TCI field set to 'tci'.  If a VLAN tag is present,
- * then 'mask' bits are cleared before 'tci' is logically OR'd into the
- * TCI field.
+/* Modify the TCI field of 'packet'.  If a VLAN tag is not present, one is
+ * added with the TCI field set to 'a->tci'.  If a VLAN tag is present, then
+ * 'a->mask' bits are cleared before 'a->tci' is logically OR'd into the TCI
+ * field.
  *
- * Note that the function does not ensure that 'tci' does not affect
- * bits outside of 'mask'.
+ * Note that the function does not ensure that 'a->tci' does not affect bits
+ * outside of 'a->mask'.
  */
 static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
+dp_netdev_set_dl_tci(struct ofpbuf *packet, const struct odp_action_dl_tci *a)
 {
     struct vlan_eth_header *veh;
     struct eth_header *eh;
@@ -1046,8 +1046,7 @@ dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
         && eh->eth_type == htons(ETH_TYPE_VLAN)) {
         /* Clear 'mask' bits, but maintain other TCI bits. */
         veh = packet->l2;
-        veh->veth_tci &= ~htons(mask);
-        veh->veth_tci |= htons(tci);
+        veh->veth_tci = (veh->veth_tci & ~a->mask) | a->tci;
     } else {
         /* Insert new 802.1Q header. */
         struct eth_header *eh = packet->l2;
@@ -1055,7 +1054,7 @@ dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
         memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
         memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
         tmp.veth_type = htons(ETH_TYPE_VLAN);
-        tmp.veth_tci = htons(tci);
+        tmp.veth_tci = htons(a->tci);
         tmp.veth_next_type = eh->eth_type;
 
         veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
@@ -1252,15 +1251,8 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
                                      key->in_port, a->controller.arg);
             break;
 
-        case ODPAT_SET_VLAN_VID:
-            dp_netdev_modify_vlan_tci(packet, ntohs(a->vlan_vid.vlan_vid),
-                                      VLAN_VID_MASK);
-             break;
-
-        case ODPAT_SET_VLAN_PCP:
-            dp_netdev_modify_vlan_tci(packet,
-                                      a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
-                                      VLAN_PCP_MASK);
+        case ODPAT_SET_DL_TCI:
+            dp_netdev_set_dl_tci(packet, &a->dl_tci);
             break;
 
         case ODPAT_STRIP_VLAN:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index b980611..512a305 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -42,10 +42,14 @@ odp_actions_add(struct odp_actions *actions, uint16_t type)
 void
 format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
 {
-    ds_put_format(ds, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT
-                  "->"ETH_ADDR_FMT" type%04x proto%"PRId8" tos%"PRIu8
-                  " ip"IP_FMT"->"IP_FMT" port%d->%d",
-                  key->in_port, ntohs(key->dl_vlan), key->dl_vlan_pcp,
+    ds_put_format(ds, "in_port%04x", key->in_port);
+    if (key->dl_tci) {
+        ds_put_format(ds, ":vlan%"PRIu16":pcp%d",
+                      vlan_tci_to_vid(key->dl_tci),
+                      vlan_tci_to_pcp(key->dl_tci));
+    }
+    ds_put_format(ds, " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" type%04x "
+                  "proto%"PRId8" tos%"PRIu8" ip"IP_FMT"->"IP_FMT" port%d->%d",
                   ETH_ADDR_ARGS(key->dl_src), ETH_ADDR_ARGS(key->dl_dst),
                   ntohs(key->dl_type), key->nw_proto, key->nw_tos,
                   IP_ARGS(&key->nw_src), IP_ARGS(&key->nw_dst),
@@ -65,11 +69,9 @@ format_odp_action(struct ds *ds, const union odp_action *a)
     case ODPAT_SET_TUNNEL:
         ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
         break;
-    case ODPAT_SET_VLAN_VID:
-        ds_put_format(ds, "set_vlan(%"PRIu16")", ntohs(a->vlan_vid.vlan_vid));
-        break;
-    case ODPAT_SET_VLAN_PCP:
-        ds_put_format(ds, "set_vlan_pcp(%"PRIu8")", a->vlan_pcp.vlan_pcp);
+    case ODPAT_SET_DL_TCI:
+        ds_put_format(ds, "set_tci(%04"PRIx16",mask=%04"PRIx16")",
+                      ntohs(a->dl_tci.tci), ntohs(a->dl_tci.mask));
         break;
     case ODPAT_STRIP_VLAN:
         ds_put_format(ds, "strip_vlan");
@@ -157,14 +159,20 @@ odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow)
     key->nw_src = flow->nw_src;
     key->nw_dst = flow->nw_dst;
     key->in_port = flow->in_port;
-    key->dl_vlan = flow->dl_vlan;
+    if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
+        key->dl_tci = htons(0);
+    } else {
+        uint16_t vid = flow->dl_vlan & htons(VLAN_VID_MASK);
+        uint16_t pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT)
+                             & VLAN_PCP_MASK);
+        key->dl_tci = vid | pcp | htons(ODP_TCI_PRESENT);
+    }
     key->dl_type = flow->dl_type;
     key->tp_src = flow->tp_src;
     key->tp_dst = flow->tp_dst;
     memcpy(key->dl_src, flow->dl_src, ETH_ADDR_LEN);
     memcpy(key->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
     key->nw_proto = flow->nw_proto;
-    key->dl_vlan_pcp = flow->dl_vlan_pcp;
     key->nw_tos = flow->nw_tos;
     memset(key->reserved, 0, sizeof key->reserved);
 }
@@ -175,13 +183,18 @@ odp_flow_key_to_flow(const struct odp_flow_key *key, struct flow *flow)
     flow->nw_src = key->nw_src;
     flow->nw_dst = key->nw_dst;
     flow->in_port = key->in_port;
-    flow->dl_vlan = key->dl_vlan;
+    if (key->dl_tci) {
+        flow->dl_vlan = htons(vlan_tci_to_vid(key->dl_tci));
+        flow->dl_vlan_pcp = vlan_tci_to_pcp(key->dl_tci);
+    } else {
+        flow->dl_vlan = htons(OFP_VLAN_NONE);
+        flow->dl_vlan_pcp = 0;
+    }
     flow->dl_type = key->dl_type;
     flow->tp_src = key->tp_src;
     flow->tp_dst = key->tp_dst;
     memcpy(flow->dl_src, key->dl_src, ETH_ADDR_LEN);
     memcpy(flow->dl_dst, key->dl_dst, ETH_ADDR_LEN);
     flow->nw_proto = key->nw_proto;
-    flow->dl_vlan_pcp = key->dl_vlan_pcp;
     flow->nw_tos = key->nw_tos;
 }
diff --git a/lib/packets.h b/lib/packets.h
index fb04407..af028eb 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -18,6 +18,8 @@
 #define PACKETS_H 1
 
 #include <inttypes.h>
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <stdint.h>
 #include <string.h>
 #include "compiler.h"
@@ -198,6 +200,24 @@ BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
 #define VLAN_PCP_MASK 0xe000
 #define VLAN_PCP_SHIFT 13
 
+#define VLAN_CFI 0x1000
+
+/* Given the vlan_tci field from an 802.1Q header, in network byte order,
+ * returns the VLAN ID in host byte order. */
+static inline uint16_t
+vlan_tci_to_vid(uint16_t vlan_tci)
+{
+    return (ntohs(vlan_tci) & VLAN_VID_MASK) >> VLAN_VID_SHIFT;
+}
+
+/* Given the vlan_tci field from an 802.1Q header, in network byte order,
+ * returns the priority code point (PCP) in host byte order. */
+static inline int
+vlan_tci_to_pcp(uint16_t vlan_tci)
+{
+    return (ntohs(vlan_tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
+}
+
 #define VLAN_HEADER_LEN 4
 struct vlan_header {
     uint16_t vlan_tci;          /* Lowest 12 bits are VLAN ID. */
diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c
index f8ff496..0fb26a6 100644
--- a/ofproto/ofproto-sflow.c
+++ b/ofproto/ofproto-sflow.c
@@ -25,6 +25,7 @@
 #include "netdev.h"
 #include "ofpbuf.h"
 #include "ofproto.h"
+#include "packets.h"
 #include "poll-loop.h"
 #include "port-array.h"
 #include "sflow_api.h"
@@ -547,12 +548,13 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
             n_outputs++;
             break;
 
-        case ODPAT_SET_VLAN_VID:
-            switchElem.flowType.sw.dst_vlan = ntohs(a->vlan_vid.vlan_vid);
-            break;
-
-        case ODPAT_SET_VLAN_PCP:
-            switchElem.flowType.sw.dst_priority = a->vlan_pcp.vlan_pcp;
+        case ODPAT_SET_DL_TCI:
+            if (a->dl_tci.mask & htons(VLAN_VID_MASK)) {
+                switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(a->dl_tci.tci);
+            }
+            if (a->dl_tci.mask & htons(VLAN_PCP_MASK)) {
+                switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(a->dl_tci.tci);
+            }
             break;
 
         default:
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 4e209f0..6b4f4a0 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2681,13 +2681,16 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             break;
 
         case OFPAT_SET_VLAN_VID:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_VID);
-            ctx->flow.dl_vlan = oa->vlan_vid.vlan_vid = ia->vlan_vid.vlan_vid;
+            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
+            oa->dl_tci.tci = ia->vlan_vid.vlan_vid & htons(VLAN_VID_MASK);
+            oa->dl_tci.mask = htons(VLAN_VID_MASK);
             break;
 
         case OFPAT_SET_VLAN_PCP:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_PCP);
-            ctx->flow.dl_vlan_pcp = oa->vlan_pcp.vlan_pcp = ia->vlan_pcp.vlan_pcp;
+            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
+            oa->dl_tci.tci = htons((ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT)
+                                   & VLAN_PCP_MASK);
+            oa->dl_tci.mask = htons(VLAN_PCP_MASK);
             break;
 
         case OFPAT_STRIP_VLAN:
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 9a3be00..f1721e5 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -2226,8 +2226,9 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan,
             if (p->vlan == OFP_VLAN_NONE) {
                 odp_actions_add(actions, ODPAT_STRIP_VLAN);
             } else {
-                a = odp_actions_add(actions, ODPAT_SET_VLAN_VID);
-                a->vlan_vid.vlan_vid = htons(p->vlan);
+                a = odp_actions_add(actions, ODPAT_SET_DL_TCI);
+                a->dl_tci.tci = htons(p->vlan & VLAN_VID_MASK);
+                a->dl_tci.mask = htons(VLAN_VID_MASK);
             }
             cur_vlan = p->vlan;
         }
-- 
1.7.1





More information about the dev mailing list