please discard this patch. I accidentally sent wrong patch. thanks, Pravin.
On Wed, Sep 7, 2011 at 4:06 PM, Pravin Shelar <pshe...@nicira.com> wrote: > Currently the kernel vlan actions mirror those used by OpenFlow 1.0. i.e. > MODIFY and STRIP. More flexible approach is to have an action to push a > tag and pop a tag off, so that it can handle multiple levels of vlan tags. > Plus it aligns with newer version of OpenFlow. > As this patch replaces MODIFY with PUSH semantic, > action mapping done in userpace is fixed accordingly. > GSO handling for multiple levels of vlan tags is also added as > Jesse suggested before. > > Signed-off-by: Pravin B Shelar <pshe...@nicira.com> > --- > datapath/actions.c | 62 +++++++++++----- > datapath/datapath.c | 8 +- > datapath/linux/compat/include/linux/if_ether.h | 1 + > datapath/linux/compat/include/linux/netdevice.h | 19 +++++ > datapath/linux/compat/netdevice.c | 91 > +++++++++++++++++++++++ > datapath/vport-netdev.c | 10 +-- > include/openvswitch/datapath-protocol.h | 4 +- > lib/bond.c | 2 +- > lib/dpif-netdev.c | 14 ++-- > lib/odp-util.c | 12 ++-- > lib/packets.c | 27 +++---- > lib/packets.h | 2 +- > ofproto/ofproto-dpif-sflow.c | 2 +- > ofproto/ofproto-dpif.c | 17 +++-- > 14 files changed, 200 insertions(+), 71 deletions(-) > > diff --git a/datapath/actions.c b/datapath/actions.c > index 8aec438..0150be2 100644 > --- a/datapath/actions.c > +++ b/datapath/actions.c > @@ -39,20 +39,12 @@ static int make_writable(struct sk_buff *skb, int > write_len) > return pskb_expand_head(skb, 0, 0, GFP_ATOMIC); > } > > -static int strip_vlan(struct sk_buff *skb) > +static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) > { > struct ethhdr *eh; > + struct vlan_ethhdr *veth; > int err; > > - if (vlan_tx_tag_present(skb)) { > - vlan_set_tci(skb, 0); > - return 0; > - } > - > - if (unlikely(skb->protocol != htons(ETH_P_8021Q) || > - skb->len < VLAN_ETH_HLEN)) > - return 0; > - > err = make_writable(skb, VLAN_ETH_HLEN); > if (unlikely(err)) > return err; > @@ -61,6 +53,9 @@ static int strip_vlan(struct sk_buff *skb) > skb->csum = csum_sub(skb->csum, csum_partial(skb->data > + ETH_HLEN, VLAN_HLEN, 0)); > > + veth = (struct vlan_ethhdr *) skb->data; > + *current_tci = veth->h_vlan_TCI; > + > memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); > > eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); > @@ -71,21 +66,46 @@ static int strip_vlan(struct sk_buff *skb) > return 0; > } > > -static int modify_vlan_tci(struct sk_buff *skb, __be16 tci) > +static int pop_vlan(struct sk_buff *skb) > { > - if (!vlan_tx_tag_present(skb) && skb->protocol == htons(ETH_P_8021Q)) > { > - int err; > + __be16 tci; > + int err; > > - if (unlikely(skb->len < VLAN_ETH_HLEN)) > + if (likely(vlan_tx_tag_present(skb))) { > + vlan_set_tci(skb, 0); > + } else { > + if (unlikely(skb->protocol != htons(ETH_P_8021Q) || > + skb->len < VLAN_ETH_HLEN)) > return 0; > > - err = strip_vlan(skb); > - if (unlikely(err)) > + err = __pop_vlan_tci(skb, &tci); > + if (err) > return err; > } > + /* move next vlan tag to hw accel tag */ > + if (likely(skb->protocol != htons(ETH_P_8021Q) || > + skb->len < VLAN_ETH_HLEN)) > + return 0; > + > + err = __pop_vlan_tci(skb, &tci); > + if (unlikely(err)) > + return err; > > __vlan_hwaccel_put_tag(skb, ntohs(tci)); > + return 0; > +} > + > +static int push_vlan(struct sk_buff *skb, __be16 new_tci) > +{ > + if (unlikely(vlan_tx_tag_present(skb))) { > + u16 current_tag; > > + current_tag = vlan_tx_tag_get(skb); > + > + if (!__vlan_put_tag(skb, current_tag)) > + return -ENOMEM; > + } > + __vlan_hwaccel_put_tag(skb, ntohs(new_tci)); > return 0; > } > > @@ -270,12 +290,14 @@ static int do_execute_actions(struct datapath *dp, > struct sk_buff *skb, > OVS_CB(skb)->tun_id = nla_get_be64(a); > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > - err = modify_vlan_tci(skb, nla_get_be16(a)); > + case OVS_ACTION_ATTR_PUSH_VLAN: > + err = push_vlan(skb, nla_get_be16(a)); > + if (unlikely(err)) /* skb already freed */ > + return err; > break; > > - case OVS_ACTION_ATTR_STRIP_VLAN: > - err = strip_vlan(skb); > + case OVS_ACTION_ATTR_POP_VLAN: > + err = pop_vlan(skb); > break; > > case OVS_ACTION_ATTR_SET_DL_SRC: > diff --git a/datapath/datapath.c b/datapath/datapath.c > index 0b6e2e5..ab800a7 100644 > --- a/datapath/datapath.c > +++ b/datapath/datapath.c > @@ -553,8 +553,8 @@ static int validate_actions(const struct nlattr *attr) > static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { > [OVS_ACTION_ATTR_OUTPUT] = 4, > [OVS_ACTION_ATTR_USERSPACE] = 8, > - [OVS_ACTION_ATTR_SET_DL_TCI] = 2, > - [OVS_ACTION_ATTR_STRIP_VLAN] = 0, > + [OVS_ACTION_ATTR_PUSH_VLAN] = 2, > + [OVS_ACTION_ATTR_POP_VLAN] = 0, > [OVS_ACTION_ATTR_SET_DL_SRC] = ETH_ALEN, > [OVS_ACTION_ATTR_SET_DL_DST] = ETH_ALEN, > [OVS_ACTION_ATTR_SET_NW_SRC] = 4, > @@ -576,7 +576,7 @@ static int validate_actions(const struct nlattr *attr) > return -EINVAL; > > case OVS_ACTION_ATTR_USERSPACE: > - case OVS_ACTION_ATTR_STRIP_VLAN: > + case OVS_ACTION_ATTR_POP_VLAN: > case OVS_ACTION_ATTR_SET_DL_SRC: > case OVS_ACTION_ATTR_SET_DL_DST: > case OVS_ACTION_ATTR_SET_NW_SRC: > @@ -594,7 +594,7 @@ static int validate_actions(const struct nlattr *attr) > return -EINVAL; > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > + case OVS_ACTION_ATTR_PUSH_VLAN: > if (nla_get_be16(a) & htons(VLAN_CFI_MASK)) > return -EINVAL; > break; > diff --git a/datapath/linux/compat/include/linux/if_ether.h > b/datapath/linux/compat/include/linux/if_ether.h > index b8390e2..75ab82c 100644 > --- a/datapath/linux/compat/include/linux/if_ether.h > +++ b/datapath/linux/compat/include/linux/if_ether.h > @@ -7,6 +7,7 @@ > #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) > > #define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ > +#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ > > #endif /* linux kernel < 2.6.28 */ > > diff --git a/datapath/linux/compat/include/linux/netdevice.h > b/datapath/linux/compat/include/linux/netdevice.h > index 04ebd89..c083477 100644 > --- a/datapath/linux/compat/include/linux/netdevice.h > +++ b/datapath/linux/compat/include/linux/netdevice.h > @@ -141,4 +141,23 @@ static inline struct net_device > *dev_get_by_index_rcu(struct net *net, int ifind > #define NETIF_F_FSO 0 > #endif > > +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) > +#define NETIF_F_FCOE_CRC (1 << 24) /* FCoE CRC32 */ > +#endif > + > +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) > +#define skb_gso_segment rpl_skb_gso_segment > +struct sk_buff *rpl_skb_gso_segment(struct sk_buff *skb, u32 features); > + > +#define netif_skb_features rpl_netif_skb_features > +u32 rpl_netif_skb_features(struct sk_buff *skb); > + > +#define netif_needs_gso rpl_netif_needs_gso > +static inline int rpl_netif_needs_gso(struct sk_buff *skb, int features) > +{ > + return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || > + unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); > +} > +#endif > + > #endif > diff --git a/datapath/linux/compat/netdevice.c > b/datapath/linux/compat/netdevice.c > index 1a6f327..a06da0c 100644 > --- a/datapath/linux/compat/netdevice.c > +++ b/datapath/linux/compat/netdevice.c > @@ -1,5 +1,7 @@ > #include <linux/if_link.h> > #include <linux/netdevice.h> > +#include <linux/if_vlan.h> > + > > /* Linux 2.6.28 introduced dev_get_stats(): > * const struct net_device_stats *dev_get_stats(struct net_device *dev); > @@ -46,4 +48,93 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device > *dev, > > return storage; > } > + > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) > +static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) > +{ > +#ifdef CONFIG_HIGHMEM > + int i; > + if (!(dev->features & NETIF_F_HIGHDMA)) { > + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) > + if (PageHighMem(skb_shinfo(skb)->frags[i].page)) > + return 1; > + } > +#endif > + return 0; > +} > + > +static bool can_checksum_protocol(unsigned long features, __be16 protocol) > +{ > + return ((features & NETIF_F_GEN_CSUM) || > + ((features & NETIF_F_V4_CSUM) && > + protocol == htons(ETH_P_IP)) || > + ((features & NETIF_F_V6_CSUM) && > + protocol == htons(ETH_P_IPV6)) || > + ((features & NETIF_F_FCOE_CRC) && > + protocol == htons(ETH_P_FCOE))); > +} > + > +static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 > features) > +{ > + if (!can_checksum_protocol(features, protocol)) { > + features &= ~NETIF_F_ALL_CSUM; > + features &= ~NETIF_F_SG; > + } else if (illegal_highdma(skb->dev, skb)) { > + features &= ~NETIF_F_SG; > + } > + > + return features; > +} > +#endif > + > +u32 rpl_netif_skb_features(struct sk_buff *skb) > +{ > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) > + __be16 protocol = skb->protocol; > + u32 features = skb->dev->features; > + > + if (protocol == htons(ETH_P_8021Q)) { > + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; > + protocol = veh->h_vlan_encapsulated_proto; > + } else if (!vlan_tx_tag_present(skb)) { > + return harmonize_features(skb, protocol, features); > + } > + > + features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX); > + > + if (protocol != htons(ETH_P_8021Q)) { > + return harmonize_features(skb, protocol, features); > + } else { > + features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | > + NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX; > + return harmonize_features(skb, protocol, features); > + } > +#else > + return 0; > +#endif > +} > + > +struct sk_buff *rpl_skb_gso_segment(struct sk_buff *skb, u32 features) > +{ > + int vlan_depth = ETH_HLEN; > + __be16 type = skb->protocol; > + > + while (type == htons(ETH_P_8021Q)) { > + struct vlan_hdr *vh; > + > + if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) > + return ERR_PTR(-EINVAL); > + > + vh = (struct vlan_hdr *)(skb->data + vlan_depth); > + type = vh->h_vlan_encapsulated_proto; > + vlan_depth += VLAN_HLEN; > + } > + > + /* this hack needed to get regular skb_gso_segment() */ > +#undef skb_gso_segment > + skb->protocol = type; > + > + return skb_gso_segment(skb, features); > +} > + > #endif /* kernel version < 2.6.36 */ > diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c > index f1e9b09..4163506 100644 > --- a/datapath/vport-netdev.c > +++ b/datapath/vport-netdev.c > @@ -316,19 +316,15 @@ static int netdev_send(struct vport *vport, struct > sk_buff *skb) > forward_ip_summed(skb, true); > > if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) { > - int features = 0; > + int features; > > -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) > - features = skb->dev->features & skb->dev->vlan_features; > -#endif > + features = netif_skb_features(skb); > > if (!vlan_tso) > features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | > NETIF_F_UFO | NETIF_F_FSO); > > - if (skb_is_gso(skb) && > - (!skb_gso_ok(skb, features) || > - unlikely(skb->ip_summed != CHECKSUM_PARTIAL))) { > + if (netif_needs_gso(skb, features)) { > struct sk_buff *nskb; > > nskb = skb_gso_segment(skb, features); > diff --git a/include/openvswitch/datapath-protocol.h > b/include/openvswitch/datapath-protocol.h > index 535aab3..522c532 100644 > --- a/include/openvswitch/datapath-protocol.h > +++ b/include/openvswitch/datapath-protocol.h > @@ -412,8 +412,8 @@ enum ovs_action_type { > OVS_ACTION_ATTR_UNSPEC, > OVS_ACTION_ATTR_OUTPUT, /* Output to switch port. */ > OVS_ACTION_ATTR_USERSPACE, /* Send copy to userspace. */ > - OVS_ACTION_ATTR_SET_DL_TCI, /* Set the 802.1q TCI value. */ > - OVS_ACTION_ATTR_STRIP_VLAN, /* Strip the 802.1q header. */ > + OVS_ACTION_ATTR_PUSH_VLAN, /* Set the 802.1q TCI value. */ > + OVS_ACTION_ATTR_POP_VLAN, /* Strip the 802.1q header. */ > OVS_ACTION_ATTR_SET_DL_SRC, /* Ethernet source address. */ > OVS_ACTION_ATTR_SET_DL_DST, /* Ethernet destination address. */ > OVS_ACTION_ATTR_SET_NW_SRC, /* IPv4 source address. */ > diff --git a/lib/bond.c b/lib/bond.c > index ae914dd..5b984fb 100644 > --- a/lib/bond.c > +++ b/lib/bond.c > @@ -532,7 +532,7 @@ bond_send_learning_packet(struct bond *bond, > compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177, > eth_src); > if (vlan) { > - eth_set_vlan_tci(&packet, htons(vlan)); > + eth_push_vlan(&packet, htons(vlan)); > } > error = netdev_send(slave->netdev, &packet); > ofpbuf_uninit(&packet); > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index d0a50f3..2723c68 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -712,7 +712,7 @@ dpif_netdev_validate_actions(const struct nlattr *actions, > case OVS_ACTION_ATTR_USERSPACE: > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > + case OVS_ACTION_ATTR_PUSH_VLAN: > *mutates = true; > if (nl_attr_get_be16(a) & htons(VLAN_CFI)) { > return EINVAL; > @@ -726,7 +726,7 @@ dpif_netdev_validate_actions(const struct nlattr *actions, > } > break; > > - case OVS_ACTION_ATTR_STRIP_VLAN: > + case OVS_ACTION_ATTR_POP_VLAN: > case OVS_ACTION_ATTR_SET_DL_SRC: > case OVS_ACTION_ATTR_SET_DL_DST: > case OVS_ACTION_ATTR_SET_NW_SRC: > @@ -1134,7 +1134,7 @@ dpif_netdev_wait(struct dpif *dpif) > } > > static void > -dp_netdev_strip_vlan(struct ofpbuf *packet) > +dp_netdev_pop_vlan(struct ofpbuf *packet) > { > struct vlan_eth_header *veh = packet->l2; > if (packet->size >= sizeof *veh > @@ -1306,12 +1306,12 @@ dp_netdev_execute_actions(struct dp_netdev *dp, > key, nl_attr_get_u64(a)); > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > - eth_set_vlan_tci(packet, nl_attr_get_be16(a)); > + case OVS_ACTION_ATTR_PUSH_VLAN: > + eth_push_vlan(packet, nl_attr_get_be16(a)); > break; > > - case OVS_ACTION_ATTR_STRIP_VLAN: > - dp_netdev_strip_vlan(packet); > + case OVS_ACTION_ATTR_POP_VLAN: > + dp_netdev_pop_vlan(packet); > break; > > case OVS_ACTION_ATTR_SET_DL_SRC: > diff --git a/lib/odp-util.c b/lib/odp-util.c > index 2830fe8..82d668a 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -49,8 +49,8 @@ odp_action_len(uint16_t type) > switch ((enum ovs_action_type) type) { > case OVS_ACTION_ATTR_OUTPUT: return 4; > case OVS_ACTION_ATTR_USERSPACE: return 8; > - case OVS_ACTION_ATTR_SET_DL_TCI: return 2; > - case OVS_ACTION_ATTR_STRIP_VLAN: return 0; > + case OVS_ACTION_ATTR_PUSH_VLAN: return 2; > + case OVS_ACTION_ATTR_POP_VLAN: return 0; > case OVS_ACTION_ATTR_SET_DL_SRC: return ETH_ADDR_LEN; > case OVS_ACTION_ATTR_SET_DL_DST: return ETH_ADDR_LEN; > case OVS_ACTION_ATTR_SET_NW_SRC: return 4; > @@ -113,13 +113,13 @@ format_odp_action(struct ds *ds, const struct nlattr *a) > ds_put_format(ds, "set_tunnel(%#"PRIx64")", > ntohll(nl_attr_get_be64(a))); > break; > - case OVS_ACTION_ATTR_SET_DL_TCI: > - ds_put_format(ds, "set_tci(vid=%"PRIu16",pcp=%d)", > + case OVS_ACTION_ATTR_PUSH_VLAN: > + ds_put_format(ds, "push_vlan(vid=%"PRIu16",pcp=%d)", > vlan_tci_to_vid(nl_attr_get_be16(a)), > vlan_tci_to_pcp(nl_attr_get_be16(a))); > break; > - case OVS_ACTION_ATTR_STRIP_VLAN: > - ds_put_format(ds, "strip_vlan"); > + case OVS_ACTION_ATTR_POP_VLAN: > + ds_put_format(ds, "pop_vlan"); > break; > case OVS_ACTION_ATTR_SET_DL_SRC: > eth = nl_attr_get_unspec(a, ETH_ADDR_LEN); > diff --git a/lib/packets.c b/lib/packets.c > index e05e3eb..da228f0 100644 > --- a/lib/packets.c > +++ b/lib/packets.c > @@ -81,27 +81,22 @@ compose_benign_packet(struct ofpbuf *b, const char *tag, > uint16_t snap_type, > * > * Also sets 'packet->l2' to point to the new Ethernet header. */ > void > -eth_set_vlan_tci(struct ofpbuf *packet, ovs_be16 tci) > +eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci) > { > struct eth_header *eh = packet->data; > struct vlan_eth_header *veh; > > - if (packet->size >= sizeof(struct vlan_eth_header) > - && eh->eth_type == htons(ETH_TYPE_VLAN)) { > - veh = packet->data; > - veh->veth_tci = 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 = tci; > - tmp.veth_next_type = eh->eth_type; > - > - veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN); > - memcpy(veh, &tmp, sizeof tmp); > - } > + /* 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 = tci; > + tmp.veth_next_type = eh->eth_type; > + > + veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN); > + memcpy(veh, &tmp, sizeof tmp); > + > packet->l2 = packet->data; > } > > diff --git a/lib/packets.h b/lib/packets.h > index a389e6a..cb12638 100644 > --- a/lib/packets.h > +++ b/lib/packets.h > @@ -131,7 +131,7 @@ void compose_benign_packet(struct ofpbuf *, const char > *tag, > uint16_t snap_type, > const uint8_t eth_src[ETH_ADDR_LEN]); > > -void eth_set_vlan_tci(struct ofpbuf *, ovs_be16 tci); > +void eth_push_vlan(struct ofpbuf *, ovs_be16 tci); > > /* Example: > * > diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c > index d41b7da..21ef799 100644 > --- a/ofproto/ofproto-dpif-sflow.c > +++ b/ofproto/ofproto-dpif-sflow.c > @@ -538,7 +538,7 @@ dpif_sflow_received(struct dpif_sflow *ds, const struct > dpif_upcall *upcall, > n_outputs++; > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > + case OVS_ACTION_ATTR_PUSH_VLAN: > tci = nl_attr_get_be16(a); > switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(tci); > switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(tci); > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index f09c230..7913cd7 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -2272,11 +2272,11 @@ facet_account(struct ofproto_dpif *ofproto, struct > facet *facet) > } > break; > > - case OVS_ACTION_ATTR_STRIP_VLAN: > + case OVS_ACTION_ATTR_POP_VLAN: > vlan_tci = htons(0); > break; > > - case OVS_ACTION_ATTR_SET_DL_TCI: > + case OVS_ACTION_ATTR_PUSH_VLAN: > vlan_tci = nl_attr_get_be16(a); > break; > } > @@ -2840,9 +2840,11 @@ commit_odp_actions(struct action_xlate_ctx *ctx) > > if (base->vlan_tci != flow->vlan_tci) { > if (!(flow->vlan_tci & htons(VLAN_CFI))) { > - nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_STRIP_VLAN); > + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN); > } else { > - nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_SET_DL_TCI, > + if (base->vlan_tci != OFP_VLAN_NONE) > + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN); > + nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN, > flow->vlan_tci & ~htons(VLAN_CFI)); > } > base->vlan_tci = flow->vlan_tci; > @@ -3639,13 +3641,16 @@ compose_actions(struct action_xlate_ctx *ctx, > uint16_t vlan, > } > if (dst->vlan != cur_vlan) { > if (dst->vlan == OFP_VLAN_NONE) { > - nl_msg_put_flag(ctx->odp_actions, > OVS_ACTION_ATTR_STRIP_VLAN); > + nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_POP_VLAN); > } else { > ovs_be16 tci; > + > + if (cur_vlan != OFP_VLAN_NONE) > + nl_msg_put_flag(ctx->odp_actions, > OVS_ACTION_ATTR_POP_VLAN); > tci = htons(dst->vlan & VLAN_VID_MASK); > tci |= ctx->flow.vlan_tci & htons(VLAN_PCP_MASK); > nl_msg_put_be16(ctx->odp_actions, > - OVS_ACTION_ATTR_SET_DL_TCI, tci); > + OVS_ACTION_ATTR_PUSH_VLAN, tci); > } > cur_vlan = dst->vlan; > } > -- > 1.7.1 > > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev