From: Ben Pfaff Date: Fri, 8 Oct 2010 23:26:21 +0000 (-0700) Subject: datapath: Combine dl_vlan and dl_vlan_pcp. X-Git-Tag: v1.1.0~1012 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=26233bb4615608fd45d89a5abe2e62f4b3d776f7;p=sliver-openvswitch.git datapath: 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. Signed-off-by: Ben Pfaff Acked-by: Jesse Gross --- diff --git a/datapath/actions.c b/datapath/actions.c index 18c4ea114..050e3735c 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 aa563fb6d..e2d005e90 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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; diff --git a/datapath/flow.c b/datapath/flow.c index 1aa6e291b..face40b3c 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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; /* 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 8bc4ac522..f41840748 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 a81226310..0cadc824b 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -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 */ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index daaa12280..aa4fdf830 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -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: diff --git a/lib/odp-util.c b/lib/odp-util.c index 49d9d34d5..16a40ded3 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -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; } diff --git a/lib/packets.h b/lib/packets.h index fb0440717..af028ebfc 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" @@ -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 e5766603e..de9bf8987 100644 --- a/ofproto/ofproto-sflow.c +++ b/ofproto/ofproto-sflow.c @@ -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: diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 1fc48dd6e..341d403d0 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -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: diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 73481ddd6..74ac87efa 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -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; }