From: Ben Pfaff Date: Thu, 1 Apr 2010 22:51:53 +0000 (-0700) Subject: Combine dl_vlan and dl_vlan_pcp. X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=04c46f4ad03d05491b72f7b1ae6196b515c45901;p=sliver-openvswitch.git Combine dl_vlan and dl_vlan_pcp. This allows eliminating padding from odp_flow_key, although actually doing that is postponed until the next commit. --- diff --git a/datapath/actions.c b/datapath/actions.c index bef7d108c..d8b6691e8 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -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); diff --git a/datapath/datapath.c b/datapath/datapath.c index 6365f9474..db374ada0 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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; diff --git a/datapath/flow.c b/datapath/flow.c index 9a94d0ba8..62eed5d35 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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); diff --git a/datapath/linux-2.6/Modules.mk b/datapath/linux-2.6/Modules.mk index 70931d862..7d4fcd042 100644 --- a/datapath/linux-2.6/Modules.mk +++ b/datapath/linux-2.6/Modules.mk @@ -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 index 000000000..63d25ae55 --- /dev/null +++ b/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_IF_VLAN_WRAPPER_H +#define __LINUX_IF_VLAN_WRAPPER_H 1 + +#include_next + +/* 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 diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index 6c5354548..18e1105da 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -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 */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index ab8910a11..da82b9d45 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -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); diff --git a/lib/odp-util.c b/lib/odp-util.c index 09d067cca..aeeda3b47 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -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; } diff --git a/lib/packets.h b/lib/packets.h index 7ea462bcf..8d59bd27c 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -18,6 +18,8 @@ #define PACKETS_H 1 #include +#include +#include #include #include #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. */ diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c index 45372003d..cd216eab2 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" @@ -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: diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index a9df90ef2..e868e9227 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -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: diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 130e09493..e5dab8474 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -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; }