ether: add soft vlan encap/decap
authorStephen Hemminger <stephen@networkplumber.org>
Mon, 9 Feb 2015 01:13:54 +0000 (09:13 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 20 Feb 2015 18:18:47 +0000 (19:18 +0100)
It is helpful to allow device drivers that don't support hardware
VLAN stripping to emulate this in software. This allows application
to be device independent.

Avoid discarding shared mbufs. Make a copy in rte_vlan_insert() of any
packet to be tagged that has a reference count > 1.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Changchun Ouyang <changchun.ouyang@intel.com>
Acked-by: Huawei Xie <huawei.xie@intel.com>
lib/librte_ether/rte_ether.h

index 7e7d22c..0797908 100644 (file)
@@ -49,6 +49,8 @@ extern "C" {
 
 #include <rte_memcpy.h>
 #include <rte_random.h>
+#include <rte_mbuf.h>
+#include <rte_byteorder.h>
 
 #define ETHER_ADDR_LEN  6 /**< Length of Ethernet address. */
 #define ETHER_TYPE_LEN  2 /**< Length of Ethernet type field. */
@@ -333,6 +335,80 @@ struct vxlan_hdr {
 #define ETHER_VXLAN_HLEN (sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr))
 /**< VXLAN tunnel header length. */
 
+/**
+ * Extract VLAN tag information into mbuf
+ *
+ * Software version of VLAN stripping
+ *
+ * @param m
+ *   The packet mbuf.
+ * @return
+ *   - 0: Success
+ *   - 1: not a vlan packet
+ */
+static inline int rte_vlan_strip(struct rte_mbuf *m)
+{
+       struct ether_hdr *eh
+                = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+       if (eh->ether_type != rte_cpu_to_be_16(ETHER_TYPE_VLAN))
+               return -1;
+
+       struct vlan_hdr *vh = (struct vlan_hdr *)(eh + 1);
+       m->ol_flags |= PKT_RX_VLAN_PKT;
+       m->vlan_tci = rte_be_to_cpu_16(vh->vlan_tci);
+
+       /* Copy ether header over rather than moving whole packet */
+       memmove(rte_pktmbuf_adj(m, sizeof(struct vlan_hdr)),
+               eh, 2 * ETHER_ADDR_LEN);
+
+       return 0;
+}
+
+/**
+ * Insert VLAN tag into mbuf.
+ *
+ * Software version of VLAN unstripping
+ *
+ * @param m
+ *   The packet mbuf.
+ * @return
+ *   - 0: On success
+ *   -EPERM: mbuf is is shared overwriting would be unsafe
+ *   -ENOSPC: not enough headroom in mbuf
+ */
+static inline int rte_vlan_insert(struct rte_mbuf **m)
+{
+       struct ether_hdr *oh, *nh;
+       struct vlan_hdr *vh;
+
+#ifdef RTE_MBUF_REFCNT
+       /* Can't insert header if mbuf is shared */
+       if (rte_mbuf_refcnt_read(*m) > 1) {
+               struct rte_mbuf *copy;
+
+               copy = rte_pktmbuf_clone(*m, (*m)->pool);
+               if (unlikely(copy == NULL))
+                       return -ENOMEM;
+               rte_pktmbuf_free(*m);
+               *m = copy;
+       }
+#endif
+       oh = rte_pktmbuf_mtod(*m, struct ether_hdr *);
+       nh = (struct ether_hdr *)
+               rte_pktmbuf_prepend(*m, sizeof(struct vlan_hdr));
+       if (nh == NULL)
+               return -ENOSPC;
+
+       memmove(nh, oh, 2 * ETHER_ADDR_LEN);
+       nh->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+
+       vh = (struct vlan_hdr *) (nh + 1);
+       vh->vlan_tci = rte_cpu_to_be_16((*m)->vlan_tci);
+
+       return 0;
+}
+
 #ifdef __cplusplus
 }
 #endif