Combine dl_vlan and dl_vlan_pcp.
authorBen Pfaff <blp@nicira.com>
Thu, 1 Apr 2010 22:51:53 +0000 (15:51 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 1 Apr 2010 22:51:53 +0000 (15:51 -0700)
This allows eliminating padding from odp_flow_key, although actually doing
that is postponed until the next commit.

12 files changed:
datapath/actions.c
datapath/datapath.c
datapath/flow.c
datapath/linux-2.6/Modules.mk
datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h [new file with mode: 0644]
include/openvswitch/datapath-protocol.h
lib/dpif-netdev.c
lib/odp-util.c
lib/packets.h
ofproto/ofproto-sflow.c
ofproto/ofproto.c
vswitchd/bridge.c

index bef7d10..d8b6691 100644 (file)
@@ -89,17 +89,10 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                struct odp_flow_key *key, const union odp_action *a,
                int n_actions, gfp_t gfp)
 {
-       u16 tci, mask;
+       __be16 mask = a->dl_tci.mask;
+       __be16 tci = a->dl_tci.tci;
 
-       if (a->type == ODPAT_SET_VLAN_VID) {
-               tci = ntohs(a->vlan_vid.vlan_vid);
-               mask = VLAN_VID_MASK;
-               key->dl_vlan = a->vlan_vid.vlan_vid;
-       } else {
-               tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
-               mask = VLAN_PCP_MASK;
-               key->dl_vlan_pcp = a->vlan_pcp.vlan_pcp;
-       }
+       key->dl_tci = (key->dl_tci & ~(mask | VLAN_TAG_PRESENT)) | tci;
 
        skb = make_writable(skb, VLAN_HLEN, gfp);
        if (!skb)
@@ -110,7 +103,7 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                struct vlan_ethhdr *vh = vlan_eth_hdr(skb);
                __be16 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 };
@@ -160,7 +153,7 @@ 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) {
                                        struct odp_flow_key segkey = *key;
@@ -191,7 +184,7 @@ 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);
 
@@ -211,7 +204,7 @@ static struct sk_buff *strip_vlan(struct sk_buff *skb,
        skb = make_writable(skb, 0, gfp);
        if (skb) {
                vlan_pull_tag(skb);
-               key->dl_vlan = htons(ODP_VLAN_NONE);
+               key->dl_tci = htons(0);
        }
        return skb;
 }
@@ -502,8 +495,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                        }
                        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);
index 6365f94..db374ad 100644 (file)
@@ -909,6 +909,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_OUTPUT:
                        if (a->output.port >= DP_MAX_PORTS)
@@ -920,14 +922,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;
 
index 9a94d0b..62eed5d 100644 (file)
@@ -202,7 +202,6 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
        int nh_ofs;
 
        memset(key, 0, sizeof *key);
-       key->dl_vlan = htons(ODP_VLAN_NONE);
        key->in_port = in_port;
 
        if (skb->len < sizeof *eth)
@@ -232,8 +231,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
            skb->len >= nh_ofs + sizeof(struct vlan_hdr)) {
                struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs);
                key->dl_type = vh->h_vlan_encapsulated_proto;
-               key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK);
-               key->dl_vlan_pcp = (ntohs(vh->h_vlan_TCI) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
+               key->dl_tci = vh->h_vlan_TCI | htons(ODP_TCI_PRESENT);
                nh_ofs += sizeof(struct vlan_hdr);
        }
        memcpy(key->dl_src, eth->h_source, ETH_ALEN);
index 70931d8..7d4fcd0 100644 (file)
@@ -11,6 +11,7 @@ openvswitch_headers += \
        linux-2.6/compat-2.6/include/linux/err.h \
        linux-2.6/compat-2.6/include/linux/icmp.h \
        linux-2.6/compat-2.6/include/linux/if_arp.h \
+       linux-2.6/compat-2.6/include/linux/if_vlan.h \
        linux-2.6/compat-2.6/include/linux/ip.h \
        linux-2.6/compat-2.6/include/linux/ipv6.h \
        linux-2.6/compat-2.6/include/linux/jiffies.h \
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
new file mode 100644 (file)
index 0000000..63d25ae
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __LINUX_IF_VLAN_WRAPPER_H
+#define __LINUX_IF_VLAN_WRAPPER_H 1
+
+#include_next <linux/if_vlan.h>
+
+/* 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
index 6c53545..18e1105 100644 (file)
@@ -190,21 +190,28 @@ struct odp_flow_stats {
     __u16 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 {
     __be32 nw_src;               /* IP source address. */
     __be32 nw_dst;               /* IP destination address. */
     __u16  in_port;              /* Input switch port. */
-    __be16 dl_vlan;              /* Input VLAN. */
+    __be16 dl_tci;               /* All zeros if 802.1Q header absent,
+                                  * ODP_TCI_PRESENT set if present. */
     __be16 dl_type;              /* Ethernet frame type. */
     __be16 tp_src;               /* TCP/UDP source port. */
     __be16 tp_dst;               /* TCP/UDP destination port. */
     __u8   dl_src[ETH_ALEN];     /* Ethernet source address. */
     __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
-    __u8   nw_proto;             /* IP protocol or lower 8 bits of 
-                                    ARP opcode. */
-    __u8   dl_vlan_pcp;          /* Input VLAN priority. */
+    __u8   nw_proto;             /* IP protocol or low 8 bits of ARP opcode. */
     __u8   nw_tos;               /* IP ToS (DSCP field, 6 bits). */
-    __u8   reserved[3];          /* Align to 32-bits...must be zeroed. */
+    __u32  reserved[1];          /* Reserved for later use. */
 };
 
 /* Flags for ODP_FLOW. */
@@ -234,17 +241,11 @@ struct odp_flowvec {
     int 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_OUTPUT_GROUP      1    /* Output to all ports in group. */
 #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. */
@@ -275,21 +276,13 @@ struct odp_action_controller {
     __u32 arg;                  /* Copied to struct odp_msg 'arg' member. */
 };
 
-/* Action structure for ODPAT_SET_VLAN_VID. */
-struct odp_action_vlan_vid {
-    __u16 type;                  /* ODPAT_SET_VLAN_VID. */
-    __be16 vlan_vid;             /* VLAN id. */
-    __u16 reserved1;
-    __u16 reserved2;
-};
-
-/* Action structure for ODPAT_SET_VLAN_PCP. */
-struct odp_action_vlan_pcp {
-    __u16 type;                  /* ODPAT_SET_VLAN_PCP. */
-    __u8 vlan_pcp;               /* VLAN priority. */
-    __u8 reserved1;
-    __u16 reserved2;
-    __u16 reserved3;
+/* Action structure for ODPAT_SET_DL_TCI. */
+struct odp_action_dl_tci {
+    __u16 type;                  /* ODPAT_SET_DL_TCI. */
+    __be16 tci;                  /* New TCI.  Bits not in mask must be zero. */
+    __be16 mask;                 /* 0x0fff to set VID, 0xe000 to set PCP,
+                                    or 0xefff to set both. */
+    __u16 reserved;
 };
 
 /* Action structure for ODPAT_SET_DL_SRC/DST. */
@@ -326,8 +319,7 @@ union odp_action {
     struct odp_action_output output;
     struct odp_action_output_group output_group;
     struct odp_action_controller controller;
-    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;
@@ -357,9 +349,4 @@ struct odp_execute {
  */
 #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 */
index ab8910a..da82b9d 100644 (file)
@@ -664,6 +664,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)) {
@@ -742,16 +744,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;
@@ -1092,25 +1092,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.
- *
- * Note that the function does not ensure that 'tci' does not affect
- * bits outside of 'mask'.
- */
+/* Modify or add a 802.1Q header in 'packet' according to 'a'. */
 static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, struct odp_flow_key *key,
-                          uint16_t tci, uint16_t mask)
+dp_netdev_set_dl_tci(struct ofpbuf *packet, struct odp_flow_key *key,
+                     const struct odp_action_dl_tci *a)
 {
     struct vlan_eth_header *veh;
 
-    if (key->dl_vlan != htons(ODP_VLAN_NONE)) {
-        /* Clear 'mask' bits, but maintain other TCI bits. */
+    if (key->dl_tci) {
         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;
@@ -1118,7 +1109,7 @@ dp_netdev_modify_vlan_tci(struct ofpbuf *packet, struct odp_flow_key *key,
         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);
@@ -1126,7 +1117,7 @@ dp_netdev_modify_vlan_tci(struct ofpbuf *packet, struct odp_flow_key *key,
         packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
     }
 
-    key->dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK);
+    key->dl_tci = veh->veth_tci | htons(ODP_TCI_PRESENT);
 }
 
 static void
@@ -1145,7 +1136,7 @@ dp_netdev_strip_vlan(struct ofpbuf *packet, struct odp_flow_key *key)
         packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
         memcpy(packet->data, &tmp, sizeof tmp);
 
-        key->dl_vlan = htons(ODP_VLAN_NONE);
+        key->dl_tci = htons(0);
     }
 }
 
@@ -1321,16 +1312,9 @@ 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, key, ntohs(a->vlan_vid.vlan_vid),
-                                      VLAN_VID_MASK);
-             break;
-
-               case ODPAT_SET_VLAN_PCP:
-                       dp_netdev_modify_vlan_tci(
-                 packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
-                 VLAN_PCP_MASK);
-              break;
+        case ODPAT_SET_DL_TCI:
+            dp_netdev_set_dl_tci(packet, key, &a->dl_tci);
+            break;
 
         case ODPAT_STRIP_VLAN:
             dp_netdev_strip_vlan(packet, key);
index 09d067c..aeeda3b 100644 (file)
@@ -45,10 +45,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),
@@ -68,11 +72,9 @@ format_odp_action(struct ds *ds, const union odp_action *a)
     case ODPAT_CONTROLLER:
         ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
         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");
@@ -154,14 +156,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_ALEN);
     memcpy(key->dl_dst, flow->dl_dst, ETH_ALEN);
     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);
 }
@@ -172,13 +180,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_ALEN);
     memcpy(flow->dl_dst, key->dl_dst, ETH_ALEN);
     flow->nw_proto = key->nw_proto;
-    flow->dl_vlan_pcp = key->dl_vlan_pcp;
     flow->nw_tos = key->nw_tos;
 }
index 7ea462b..8d59bd2 100644 (file)
@@ -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"
@@ -195,6 +197,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. */
index 4537200..cd216ea 100644 (file)
@@ -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"
@@ -550,12 +551,13 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
                           : 0);
             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:
index a9df90e..e868e92 100644 (file)
@@ -2180,13 +2180,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);
-            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);
-            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:
index 130e094..e5dab84 100644 (file)
@@ -2078,8 +2078,9 @@ compose_actions(struct bridge *br, const flow_t *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;
         }