datapath: Combine dl_vlan and dl_vlan_pcp.
authorBen Pfaff <blp@nicira.com>
Fri, 8 Oct 2010 23:26:21 +0000 (16:26 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 11 Oct 2010 20:31:43 +0000 (13:31 -0700)
This allows eliminating padding from odp_flow_key, although actually doing
that is postponed until the next commit.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
datapath/actions.c
datapath/datapath.c
datapath/flow.c
datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h
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 18c4ea114882c81a07f2ecb72adddaf303d6cd2d..050e3735c6bc59c1d813569f2a19a7c793f81ff1 100644 (file)
@@ -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);
index aa563fb6d43cdca38b814cf63930b59b95f827e6..e2d005e902afae759015b3b0edf994b41c3a3570 100644 (file)
@@ -904,6 +904,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:
@@ -925,14 +927,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 1aa6e291bf903f7fdb690cee1dadf19521d9df67..face40b3c9f4e4da96a0587c005db4ac8fd56502 100644 (file)
@@ -205,8 +205,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));
 }
 
@@ -247,6 +246,8 @@ static __be16 parse_ethertype(struct sk_buff *skb)
  * Ethernet header
  * @in_port: port number on which @skb was received.
  * @key: output flow key
+ * @is_frag: set to 1 if @skb contains an IPv4 fragment, or to 0 if @skb does
+ * not contain an IPv4 packet or if it is not a fragment.
  *
  * The caller must ensure that skb->len >= ETH_HLEN.
  *
@@ -275,7 +276,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);
        *is_frag = false;
 
        /*
index 8bc4ac522e4cf88604630ce3cd1b14b1dc142a85..f418407487d890feb63910f4893207ac052c04a1 100644 (file)
@@ -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 */
index a8122631071fec761b87097ee35952dc036f3938..0cadc824bf38671b9a680f01832e6b87a86f201f 100644 (file)
@@ -203,12 +203,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. */
@@ -216,9 +225,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. */
@@ -248,16 +256,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. */
@@ -291,21 +293,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. */
@@ -349,8 +343,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;
@@ -419,9 +412,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 */
index daaa12280f5ac82e7047ed326d9015e9c880854b..aa4fdf830bf8cc7c14a3cf52c793c5553d26a4f6 100644 (file)
@@ -665,16 +665,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;
@@ -1013,16 +1011,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;
@@ -1032,15 +1030,14 @@ 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 vlan_eth_header tmp;
         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);
@@ -1237,15 +1234,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:
index 49d9d34d5ca133d245f1db25cb18762f929e0ee1..16a40ded3cb39ff5dc2d1e2825cd6e610146a4a6 100644 (file)
@@ -42,10 +42,16 @@ 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 tci(", 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));
+    } else {
+        ds_put_char(ds, '0');
+    }
+    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 +71,27 @@ 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: {
+        int vid = vlan_tci_to_vid(a->dl_tci.tci);
+        int pcp = vlan_tci_to_pcp(a->dl_tci.tci);
+
+        ds_put_cstr(ds, "set_tci(");
+        switch (ntohs(a->dl_tci.mask)) {
+        case VLAN_VID_MASK:
+            ds_put_format(ds, "set_tci(vlan=%d)", vid);
+            break;
+        case VLAN_PCP_MASK:
+            ds_put_format(ds, "set_tci(pcp=%d)", pcp);
+            break;
+        case VLAN_VID_MASK | VLAN_PCP_MASK:
+            ds_put_format(ds, "set_tci(vlan=%d,pcp=%d)", vid, pcp);
+            break;
+        default:
+            ds_put_format(ds, "set_tci(tci=%04"PRIx16",mask=%04"PRIx16")",
+                          ntohs(a->dl_tci.tci), ntohs(a->dl_tci.mask));
+            break;
+        }
+    }
         break;
     case ODPAT_STRIP_VLAN:
         ds_put_format(ds, "strip_vlan");
@@ -161,14 +183,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);
 }
@@ -180,13 +208,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;
 }
index fb044071780624ec8889131e900d3e74251b0873..af028ebfcbe3cc2a859fe622edf02ad6adef443a 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"
@@ -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. */
index e5766603eb267160b7df389fb5de231c5573ca5b..de9bf8987af2e3307f057d38aebd7bedc5e3054f 100644 (file)
@@ -27,6 +27,7 @@
 #include "netdev.h"
 #include "ofpbuf.h"
 #include "ofproto.h"
+#include "packets.h"
 #include "poll-loop.h"
 #include "sflow_api.h"
 #include "socket-util.h"
@@ -573,12 +574,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:
index 1fc48dd6e1605270d6592f9e9348952bdf17b1bd..341d403d08974e3f40a39b9676591c87ecaa941b 100644 (file)
@@ -2757,13 +2757,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:
index 73481ddd6da5bd4f01e27d423dfbda8ce4e142ce..74ac87efa1d85c81b98778c4a1a3699c09719fab 100644 (file)
@@ -2312,8 +2312,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;
         }