DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 01/12] virtio: move device initialization in a function
From: Olivier Matz @ 2016-10-03  9:00 UTC (permalink / raw)
  To: dev, yuanhan.liu
  Cc: konstantin.ananyev, sugesh.chandran, bruce.richardson,
	jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
	xiao.w.wang
In-Reply-To: <1475485223-30566-1-git-send-email-olivier.matz@6wind.com>

Move all code related to device initialization in a new function
virtio_init_device().

This commit brings no functional change, it prepares the next commits
that will add the offload support. For that, it will be needed to
reinitialize the device from ethdev->configure(), using this new
function.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 drivers/net/virtio/virtio_ethdev.c | 99 ++++++++++++++++++++++----------------
 1 file changed, 58 insertions(+), 41 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index ef0d6ee..21ed945 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1118,46 +1118,13 @@ rx_func_get(struct rte_eth_dev *eth_dev)
 		eth_dev->rx_pkt_burst = &virtio_recv_pkts;
 }
 
-/*
- * This function is based on probe() function in virtio_pci.c
- * It returns 0 on success.
- */
-int
-eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
+static int
+virtio_init_device(struct rte_eth_dev *eth_dev)
 {
 	struct virtio_hw *hw = eth_dev->data->dev_private;
 	struct virtio_net_config *config;
 	struct virtio_net_config local_config;
-	struct rte_pci_device *pci_dev;
-	uint32_t dev_flags = RTE_ETH_DEV_DETACHABLE;
-	int ret;
-
-	RTE_BUILD_BUG_ON(RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr_mrg_rxbuf));
-
-	eth_dev->dev_ops = &virtio_eth_dev_ops;
-	eth_dev->tx_pkt_burst = &virtio_xmit_pkts;
-
-	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
-		rx_func_get(eth_dev);
-		return 0;
-	}
-
-	/* Allocate memory for storing MAC addresses */
-	eth_dev->data->mac_addrs = rte_zmalloc("virtio", VIRTIO_MAX_MAC_ADDRS * ETHER_ADDR_LEN, 0);
-	if (eth_dev->data->mac_addrs == NULL) {
-		PMD_INIT_LOG(ERR,
-			"Failed to allocate %d bytes needed to store MAC addresses",
-			VIRTIO_MAX_MAC_ADDRS * ETHER_ADDR_LEN);
-		return -ENOMEM;
-	}
-
-	pci_dev = eth_dev->pci_dev;
-
-	if (pci_dev) {
-		ret = vtpci_init(pci_dev, hw, &dev_flags);
-		if (ret)
-			return ret;
-	}
+	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
 
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
@@ -1172,10 +1139,11 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
-		dev_flags &= ~RTE_ETH_DEV_INTR_LSC;
+		eth_dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC;
+	else
+		eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
-	eth_dev->data->dev_flags = dev_flags;
 
 	rx_func_get(eth_dev);
 
@@ -1254,12 +1222,61 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 			eth_dev->data->port_id, pci_dev->id.vendor_id,
 			pci_dev->id.device_id);
 
+	virtio_dev_cq_start(eth_dev);
+
+	return 0;
+}
+
+/*
+ * This function is based on probe() function in virtio_pci.c
+ * It returns 0 on success.
+ */
+int
+eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct virtio_hw *hw = eth_dev->data->dev_private;
+	struct rte_pci_device *pci_dev;
+	uint32_t dev_flags = RTE_ETH_DEV_DETACHABLE;
+	int ret;
+
+	RTE_BUILD_BUG_ON(RTE_PKTMBUF_HEADROOM < sizeof(struct virtio_net_hdr_mrg_rxbuf));
+
+	eth_dev->dev_ops = &virtio_eth_dev_ops;
+	eth_dev->tx_pkt_burst = &virtio_xmit_pkts;
+
+	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
+		rx_func_get(eth_dev);
+		return 0;
+	}
+
+	/* Allocate memory for storing MAC addresses */
+	eth_dev->data->mac_addrs = rte_zmalloc("virtio", VIRTIO_MAX_MAC_ADDRS * ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL) {
+		PMD_INIT_LOG(ERR,
+			"Failed to allocate %d bytes needed to store MAC addresses",
+			VIRTIO_MAX_MAC_ADDRS * ETHER_ADDR_LEN);
+		return -ENOMEM;
+	}
+
+	pci_dev = eth_dev->pci_dev;
+
+	if (pci_dev) {
+		ret = vtpci_init(pci_dev, hw, &dev_flags);
+		if (ret)
+			return ret;
+	}
+
+	eth_dev->data->dev_flags = dev_flags;
+
+	/* reset device and negotiate features */
+	ret = virtio_init_device(eth_dev);
+	if (ret < 0)
+		return ret;
+
 	/* Setup interrupt callback  */
 	if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)
 		rte_intr_callback_register(&pci_dev->intr_handle,
-				   virtio_interrupt_handler, eth_dev);
-
-	virtio_dev_cq_start(eth_dev);
+			virtio_interrupt_handler, eth_dev);
 
 	return 0;
 }
-- 
2.8.1

^ permalink raw reply related

* [PATCH v2 00/12] net/virtio: add offload support
From: Olivier Matz @ 2016-10-03  9:00 UTC (permalink / raw)
  To: dev, yuanhan.liu
  Cc: konstantin.ananyev, sugesh.chandran, bruce.richardson,
	jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
	xiao.w.wang
In-Reply-To: <1469088510-7552-1-git-send-email-olivier.matz@6wind.com>

This patchset, targetted for 16.11, introduces the support of rx and tx
offload in virtio pmd.  To achieve this, some new mbuf flags must be
introduced, as discussed in [1].

It applies on top of:
- software packet type [2]
- testpmd enhancements [3]

The new mbuf checksum flags are backward compatible for current
applications that assume that unknown_csum = good_cum (since there
was only a bad_csum flag). But it the patchset is integrated, we
should consider updating the PMDs to match the new API for 16.11.

[1] http://dpdk.org/ml/archives/dev/2016-May/039920.html
[2] http://dpdk.org/ml/archives/dev/2016-October/048073.html
[3] http://dpdk.org/ml/archives/dev/2016-September/046443.html

changes v1 -> v2
- change mbuf checksum calculation static inline
- fix checksum calculation for protocol where csum=0 means no csum
- move mbuf checksum calculation in librte_net
- use RTE_MIN() to set max rx/tx queue
- rebase on top of head

Olivier Matz (12):
  virtio: move device initialization in a function
  virtio: setup and start cq in configure callback
  virtio: reinitialize the device in configure callback
  net: add function to calculate a checksum in a mbuf
  mbuf: add new Rx checksum mbuf flags
  app/testpmd: fix checksum stats in csum engine
  mbuf: new flag for LRO
  app/testpmd: display lro segment size
  virtio: add Rx checksum offload support
  virtio: add Tx checksum offload support
  virtio: add Lro support
  virtio: add Tso support

 app/test-pmd/csumonly.c                |   8 +-
 doc/guides/rel_notes/release_16_11.rst |  16 ++
 drivers/net/virtio/virtio_ethdev.c     | 182 +++++++++++++---------
 drivers/net/virtio/virtio_ethdev.h     |  18 +--
 drivers/net/virtio/virtio_pci.h        |   4 +-
 drivers/net/virtio/virtio_rxtx.c       | 270 ++++++++++++++++++++++++++++++---
 drivers/net/virtio/virtqueue.h         |   1 +
 lib/librte_mbuf/rte_mbuf.c             |  18 ++-
 lib/librte_mbuf/rte_mbuf.h             |  58 ++++++-
 lib/librte_net/rte_ip.h                |  60 ++++++++
 10 files changed, 526 insertions(+), 109 deletions(-)

Test plan
=========

(not fully replayed on v2, but no major change)

Platform description
--------------------

  guest (dpdk)
  +----------------+
  |                |
  |                |
  |         port0  +-----<---+
  |       ixgbe /  |         |
  |       directio |         |
  |                |         |
  |    port1       |         ^ flow1
  +----------------+         | (flow2 is the reverse)
         |                   |
         | virtio            |
         v                   |
  +----------------+         |
  |     tap0   /   |         |
  |1.1.1.1   /     |         |
  |ns-tap  /       |         |
  |      /         |         |
  |    /   ixgbe2  +------>--+
  |  /    1.1.1.2  |
  |/      ns-ixgbe |
  +----------------+
  host (linux, vhost-net)


flow1:
  host -(ixgbe)-> guest -(virtio)-> host
  1.1.1.2 -> 1.1.1.1

flow2:
  host -(virtio)-> guest -(ixgbe)-> host
  1.1.1.2 -> 1.1.1.1

Host configuration
------------------

Start qemu with:

- a ne2k management interface to avoi any conflict with dpdk
- 2 ixgbe interfaces given to with vm through vfio
- a virtio net device, connected to a tap interface through vhost-net

  /usr/bin/qemu-system-x86_64 -k fr -daemonize --enable-kvm -m 1G -cpu host \
    -smp 3 -serial telnet::40564,server,nowait -serial null \
    -qmp tcp::44340,server,nowait -monitor telnet::49229,server,nowait \
    -device ne2k_pci,mac=de:ad:de:01:02:03,netdev=user.0,addr=03 \
    -netdev user,id=user.0,hostfwd=tcp::34965-:22 \
    -device vfio-pci,host=0000:04:00.0 -device vfio-pci,host=0000:04:00.1 \
    -netdev type=tap,id=vhostnet0,script=no,vhost=on,queues=8 \
    -device virtio-net-pci,netdev=vhostnet0,ioeventfd=on,mq=on,vectors=17 \
    -hda "/path/to/ubuntu-14.04-template.qcow2" \
    -snapshot -vga none -display none

Move the tap interface in a netns, and configure it:

  ip netns add ns-tap
  ip netns exec ns-tap ip l set lo up
  ip link set tap0 netns ns-tap
  ip netns exec ns-tap ip l set tap0 down
  ip netns exec ns-tap ip l set addr 02:00:00:00:00:01 dev tap0
  ip netns exec ns-tap ip l set tap0 up
  ip netns exec ns-tap ip a a 1.1.1.1/24 dev tap0
  ip netns exec ns-tap arp -s 1.1.1.2 02:00:00:00:00:00
  ip netns exec ns-tap ip a

Move the ixgbe interface in a netns, and configure it:

  IXGBE=ixgbe2
  ip netns add ns-ixgbe
  ip netns exec ns-ixgbe ip l set lo up
  ip link set ${IXGBE} netns ns-ixgbe
  ip netns exec ns-ixgbe ip l set ${IXGBE} down
  ip netns exec ns-ixgbe ip l set addr 02:00:00:00:00:00 dev ${IXGBE}
  ip netns exec ns-ixgbe ip l set ${IXGBE} up
  ip netns exec ns-ixgbe ip a a 1.1.1.2/24 dev ${IXGBE}
  ip netns exec ns-ixgbe arp -s 1.1.1.1 02:00:00:00:00:01
  ip netns exec ns-ixgbe ip a

Guest configuration
-------------------

List of pci devices:

  00:02.0 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
  00:03.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL-8029(AS) [10ec:8029]
  00:04.0 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
  00:05.0 Ethernet controller [0200]: Red Hat, Inc Virtio network device [1af4:1000]

Compile dpdk:

  cd dpdk.org
  make config T=x86_64-native-linuxapp-gcc
  make -j4

Prepare environment:

  mkdir -p /mnt/huge
  mount -t hugetlbfs nodev /mnt/huge
  echo 256 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
  modprobe uio_pci_generic
  python tools/dpdk_nic_bind.py -b uio_pci_generic 0000:00:02.0
  python tools/dpdk_nic_bind.py -b uio_pci_generic 0000:00:05.0

Run test
========

The test uses iperf to validate connectivity between the 2 netns of the
host and trough the guest.

Iperf is run with:

  # flow1: host -(ixgbe)-> guest -(virtio)-> host
  ip netns exec ns-tap iperf -s
  ip netns exec ns-ixgbe iperf -c 1.1.1.1 -t 10

  # flow2: host -(virtio)-> guest -(ixgbe)-> host
  ip netns exec ns-ixgbe iperf -s
  ip netns exec ns-tap iperf -c 1.1.1.2 -t 10

The guest runs testpmd with csum forward engine, its configuration
depends on the test case.

test1: large packets (lro/tso)
------------------------------

Configuration of testpmd:

  ./build/app/testpmd -l 0,1 --log-level 8 -- --total-num-mbufs=16384 \
    -i --port-topology=chained --disable-hw-vlan-filter \
    --disable-hw-vlan-strip --enable-rx-cksum --enable-lro \
    --crc-strip --txqflags=0

  set fwd csum
  tso set 1440 0
  csum set ip hw 0
  csum set tcp hw 0
  tso set 1440 1
  #csum set ip hw 1 # not supported by virtio
  csum set tcp hw 1
  start

Iperf log:

  root@ubuntu1404:~# ip netns exec ns-ixgbe iperf -c 1.1.1.1 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.1, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.2 port 54460 connected with 1.1.1.1 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  6.14 GBytes  5.27 Gbits/sec
  root@ubuntu1404:~# ip netns exec ns-tap iperf -c 1.1.1.2 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.2, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.1 port 58312 connected with 1.1.1.2 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  6.70 GBytes  5.76 Gbits/sec

Example of what we see with "set verbose 1" in testpmd:

  -- flow1: ixgbe2 -> port0 (ixgbe) -> testpmd -> port1 (virtio) <-> tap0
  port=0, mbuf=0x7f968ad9fdc0, pkt_len=24682, nb_segs=13:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_UNKNOWN
  tx: m->l2_len=14 m->l3_len=20 m->l4_len=32
  tx: m->tso_segsz=1440
  tx: flags=PKT_TX_IP_CKSUM PKT_TX_L4_NO_CKSUM PKT_TX_TCP_SEG PKT_TX_IPV4

  -- flow2: tap0 -> port1 (virtio)-> testpmd -> port0 (ixgbe) -> ixgbe2
  port=1, mbuf=0x7f968acc9f40, pkt_len=42058, nb_segs=21:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_NONE PKT_RX_IP_CKSUM_UNKNOWN PKT_RX_LRO
  rx: m->lro_segsz=1440
  tx: m->l2_len=14 m->l3_len=20 m->l4_len=32
  tx: m->tso_segsz=1440
  tx: flags=PKT_TX_IP_CKSUM PKT_TX_L4_NO_CKSUM PKT_TX_TCP_SEG PKT_TX_IPV4

test2: hardware checksum only
-----------------------------

Configuration of testpmd:

  ./build/app/testpmd -l 0,1 --log-level 8 -- --total-num-mbufs=16384 \
    -i --port-topology=chained --disable-hw-vlan-filter \
    --disable-hw-vlan-strip --enable-rx-cksum --crc-strip --txqflags=0

  set fwd csum
  csum set ip hw 0
  csum set tcp hw 0
  csum set tcp hw 1
  start

Iperf log:

  root@ubuntu1404:~# ip netns exec ns-ixgbe iperf -c 1.1.1.1 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.1, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.2 port 54462 connected with 1.1.1.1 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  4.49 GBytes  3.86 Gbits/sec
  root@ubuntu1404:~# ip netns exec ns-tap iperf -c 1.1.1.2 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.2, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.1 port 58314 connected with 1.1.1.2 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  6.66 GBytes  5.72 Gbits/sec

Example of what we see with "set verbose 1" in testpmd:

  -- flow1: ixgbe2 -> port0 (ixgbe) -> testpmd -> port1 (virtio) <-> tap0
  port=0, mbuf=0x7f0adca89b40, pkt_len=1514, nb_segs=1:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_UNKNOWN
  tx: m->l2_len=14 m->l3_len=20 m->l4_len=32
  tx: flags=PKT_TX_TCP_CKSUM PKT_TX_IPV4

  -- flow2: tap0 -> port1 (virtio)-> testpmd -> port0 (ixgbe) -> ixgbe2
  port=1, mbuf=0x7f0adcb98d80, pkt_len=1514, nb_segs=1:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_NONE PKT_RX_IP_CKSUM_UNKNOWN
  tx: m->l2_len=14 m->l3_len=20 m->l4_len=32
  tx: flags=PKT_TX_IP_CKSUM PKT_TX_TCP_CKSUM PKT_TX_IPV4

test3: no offload
-----------------

Configuration of testpmd:

  ./build/app/testpmd -l 0,1 --log-level 8 -- --total-num-mbufs=16384 \
    -i --port-topology=chained --disable-hw-vlan-filter --disable-hw-vlan-strip

  set fwd csum
  start

Iperf log:

  root@ubuntu1404:~# ip netns exec ns-ixgbe iperf -c 1.1.1.1 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.1, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.2 port 54466 connected with 1.1.1.1 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  4.29 GBytes  3.68 Gbits/sec
  root@ubuntu1404:~# ip netns exec ns-tap iperf -c 1.1.1.2 -t 10
  ------------------------------------------------------------
  Client connecting to 1.1.1.2, TCP port 5001
  TCP window size: 85.0 KByte (default)
  ------------------------------------------------------------
  [  3] local 1.1.1.1 port 58316 connected with 1.1.1.2 port 5001
  [ ID] Interval       Transfer     Bandwidth
  [  3]  0.0-10.0 sec  6.66 GBytes  5.72 Gbits/sec

Example of what we see with "set verbose 1" in testpmd:

  -- flow1: ixgbe2 -> port0 (ixgbe) -> testpmd -> port1 (virtio) <-> tap0
  port=0, mbuf=0x7faf38b3e700, pkt_len=1514, nb_segs=1:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_UNKNOWN
  tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4

  -- flow2: tap0 -> port1 (virtio)-> testpmd -> port0 (ixgbe) -> ixgbe2
  port=1, mbuf=0x7faf38b71500, pkt_len=1514, nb_segs=1:
  rx: l2_len=14 ethertype=800 l3_len=20 l4_proto=6 l4_len=32 flags=PKT_RX_L4_CKSUM_UNKNOWN PKT_RX_IP_CKSUM_UNKNOWN
  tx: flags=PKT_TX_L4_NO_CKSUM PKT_TX_IPV4

-- 
2.8.1

^ permalink raw reply

* Re: [RFC PATCH v2 1/5] librte_ether: add internal callback functions
From: Iremonger, Bernard @ 2016-10-03  8:58 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: Shah, Rahul R, Lu, Wenzhuo, dev@dpdk.org, ZELEZNIAK, ALEX
In-Reply-To: <20160914112811.GA8364@localhost.localdomain>

Hi Jerin,

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Wednesday, September 14, 2016 12:28 PM
> To: ZELEZNIAK, ALEX <az5157@att.com>
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>; Shah, Rahul R
> <rahul.r.shah@intel.com>; Lu, Wenzhuo <wenzhuo.lu@intel.com>;
> dev@dpdk.org
> Subject: Re: [dpdk-dev] [RFC PATCH v2 1/5] librte_ether: add internal
> callback functions
> 
> On Tue, Sep 13, 2016 at 02:05:49PM +0000, ZELEZNIAK, ALEX wrote:
> > Idea here is not to allow VM to control policies assigned to it for
> > security and other reasons. PF is controlled by host and dictates what
> > VM can and can't do in regards of setting VF parameters.
> 
> I think the proposed scheme, The VM does not take any action on its own.
> The VM will just follow what the centralized entity to do so.
> I think if you are planning to support different varieties of PMD then this
> could be an option.However, if you wish to support only a subset of PMDs
> then PF MBOX based scheme may be enough.
> In any case, I think exposing the fine details of PF/VF MBOX scheme in the
> ethdev spec is not a good idea.

I have reworked these patches (1/5 and 2/5) using the new rte_pmd_ixgbe.h file and submitted as a separate patchset.

[PATCH v3 0/2] add callbacks for VF management
http://dpdk.org/dev/patchwork/patch/16321/
http://dpdk.org/dev/patchwork/patch/16322/

Regards,

Bernard.

> > > -----Original Message-----
> > > From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> > > Sent: Tuesday, September 13, 2016 4:46 AM
> > > To: ZELEZNIAK, ALEX <az5157@att.com>
> > > Cc: Bernard Iremonger <bernard.iremonger@intel.com>;
> > > rahul.r.shah@intel.com; wenzhuo.lu@intel.com; dev@dpdk.org
> > > Subject: Re: [dpdk-dev] [RFC PATCH v2 1/5] librte_ether: add
> > > internal callback functions
> > >
> > > On Fri, Sep 09, 2016 at 04:32:07PM +0000, ZELEZNIAK, ALEX wrote:
> > > > Use case could be to inform application managing SRIOV about VM's
> > > intention
> > > > to modify parameters like add VLAN which might not be the one
> > > > which is assigned to VF or inform about VF reset and reapply
> > > > settings like
> > > strip/insert
> > > > VLAN id based on policy.
> > >
> > > Is there any other way(more portable way) where we can realize the
> > > same use case?
> > >
> > > Something like,
> > >
> > > 1) The assigned VM operates/control the VF
> > > 2) A centralized entity post messages through UNIX socket or
> > > something(like vhost user communicates with VM).
> > > On message receive, VM can take necessary action on assigned VF.
> > >
> > > This will avoid the need of defining specifics of PF to VF mailbox
> > > communication in normative ethdev specification.
> > >
> > > And I guess it will work almost the PMD drivers as their is no PMD
> > > specific work here.
> > >
> > > Just a thought.
> > >
> > > >
> > > > > -----Original Message-----
> > > > > From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> > > > > Sent: Friday, September 09, 2016 10:11 AM
> > > > > To: Bernard Iremonger <bernard.iremonger@intel.com>
> > > > > Cc: rahul.r.shah@intel.com; wenzhuo.lu@intel.com; dev@dpdk.org;
> > > > > ZELEZNIAK, ALEX <az5157@att.com>
> > > > > Subject: Re: [dpdk-dev] [RFC PATCH v2 1/5] librte_ether: add
> > > > > internal callback functions
> > > > >
> > > > > On Fri, Aug 26, 2016 at 10:10:16AM +0100, Bernard Iremonger wrote:
> > > > > > add _rte_eth_dev_callback_process_vf function.
> > > > > > add _rte_eth_dev_callback_process_generic function
> > > > > >
> > > > > > Adding a callback to the user application on VF to PF mailbox
> > > > > > message, allows passing information to the application
> > > > > > controlling the PF when a VF mailbox event message is received,
> such as VF reset.
> > > > > >
> > > > > > Signed-off-by: azelezniak <alexz@att.com>
> > > > > > Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> > > > > > ---
> > > > > >  lib/librte_ether/rte_ethdev.c          | 17 ++++++++++
> > > > > >  lib/librte_ether/rte_ethdev.h          | 61
> > > > > ++++++++++++++++++++++++++++++++++
> > > > > >  lib/librte_ether/rte_ether_version.map |  7 ++++
> > > > > >  3 files changed, 85 insertions(+)
> > > > > >
> > > > > > diff --git a/lib/librte_ether/rte_ethdev.c
> > > b/lib/librte_ether/rte_ethdev.c
> > > > > > index f62a9ec..1388ea3 100644
> > > > > > --- a/lib/librte_ether/rte_ethdev.c
> > > > > > +++ b/lib/librte_ether/rte_ethdev.c
> > > > > > @@ -2690,6 +2690,20 @@ void
> > > > > >  _rte_eth_dev_callback_process(struct rte_eth_dev *dev,
> > > > > >  	enum rte_eth_event_type event)  {
> > > > > > +	return _rte_eth_dev_callback_process_generic(dev, event,
> > > > > > +NULL); }
> > > > > > +
> > > > > > +void
> > > > > > +_rte_eth_dev_callback_process_vf(struct rte_eth_dev *dev,
> > > > > > +	enum rte_eth_event_type event, void *param) {
> > > > > > +	return _rte_eth_dev_callback_process_generic(dev, event,
> > > > > > +param); }
> > > > > > +
> > > > > > +void
> > > > > > +_rte_eth_dev_callback_process_generic(struct rte_eth_dev
> *dev,
> > > > > > +	enum rte_eth_event_type event, void *param) {
> > > > > >  	struct rte_eth_dev_callback *cb_lst;
> > > > > >  	struct rte_eth_dev_callback dev_cb;
> > > > > >
> > > > > > @@ -2699,6 +2713,9 @@ _rte_eth_dev_callback_process(struct
> > > > > rte_eth_dev *dev,
> > > > > >  			continue;
> > > > > >  		dev_cb = *cb_lst;
> > > > > >  		cb_lst->active = 1;
> > > > > > +		if (param != NULL)
> > > > > > +			dev_cb.cb_arg = (void *) param;
> > > > > > +
> > > > > >  		rte_spinlock_unlock(&rte_eth_dev_cb_lock);
> > > > > >  		dev_cb.cb_fn(dev->data->port_id, dev_cb.event,
> > > > > >  						dev_cb.cb_arg);
> > > > > > diff --git a/lib/librte_ether/rte_ethdev.h
> > > b/lib/librte_ether/rte_ethdev.h
> > > > > > index b0fe033..4fb0b9c 100644
> > > > > > --- a/lib/librte_ether/rte_ethdev.h
> > > > > > +++ b/lib/librte_ether/rte_ethdev.h
> > > > > > @@ -3047,9 +3047,27 @@ enum rte_eth_event_type {
> > > > > >  				/**< queue state event
> (enabled/disabled)
> > > > > */
> > > > > >  	RTE_ETH_EVENT_INTR_RESET,
> > > > > >  			/**< reset interrupt event, sent to VF on PF
> reset */
> > > > > > +	RTE_ETH_EVENT_VF_MBOX,  /**< PF mailbox processing
> callback
> > > > > > +*/
> > > > > >  	RTE_ETH_EVENT_MAX       /**< max value of this enum */
> > > > > >  };
> > > > > >
> > > > > > +/**
> > > > > > + * Response sent back to ixgbe driver from user app after
> > > > > > +callback  */ enum rte_eth_mb_event_rsp {
> > > > > > +	RTE_ETH_MB_EVENT_NOOP_ACK,  /**< skip mbox request
> and ACK
> > > > > */
> > > > > > +	RTE_ETH_MB_EVENT_NOOP_NACK, /**< skip mbox request
> and
> > > > > NACK */
> > > > > > +	RTE_ETH_MB_EVENT_PROCEED,  /**< proceed with mbox
> request
> > > > > */
> > > > > > +	RTE_ETH_MB_EVENT_MAX       /**< max value of this enum
> */
> > > > > > +};
> > > > >
> > > > > Do we really need to define the specifics of PF to VF MBOX
> > > communication
> > > > > in normative ethdev specification?
> > > > > Each drivers may have different PF to VF MBOX definitions so it
> > > > > may not
> > > be
> > > > > very portable.
> > > > > What is the use-case here? If its for VF configuration, I think
> > > > > we can do it as separate 'sync' functions for each functionality
> > > > > so that PMDs will have room hiding the specifics on MBOX definitions.
> > > >

^ permalink raw reply

* Last few spaces & Agenda released for DPDK Userspace Summit 2016
From: Butler, Siobhan A @ 2016-10-03  8:55 UTC (permalink / raw)
  To: dev@dpdk.org

Hi all,
There are just a few spaces left at this year's DPDK Userspace Summit, if you want to attend please register at www.dpdksummit.com<http://www.dpdksummit.com> where you can review the agenda for the two days of the event. Thanks to those who have already registered, but again if you can't make it please let us know!

Look forward to seeing you in Dublin!
Siobhán

^ permalink raw reply

* [PATCH v3 15/16] app/testpmd: dump ptype using the new function
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Use the function introduced in previous commit to dump the packet type
of the received packet.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 app/test-pmd/rxonly.c | 175 ++------------------------------------------------
 1 file changed, 4 insertions(+), 171 deletions(-)

diff --git a/app/test-pmd/rxonly.c b/app/test-pmd/rxonly.c
index b1fc5bf..9a6e394 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -91,6 +91,7 @@ pkt_burst_receive(struct fwd_stream *fs)
 	uint16_t nb_rx;
 	uint16_t i, packet_type;
 	uint16_t is_encapsulation;
+	char buf[256];
 
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
 	uint64_t start_tsc;
@@ -161,177 +162,9 @@ pkt_burst_receive(struct fwd_stream *fs)
 			printf(" - QinQ VLAN tci=0x%x, VLAN tci outer=0x%x",
 					mb->vlan_tci, mb->vlan_tci_outer);
 		if (mb->packet_type) {
-			uint32_t ptype;
-
-			/* (outer) L2 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_L2_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_L2_ETHER:
-				printf(" - (outer) L2 type: ETHER");
-				break;
-			case RTE_PTYPE_L2_ETHER_TIMESYNC:
-				printf(" - (outer) L2 type: ETHER_Timesync");
-				break;
-			case RTE_PTYPE_L2_ETHER_ARP:
-				printf(" - (outer) L2 type: ETHER_ARP");
-				break;
-			case RTE_PTYPE_L2_ETHER_LLDP:
-				printf(" - (outer) L2 type: ETHER_LLDP");
-				break;
-			case RTE_PTYPE_L2_ETHER_NSH:
-				printf(" - (outer) L2 type: ETHER_NSH");
-				break;
-			default:
-				printf(" - (outer) L2 type: Unknown");
-				break;
-			}
-
-			/* (outer) L3 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_L3_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_L3_IPV4:
-				printf(" - (outer) L3 type: IPV4");
-				break;
-			case RTE_PTYPE_L3_IPV4_EXT:
-				printf(" - (outer) L3 type: IPV4_EXT");
-				break;
-			case RTE_PTYPE_L3_IPV6:
-				printf(" - (outer) L3 type: IPV6");
-				break;
-			case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN:
-				printf(" - (outer) L3 type: IPV4_EXT_UNKNOWN");
-				break;
-			case RTE_PTYPE_L3_IPV6_EXT:
-				printf(" - (outer) L3 type: IPV6_EXT");
-				break;
-			case RTE_PTYPE_L3_IPV6_EXT_UNKNOWN:
-				printf(" - (outer) L3 type: IPV6_EXT_UNKNOWN");
-				break;
-			default:
-				printf(" - (outer) L3 type: Unknown");
-				break;
-			}
-
-			/* (outer) L4 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_L4_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_L4_TCP:
-				printf(" - (outer) L4 type: TCP");
-				break;
-			case RTE_PTYPE_L4_UDP:
-				printf(" - (outer) L4 type: UDP");
-				break;
-			case RTE_PTYPE_L4_FRAG:
-				printf(" - (outer) L4 type: L4_FRAG");
-				break;
-			case RTE_PTYPE_L4_SCTP:
-				printf(" - (outer) L4 type: SCTP");
-				break;
-			case RTE_PTYPE_L4_ICMP:
-				printf(" - (outer) L4 type: ICMP");
-				break;
-			case RTE_PTYPE_L4_NONFRAG:
-				printf(" - (outer) L4 type: L4_NONFRAG");
-				break;
-			default:
-				printf(" - (outer) L4 type: Unknown");
-				break;
-			}
-
-			/* packet tunnel type */
-			ptype = mb->packet_type & RTE_PTYPE_TUNNEL_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_TUNNEL_IP:
-				printf(" - Tunnel type: IP");
-				break;
-			case RTE_PTYPE_TUNNEL_GRE:
-				printf(" - Tunnel type: GRE");
-				break;
-			case RTE_PTYPE_TUNNEL_VXLAN:
-				printf(" - Tunnel type: VXLAN");
-				break;
-			case RTE_PTYPE_TUNNEL_NVGRE:
-				printf(" - Tunnel type: NVGRE");
-				break;
-			case RTE_PTYPE_TUNNEL_GENEVE:
-				printf(" - Tunnel type: GENEVE");
-				break;
-			case RTE_PTYPE_TUNNEL_GRENAT:
-				printf(" - Tunnel type: GRENAT");
-				break;
-			default:
-				printf(" - Tunnel type: Unknown");
-				break;
-			}
-
-			/* inner L2 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_INNER_L2_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_INNER_L2_ETHER:
-				printf(" - Inner L2 type: ETHER");
-				break;
-			case RTE_PTYPE_INNER_L2_ETHER_VLAN:
-				printf(" - Inner L2 type: ETHER_VLAN");
-				break;
-			default:
-				printf(" - Inner L2 type: Unknown");
-				break;
-			}
-
-			/* inner L3 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_INNER_L3_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_INNER_L3_IPV4:
-				printf(" - Inner L3 type: IPV4");
-				break;
-			case RTE_PTYPE_INNER_L3_IPV4_EXT:
-				printf(" - Inner L3 type: IPV4_EXT");
-				break;
-			case RTE_PTYPE_INNER_L3_IPV6:
-				printf(" - Inner L3 type: IPV6");
-				break;
-			case RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN:
-				printf(" - Inner L3 type: IPV4_EXT_UNKNOWN");
-				break;
-			case RTE_PTYPE_INNER_L3_IPV6_EXT:
-				printf(" - Inner L3 type: IPV6_EXT");
-				break;
-			case RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN:
-				printf(" - Inner L3 type: IPV6_EXT_UNKNOWN");
-				break;
-			default:
-				printf(" - Inner L3 type: Unknown");
-				break;
-			}
-
-			/* inner L4 packet type */
-			ptype = mb->packet_type & RTE_PTYPE_INNER_L4_MASK;
-			switch (ptype) {
-			case RTE_PTYPE_INNER_L4_TCP:
-				printf(" - Inner L4 type: TCP");
-				break;
-			case RTE_PTYPE_INNER_L4_UDP:
-				printf(" - Inner L4 type: UDP");
-				break;
-			case RTE_PTYPE_INNER_L4_FRAG:
-				printf(" - Inner L4 type: L4_FRAG");
-				break;
-			case RTE_PTYPE_INNER_L4_SCTP:
-				printf(" - Inner L4 type: SCTP");
-				break;
-			case RTE_PTYPE_INNER_L4_ICMP:
-				printf(" - Inner L4 type: ICMP");
-				break;
-			case RTE_PTYPE_INNER_L4_NONFRAG:
-				printf(" - Inner L4 type: L4_NONFRAG");
-				break;
-			default:
-				printf(" - Inner L4 type: Unknown");
-				break;
-			}
-			printf("\n");
-		} else
-			printf("Unknown packet type\n");
+			rte_get_ptype_name(mb->packet_type, buf, sizeof(buf));
+			printf(" - %s", buf);
+		}
 		if (is_encapsulation) {
 			struct ipv4_hdr *ipv4_hdr;
 			struct ipv6_hdr *ipv6_hdr;
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 14/16] mbuf: clarify definition of fragment packet types
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

An IPv4 packet is considered as a fragment if:
- MF (more fragment) bit is set
- or Fragment_Offset field is non-zero

Update the API documentation of packet types to reflect this.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mbuf/rte_mbuf_ptype.h | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index f19c56c..ff6de9d 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -227,7 +227,7 @@ extern "C" {
  *
  * Packet format:
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=6, 'MF'=0>
+ * | 'version'=4, 'protocol'=6, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=6>
@@ -239,7 +239,7 @@ extern "C" {
  *
  * Packet format:
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17, 'MF'=0>
+ * | 'version'=4, 'protocol'=17, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=17>
@@ -258,6 +258,9 @@ extern "C" {
  * <'ether type'=0x0800
  * | 'version'=4, 'MF'=1>
  * or,
+ * <'ether type'=0x0800
+ * | 'version'=4, 'frag_offset'!=0>
+ * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=44>
  */
@@ -268,7 +271,7 @@ extern "C" {
  *
  * Packet format:
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=132, 'MF'=0>
+ * | 'version'=4, 'protocol'=132, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=132>
@@ -280,7 +283,7 @@ extern "C" {
  *
  * Packet format:
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=1, 'MF'=0>
+ * | 'version'=4, 'protocol'=1, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=1>
@@ -296,7 +299,7 @@ extern "C" {
  *
  * Packet format:
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
+ * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'!=[6|17|44|132|1]>
@@ -473,7 +476,7 @@ extern "C" {
  *
  * Packet format (inner only):
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=6, 'MF'=0>
+ * | 'version'=4, 'protocol'=6, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=6>
@@ -485,7 +488,7 @@ extern "C" {
  *
  * Packet format (inner only):
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17, 'MF'=0>
+ * | 'version'=4, 'protocol'=17, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=17>
@@ -499,6 +502,9 @@ extern "C" {
  * <'ether type'=0x0800
  * | 'version'=4, 'MF'=1>
  * or,
+ * <'ether type'=0x0800
+ * | 'version'=4, 'frag_offset'!=0>
+ * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=44>
  */
@@ -509,7 +515,7 @@ extern "C" {
  *
  * Packet format (inner only):
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=132, 'MF'=0>
+ * | 'version'=4, 'protocol'=132, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=132>
@@ -521,7 +527,7 @@ extern "C" {
  *
  * Packet format (inner only):
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=1, 'MF'=0>
+ * | 'version'=4, 'protocol'=1, 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'=1>
@@ -534,7 +540,7 @@ extern "C" {
  *
  * Packet format (inner only):
  * <'ether type'=0x0800
- * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
+ * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0, 'frag_offset'=0>
  * or,
  * <'ether type'=0x86DD
  * | 'version'=6, 'next header'!=[6|17|44|132|1]>
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 16/16] app/testpmd: display software packet type
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

In addition to the packet type returned by the PMD, also display the
packet type calculated by parsing the packet in software. This is
particularly useful to compare the 2 values.

Note: it does not mean that both hw and sw always have to provide the
same value, since it depends on what hardware supports.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 app/test-pmd/rxonly.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/app/test-pmd/rxonly.c b/app/test-pmd/rxonly.c
index 9a6e394..9acc4c6 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -66,6 +66,7 @@
 #include <rte_string_fns.h>
 #include <rte_ip.h>
 #include <rte_udp.h>
+#include <rte_net.h>
 
 #include "testpmd.h"
 
@@ -92,6 +93,8 @@ pkt_burst_receive(struct fwd_stream *fs)
 	uint16_t i, packet_type;
 	uint16_t is_encapsulation;
 	char buf[256];
+	struct rte_net_hdr_lens hdr_lens;
+	uint32_t sw_packet_type;
 
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
 	uint64_t start_tsc;
@@ -163,8 +166,26 @@ pkt_burst_receive(struct fwd_stream *fs)
 					mb->vlan_tci, mb->vlan_tci_outer);
 		if (mb->packet_type) {
 			rte_get_ptype_name(mb->packet_type, buf, sizeof(buf));
-			printf(" - %s", buf);
+			printf(" - hw ptype: %s", buf);
 		}
+		sw_packet_type = rte_net_get_ptype(mb, &hdr_lens,
+			RTE_PTYPE_ALL_MASK);
+		rte_get_ptype_name(sw_packet_type, buf, sizeof(buf));
+		printf(" - sw ptype: %s", buf);
+		if (sw_packet_type & RTE_PTYPE_L2_MASK)
+			printf(" - l2_len=%d", hdr_lens.l2_len);
+		if (sw_packet_type & RTE_PTYPE_L3_MASK)
+			printf(" - l3_len=%d", hdr_lens.l3_len);
+		if (sw_packet_type & RTE_PTYPE_L4_MASK)
+			printf(" - l4_len=%d", hdr_lens.l4_len);
+		if (sw_packet_type & RTE_PTYPE_TUNNEL_MASK)
+			printf(" - tunnel_len=%d", hdr_lens.tunnel_len);
+		if (sw_packet_type & RTE_PTYPE_INNER_L2_MASK)
+			printf(" - inner_l2_len=%d", hdr_lens.inner_l2_len);
+		if (sw_packet_type & RTE_PTYPE_INNER_L3_MASK)
+			printf(" - inner_l3_len=%d", hdr_lens.inner_l3_len);
+		if (sw_packet_type & RTE_PTYPE_INNER_L4_MASK)
+			printf(" - inner_l4_len=%d", hdr_lens.inner_l4_len);
 		if (is_encapsulation) {
 			struct ipv4_hdr *ipv4_hdr;
 			struct ipv6_hdr *ipv6_hdr;
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 13/16] mbuf: add functions to dump packet type
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Dumping the packet type is useful for debug purposes. Instead
of having each application providing its function to do that,
introduce functions to do it.

It factorizes the code and reduces the risk of desynchronization between
the new packet types and the dump function.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 doc/guides/rel_notes/release_16_11.rst |   4 +
 lib/librte_mbuf/Makefile               |   2 +-
 lib/librte_mbuf/rte_mbuf_ptype.c       | 227 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h       |  89 +++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |   8 ++
 5 files changed, 329 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index b3b9dfb..40c09ca 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -46,6 +46,10 @@ New Features
   Added a new function ``rte_net_get_ptype()`` to parse an Ethernet packet
   in an mbuf chain and retrieve its packet type by software.
 
+* **Added functions to dump the packet type as a string.**
+
+  Added new functions ``rte_get_ptype_*()`` to dump a packet type as a string.
+
 Resolved Issues
 ---------------
 
diff --git a/lib/librte_mbuf/Makefile b/lib/librte_mbuf/Makefile
index 27e037c..4ae2e8c 100644
--- a/lib/librte_mbuf/Makefile
+++ b/lib/librte_mbuf/Makefile
@@ -41,7 +41,7 @@ EXPORT_MAP := rte_mbuf_version.map
 LIBABIVER := 2
 
 # all source are stored in SRCS-y
-SRCS-$(CONFIG_RTE_LIBRTE_MBUF) := rte_mbuf.c
+SRCS-$(CONFIG_RTE_LIBRTE_MBUF) := rte_mbuf.c rte_mbuf_ptype.c
 
 # install includes
 SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_mbuf.h rte_mbuf_ptype.h
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
new file mode 100644
index 0000000..e5c4fae
--- /dev/null
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -0,0 +1,227 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2016 6WIND S.A.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+#include <rte_mbuf_ptype.h>
+
+/* get the name of the l2 packet type */
+const char *rte_get_ptype_l2_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_L2_MASK) {
+	case RTE_PTYPE_L2_ETHER: return "L2_ETHER";
+	case RTE_PTYPE_L2_ETHER_TIMESYNC: return "L2_ETHER_TIMESYNC";
+	case RTE_PTYPE_L2_ETHER_ARP: return "L2_ETHER_ARP";
+	case RTE_PTYPE_L2_ETHER_LLDP: return "L2_ETHER_LLDP";
+	case RTE_PTYPE_L2_ETHER_NSH: return "L2_ETHER_NSH";
+	case RTE_PTYPE_L2_ETHER_VLAN: return "L2_ETHER_VLAN";
+	case RTE_PTYPE_L2_ETHER_QINQ: return "L2_ETHER_QINQ";
+	default: return "L2_UNKNOWN";
+	}
+}
+
+/* get the name of the l3 packet type */
+const char *rte_get_ptype_l3_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_L3_MASK) {
+	case RTE_PTYPE_L3_IPV4: return "L3_IPV4";
+	case RTE_PTYPE_L3_IPV4_EXT: return "L3_IPV4_EXT";
+	case RTE_PTYPE_L3_IPV6: return "L3_IPV6";
+	case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN: return "L3_IPV4_EXT_UNKNOWN";
+	case RTE_PTYPE_L3_IPV6_EXT: return "L3_IPV6_EXT";
+	case RTE_PTYPE_L3_IPV6_EXT_UNKNOWN: return "L3_IPV6_EXT_UNKNOWN";
+	default: return "L3_UNKNOWN";
+	}
+}
+
+/* get the name of the l4 packet type */
+const char *rte_get_ptype_l4_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_L4_MASK) {
+	case RTE_PTYPE_L4_TCP: return "L4_TCP";
+	case RTE_PTYPE_L4_UDP: return "L4_UDP";
+	case RTE_PTYPE_L4_FRAG: return "L4_FRAG";
+	case RTE_PTYPE_L4_SCTP: return "L4_SCTP";
+	case RTE_PTYPE_L4_ICMP: return "L4_ICMP";
+	case RTE_PTYPE_L4_NONFRAG: return "L4_NONFRAG";
+	default: return "L4_UNKNOWN";
+	}
+}
+
+/* get the name of the tunnel packet type */
+const char *rte_get_ptype_tunnel_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_TUNNEL_MASK) {
+	case RTE_PTYPE_TUNNEL_IP: return "TUNNEL_IP";
+	case RTE_PTYPE_TUNNEL_GRE: return "TUNNEL_GRE";
+	case RTE_PTYPE_TUNNEL_VXLAN: return "TUNNEL_VXLAN";
+	case RTE_PTYPE_TUNNEL_NVGRE: return "TUNNEL_NVGRE";
+	case RTE_PTYPE_TUNNEL_GENEVE: return "TUNNEL_GENEVE";
+	case RTE_PTYPE_TUNNEL_GRENAT: return "TUNNEL_GRENAT";
+	default: return "TUNNEL_UNKNOWN";
+	}
+}
+
+/* get the name of the inner_l2 packet type */
+const char *rte_get_ptype_inner_l2_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_INNER_L2_MASK) {
+	case RTE_PTYPE_INNER_L2_ETHER: return "INNER_L2_ETHER";
+	case RTE_PTYPE_INNER_L2_ETHER_VLAN: return "INNER_L2_ETHER_VLAN";
+	case RTE_PTYPE_INNER_L2_ETHER_QINQ: return "INNER_L2_ETHER_QINQ";
+	default: return "INNER_L2_UNKNOWN";
+	}
+}
+
+/* get the name of the inner_l3 packet type */
+const char *rte_get_ptype_inner_l3_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_INNER_L3_MASK) {
+	case RTE_PTYPE_INNER_L3_IPV4: return "INNER_L3_IPV4";
+	case RTE_PTYPE_INNER_L3_IPV4_EXT: return "INNER_L3_IPV4_EXT";
+	case RTE_PTYPE_INNER_L3_IPV6: return "INNER_L3_IPV6";
+	case RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN:
+		return "INNER_L3_IPV4_EXT_UNKNOWN";
+	case RTE_PTYPE_INNER_L3_IPV6_EXT: return "INNER_L3_IPV6_EXT";
+	case RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN:
+		return "INNER_L3_IPV6_EXT_UNKNOWN";
+	default: return "INNER_L3_UNKNOWN";
+	}
+}
+
+/* get the name of the inner_l4 packet type */
+const char *rte_get_ptype_inner_l4_name(uint32_t ptype)
+{
+	switch (ptype & RTE_PTYPE_INNER_L4_MASK) {
+	case RTE_PTYPE_INNER_L4_TCP: return "INNER_L4_TCP";
+	case RTE_PTYPE_INNER_L4_UDP: return "INNER_L4_UDP";
+	case RTE_PTYPE_INNER_L4_FRAG: return "INNER_L4_FRAG";
+	case RTE_PTYPE_INNER_L4_SCTP: return "INNER_L4_SCTP";
+	case RTE_PTYPE_INNER_L4_ICMP: return "INNER_L4_ICMP";
+	case RTE_PTYPE_INNER_L4_NONFRAG: return "INNER_L4_NONFRAG";
+	default: return "INNER_L4_UNKNOWN";
+	}
+}
+
+/* write the packet type name into the buffer */
+int rte_get_ptype_name(uint32_t ptype, char *buf, size_t buflen)
+{
+	int ret;
+
+	if (buflen == 0)
+		return -1;
+
+	buf[0] = '\0';
+	if ((ptype & RTE_PTYPE_ALL_MASK) == RTE_PTYPE_UNKNOWN) {
+		ret = snprintf(buf, buflen, "UNKNOWN");
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		return 0;
+	}
+
+	if ((ptype & RTE_PTYPE_L2_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_l2_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_L3_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_l3_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_L4_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_l4_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_TUNNEL_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_tunnel_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_INNER_L2_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_inner_l2_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_INNER_L3_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_inner_l3_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+	if ((ptype & RTE_PTYPE_INNER_L4_MASK) != 0) {
+		ret = snprintf(buf, buflen, "%s ",
+			rte_get_ptype_inner_l4_name(ptype));
+		if (ret < 0)
+			return -1;
+		if ((size_t)ret >= buflen)
+			return -1;
+		buf += ret;
+		buflen -= ret;
+	}
+
+	return 0;
+}
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index fbe764a..f19c56c 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -544,6 +544,10 @@ extern "C" {
  * Mask of inner layer 4 packet types.
  */
 #define RTE_PTYPE_INNER_L4_MASK             0x0f000000
+/**
+ * All valid layer masks.
+ */
+#define RTE_PTYPE_ALL_MASK                  0x0fffffff
 
 /**
  * Check if the (outer) L3 header is IPv4. To avoid comparing IPv4 types one by
@@ -566,6 +570,91 @@ extern "C" {
 		RTE_PTYPE_INNER_L3_MASK |				\
 		RTE_PTYPE_INNER_L4_MASK))
 
+/**
+ * Get the name of the l2 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_l2_name(uint32_t ptype);
+
+/**
+ * Get the name of the l3 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_l3_name(uint32_t ptype);
+
+/**
+ * Get the name of the l4 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_l4_name(uint32_t ptype);
+
+/**
+ * Get the name of the tunnel packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_tunnel_name(uint32_t ptype);
+
+/**
+ * Get the name of the inner_l2 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_inner_l2_name(uint32_t ptype);
+
+/**
+ * Get the name of the inner_l3 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_inner_l3_name(uint32_t ptype);
+
+/**
+ * Get the name of the inner_l4 packet type
+ *
+ * @param ptype
+ *   The packet type value.
+ * @return
+ *   A non-null string describing the packet type.
+ */
+const char *rte_get_ptype_inner_l4_name(uint32_t ptype);
+
+/**
+ * Write the packet type name into the buffer
+ *
+ * @param ptype
+ *   The packet type value.
+ * @param buf
+ *   The buffer where the string is written.
+ * @param buflen
+ *   The length of the buffer.
+ * @return
+ *   - 0 on success
+ *   - (-1) if the buffer is too small
+ */
+int rte_get_ptype_name(uint32_t ptype, char *buf, size_t buflen);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map
index 79e4dd8..5455ba6 100644
--- a/lib/librte_mbuf/rte_mbuf_version.map
+++ b/lib/librte_mbuf/rte_mbuf_version.map
@@ -23,5 +23,13 @@ DPDK_16.11 {
 	global:
 
 	__rte_pktmbuf_read;
+	rte_get_ptype_inner_l2_name;
+	rte_get_ptype_inner_l3_name;
+	rte_get_ptype_inner_l4_name;
+	rte_get_ptype_l2_name;
+	rte_get_ptype_l3_name;
+	rte_get_ptype_l4_name;
+	rte_get_ptype_name;
+	rte_get_ptype_tunnel_name;
 
 } DPDK_2.1;
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 12/16] net: get ptype for the first layers only
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add a parameter to rte_net_get_ptype() to select which
layers should be parsed. This avoids to parse all layers if
only the first ones are required.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_net/rte_net.c | 33 ++++++++++++++++++++++++++++++++-
 lib/librte_net/rte_net.h |  7 ++++++-
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index 53cfef8..a8c7aff 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -254,7 +254,7 @@ skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
 
 /* parse mbuf data to get packet type */
 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
-	struct rte_net_hdr_lens *hdr_lens)
+	struct rte_net_hdr_lens *hdr_lens, uint32_t layers)
 {
 	struct rte_net_hdr_lens local_hdr_lens;
 	const struct ether_hdr *eh;
@@ -273,6 +273,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	off = sizeof(*eh);
 	hdr_lens->l2_len = off;
 
+	if ((layers & RTE_PTYPE_L2_MASK) == 0)
+		return 0;
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
 		goto l3; /* fast path if packet is IPv4 */
 
@@ -302,6 +305,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	}
 
  l3:
+	if ((layers & RTE_PTYPE_L3_MASK) == 0)
+		return pkt_type;
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
 		struct ipv4_hdr ip4h_copy;
@@ -313,6 +319,10 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
 		hdr_lens->l3_len = ip4_hlen(ip4h);
 		off += hdr_lens->l3_len;
+
+		if ((layers & RTE_PTYPE_L4_MASK) == 0)
+			return pkt_type;
+
 		if (ip4h->fragment_offset & rte_cpu_to_be_16(
 				IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
 			pkt_type |= RTE_PTYPE_L4_FRAG;
@@ -340,6 +350,10 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		}
 		if (proto == 0)
 			return pkt_type;
+
+		if ((layers & RTE_PTYPE_L4_MASK) == 0)
+			return pkt_type;
+
 		if (frag) {
 			pkt_type |= RTE_PTYPE_L4_FRAG;
 			hdr_lens->l4_len = 0;
@@ -368,6 +382,10 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		uint32_t prev_off = off;
 
 		hdr_lens->l4_len = 0;
+
+		if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0)
+			return pkt_type;
+
 		pkt_type |= ptype_tunnel(&proto, m, &off);
 		hdr_lens->tunnel_len = off - prev_off;
 	}
@@ -375,6 +393,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	/* same job for inner header: we need to duplicate the code
 	 * because the packet types do not have the same value.
 	 */
+	if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0)
+		return pkt_type;
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
 		eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
 		if (unlikely(eh == NULL))
@@ -412,6 +433,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		proto = vh->eth_proto;
 	}
 
+	if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0)
+		return pkt_type;
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
 		struct ipv4_hdr ip4h_copy;
@@ -423,6 +447,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
 		hdr_lens->inner_l3_len = ip4_hlen(ip4h);
 		off += hdr_lens->inner_l3_len;
+
+		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
+			return pkt_type;
 		if (ip4h->fragment_offset &
 				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
 					IPV4_HDR_MF_FLAG)) {
@@ -455,6 +482,10 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		}
 		if (proto == 0)
 			return pkt_type;
+
+		if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0)
+			return pkt_type;
+
 		if (frag) {
 			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
 			hdr_lens->inner_l4_len = 0;
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index 02299db..d4156ae 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -75,11 +75,16 @@ struct rte_net_hdr_lens {
  * @param hdr_lens
  *   A pointer to a structure where the header lengths will be returned,
  *   or NULL.
+ * @param layers
+ *   List of layers to parse. The function will stop at the first
+ *   empty layer. Examples:
+ *   - To parse all known layers, use RTE_PTYPE_ALL_MASK.
+ *   - To parse only L2 and L3, use RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK
  * @return
  *   The packet type of the packet.
  */
 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
-	struct rte_net_hdr_lens *hdr_lens);
+	struct rte_net_hdr_lens *hdr_lens, uint32_t layers);
 
 #ifdef __cplusplus
 }
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 11/16] net: support Nvgre in software packet type parser
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Jean Dao
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add support of Nvgre tunnels in rte_net_get_ptype(). At the same
time, as Nvgre transports Ethernet, we need to add the support for inner
Vlan, QinQ, and Mpls.

Signed-off-by: Jean Dao <jean.dao@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mbuf/rte_mbuf_ptype.h |  7 +++++++
 lib/librte_net/rte_net.c         | 42 ++++++++++++++++++++++++++++++++++++++--
 lib/librte_net/rte_net.h         |  2 +-
 3 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 6e62492..fbe764a 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -396,6 +396,13 @@ extern "C" {
  */
 #define RTE_PTYPE_INNER_L2_ETHER_VLAN       0x00020000
 /**
+ * QinQ packet type.
+ *
+ * Packet format:
+ * <'ether type'=[0x88A8]>
+ */
+#define RTE_PTYPE_INNER_L2_ETHER_QINQ       0x00030000
+/**
  * Mask of inner layer 2 packet types.
  */
 #define RTE_PTYPE_INNER_L2_MASK             0x000f0000
diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index 66db2c8..53cfef8 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -183,7 +183,10 @@ ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
 
 		*off += opt_len[flags];
 		*proto = gh->proto;
-		return RTE_PTYPE_TUNNEL_GRE;
+		if (*proto == rte_cpu_to_be_16(ETHER_TYPE_TEB))
+			return RTE_PTYPE_TUNNEL_NVGRE;
+		else
+			return RTE_PTYPE_TUNNEL_GRE;
 	}
 	case IPPROTO_IPIP:
 		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
@@ -372,7 +375,42 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	/* same job for inner header: we need to duplicate the code
 	 * because the packet types do not have the same value.
 	 */
-	hdr_lens->inner_l2_len = 0;
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) {
+		eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
+		if (unlikely(eh == NULL))
+			return pkt_type;
+		pkt_type |= RTE_PTYPE_INNER_L2_ETHER;
+		proto = eh->ether_type;
+		off += sizeof(*eh);
+		hdr_lens->inner_l2_len = sizeof(*eh);
+	}
+
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+		const struct vlan_hdr *vh;
+		struct vlan_hdr vh_copy;
+
+		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
+		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN;
+		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
+		if (unlikely(vh == NULL))
+			return pkt_type;
+		off += sizeof(*vh);
+		hdr_lens->inner_l2_len += sizeof(*vh);
+		proto = vh->eth_proto;
+	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
+		const struct vlan_hdr *vh;
+		struct vlan_hdr vh_copy;
+
+		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
+		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ;
+		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
+			&vh_copy);
+		if (unlikely(vh == NULL))
+			return pkt_type;
+		off += 2 * sizeof(*vh);
+		hdr_lens->inner_l2_len += 2 * sizeof(*vh);
+		proto = vh->eth_proto;
+	}
 
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index 4a72b1b..02299db 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -68,7 +68,7 @@ struct rte_net_hdr_lens {
  *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
- *   Tunnels: IPv4, IPv6, Gre
+ *   Tunnels: IPv4, IPv6, Gre, Nvgre
  *
  * @param m
  *   The packet mbuf to be parsed.
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 10/16] net: support Gre in software packet type parser
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Jean Dao
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add support of Gre tunnels in rte_net_get_ptype().

Signed-off-by: Jean Dao <jean.dao@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_net/rte_net.c | 40 ++++++++++++++++++++++++++++++++++++----
 lib/librte_net/rte_net.h |  2 +-
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index 87294bb..66db2c8 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -41,6 +41,7 @@
 #include <rte_tcp.h>
 #include <rte_udp.h>
 #include <rte_sctp.h>
+#include <rte_gre.h>
 #include <rte_net.h>
 
 /* get l3 packet type from ip6 next protocol */
@@ -150,11 +151,40 @@ ptype_inner_l4(uint8_t proto)
 	return ptype_inner_l4_proto[proto];
 }
 
-/* get the tunnel packet type if any, update proto. */
+/* get the tunnel packet type if any, update proto and off. */
 static uint32_t
-ptype_tunnel(uint16_t *proto)
+ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m,
+	uint32_t *off)
 {
 	switch (*proto) {
+	case IPPROTO_GRE: {
+		static const uint8_t opt_len[16] = {
+			[0x0] = 4,
+			[0x1] = 8,
+			[0x2] = 8,
+			[0x8] = 8,
+			[0x3] = 12,
+			[0x9] = 12,
+			[0xa] = 12,
+			[0xb] = 16,
+		};
+		const struct gre_hdr *gh;
+		struct gre_hdr gh_copy;
+		uint16_t flags;
+
+		gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy);
+		if (unlikely(gh == NULL))
+			return 0;
+
+		flags = rte_be_to_cpu_16(*(const uint16_t *)gh);
+		flags >>= 12;
+		if (opt_len[flags] == 0)
+			return 0;
+
+		*off += opt_len[flags];
+		*proto = gh->proto;
+		return RTE_PTYPE_TUNNEL_GRE;
+	}
 	case IPPROTO_IPIP:
 		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
 		return RTE_PTYPE_TUNNEL_IP;
@@ -332,9 +362,11 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		hdr_lens->l4_len = sizeof(struct sctp_hdr);
 		return pkt_type;
 	} else {
+		uint32_t prev_off = off;
+
 		hdr_lens->l4_len = 0;
-		pkt_type |= ptype_tunnel(&proto);
-		hdr_lens->tunnel_len = 0;
+		pkt_type |= ptype_tunnel(&proto, m, &off);
+		hdr_lens->tunnel_len = off - prev_off;
 	}
 
 	/* same job for inner header: we need to duplicate the code
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index f433389..4a72b1b 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -68,7 +68,7 @@ struct rte_net_hdr_lens {
  *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
- *   Tunnels: IPv4, IPv6
+ *   Tunnels: IPv4, IPv6, Gre
  *
  * @param m
  *   The packet mbuf to be parsed.
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 09/16] net: add Gre header structure
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Jean Dao
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add the Gre header structure in librte_net. It will be used by next
patches that adds the support of Gre tunnels in the software packet type
parser.

The extended headers (checksum, key or sequence number) are not defined.

Signed-off-by: Jean Dao <jean.dao@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_net/Makefile  |  2 +-
 lib/librte_net/rte_gre.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_net/rte_gre.h

diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index c16b542..e5758ce 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -43,7 +43,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_NET) := rte_net.c
 # install includes
 SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_sctp.h rte_icmp.h rte_arp.h
-SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_ether.h rte_net.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_ether.h rte_gre.h rte_net.h
 
 DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_eal lib/librte_mempool
 DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_mbuf
diff --git a/lib/librte_net/rte_gre.h b/lib/librte_net/rte_gre.h
new file mode 100644
index 0000000..46568ff
--- /dev/null
+++ b/lib/librte_net/rte_gre.h
@@ -0,0 +1,71 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2016 6WIND S.A.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_GRE_H_
+#define _RTE_GRE_H_
+
+#include <stdint.h>
+#include <rte_byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * GRE Header
+ */
+struct gre_hdr {
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+	uint16_t res2:4; /**< Reserved */
+	uint16_t s:1;    /**< Sequence Number Present bit */
+	uint16_t k:1;    /**< Key Present bit */
+	uint16_t res1:1; /**< Reserved */
+	uint16_t c:1;    /**< Checksum Present bit */
+	uint16_t ver:3;  /**< Version Number */
+	uint16_t res3:5; /**< Reserved */
+#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	uint16_t c:1;    /**< Checksum Present bit */
+	uint16_t res1:1; /**< Reserved */
+	uint16_t k:1;    /**< Key Present bit */
+	uint16_t s:1;    /**< Sequence Number Present bit */
+	uint16_t res2:4; /**< Reserved */
+	uint16_t res3:5; /**< Reserved */
+	uint16_t ver:3;  /**< Version Number */
+#endif
+	uint16_t proto;  /**< Protocol Type */
+} __attribute__((__packed__));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_GRE_H_ */
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 08/16] net: support Ip tunnels in software packet type parser
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Jean Dao
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add support of IP and IP6 tunnels in rte_net_get_ptype().

We need to duplicate some code because the packet types do not have the
same value for a given protocol between inner and outer.

Signed-off-by: Jean Dao <jean.dao@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_net/rte_net.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++-
 lib/librte_net/rte_net.h |   1 +
 2 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index dc9e376..87294bb 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -93,6 +93,79 @@ ptype_l4(uint8_t proto)
 	return ptype_l4_proto[proto];
 }
 
+/* get inner l3 packet type from ip6 next protocol */
+static uint32_t
+ptype_inner_l3_ip6(uint8_t ip6_proto)
+{
+	static const uint32_t ptype_inner_ip6_ext_proto_map[256] = {
+		[IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+		[IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT -
+			RTE_PTYPE_INNER_L3_IPV6,
+	};
+
+	return RTE_PTYPE_INNER_L3_IPV6 +
+		ptype_inner_ip6_ext_proto_map[ip6_proto];
+}
+
+/* get inner l3 packet type from ip version and header length */
+static uint32_t
+ptype_inner_l3_ip(uint8_t ipv_ihl)
+{
+	static const uint32_t ptype_inner_l3_ip_proto_map[256] = {
+		[0x45] = RTE_PTYPE_INNER_L3_IPV4,
+		[0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+		[0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT,
+	};
+
+	return ptype_inner_l3_ip_proto_map[ipv_ihl];
+}
+
+/* get inner l4 packet type from proto */
+static uint32_t
+ptype_inner_l4(uint8_t proto)
+{
+	static const uint32_t ptype_inner_l4_proto[256] = {
+		[IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP,
+		[IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP,
+		[IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP,
+	};
+
+	return ptype_inner_l4_proto[proto];
+}
+
+/* get the tunnel packet type if any, update proto. */
+static uint32_t
+ptype_tunnel(uint16_t *proto)
+{
+	switch (*proto) {
+	case IPPROTO_IPIP:
+		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		return RTE_PTYPE_TUNNEL_IP;
+	case IPPROTO_IPV6:
+		*proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */
+	default:
+		return 0;
+	}
+}
+
 /* get the ipv4 header length */
 static uint8_t
 ip4_hlen(const struct ipv4_hdr *hdr)
@@ -207,9 +280,8 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
 		hdr_lens->l3_len = ip4_hlen(ip4h);
 		off += hdr_lens->l3_len;
-		if (ip4h->fragment_offset &
-				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
-					IPV4_HDR_MF_FLAG)) {
+		if (ip4h->fragment_offset & rte_cpu_to_be_16(
+				IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) {
 			pkt_type |= RTE_PTYPE_L4_FRAG;
 			hdr_lens->l4_len = 0;
 			return pkt_type;
@@ -245,6 +317,7 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 
 	if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
 		hdr_lens->l4_len = sizeof(struct udp_hdr);
+		return pkt_type;
 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
 		const struct tcp_hdr *th;
 		struct tcp_hdr th_copy;
@@ -254,10 +327,89 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 			return pkt_type & (RTE_PTYPE_L2_MASK |
 				RTE_PTYPE_L3_MASK);
 		hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
+		return pkt_type;
 	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
 		hdr_lens->l4_len = sizeof(struct sctp_hdr);
+		return pkt_type;
 	} else {
 		hdr_lens->l4_len = 0;
+		pkt_type |= ptype_tunnel(&proto);
+		hdr_lens->tunnel_len = 0;
+	}
+
+	/* same job for inner header: we need to duplicate the code
+	 * because the packet types do not have the same value.
+	 */
+	hdr_lens->inner_l2_len = 0;
+
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		const struct ipv4_hdr *ip4h;
+		struct ipv4_hdr ip4h_copy;
+
+		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
+		if (unlikely(ip4h == NULL))
+			return pkt_type;
+
+		pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl);
+		hdr_lens->inner_l3_len = ip4_hlen(ip4h);
+		off += hdr_lens->inner_l3_len;
+		if (ip4h->fragment_offset &
+				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
+					IPV4_HDR_MF_FLAG)) {
+			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
+			hdr_lens->inner_l4_len = 0;
+			return pkt_type;
+		}
+		proto = ip4h->next_proto_id;
+		pkt_type |= ptype_inner_l4(proto);
+	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		const struct ipv6_hdr *ip6h;
+		struct ipv6_hdr ip6h_copy;
+		int frag = 0;
+
+		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
+		if (unlikely(ip6h == NULL))
+			return pkt_type;
+
+		proto = ip6h->proto;
+		hdr_lens->inner_l3_len = sizeof(*ip6h);
+		off += hdr_lens->inner_l3_len;
+		pkt_type |= ptype_inner_l3_ip6(proto);
+		if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) ==
+				RTE_PTYPE_INNER_L3_IPV6_EXT) {
+			uint32_t prev_off;
+
+			prev_off = off;
+			proto = skip_ip6_ext(proto, m, &off, &frag);
+			hdr_lens->inner_l3_len += off - prev_off;
+		}
+		if (proto == 0)
+			return pkt_type;
+		if (frag) {
+			pkt_type |= RTE_PTYPE_INNER_L4_FRAG;
+			hdr_lens->inner_l4_len = 0;
+			return pkt_type;
+		}
+		pkt_type |= ptype_inner_l4(proto);
+	}
+
+	if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) {
+		hdr_lens->inner_l4_len = sizeof(struct udp_hdr);
+	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
+			RTE_PTYPE_INNER_L4_TCP) {
+		const struct tcp_hdr *th;
+		struct tcp_hdr th_copy;
+
+		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
+		if (unlikely(th == NULL))
+			return pkt_type & (RTE_PTYPE_INNER_L2_MASK |
+				RTE_PTYPE_INNER_L3_MASK);
+		hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2;
+	} else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) ==
+			RTE_PTYPE_INNER_L4_SCTP) {
+		hdr_lens->inner_l4_len = sizeof(struct sctp_hdr);
+	} else {
+		hdr_lens->inner_l4_len = 0;
 	}
 
 	return pkt_type;
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index 1224b0e..f433389 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -68,6 +68,7 @@ struct rte_net_hdr_lens {
  *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
+ *   Tunnels: IPv4, IPv6
  *
  * @param m
  *   The packet mbuf to be parsed.
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 07/16] net: support QinQ in software packet type parser
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Didier Pallard
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add a new RTE_PTYPE_L2_ETHER_QINQ packet type, and its support in
rte_net_get_ptype().

Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mbuf/rte_mbuf_ptype.h |  7 +++++++
 lib/librte_net/rte_ether.h       |  1 +
 lib/librte_net/rte_net.c         | 16 ++++++++++++++++
 lib/librte_net/rte_net.h         |  2 +-
 4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index a955c5a..6e62492 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -143,6 +143,13 @@ extern "C" {
  */
 #define RTE_PTYPE_L2_ETHER_VLAN             0x00000006
 /**
+ * QinQ packet type.
+ *
+ * Packet format:
+ * <'ether type'=[0x88A8]>
+ */
+#define RTE_PTYPE_L2_ETHER_QINQ             0x00000007
+/**
  * Mask of layer 2 packet types.
  * It is used for outer packet for tunneling cases.
  */
diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
index 647e6c9..ff3d065 100644
--- a/lib/librte_net/rte_ether.h
+++ b/lib/librte_net/rte_ether.h
@@ -329,6 +329,7 @@ struct vxlan_hdr {
 #define ETHER_TYPE_ARP  0x0806 /**< Arp Protocol. */
 #define ETHER_TYPE_RARP 0x8035 /**< Reverse Arp Protocol. */
 #define ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
+#define ETHER_TYPE_QINQ 0x88A8 /**< IEEE 802.1ad QinQ tagging. */
 #define ETHER_TYPE_1588 0x88F7 /**< IEEE 802.1AS 1588 Precise Time Protocol. */
 #define ETHER_TYPE_SLOW 0x8809 /**< Slow protocols (LACP and Marker). */
 #define ETHER_TYPE_TEB  0x6558 /**< Transparent Ethernet Bridging. */
diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index a75b509..dc9e376 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -167,6 +167,9 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	off = sizeof(*eh);
 	hdr_lens->l2_len = off;
 
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
+		goto l3; /* fast path if packet is IPv4 */
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
 		const struct vlan_hdr *vh;
 		struct vlan_hdr vh_copy;
@@ -178,8 +181,21 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 		off += sizeof(*vh);
 		hdr_lens->l2_len += sizeof(*vh);
 		proto = vh->eth_proto;
+	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) {
+		const struct vlan_hdr *vh;
+		struct vlan_hdr vh_copy;
+
+		pkt_type = RTE_PTYPE_L2_ETHER_QINQ;
+		vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh),
+			&vh_copy);
+		if (unlikely(vh == NULL))
+			return pkt_type;
+		off += 2 * sizeof(*vh);
+		hdr_lens->l2_len += 2 * sizeof(*vh);
+		proto = vh->eth_proto;
 	}
 
+ l3:
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
 		struct ipv4_hdr ip4h_copy;
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
index 81979f1..1224b0e 100644
--- a/lib/librte_net/rte_net.h
+++ b/lib/librte_net/rte_net.h
@@ -65,7 +65,7 @@ struct rte_net_hdr_lens {
  * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
  *
  * Supported packet types are:
- *   L2: Ether
+ *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
  *
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 06/16] net: support Vlan in software packet type parser
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Didier Pallard
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Add a new RTE_PTYPE_L2_ETHER_VLAN packet type, and its support in
rte_net_get_ptype().

Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mbuf/rte_mbuf_ptype.h |  7 +++++++
 lib/librte_net/rte_net.c         | 13 +++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 65e9ced..a955c5a 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -136,6 +136,13 @@ extern "C" {
  */
 #define RTE_PTYPE_L2_ETHER_NSH              0x00000005
 /**
+ * VLAN packet type.
+ *
+ * Packet format:
+ * <'ether type'=[0x8100]>
+ */
+#define RTE_PTYPE_L2_ETHER_VLAN             0x00000006
+/**
  * Mask of layer 2 packet types.
  * It is used for outer packet for tunneling cases.
  */
diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index 93e9df0..a75b509 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -167,6 +167,19 @@ uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
 	off = sizeof(*eh);
 	hdr_lens->l2_len = off;
 
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+		const struct vlan_hdr *vh;
+		struct vlan_hdr vh_copy;
+
+		pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
+		vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
+		if (unlikely(vh == NULL))
+			return pkt_type;
+		off += sizeof(*vh);
+		hdr_lens->l2_len += sizeof(*vh);
+		proto = vh->eth_proto;
+	}
+
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
 		struct ipv4_hdr ip4h_copy;
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 05/16] net: add function to get packet type from data
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Didier Pallard, Jean Dao
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Introduce the function rte_net_get_ptype() that parses a mbuf and
returns its packet type. For now, the following packet types are parsed:
   L2: Ether
   L3: IPv4, IPv6
   L4: TCP, UDP, SCTP

The goal here is to provide a reference implementation for packet type
parsing. This function will be used by testpmd in next commits, allowing
to compare its result with the value given by the hardware.

This function will also be useful when implementing Rx offload support
in virtio pmd. Indeed, the virtio protocol gives the csum start and
offset, but it does not give the L4 protocol nor it tells if the
checksum is relevant for inner or outer. This information has to be
known to properly set the ol_flags in mbuf.

Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
Signed-off-by: Jean Dao <jean.dao@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 doc/guides/rel_notes/release_16_11.rst |   5 +
 lib/librte_net/Makefile                |   4 +-
 lib/librte_net/rte_net.c               | 235 +++++++++++++++++++++++++++++++++
 lib/librte_net/rte_net.h               |  88 ++++++++++++
 lib/librte_net/rte_net_version.map     |   3 +
 5 files changed, 334 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_net/rte_net.h

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index ae24da2..b3b9dfb 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -41,6 +41,11 @@ New Features
   Added a new function ``rte_pktmbuf_read()`` to read the packet data from an
   mbuf chain, linearizing if required.
 
+* **Added a function to get the packet type from packet data.**
+
+  Added a new function ``rte_net_get_ptype()`` to parse an Ethernet packet
+  in an mbuf chain and retrieve its packet type by software.
+
 Resolved Issues
 ---------------
 
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index a6be7ae..c16b542 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -41,7 +41,9 @@ LIBABIVER := 1
 SRCS-$(CONFIG_RTE_LIBRTE_NET) := rte_net.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h rte_ether.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_sctp.h rte_icmp.h rte_arp.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_ether.h rte_net.h
 
 DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_eal lib/librte_mempool
 DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_mbuf
diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
index e69de29..93e9df0 100644
--- a/lib/librte_net/rte_net.c
+++ b/lib/librte_net/rte_net.c
@@ -0,0 +1,235 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2016 6WIND S.A.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+#include <rte_mbuf_ptype.h>
+#include <rte_byteorder.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_sctp.h>
+#include <rte_net.h>
+
+/* get l3 packet type from ip6 next protocol */
+static uint32_t
+ptype_l3_ip6(uint8_t ip6_proto)
+{
+	static const uint32_t ip6_ext_proto_map[256] = {
+		[IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+		[IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+		[IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+		[IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+		[IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+		[IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
+	};
+
+	return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
+}
+
+/* get l3 packet type from ip version and header length */
+static uint32_t
+ptype_l3_ip(uint8_t ipv_ihl)
+{
+	static const uint32_t ptype_l3_ip_proto_map[256] = {
+		[0x45] = RTE_PTYPE_L3_IPV4,
+		[0x46] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x47] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x48] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x49] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4A] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4B] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4C] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4D] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4E] = RTE_PTYPE_L3_IPV4_EXT,
+		[0x4F] = RTE_PTYPE_L3_IPV4_EXT,
+	};
+
+	return ptype_l3_ip_proto_map[ipv_ihl];
+}
+
+/* get l4 packet type from proto */
+static uint32_t
+ptype_l4(uint8_t proto)
+{
+	static const uint32_t ptype_l4_proto[256] = {
+		[IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
+		[IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
+		[IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
+	};
+
+	return ptype_l4_proto[proto];
+}
+
+/* get the ipv4 header length */
+static uint8_t
+ip4_hlen(const struct ipv4_hdr *hdr)
+{
+	return (hdr->version_ihl & 0xf) * 4;
+}
+
+/* parse ipv6 extended headers, update offset and return next proto */
+static uint16_t
+skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
+	int *frag)
+{
+	struct ext_hdr {
+		uint8_t next_hdr;
+		uint8_t len;
+	};
+	const struct ext_hdr *xh;
+	struct ext_hdr xh_copy;
+	unsigned int i;
+
+	*frag = 0;
+
+#define MAX_EXT_HDRS 5
+	for (i = 0; i < MAX_EXT_HDRS; i++) {
+		switch (proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
+				&xh_copy);
+			if (xh == NULL)
+				return 0;
+			*off += (xh->len + 1) * 8;
+			proto = xh->next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
+				&xh_copy);
+			if (xh == NULL)
+				return 0;
+			*off += 8;
+			proto = xh->next_hdr;
+			*frag = 1;
+			return proto; /* this is always the last ext hdr */
+		case IPPROTO_NONE:
+			return 0;
+		default:
+			return proto;
+		}
+	}
+	return 0;
+}
+
+/* parse mbuf data to get packet type */
+uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
+	struct rte_net_hdr_lens *hdr_lens)
+{
+	struct rte_net_hdr_lens local_hdr_lens;
+	const struct ether_hdr *eh;
+	struct ether_hdr eh_copy;
+	uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
+	uint32_t off = 0;
+	uint16_t proto;
+
+	if (hdr_lens == NULL)
+		hdr_lens = &local_hdr_lens;
+
+	eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
+	if (unlikely(eh == NULL))
+		return 0;
+	proto = eh->ether_type;
+	off = sizeof(*eh);
+	hdr_lens->l2_len = off;
+
+	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		const struct ipv4_hdr *ip4h;
+		struct ipv4_hdr ip4h_copy;
+
+		ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
+		if (unlikely(ip4h == NULL))
+			return pkt_type;
+
+		pkt_type |= ptype_l3_ip(ip4h->version_ihl);
+		hdr_lens->l3_len = ip4_hlen(ip4h);
+		off += hdr_lens->l3_len;
+		if (ip4h->fragment_offset &
+				rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
+					IPV4_HDR_MF_FLAG)) {
+			pkt_type |= RTE_PTYPE_L4_FRAG;
+			hdr_lens->l4_len = 0;
+			return pkt_type;
+		}
+		proto = ip4h->next_proto_id;
+		pkt_type |= ptype_l4(proto);
+	} else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		const struct ipv6_hdr *ip6h;
+		struct ipv6_hdr ip6h_copy;
+		int frag = 0;
+
+		ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
+		if (unlikely(ip6h == NULL))
+			return pkt_type;
+
+		proto = ip6h->proto;
+		hdr_lens->l3_len = sizeof(*ip6h);
+		off += hdr_lens->l3_len;
+		pkt_type |= ptype_l3_ip6(proto);
+		if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
+			proto = skip_ip6_ext(proto, m, &off, &frag);
+			hdr_lens->l3_len = off - hdr_lens->l2_len;
+		}
+		if (proto == 0)
+			return pkt_type;
+		if (frag) {
+			pkt_type |= RTE_PTYPE_L4_FRAG;
+			hdr_lens->l4_len = 0;
+			return pkt_type;
+		}
+		pkt_type |= ptype_l4(proto);
+	}
+
+	if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
+		hdr_lens->l4_len = sizeof(struct udp_hdr);
+	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
+		const struct tcp_hdr *th;
+		struct tcp_hdr th_copy;
+
+		th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
+		if (unlikely(th == NULL))
+			return pkt_type & (RTE_PTYPE_L2_MASK |
+				RTE_PTYPE_L3_MASK);
+		hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
+	} else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
+		hdr_lens->l4_len = sizeof(struct sctp_hdr);
+	} else {
+		hdr_lens->l4_len = 0;
+	}
+
+	return pkt_type;
+}
diff --git a/lib/librte_net/rte_net.h b/lib/librte_net/rte_net.h
new file mode 100644
index 0000000..81979f1
--- /dev/null
+++ b/lib/librte_net/rte_net.h
@@ -0,0 +1,88 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2016 6WIND S.A.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_NET_PTYPE_H_
+#define _RTE_NET_PTYPE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Structure containing header lengths associated to a packet, filled
+ * by rte_net_get_ptype().
+ */
+struct rte_net_hdr_lens {
+	uint8_t l2_len;
+	uint8_t l3_len;
+	uint8_t l4_len;
+	uint8_t tunnel_len;
+	uint8_t inner_l2_len;
+	uint8_t inner_l3_len;
+	uint8_t inner_l4_len;
+};
+
+/**
+ * Parse an Ethernet packet to get its packet type.
+ *
+ * This function parses the network headers in mbuf data and return its
+ * packet type.
+ *
+ * If it is provided by the user, it also fills a rte_net_hdr_lens
+ * structure that contains the lengths of the parsed network
+ * headers. Each length field is valid only if the associated packet
+ * type is set. For instance, hdr_lens->l2_len is valid only if
+ * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
+ *
+ * Supported packet types are:
+ *   L2: Ether
+ *   L3: IPv4, IPv6
+ *   L4: TCP, UDP, SCTP
+ *
+ * @param m
+ *   The packet mbuf to be parsed.
+ * @param hdr_lens
+ *   A pointer to a structure where the header lengths will be returned,
+ *   or NULL.
+ * @return
+ *   The packet type of the packet.
+ */
+uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
+	struct rte_net_hdr_lens *hdr_lens);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _RTE_NET_PTYPE_H_ */
diff --git a/lib/librte_net/rte_net_version.map b/lib/librte_net/rte_net_version.map
index cc5829e..3b15e65 100644
--- a/lib/librte_net/rte_net_version.map
+++ b/lib/librte_net/rte_net_version.map
@@ -1,3 +1,6 @@
 DPDK_16.11 {
+	global:
+	rte_net_get_ptype;
+
 	local: *;
 };
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 04/16] net: introduce net library
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Previously, librte_net only contained header files. Add a C file
(empty for now) and generate a library. It will contain network helpers
like checksum calculation, software packet type parser, ...

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 MAINTAINERS                        |  1 +
 lib/librte_net/Makefile            | 11 ++++++++++-
 lib/librte_net/rte_net.c           |  0
 lib/librte_net/rte_net_version.map |  3 +++
 mk/rte.app.mk                      |  1 +
 mk/rte.lib.mk                      |  2 +-
 6 files changed, 16 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_net/rte_net.c
 create mode 100644 lib/librte_net/rte_net_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 7c33ad4..3885df5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -439,6 +439,7 @@ Packet processing
 -----------------
 
 Network headers
+M: Olivier Matz <olivier.matz@6wind.com>
 F: lib/librte_net/
 
 IP fragmentation & reassembly
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index fc332ff..a6be7ae 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -31,10 +31,19 @@
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+LIB = librte_net.a
+
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 
+EXPORT_MAP := rte_net_version.map
+LIBABIVER := 1
+
+SRCS-$(CONFIG_RTE_LIBRTE_NET) := rte_net.c
+
 # install includes
 SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h rte_ether.h
 
+DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_eal lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_NET) += lib/librte_mbuf
 
-include $(RTE_SDK)/mk/rte.install.mk
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_net/rte_net.c b/lib/librte_net/rte_net.c
new file mode 100644
index 0000000..e69de29
diff --git a/lib/librte_net/rte_net_version.map b/lib/librte_net/rte_net_version.map
new file mode 100644
index 0000000..cc5829e
--- /dev/null
+++ b/lib/librte_net/rte_net_version.map
@@ -0,0 +1,3 @@
+DPDK_16.11 {
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a0095b..b519e08 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -90,6 +90,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST)          += -lrte_vhost
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
+_LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
diff --git a/mk/rte.lib.mk b/mk/rte.lib.mk
index 830f81a..7b96fd4 100644
--- a/mk/rte.lib.mk
+++ b/mk/rte.lib.mk
@@ -79,7 +79,7 @@ endif
 
 # Translate DEPDIRS-y into LDLIBS
 # Ignore (sub)directory dependencies which do not provide an actual library
-_IGNORE_DIRS = lib/librte_eal/% lib/librte_net lib/librte_compat
+_IGNORE_DIRS = lib/librte_eal/% lib/librte_compat
 _DEPDIRS = $(filter-out $(_IGNORE_DIRS),$(DEPDIRS-y))
 _LDDIRS = $(subst librte_ether,libethdev,$(_DEPDIRS))
 LDLIBS += $(subst lib/lib,-l,$(_LDDIRS))
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 03/16] mbuf: move packet type definitions in a new file
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

The file rte_mbuf.h starts to be quite big, and next commits
will introduce more functions related to packet types. Let's
move them in a new file.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_mbuf/Makefile         |   2 +-
 lib/librte_mbuf/rte_mbuf.h       | 495 +----------------------------------
 lib/librte_mbuf/rte_mbuf_ptype.h | 552 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 554 insertions(+), 495 deletions(-)
 create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.h

diff --git a/lib/librte_mbuf/Makefile b/lib/librte_mbuf/Makefile
index 8d62b0d..27e037c 100644
--- a/lib/librte_mbuf/Makefile
+++ b/lib/librte_mbuf/Makefile
@@ -44,7 +44,7 @@ LIBABIVER := 2
 SRCS-$(CONFIG_RTE_LIBRTE_MBUF) := rte_mbuf.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_mbuf.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_mbuf.h rte_mbuf_ptype.h
 
 # this lib needs eal
 DEPDIRS-$(CONFIG_RTE_LIBRTE_MBUF) += lib/librte_eal lib/librte_mempool
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index a26b9b9..1451ec3 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -60,6 +60,7 @@
 #include <rte_atomic.h>
 #include <rte_prefetch.h>
 #include <rte_branch_prediction.h>
+#include <rte_mbuf_ptype.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -225,500 +226,6 @@ extern "C" {
 /* Use final bit of flags to indicate a control mbuf */
 #define CTRL_MBUF_FLAG       (1ULL << 63) /**< Mbuf contains control data */
 
-/*
- * 32 bits are divided into several fields to mark packet types. Note that
- * each field is indexical.
- * - Bit 3:0 is for L2 types.
- * - Bit 7:4 is for L3 or outer L3 (for tunneling case) types.
- * - Bit 11:8 is for L4 or outer L4 (for tunneling case) types.
- * - Bit 15:12 is for tunnel types.
- * - Bit 19:16 is for inner L2 types.
- * - Bit 23:20 is for inner L3 types.
- * - Bit 27:24 is for inner L4 types.
- * - Bit 31:28 is reserved.
- *
- * To be compatible with Vector PMD, RTE_PTYPE_L3_IPV4, RTE_PTYPE_L3_IPV4_EXT,
- * RTE_PTYPE_L3_IPV6, RTE_PTYPE_L3_IPV6_EXT, RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP
- * and RTE_PTYPE_L4_SCTP should be kept as below in a contiguous 7 bits.
- *
- * Note that L3 types values are selected for checking IPV4/IPV6 header from
- * performance point of view. Reading annotations of RTE_ETH_IS_IPV4_HDR and
- * RTE_ETH_IS_IPV6_HDR is needed for any future changes of L3 type values.
- *
- * Note that the packet types of the same packet recognized by different
- * hardware may be different, as different hardware may have different
- * capability of packet type recognition.
- *
- * examples:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=0x29
- * | 'version'=6, 'next header'=0x3A
- * | 'ICMPv6 header'>
- * will be recognized on i40e hardware as packet type combination of,
- * RTE_PTYPE_L2_ETHER |
- * RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
- * RTE_PTYPE_TUNNEL_IP |
- * RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
- * RTE_PTYPE_INNER_L4_ICMP.
- *
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=0x2F
- * | 'GRE header'
- * | 'version'=6, 'next header'=0x11
- * | 'UDP header'>
- * will be recognized on i40e hardware as packet type combination of,
- * RTE_PTYPE_L2_ETHER |
- * RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
- * RTE_PTYPE_TUNNEL_GRENAT |
- * RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
- * RTE_PTYPE_INNER_L4_UDP.
- */
-#define RTE_PTYPE_UNKNOWN                   0x00000000
-/**
- * Ethernet packet type.
- * It is used for outer packet for tunneling cases.
- *
- * Packet format:
- * <'ether type'=[0x0800|0x86DD]>
- */
-#define RTE_PTYPE_L2_ETHER                  0x00000001
-/**
- * Ethernet packet type for time sync.
- *
- * Packet format:
- * <'ether type'=0x88F7>
- */
-#define RTE_PTYPE_L2_ETHER_TIMESYNC         0x00000002
-/**
- * ARP (Address Resolution Protocol) packet type.
- *
- * Packet format:
- * <'ether type'=0x0806>
- */
-#define RTE_PTYPE_L2_ETHER_ARP              0x00000003
-/**
- * LLDP (Link Layer Discovery Protocol) packet type.
- *
- * Packet format:
- * <'ether type'=0x88CC>
- */
-#define RTE_PTYPE_L2_ETHER_LLDP             0x00000004
-/**
- * NSH (Network Service Header) packet type.
- *
- * Packet format:
- * <'ether type'=0x894F>
- */
-#define RTE_PTYPE_L2_ETHER_NSH              0x00000005
-/**
- * Mask of layer 2 packet types.
- * It is used for outer packet for tunneling cases.
- */
-#define RTE_PTYPE_L2_MASK                   0x0000000f
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for outer packet for tunneling cases, and does not contain any
- * header option.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=5>
- */
-#define RTE_PTYPE_L3_IPV4                   0x00000010
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for outer packet for tunneling cases, and contains header
- * options.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=[6-15], 'options'>
- */
-#define RTE_PTYPE_L3_IPV4_EXT               0x00000030
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for outer packet for tunneling cases, and does not contain any
- * extension header.
- *
- * Packet format:
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=0x3B>
- */
-#define RTE_PTYPE_L3_IPV6                   0x00000040
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for outer packet for tunneling cases, and may or maynot contain
- * header options.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=[5-15], <'options'>>
- */
-#define RTE_PTYPE_L3_IPV4_EXT_UNKNOWN       0x00000090
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for outer packet for tunneling cases, and contains extension
- * headers.
- *
- * Packet format:
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=[0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
- *   'extension headers'>
- */
-#define RTE_PTYPE_L3_IPV6_EXT               0x000000c0
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for outer packet for tunneling cases, and may or maynot contain
- * extension headers.
- *
- * Packet format:
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=[0x3B|0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
- *   <'extension headers'>>
- */
-#define RTE_PTYPE_L3_IPV6_EXT_UNKNOWN       0x000000e0
-/**
- * Mask of layer 3 packet types.
- * It is used for outer packet for tunneling cases.
- */
-#define RTE_PTYPE_L3_MASK                   0x000000f0
-/**
- * TCP (Transmission Control Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=6, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=6>
- */
-#define RTE_PTYPE_L4_TCP                    0x00000100
-/**
- * UDP (User Datagram Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=17>
- */
-#define RTE_PTYPE_L4_UDP                    0x00000200
-/**
- * Fragmented IP (Internet Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * It refers to those packets of any IP types, which can be recognized as
- * fragmented. A fragmented packet cannot be recognized as any other L4 types
- * (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP,
- * RTE_PTYPE_L4_NONFRAG).
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'MF'=1>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=44>
- */
-#define RTE_PTYPE_L4_FRAG                   0x00000300
-/**
- * SCTP (Stream Control Transmission Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=132, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=132>
- */
-#define RTE_PTYPE_L4_SCTP                   0x00000400
-/**
- * ICMP (Internet Control Message Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=1, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=1>
- */
-#define RTE_PTYPE_L4_ICMP                   0x00000500
-/**
- * Non-fragmented IP (Internet Protocol) packet type.
- * It is used for outer packet for tunneling cases.
- *
- * It refers to those packets of any IP types, while cannot be recognized as
- * any of above L4 types (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP,
- * RTE_PTYPE_L4_FRAG, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP).
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'!=[6|17|44|132|1]>
- */
-#define RTE_PTYPE_L4_NONFRAG                0x00000600
-/**
- * Mask of layer 4 packet types.
- * It is used for outer packet for tunneling cases.
- */
-#define RTE_PTYPE_L4_MASK                   0x00000f00
-/**
- * IP (Internet Protocol) in IP (Internet Protocol) tunneling packet type.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=[4|41]>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=[4|41]>
- */
-#define RTE_PTYPE_TUNNEL_IP                 0x00001000
-/**
- * GRE (Generic Routing Encapsulation) tunneling packet type.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=47>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=47>
- */
-#define RTE_PTYPE_TUNNEL_GRE                0x00002000
-/**
- * VXLAN (Virtual eXtensible Local Area Network) tunneling packet type.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17
- * | 'destination port'=4798>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=17
- * | 'destination port'=4798>
- */
-#define RTE_PTYPE_TUNNEL_VXLAN              0x00003000
-/**
- * NVGRE (Network Virtualization using Generic Routing Encapsulation) tunneling
- * packet type.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=47
- * | 'protocol type'=0x6558>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=47
- * | 'protocol type'=0x6558'>
- */
-#define RTE_PTYPE_TUNNEL_NVGRE              0x00004000
-/**
- * GENEVE (Generic Network Virtualization Encapsulation) tunneling packet type.
- *
- * Packet format:
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17
- * | 'destination port'=6081>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=17
- * | 'destination port'=6081>
- */
-#define RTE_PTYPE_TUNNEL_GENEVE             0x00005000
-/**
- * Tunneling packet type of Teredo, VXLAN (Virtual eXtensible Local Area
- * Network) or GRE (Generic Routing Encapsulation) could be recognized as this
- * packet type, if they can not be recognized independently as of hardware
- * capability.
- */
-#define RTE_PTYPE_TUNNEL_GRENAT             0x00006000
-/**
- * Mask of tunneling packet types.
- */
-#define RTE_PTYPE_TUNNEL_MASK               0x0000f000
-/**
- * Ethernet packet type.
- * It is used for inner packet type only.
- *
- * Packet format (inner only):
- * <'ether type'=[0x800|0x86DD]>
- */
-#define RTE_PTYPE_INNER_L2_ETHER            0x00010000
-/**
- * Ethernet packet type with VLAN (Virtual Local Area Network) tag.
- *
- * Packet format (inner only):
- * <'ether type'=[0x800|0x86DD], vlan=[1-4095]>
- */
-#define RTE_PTYPE_INNER_L2_ETHER_VLAN       0x00020000
-/**
- * Mask of inner layer 2 packet types.
- */
-#define RTE_PTYPE_INNER_L2_MASK             0x000f0000
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for inner packet only, and does not contain any header option.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=5>
- */
-#define RTE_PTYPE_INNER_L3_IPV4             0x00100000
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for inner packet only, and contains header options.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=[6-15], 'options'>
- */
-#define RTE_PTYPE_INNER_L3_IPV4_EXT         0x00200000
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for inner packet only, and does not contain any extension header.
- *
- * Packet format (inner only):
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=0x3B>
- */
-#define RTE_PTYPE_INNER_L3_IPV6             0x00300000
-/**
- * IP (Internet Protocol) version 4 packet type.
- * It is used for inner packet only, and may or maynot contain header options.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'ihl'=[5-15], <'options'>>
- */
-#define RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN 0x00400000
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for inner packet only, and contains extension headers.
- *
- * Packet format (inner only):
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=[0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
- *   'extension headers'>
- */
-#define RTE_PTYPE_INNER_L3_IPV6_EXT         0x00500000
-/**
- * IP (Internet Protocol) version 6 packet type.
- * It is used for inner packet only, and may or maynot contain extension
- * headers.
- *
- * Packet format (inner only):
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=[0x3B|0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
- *   <'extension headers'>>
- */
-#define RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN 0x00600000
-/**
- * Mask of inner layer 3 packet types.
- */
-#define RTE_PTYPE_INNER_L3_MASK             0x00f00000
-/**
- * TCP (Transmission Control Protocol) packet type.
- * It is used for inner packet only.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=6, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=6>
- */
-#define RTE_PTYPE_INNER_L4_TCP              0x01000000
-/**
- * UDP (User Datagram Protocol) packet type.
- * It is used for inner packet only.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=17, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=17>
- */
-#define RTE_PTYPE_INNER_L4_UDP              0x02000000
-/**
- * Fragmented IP (Internet Protocol) packet type.
- * It is used for inner packet only, and may or maynot have layer 4 packet.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'MF'=1>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=44>
- */
-#define RTE_PTYPE_INNER_L4_FRAG             0x03000000
-/**
- * SCTP (Stream Control Transmission Protocol) packet type.
- * It is used for inner packet only.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=132, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=132>
- */
-#define RTE_PTYPE_INNER_L4_SCTP             0x04000000
-/**
- * ICMP (Internet Control Message Protocol) packet type.
- * It is used for inner packet only.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'=1, 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'=1>
- */
-#define RTE_PTYPE_INNER_L4_ICMP             0x05000000
-/**
- * Non-fragmented IP (Internet Protocol) packet type.
- * It is used for inner packet only, and may or maynot have other unknown layer
- * 4 packet types.
- *
- * Packet format (inner only):
- * <'ether type'=0x0800
- * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
- * or,
- * <'ether type'=0x86DD
- * | 'version'=6, 'next header'!=[6|17|44|132|1]>
- */
-#define RTE_PTYPE_INNER_L4_NONFRAG          0x06000000
-/**
- * Mask of inner layer 4 packet types.
- */
-#define RTE_PTYPE_INNER_L4_MASK             0x0f000000
-
-/**
- * Check if the (outer) L3 header is IPv4. To avoid comparing IPv4 types one by
- * one, bit 4 is selected to be used for IPv4 only. Then checking bit 4 can
- * determine if it is an IPV4 packet.
- */
-#define  RTE_ETH_IS_IPV4_HDR(ptype) ((ptype) & RTE_PTYPE_L3_IPV4)
-
-/**
- * Check if the (outer) L3 header is IPv4. To avoid comparing IPv4 types one by
- * one, bit 6 is selected to be used for IPv4 only. Then checking bit 6 can
- * determine if it is an IPV4 packet.
- */
-#define  RTE_ETH_IS_IPV6_HDR(ptype) ((ptype) & RTE_PTYPE_L3_IPV6)
-
-/* Check if it is a tunneling packet */
-#define RTE_ETH_IS_TUNNEL_PKT(ptype) ((ptype) & (RTE_PTYPE_TUNNEL_MASK | \
-                                                 RTE_PTYPE_INNER_L2_MASK | \
-                                                 RTE_PTYPE_INNER_L3_MASK | \
-                                                 RTE_PTYPE_INNER_L4_MASK))
-
 /** Alignment constraint of mbuf private area. */
 #define RTE_MBUF_PRIV_ALIGN 8
 
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
new file mode 100644
index 0000000..65e9ced
--- /dev/null
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -0,0 +1,552 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 Intel Corporation.
+ *   Copyright 2014-2016 6WIND S.A.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_MBUF_PTYPE_H_
+#define _RTE_MBUF_PTYPE_H_
+
+/**
+ * @file
+ * RTE Mbuf Packet Types
+ *
+ * This file contains declarations for features related to mbuf packet
+ * types. The packet type gives information about the data carried by the
+ * mbuf, and is stored in the mbuf in a 32 bits field.
+ *
+ * The 32 bits are divided into several fields to mark packet types. Note that
+ * each field is indexical.
+ * - Bit 3:0 is for L2 types.
+ * - Bit 7:4 is for L3 or outer L3 (for tunneling case) types.
+ * - Bit 11:8 is for L4 or outer L4 (for tunneling case) types.
+ * - Bit 15:12 is for tunnel types.
+ * - Bit 19:16 is for inner L2 types.
+ * - Bit 23:20 is for inner L3 types.
+ * - Bit 27:24 is for inner L4 types.
+ * - Bit 31:28 is reserved.
+ *
+ * To be compatible with Vector PMD, RTE_PTYPE_L3_IPV4, RTE_PTYPE_L3_IPV4_EXT,
+ * RTE_PTYPE_L3_IPV6, RTE_PTYPE_L3_IPV6_EXT, RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP
+ * and RTE_PTYPE_L4_SCTP should be kept as below in a contiguous 7 bits.
+ *
+ * Note that L3 types values are selected for checking IPV4/IPV6 header from
+ * performance point of view. Reading annotations of RTE_ETH_IS_IPV4_HDR and
+ * RTE_ETH_IS_IPV6_HDR is needed for any future changes of L3 type values.
+ *
+ * Note that the packet types of the same packet recognized by different
+ * hardware may be different, as different hardware may have different
+ * capability of packet type recognition.
+ *
+ * examples:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=0x29
+ * | 'version'=6, 'next header'=0x3A
+ * | 'ICMPv6 header'>
+ * will be recognized on i40e hardware as packet type combination of,
+ * RTE_PTYPE_L2_ETHER |
+ * RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+ * RTE_PTYPE_TUNNEL_IP |
+ * RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+ * RTE_PTYPE_INNER_L4_ICMP.
+ *
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=0x2F
+ * | 'GRE header'
+ * | 'version'=6, 'next header'=0x11
+ * | 'UDP header'>
+ * will be recognized on i40e hardware as packet type combination of,
+ * RTE_PTYPE_L2_ETHER |
+ * RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
+ * RTE_PTYPE_TUNNEL_GRENAT |
+ * RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
+ * RTE_PTYPE_INNER_L4_UDP.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * No packet type information.
+ */
+#define RTE_PTYPE_UNKNOWN                   0x00000000
+/**
+ * Ethernet packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * Packet format:
+ * <'ether type'=[0x0800|0x86DD]>
+ */
+#define RTE_PTYPE_L2_ETHER                  0x00000001
+/**
+ * Ethernet packet type for time sync.
+ *
+ * Packet format:
+ * <'ether type'=0x88F7>
+ */
+#define RTE_PTYPE_L2_ETHER_TIMESYNC         0x00000002
+/**
+ * ARP (Address Resolution Protocol) packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0806>
+ */
+#define RTE_PTYPE_L2_ETHER_ARP              0x00000003
+/**
+ * LLDP (Link Layer Discovery Protocol) packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x88CC>
+ */
+#define RTE_PTYPE_L2_ETHER_LLDP             0x00000004
+/**
+ * NSH (Network Service Header) packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x894F>
+ */
+#define RTE_PTYPE_L2_ETHER_NSH              0x00000005
+/**
+ * Mask of layer 2 packet types.
+ * It is used for outer packet for tunneling cases.
+ */
+#define RTE_PTYPE_L2_MASK                   0x0000000f
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for outer packet for tunneling cases, and does not contain any
+ * header option.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=5>
+ */
+#define RTE_PTYPE_L3_IPV4                   0x00000010
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for outer packet for tunneling cases, and contains header
+ * options.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=[6-15], 'options'>
+ */
+#define RTE_PTYPE_L3_IPV4_EXT               0x00000030
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for outer packet for tunneling cases, and does not contain any
+ * extension header.
+ *
+ * Packet format:
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=0x3B>
+ */
+#define RTE_PTYPE_L3_IPV6                   0x00000040
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for outer packet for tunneling cases, and may or maynot contain
+ * header options.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=[5-15], <'options'>>
+ */
+#define RTE_PTYPE_L3_IPV4_EXT_UNKNOWN       0x00000090
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for outer packet for tunneling cases, and contains extension
+ * headers.
+ *
+ * Packet format:
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=[0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
+ *   'extension headers'>
+ */
+#define RTE_PTYPE_L3_IPV6_EXT               0x000000c0
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for outer packet for tunneling cases, and may or maynot contain
+ * extension headers.
+ *
+ * Packet format:
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=[0x3B|0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
+ *   <'extension headers'>>
+ */
+#define RTE_PTYPE_L3_IPV6_EXT_UNKNOWN       0x000000e0
+/**
+ * Mask of layer 3 packet types.
+ * It is used for outer packet for tunneling cases.
+ */
+#define RTE_PTYPE_L3_MASK                   0x000000f0
+/**
+ * TCP (Transmission Control Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=6, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=6>
+ */
+#define RTE_PTYPE_L4_TCP                    0x00000100
+/**
+ * UDP (User Datagram Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=17, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=17>
+ */
+#define RTE_PTYPE_L4_UDP                    0x00000200
+/**
+ * Fragmented IP (Internet Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * It refers to those packets of any IP types, which can be recognized as
+ * fragmented. A fragmented packet cannot be recognized as any other L4 types
+ * (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP,
+ * RTE_PTYPE_L4_NONFRAG).
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'MF'=1>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=44>
+ */
+#define RTE_PTYPE_L4_FRAG                   0x00000300
+/**
+ * SCTP (Stream Control Transmission Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=132, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=132>
+ */
+#define RTE_PTYPE_L4_SCTP                   0x00000400
+/**
+ * ICMP (Internet Control Message Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=1, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=1>
+ */
+#define RTE_PTYPE_L4_ICMP                   0x00000500
+/**
+ * Non-fragmented IP (Internet Protocol) packet type.
+ * It is used for outer packet for tunneling cases.
+ *
+ * It refers to those packets of any IP types, while cannot be recognized as
+ * any of above L4 types (RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP,
+ * RTE_PTYPE_L4_FRAG, RTE_PTYPE_L4_SCTP, RTE_PTYPE_L4_ICMP).
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'!=[6|17|44|132|1]>
+ */
+#define RTE_PTYPE_L4_NONFRAG                0x00000600
+/**
+ * Mask of layer 4 packet types.
+ * It is used for outer packet for tunneling cases.
+ */
+#define RTE_PTYPE_L4_MASK                   0x00000f00
+/**
+ * IP (Internet Protocol) in IP (Internet Protocol) tunneling packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=[4|41]>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=[4|41]>
+ */
+#define RTE_PTYPE_TUNNEL_IP                 0x00001000
+/**
+ * GRE (Generic Routing Encapsulation) tunneling packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=47>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=47>
+ */
+#define RTE_PTYPE_TUNNEL_GRE                0x00002000
+/**
+ * VXLAN (Virtual eXtensible Local Area Network) tunneling packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=17
+ * | 'destination port'=4798>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=17
+ * | 'destination port'=4798>
+ */
+#define RTE_PTYPE_TUNNEL_VXLAN              0x00003000
+/**
+ * NVGRE (Network Virtualization using Generic Routing Encapsulation) tunneling
+ * packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=47
+ * | 'protocol type'=0x6558>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=47
+ * | 'protocol type'=0x6558'>
+ */
+#define RTE_PTYPE_TUNNEL_NVGRE              0x00004000
+/**
+ * GENEVE (Generic Network Virtualization Encapsulation) tunneling packet type.
+ *
+ * Packet format:
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=17
+ * | 'destination port'=6081>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=17
+ * | 'destination port'=6081>
+ */
+#define RTE_PTYPE_TUNNEL_GENEVE             0x00005000
+/**
+ * Tunneling packet type of Teredo, VXLAN (Virtual eXtensible Local Area
+ * Network) or GRE (Generic Routing Encapsulation) could be recognized as this
+ * packet type, if they can not be recognized independently as of hardware
+ * capability.
+ */
+#define RTE_PTYPE_TUNNEL_GRENAT             0x00006000
+/**
+ * Mask of tunneling packet types.
+ */
+#define RTE_PTYPE_TUNNEL_MASK               0x0000f000
+/**
+ * Ethernet packet type.
+ * It is used for inner packet type only.
+ *
+ * Packet format (inner only):
+ * <'ether type'=[0x800|0x86DD]>
+ */
+#define RTE_PTYPE_INNER_L2_ETHER            0x00010000
+/**
+ * Ethernet packet type with VLAN (Virtual Local Area Network) tag.
+ *
+ * Packet format (inner only):
+ * <'ether type'=[0x800|0x86DD], vlan=[1-4095]>
+ */
+#define RTE_PTYPE_INNER_L2_ETHER_VLAN       0x00020000
+/**
+ * Mask of inner layer 2 packet types.
+ */
+#define RTE_PTYPE_INNER_L2_MASK             0x000f0000
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for inner packet only, and does not contain any header option.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=5>
+ */
+#define RTE_PTYPE_INNER_L3_IPV4             0x00100000
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for inner packet only, and contains header options.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=[6-15], 'options'>
+ */
+#define RTE_PTYPE_INNER_L3_IPV4_EXT         0x00200000
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for inner packet only, and does not contain any extension header.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=0x3B>
+ */
+#define RTE_PTYPE_INNER_L3_IPV6             0x00300000
+/**
+ * IP (Internet Protocol) version 4 packet type.
+ * It is used for inner packet only, and may or maynot contain header options.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'ihl'=[5-15], <'options'>>
+ */
+#define RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN 0x00400000
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for inner packet only, and contains extension headers.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=[0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
+ *   'extension headers'>
+ */
+#define RTE_PTYPE_INNER_L3_IPV6_EXT         0x00500000
+/**
+ * IP (Internet Protocol) version 6 packet type.
+ * It is used for inner packet only, and may or maynot contain extension
+ * headers.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=[0x3B|0x0|0x2B|0x2C|0x32|0x33|0x3C|0x87],
+ *   <'extension headers'>>
+ */
+#define RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN 0x00600000
+/**
+ * Mask of inner layer 3 packet types.
+ */
+#define RTE_PTYPE_INNER_L3_MASK             0x00f00000
+/**
+ * TCP (Transmission Control Protocol) packet type.
+ * It is used for inner packet only.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=6, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=6>
+ */
+#define RTE_PTYPE_INNER_L4_TCP              0x01000000
+/**
+ * UDP (User Datagram Protocol) packet type.
+ * It is used for inner packet only.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=17, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=17>
+ */
+#define RTE_PTYPE_INNER_L4_UDP              0x02000000
+/**
+ * Fragmented IP (Internet Protocol) packet type.
+ * It is used for inner packet only, and may or maynot have layer 4 packet.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'MF'=1>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=44>
+ */
+#define RTE_PTYPE_INNER_L4_FRAG             0x03000000
+/**
+ * SCTP (Stream Control Transmission Protocol) packet type.
+ * It is used for inner packet only.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=132, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=132>
+ */
+#define RTE_PTYPE_INNER_L4_SCTP             0x04000000
+/**
+ * ICMP (Internet Control Message Protocol) packet type.
+ * It is used for inner packet only.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'=1, 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'=1>
+ */
+#define RTE_PTYPE_INNER_L4_ICMP             0x05000000
+/**
+ * Non-fragmented IP (Internet Protocol) packet type.
+ * It is used for inner packet only, and may or maynot have other unknown layer
+ * 4 packet types.
+ *
+ * Packet format (inner only):
+ * <'ether type'=0x0800
+ * | 'version'=4, 'protocol'!=[6|17|132|1], 'MF'=0>
+ * or,
+ * <'ether type'=0x86DD
+ * | 'version'=6, 'next header'!=[6|17|44|132|1]>
+ */
+#define RTE_PTYPE_INNER_L4_NONFRAG          0x06000000
+/**
+ * Mask of inner layer 4 packet types.
+ */
+#define RTE_PTYPE_INNER_L4_MASK             0x0f000000
+
+/**
+ * Check if the (outer) L3 header is IPv4. To avoid comparing IPv4 types one by
+ * one, bit 4 is selected to be used for IPv4 only. Then checking bit 4 can
+ * determine if it is an IPV4 packet.
+ */
+#define  RTE_ETH_IS_IPV4_HDR(ptype) ((ptype) & RTE_PTYPE_L3_IPV4)
+
+/**
+ * Check if the (outer) L3 header is IPv4. To avoid comparing IPv4 types one by
+ * one, bit 6 is selected to be used for IPv4 only. Then checking bit 6 can
+ * determine if it is an IPV4 packet.
+ */
+#define  RTE_ETH_IS_IPV6_HDR(ptype) ((ptype) & RTE_PTYPE_L3_IPV6)
+
+/* Check if it is a tunneling packet */
+#define RTE_ETH_IS_TUNNEL_PKT(ptype) ((ptype) &				\
+	(RTE_PTYPE_TUNNEL_MASK |					\
+		RTE_PTYPE_INNER_L2_MASK |				\
+		RTE_PTYPE_INNER_L3_MASK |				\
+		RTE_PTYPE_INNER_L4_MASK))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_MBUF_PTYPE_H_ */
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 02/16] net: move Ethernet header definitions to the net library
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev,
	Didier Pallard
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

The proper place for rte_ether.h is in librte_net because it defines
network headers.

Moving it will also prevent to have circular references in the following
patches that will require the Ethernet header definition in rte_mbuf.c.
By the way, fix minor checkpatch issues.

Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_ether/Makefile    |   3 +-
 lib/librte_ether/rte_ether.h | 416 -------------------------------------------
 lib/librte_net/Makefile      |   2 +-
 lib/librte_net/rte_ether.h   | 416 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 418 insertions(+), 419 deletions(-)
 delete mode 100644 lib/librte_ether/rte_ether.h
 create mode 100644 lib/librte_net/rte_ether.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 0bb5dc9..488b7c8 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -48,12 +48,11 @@ SRCS-y += rte_ethdev.c
 #
 # Export include files
 #
-SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
 SYMLINK-y-include += rte_eth_ctrl.h
 SYMLINK-y-include += rte_dev_info.h
 
 # this lib depends upon:
-DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
+DEPDIRS-y += lib/librte_net lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ether/rte_ether.h b/lib/librte_ether/rte_ether.h
deleted file mode 100644
index 1d62d8e..0000000
--- a/lib/librte_ether/rte_ether.h
+++ /dev/null
@@ -1,416 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _RTE_ETHER_H_
-#define _RTE_ETHER_H_
-
-/**
- * @file
- *
- * Ethernet Helpers in RTE
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <stdio.h>
-
-#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. */
-#define ETHER_CRC_LEN   4 /**< Length of Ethernet CRC. */
-#define ETHER_HDR_LEN   \
-	(ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) /**< Length of Ethernet header. */
-#define ETHER_MIN_LEN   64    /**< Minimum frame len, including CRC. */
-#define ETHER_MAX_LEN   1518  /**< Maximum frame len, including CRC. */
-#define ETHER_MTU       \
-	(ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) /**< Ethernet MTU. */
-
-#define ETHER_MAX_VLAN_FRAME_LEN \
-	(ETHER_MAX_LEN + 4) /**< Maximum VLAN frame length, including CRC. */
-
-#define ETHER_MAX_JUMBO_FRAME_LEN \
-	0x3F00 /**< Maximum Jumbo frame length, including CRC. */
-
-#define ETHER_MAX_VLAN_ID  4095 /**< Maximum VLAN ID. */
-
-#define ETHER_MIN_MTU 68 /**< Minimum MTU for IPv4 packets, see RFC 791. */
-
-/**
- * Ethernet address:
- * A universally administered address is uniquely assigned to a device by its
- * manufacturer. The first three octets (in transmission order) contain the
- * Organizationally Unique Identifier (OUI). The following three (MAC-48 and
- * EUI-48) octets are assigned by that organization with the only constraint
- * of uniqueness.
- * A locally administered address is assigned to a device by a network
- * administrator and does not contain OUIs.
- * See http://standards.ieee.org/regauth/groupmac/tutorial.html
- */
-struct ether_addr {
-	uint8_t addr_bytes[ETHER_ADDR_LEN]; /**< Address bytes in transmission order */
-} __attribute__((__packed__));
-
-#define ETHER_LOCAL_ADMIN_ADDR 0x02 /**< Locally assigned Eth. address. */
-#define ETHER_GROUP_ADDR       0x01 /**< Multicast or broadcast Eth. address. */
-
-/**
- * Check if two Ethernet addresses are the same.
- *
- * @param ea1
- *  A pointer to the first ether_addr structure containing
- *  the ethernet address.
- * @param ea2
- *  A pointer to the second ether_addr structure containing
- *  the ethernet address.
- *
- * @return
- *  True  (1) if the given two ethernet address are the same;
- *  False (0) otherwise.
- */
-static inline int is_same_ether_addr(const struct ether_addr *ea1,
-				     const struct ether_addr *ea2)
-{
-	int i;
-	for (i = 0; i < ETHER_ADDR_LEN; i++)
-		if (ea1->addr_bytes[i] != ea2->addr_bytes[i])
-			return 0;
-	return 1;
-}
-
-/**
- * Check if an Ethernet address is filled with zeros.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is filled with zeros;
- *   false (0) otherwise.
- */
-static inline int is_zero_ether_addr(const struct ether_addr *ea)
-{
-	int i;
-	for (i = 0; i < ETHER_ADDR_LEN; i++)
-		if (ea->addr_bytes[i] != 0x00)
-			return 0;
-	return 1;
-}
-
-/**
- * Check if an Ethernet address is a unicast address.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is a unicast address;
- *   false (0) otherwise.
- */
-static inline int is_unicast_ether_addr(const struct ether_addr *ea)
-{
-	return (ea->addr_bytes[0] & ETHER_GROUP_ADDR) == 0;
-}
-
-/**
- * Check if an Ethernet address is a multicast address.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is a multicast address;
- *   false (0) otherwise.
- */
-static inline int is_multicast_ether_addr(const struct ether_addr *ea)
-{
-	return ea->addr_bytes[0] & ETHER_GROUP_ADDR;
-}
-
-/**
- * Check if an Ethernet address is a broadcast address.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is a broadcast address;
- *   false (0) otherwise.
- */
-static inline int is_broadcast_ether_addr(const struct ether_addr *ea)
-{
-	const unaligned_uint16_t *ea_words = (const unaligned_uint16_t *)ea;
-
-	return (ea_words[0] == 0xFFFF && ea_words[1] == 0xFFFF &&
-		ea_words[2] == 0xFFFF);
-}
-
-/**
- * Check if an Ethernet address is a universally assigned address.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is a universally assigned address;
- *   false (0) otherwise.
- */
-static inline int is_universal_ether_addr(const struct ether_addr *ea)
-{
-	return (ea->addr_bytes[0] & ETHER_LOCAL_ADMIN_ADDR) == 0;
-}
-
-/**
- * Check if an Ethernet address is a locally assigned address.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is a locally assigned address;
- *   false (0) otherwise.
- */
-static inline int is_local_admin_ether_addr(const struct ether_addr *ea)
-{
-	return (ea->addr_bytes[0] & ETHER_LOCAL_ADMIN_ADDR) != 0;
-}
-
-/**
- * Check if an Ethernet address is a valid address. Checks that the address is a
- * unicast address and is not filled with zeros.
- *
- * @param ea
- *   A pointer to a ether_addr structure containing the ethernet address
- *   to check.
- * @return
- *   True  (1) if the given ethernet address is valid;
- *   false (0) otherwise.
- */
-static inline int is_valid_assigned_ether_addr(const struct ether_addr *ea)
-{
-	return is_unicast_ether_addr(ea) && (! is_zero_ether_addr(ea));
-}
-
-/**
- * Generate a random Ethernet address that is locally administered
- * and not multicast.
- * @param addr
- *   A pointer to Ethernet address.
- */
-static inline void eth_random_addr(uint8_t *addr)
-{
-	uint64_t rand = rte_rand();
-	uint8_t *p = (uint8_t*)&rand;
-
-	rte_memcpy(addr, p, ETHER_ADDR_LEN);
-	addr[0] &= ~ETHER_GROUP_ADDR;       /* clear multicast bit */
-	addr[0] |= ETHER_LOCAL_ADMIN_ADDR;  /* set local assignment bit */
-}
-
-/**
- * Fast copy an Ethernet address.
- *
- * @param ea_from
- *   A pointer to a ether_addr structure holding the Ethernet address to copy.
- * @param ea_to
- *   A pointer to a ether_addr structure where to copy the Ethernet address.
- */
-static inline void ether_addr_copy(const struct ether_addr *ea_from,
-				   struct ether_addr *ea_to)
-{
-#ifdef __INTEL_COMPILER
-	uint16_t *from_words = (uint16_t *)(ea_from->addr_bytes);
-	uint16_t *to_words   = (uint16_t *)(ea_to->addr_bytes);
-
-	to_words[0] = from_words[0];
-	to_words[1] = from_words[1];
-	to_words[2] = from_words[2];
-#else
-	/*
-	 * Use the common way, because of a strange gcc warning.
-	 */
-	*ea_to = *ea_from;
-#endif
-}
-
-#define ETHER_ADDR_FMT_SIZE         18
-/**
- * Format 48bits Ethernet address in pattern xx:xx:xx:xx:xx:xx.
- *
- * @param buf
- *   A pointer to buffer contains the formatted MAC address.
- * @param size
- *   The format buffer size.
- * @param eth_addr
- *   A pointer to a ether_addr structure.
- */
-static inline void
-ether_format_addr(char *buf, uint16_t size,
-		  const struct ether_addr *eth_addr)
-{
-	snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X",
-		 eth_addr->addr_bytes[0],
-		 eth_addr->addr_bytes[1],
-		 eth_addr->addr_bytes[2],
-		 eth_addr->addr_bytes[3],
-		 eth_addr->addr_bytes[4],
-		 eth_addr->addr_bytes[5]);
-}
-
-/**
- * Ethernet header: Contains the destination address, source address
- * and frame type.
- */
-struct ether_hdr {
-	struct ether_addr d_addr; /**< Destination address. */
-	struct ether_addr s_addr; /**< Source address. */
-	uint16_t ether_type;      /**< Frame type. */
-} __attribute__((__packed__));
-
-/**
- * Ethernet VLAN Header.
- * Contains the 16-bit VLAN Tag Control Identifier and the Ethernet type
- * of the encapsulated frame.
- */
-struct vlan_hdr {
-	uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
-	uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
-} __attribute__((__packed__));
-
-/**
- * VXLAN protocol header.
- * Contains the 8-bit flag, 24-bit VXLAN Network Identifier and
- * Reserved fields (24 bits and 8 bits)
- */
-struct vxlan_hdr {
-	uint32_t vx_flags; /**< flag (8) + Reserved (24). */
-	uint32_t vx_vni;   /**< VNI (24) + Reserved (8). */
-} __attribute__((__packed__));
-
-/* Ethernet frame types */
-#define ETHER_TYPE_IPv4 0x0800 /**< IPv4 Protocol. */
-#define ETHER_TYPE_IPv6 0x86DD /**< IPv6 Protocol. */
-#define ETHER_TYPE_ARP  0x0806 /**< Arp Protocol. */
-#define ETHER_TYPE_RARP 0x8035 /**< Reverse Arp Protocol. */
-#define ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
-#define ETHER_TYPE_1588 0x88F7 /**< IEEE 802.1AS 1588 Precise Time Protocol. */
-#define ETHER_TYPE_SLOW 0x8809 /**< Slow protocols (LACP and Marker). */
-#define ETHER_TYPE_TEB  0x6558 /**< Transparent Ethernet Bridging. */
-
-#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;
-
-	/* 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;
-	}
-
-	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
-
-#endif /* _RTE_ETHER_H_ */
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index ad2e482..fc332ff 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -34,7 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h rte_ether.h
 
 
 include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
new file mode 100644
index 0000000..647e6c9
--- /dev/null
+++ b/lib/librte_net/rte_ether.h
@@ -0,0 +1,416 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETHER_H_
+#define _RTE_ETHER_H_
+
+/**
+ * @file
+ *
+ * Ethernet Helpers in RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+
+#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. */
+#define ETHER_CRC_LEN   4 /**< Length of Ethernet CRC. */
+#define ETHER_HDR_LEN   \
+	(ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) /**< Length of Ethernet header. */
+#define ETHER_MIN_LEN   64    /**< Minimum frame len, including CRC. */
+#define ETHER_MAX_LEN   1518  /**< Maximum frame len, including CRC. */
+#define ETHER_MTU       \
+	(ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) /**< Ethernet MTU. */
+
+#define ETHER_MAX_VLAN_FRAME_LEN \
+	(ETHER_MAX_LEN + 4) /**< Maximum VLAN frame length, including CRC. */
+
+#define ETHER_MAX_JUMBO_FRAME_LEN \
+	0x3F00 /**< Maximum Jumbo frame length, including CRC. */
+
+#define ETHER_MAX_VLAN_ID  4095 /**< Maximum VLAN ID. */
+
+#define ETHER_MIN_MTU 68 /**< Minimum MTU for IPv4 packets, see RFC 791. */
+
+/**
+ * Ethernet address:
+ * A universally administered address is uniquely assigned to a device by its
+ * manufacturer. The first three octets (in transmission order) contain the
+ * Organizationally Unique Identifier (OUI). The following three (MAC-48 and
+ * EUI-48) octets are assigned by that organization with the only constraint
+ * of uniqueness.
+ * A locally administered address is assigned to a device by a network
+ * administrator and does not contain OUIs.
+ * See http://standards.ieee.org/regauth/groupmac/tutorial.html
+ */
+struct ether_addr {
+	uint8_t addr_bytes[ETHER_ADDR_LEN]; /**< Addr bytes in tx order */
+} __attribute__((__packed__));
+
+#define ETHER_LOCAL_ADMIN_ADDR 0x02 /**< Locally assigned Eth. address. */
+#define ETHER_GROUP_ADDR       0x01 /**< Multicast or broadcast Eth. address. */
+
+/**
+ * Check if two Ethernet addresses are the same.
+ *
+ * @param ea1
+ *  A pointer to the first ether_addr structure containing
+ *  the ethernet address.
+ * @param ea2
+ *  A pointer to the second ether_addr structure containing
+ *  the ethernet address.
+ *
+ * @return
+ *  True  (1) if the given two ethernet address are the same;
+ *  False (0) otherwise.
+ */
+static inline int is_same_ether_addr(const struct ether_addr *ea1,
+				     const struct ether_addr *ea2)
+{
+	int i;
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		if (ea1->addr_bytes[i] != ea2->addr_bytes[i])
+			return 0;
+	return 1;
+}
+
+/**
+ * Check if an Ethernet address is filled with zeros.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is filled with zeros;
+ *   false (0) otherwise.
+ */
+static inline int is_zero_ether_addr(const struct ether_addr *ea)
+{
+	int i;
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		if (ea->addr_bytes[i] != 0x00)
+			return 0;
+	return 1;
+}
+
+/**
+ * Check if an Ethernet address is a unicast address.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is a unicast address;
+ *   false (0) otherwise.
+ */
+static inline int is_unicast_ether_addr(const struct ether_addr *ea)
+{
+	return (ea->addr_bytes[0] & ETHER_GROUP_ADDR) == 0;
+}
+
+/**
+ * Check if an Ethernet address is a multicast address.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is a multicast address;
+ *   false (0) otherwise.
+ */
+static inline int is_multicast_ether_addr(const struct ether_addr *ea)
+{
+	return ea->addr_bytes[0] & ETHER_GROUP_ADDR;
+}
+
+/**
+ * Check if an Ethernet address is a broadcast address.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is a broadcast address;
+ *   false (0) otherwise.
+ */
+static inline int is_broadcast_ether_addr(const struct ether_addr *ea)
+{
+	const unaligned_uint16_t *ea_words = (const unaligned_uint16_t *)ea;
+
+	return (ea_words[0] == 0xFFFF && ea_words[1] == 0xFFFF &&
+		ea_words[2] == 0xFFFF);
+}
+
+/**
+ * Check if an Ethernet address is a universally assigned address.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is a universally assigned address;
+ *   false (0) otherwise.
+ */
+static inline int is_universal_ether_addr(const struct ether_addr *ea)
+{
+	return (ea->addr_bytes[0] & ETHER_LOCAL_ADMIN_ADDR) == 0;
+}
+
+/**
+ * Check if an Ethernet address is a locally assigned address.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is a locally assigned address;
+ *   false (0) otherwise.
+ */
+static inline int is_local_admin_ether_addr(const struct ether_addr *ea)
+{
+	return (ea->addr_bytes[0] & ETHER_LOCAL_ADMIN_ADDR) != 0;
+}
+
+/**
+ * Check if an Ethernet address is a valid address. Checks that the address is a
+ * unicast address and is not filled with zeros.
+ *
+ * @param ea
+ *   A pointer to a ether_addr structure containing the ethernet address
+ *   to check.
+ * @return
+ *   True  (1) if the given ethernet address is valid;
+ *   false (0) otherwise.
+ */
+static inline int is_valid_assigned_ether_addr(const struct ether_addr *ea)
+{
+	return is_unicast_ether_addr(ea) && (!is_zero_ether_addr(ea));
+}
+
+/**
+ * Generate a random Ethernet address that is locally administered
+ * and not multicast.
+ * @param addr
+ *   A pointer to Ethernet address.
+ */
+static inline void eth_random_addr(uint8_t *addr)
+{
+	uint64_t rand = rte_rand();
+	uint8_t *p = (uint8_t *)&rand;
+
+	rte_memcpy(addr, p, ETHER_ADDR_LEN);
+	addr[0] &= ~ETHER_GROUP_ADDR;       /* clear multicast bit */
+	addr[0] |= ETHER_LOCAL_ADMIN_ADDR;  /* set local assignment bit */
+}
+
+/**
+ * Fast copy an Ethernet address.
+ *
+ * @param ea_from
+ *   A pointer to a ether_addr structure holding the Ethernet address to copy.
+ * @param ea_to
+ *   A pointer to a ether_addr structure where to copy the Ethernet address.
+ */
+static inline void ether_addr_copy(const struct ether_addr *ea_from,
+				   struct ether_addr *ea_to)
+{
+#ifdef __INTEL_COMPILER
+	uint16_t *from_words = (uint16_t *)(ea_from->addr_bytes);
+	uint16_t *to_words   = (uint16_t *)(ea_to->addr_bytes);
+
+	to_words[0] = from_words[0];
+	to_words[1] = from_words[1];
+	to_words[2] = from_words[2];
+#else
+	/*
+	 * Use the common way, because of a strange gcc warning.
+	 */
+	*ea_to = *ea_from;
+#endif
+}
+
+#define ETHER_ADDR_FMT_SIZE         18
+/**
+ * Format 48bits Ethernet address in pattern xx:xx:xx:xx:xx:xx.
+ *
+ * @param buf
+ *   A pointer to buffer contains the formatted MAC address.
+ * @param size
+ *   The format buffer size.
+ * @param eth_addr
+ *   A pointer to a ether_addr structure.
+ */
+static inline void
+ether_format_addr(char *buf, uint16_t size,
+		  const struct ether_addr *eth_addr)
+{
+	snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X",
+		 eth_addr->addr_bytes[0],
+		 eth_addr->addr_bytes[1],
+		 eth_addr->addr_bytes[2],
+		 eth_addr->addr_bytes[3],
+		 eth_addr->addr_bytes[4],
+		 eth_addr->addr_bytes[5]);
+}
+
+/**
+ * Ethernet header: Contains the destination address, source address
+ * and frame type.
+ */
+struct ether_hdr {
+	struct ether_addr d_addr; /**< Destination address. */
+	struct ether_addr s_addr; /**< Source address. */
+	uint16_t ether_type;      /**< Frame type. */
+} __attribute__((__packed__));
+
+/**
+ * Ethernet VLAN Header.
+ * Contains the 16-bit VLAN Tag Control Identifier and the Ethernet type
+ * of the encapsulated frame.
+ */
+struct vlan_hdr {
+	uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
+	uint16_t eth_proto;/**< Ethernet type of encapsulated frame. */
+} __attribute__((__packed__));
+
+/**
+ * VXLAN protocol header.
+ * Contains the 8-bit flag, 24-bit VXLAN Network Identifier and
+ * Reserved fields (24 bits and 8 bits)
+ */
+struct vxlan_hdr {
+	uint32_t vx_flags; /**< flag (8) + Reserved (24). */
+	uint32_t vx_vni;   /**< VNI (24) + Reserved (8). */
+} __attribute__((__packed__));
+
+/* Ethernet frame types */
+#define ETHER_TYPE_IPv4 0x0800 /**< IPv4 Protocol. */
+#define ETHER_TYPE_IPv6 0x86DD /**< IPv6 Protocol. */
+#define ETHER_TYPE_ARP  0x0806 /**< Arp Protocol. */
+#define ETHER_TYPE_RARP 0x8035 /**< Reverse Arp Protocol. */
+#define ETHER_TYPE_VLAN 0x8100 /**< IEEE 802.1Q VLAN tagging. */
+#define ETHER_TYPE_1588 0x88F7 /**< IEEE 802.1AS 1588 Precise Time Protocol. */
+#define ETHER_TYPE_SLOW 0x8809 /**< Slow protocols (LACP and Marker). */
+#define ETHER_TYPE_TEB  0x6558 /**< Transparent Ethernet Bridging. */
+
+#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;
+
+	/* 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;
+	}
+
+	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
+
+#endif /* _RTE_ETHER_H_ */
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 01/16] mbuf: add function to read packet data
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1475483937-21696-1-git-send-email-olivier.matz@6wind.com>

Introduce a new function to read the packet data from an mbuf chain. It
linearizes the data if required, and also ensures that the mbuf is large
enough.

This function is used in next commits that add a software parser to
retrieve the packet type.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 doc/guides/rel_notes/release_16_11.rst |  4 ++++
 lib/librte_mbuf/rte_mbuf.c             | 35 ++++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h             | 35 ++++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |  7 +++++++
 4 files changed, 81 insertions(+)

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index a9a6095..ae24da2 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -36,6 +36,10 @@ New Features
 
      This section is a comment. Make sure to start the actual text at the margin.
 
+* **Added function to read packet data.**
+
+  Added a new function ``rte_pktmbuf_read()`` to read the packet data from an
+  mbuf chain, linearizing if required.
 
 Resolved Issues
 ---------------
diff --git a/lib/librte_mbuf/rte_mbuf.c b/lib/librte_mbuf/rte_mbuf.c
index 80b1713..37fd72b 100644
--- a/lib/librte_mbuf/rte_mbuf.c
+++ b/lib/librte_mbuf/rte_mbuf.c
@@ -58,6 +58,7 @@
 #include <rte_string_fns.h>
 #include <rte_hexdump.h>
 #include <rte_errno.h>
+#include <rte_memcpy.h>
 
 /*
  * ctrlmbuf constructor, given as a callback function to
@@ -261,6 +262,40 @@ rte_pktmbuf_dump(FILE *f, const struct rte_mbuf *m, unsigned dump_len)
 	}
 }
 
+/* read len data bytes in a mbuf at specified offset (internal) */
+const void *__rte_pktmbuf_read(const struct rte_mbuf *m, uint32_t off,
+	uint32_t len, void *buf)
+{
+	const struct rte_mbuf *seg = m;
+	uint32_t buf_off = 0, copy_len;
+
+	if (off + len > rte_pktmbuf_pkt_len(m))
+		return NULL;
+
+	while (off >= rte_pktmbuf_data_len(seg)) {
+		off -= rte_pktmbuf_data_len(seg);
+		seg = seg->next;
+	}
+
+	if (off + len <= rte_pktmbuf_data_len(seg))
+		return rte_pktmbuf_mtod_offset(seg, char *, off);
+
+	/* rare case: header is split among several segments */
+	while (len > 0) {
+		copy_len = rte_pktmbuf_data_len(seg) - off;
+		if (copy_len > len)
+			copy_len = len;
+		rte_memcpy((char *)buf + buf_off,
+			rte_pktmbuf_mtod_offset(seg, char *, off), copy_len);
+		off = 0;
+		buf_off += copy_len;
+		len -= copy_len;
+		seg = seg->next;
+	}
+
+	return buf;
+}
+
 /*
  * Get the name of a RX offload flag. Must be kept synchronized with flag
  * definitions in rte_mbuf.h.
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index 23b7bf8..a26b9b9 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -1960,6 +1960,41 @@ static inline int rte_pktmbuf_is_contiguous(const struct rte_mbuf *m)
 }
 
 /**
+ * @internal used by rte_pktmbuf_read().
+ */
+const void *__rte_pktmbuf_read(const struct rte_mbuf *m, uint32_t off,
+	uint32_t len, void *buf);
+
+/**
+ * Read len data bytes in a mbuf at specified offset.
+ *
+ * If the data is contiguous, return the pointer in the mbuf data, else
+ * copy the data in the buffer provided by the user and return its
+ * pointer.
+ *
+ * @param m
+ *   The pointer to the mbuf.
+ * @param off
+ *   The offset of the data in the mbuf.
+ * @param len
+ *   The amount of bytes to read.
+ * @param buf
+ *   The buffer where data is copied if it is not contigous in mbuf
+ *   data. Its length should be at least equal to the len parameter.
+ * @return
+ *   The pointer to the data, either in the mbuf if it is contiguous,
+ *   or in the user buffer. If mbuf is too small, NULL is returned.
+ */
+static inline const void *rte_pktmbuf_read(const struct rte_mbuf *m,
+	uint32_t off, uint32_t len, void *buf)
+{
+	if (likely(off + len <= rte_pktmbuf_data_len(m)))
+		return rte_pktmbuf_mtod_offset(m, char *, off);
+	else
+		return __rte_pktmbuf_read(m, off, len, buf);
+}
+
+/**
  * Chain an mbuf to another, thereby creating a segmented packet.
  *
  * Note: The implementation will do a linear walk over the segments to find
diff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map
index e10f6bd..79e4dd8 100644
--- a/lib/librte_mbuf/rte_mbuf_version.map
+++ b/lib/librte_mbuf/rte_mbuf_version.map
@@ -18,3 +18,10 @@ DPDK_2.1 {
 	rte_pktmbuf_pool_create;
 
 } DPDK_2.0;
+
+DPDK_16.11 {
+	global:
+
+	__rte_pktmbuf_read;
+
+} DPDK_2.1;
-- 
2.8.1

^ permalink raw reply related

* [PATCH v3 00/16] software parser for packet type
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev
In-Reply-To: <1472481335-21226-1-git-send-email-olivier.matz@6wind.com>

This patchset introduces a software packet type parser. This
feature is targeted for v16.11.

The goal here is to provide a reference implementation for packet type
parsing. This function will be used by testpmd to compare its result
with the value given by the hardware.

It will also be useful when implementing Rx offload support in virtio
pmd. Indeed, the virtio protocol gives the csum start and offset, but
it does not give the L4 protocol nor it tells if the checksum is
relevant for inner or outer. This information has to be known to
properly set the ol_flags in mbuf.

changes v2 -> v3
- fix in rte_pktmbuf_read(): allow empty segments
- fix shared lib compilation by removing librte_net from automatic
  directory dependency filter in rte.lib.mk
- fix typo in license header
- rebase on top of head

changes v1 -> v2
- implement sw parser in librte_net instead of librte_mbuf
- remove MPLS parser for now, mapping mpls to packet type requires
  more discussion
- remove the patch adding the 16.11 release notes template, the
  file is already present now
- rebase on current head

Olivier Matz (16):
  mbuf: add function to read packet data
  net: move Ethernet header definitions to the net library
  mbuf: move packet type definitions in a new file
  net: introduce net library
  net: add function to get packet type from data
  net: support Vlan in software packet type parser
  net: support QinQ in software packet type parser
  net: support Ip tunnels in software packet type parser
  net: add Gre header structure
  net: support Gre in software packet type parser
  net: support Nvgre in software packet type parser
  net: get ptype for the first layers only
  mbuf: add functions to dump packet type
  mbuf: clarify definition of fragment packet types
  app/testpmd: dump ptype using the new function
  app/testpmd: display software packet type

 MAINTAINERS                            |   1 +
 app/test-pmd/rxonly.c                  | 196 ++--------
 doc/guides/rel_notes/release_16_11.rst |  13 +
 lib/librte_ether/Makefile              |   3 +-
 lib/librte_ether/rte_ether.h           | 416 --------------------
 lib/librte_mbuf/Makefile               |   4 +-
 lib/librte_mbuf/rte_mbuf.c             |  35 ++
 lib/librte_mbuf/rte_mbuf.h             | 530 ++------------------------
 lib/librte_mbuf/rte_mbuf_ptype.c       | 227 +++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h       | 668 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |  15 +
 lib/librte_net/Makefile                |  15 +-
 lib/librte_net/rte_ether.h             | 417 ++++++++++++++++++++
 lib/librte_net/rte_gre.h               |  71 ++++
 lib/librte_net/rte_net.c               | 517 +++++++++++++++++++++++++
 lib/librte_net/rte_net.h               |  94 +++++
 lib/librte_net/rte_net_version.map     |   6 +
 mk/rte.app.mk                          |   1 +
 mk/rte.lib.mk                          |   2 +-
 19 files changed, 2143 insertions(+), 1088 deletions(-)
 delete mode 100644 lib/librte_ether/rte_ether.h
 create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
 create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.h
 create mode 100644 lib/librte_net/rte_ether.h
 create mode 100644 lib/librte_net/rte_gre.h
 create mode 100644 lib/librte_net/rte_net.c
 create mode 100644 lib/librte_net/rte_net.h
 create mode 100644 lib/librte_net/rte_net_version.map

Test report
===========

(not fully replayed on v3, but no major change)

Topology:

     dut            
   +-------------+   
   |             |   
   | ixgbe pmd   +---.
   |             |   |
   |             |   |
   | ixgbe linux +---'
   |             |   
   +-------------+   

We will send packets with scapy from the kernel interface to
testpmd with rxonly engine, and check the logs to verify the
packet type.

# compile and run testpmd
cd dpdk.org/
make config T=x86_64-native-linuxapp-gcc
make -j32

mkdir -p /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
echo 256 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
modprobe uio_pci_generic
python tools/dpdk_nic_bind.py -b uio_pci_generic 0000:04:00.0

./build/app/testpmd -l 2,4 -- --total-num-mbufs=65536 -i --port-topology=chained --enable-rx-cksum --disable-hw-vlan-filter --disable-hw-vlan-strip
  set fwd rxonly
  set verbose 1
  start

# on another terminal, run scapy
scapy

eh = Ether(src="00:01:02:03:04:05", dst="00:1B:21:AB:8F:10")
vlan = Dot1Q(vlan=0x666)
eth = "ixgbe2"

bind_layers(GRE, IPv6, type=0x86dd)

v4/udp
======

# scapy
p = eh/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/vlan/IP()/UDP()/Raw("x"*32)
p.type=0x88A8 # QinQ
sendp(p, iface=eth)
p = eh/IP(options=IPOption('\x83\x03\x10'))/UDP()/Raw("x"*32)
sendp(p, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=74 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 L4_UDP  - sw ptype: L2_ETHER L3_IPV4 L4_UDP  - l2_len=14 - l3_len=20 - l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x8100 - length=78 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 L4_UDP  - sw ptype: L2_ETHER_VLAN L3_IPV4 L4_UDP  - l2_len=18 - l3_len=20 - l4_len=8 - Receive queue=0x0
  PKT_RX_VLAN_PKT
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x88a8 - length=82 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER_QINQ L3_IPV4 L4_UDP  - l2_len=22 - l3_len=20 - l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=78 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4_EXT L4_UDP  - sw ptype: L2_ETHER L3_IPV4_EXT L4_UDP  - l2_len=14 - l3_len=24 - l4_len=8 - Receive queue=0x0

v4/tcp
======

# scapy
p = eh/IP()/TCP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/IP()/TCP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/vlan/IP()/TCP()/Raw("x"*32)
p.type=0x88A8 # QinQ
sendp(p, iface=eth)
p = eh/IP(options=IPOption('\x83\x03\x10'))/TCP()/Raw("x"*32)
sendp(p, iface=eth)
0p = eh/IP()/TCP(options=[('MSS',1200)])/Raw("x"*32)
sendp(p, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=86 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 L4_TCP  - sw ptype: L2_ETHER L3_IPV4 L4_TCP  - l2_len=14 - l3_len=20 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x8100 - length=90 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 L4_TCP  - sw ptype: L2_ETHER_VLAN L3_IPV4 L4_TCP  - l2_len=18 - l3_len=20 - l4_len=20 - Receive queue=0x0
  PKT_RX_VLAN_PKT
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x88a8 - length=94 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER_QINQ L3_IPV4 L4_TCP  - l2_len=22 - l3_len=20 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=90 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4_EXT L4_TCP  - sw ptype: L2_ETHER L3_IPV4_EXT L4_TCP  - l2_len=14 - l3_len=24 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=90 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 L4_TCP  - sw ptype: L2_ETHER L3_IPV4 L4_TCP  - l2_len=14 - l3_len=20 - l4_len=24 - Receive queue=0x0

v6/udp
======

# scapy
p = eh/IPv6()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/IPv6()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/vlan/IPv6()/UDP()/Raw("x"*32)
p.type=0x88A8 # QinQ
sendp(p, iface=eth)
p = eh/IPv6()/IPv6ExtHdrHopByHop()/UDP()/Raw("x"*32)
sendp(p, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=94 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6 L4_UDP  - sw ptype: L2_ETHER L3_IPV6 L4_UDP  - l2_len=14 - l3_len=40 - l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x8100 - length=98 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6 L4_UDP  - sw ptype: L2_ETHER_VLAN L3_IPV6 L4_UDP  - l2_len=18 - l3_len=40 - l4_len=8 - Receive queue=0x0
  PKT_RX_VLAN_PKT
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x88a8 - length=102 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER_QINQ L3_IPV6 L4_UDP  - l2_len=22 - l3_len=40 - l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=102 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6_EXT L4_UDP  - sw ptype: L2_ETHER L3_IPV6_EXT L4_UDP  - l2_len=14 - l3_len=48 - l4_len=8 - Receive queue=0x0


v6/tcp
======

# scapy
p = eh/IPv6()/TCP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/IPv6()/TCP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/vlan/vlan/IPv6()/TCP()/Raw("x"*32)
p.type=0x88A8 # QinQ
sendp(p, iface=eth)
p = eh/IPv6()/TCP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IPv6()/IPv6ExtHdrHopByHop()/TCP(options=[('MSS',1200)])/Raw("x"*32)
sendp(p, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=106 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6 L4_TCP  - sw ptype: L2_ETHER L3_IPV6 L4_TCP  - l2_len=14 - l3_len=40 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x8100 - length=110 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6 L4_TCP  - sw ptype: L2_ETHER_VLAN L3_IPV6 L4_TCP  - l2_len=18 - l3_len=40 - l4_len=20 - Receive queue=0x0
  PKT_RX_VLAN_PKT
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x88a8 - length=114 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER_QINQ L3_IPV6 L4_TCP  - l2_len=22 - l3_len=40 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=106 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6 L4_TCP  - sw ptype: L2_ETHER L3_IPV6 L4_TCP  - l2_len=14 - l3_len=40 - l4_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=118 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6_EXT L4_TCP  - sw ptype: L2_ETHER L3_IPV6_EXT L4_TCP  - l2_len=14 - l3_len=48 - l4_len=24 - Receive queue=0x0


tunnels
=======

# scapy
p = eh/IP()/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP(options=IPOption('\x83\x03\x10'))/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP()/IPv6()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IPv6(nh=4)/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IPv6()/IPv6()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP()/GRE()/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP(options=IPOption('\x83\x03\x10'))/GRE()/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP()/GRE(key_present=1)/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP()/GRE(proto=0x86dd)/IPv6()/UDP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IP()/GRE(proto=0x6558)/Ether()/IP()/UDP()/Raw("x"*32)
sendp(p, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=94 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_IP INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=0 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=98 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4_EXT  - sw ptype: L2_ETHER L3_IPV4_EXT TUNNEL_IP INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=24 - tunnel_len=0 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=114 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4 TUNNEL_IP INNER_L3_IPV6 INNER_L4_UDP  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_IP INNER_L3_IPV6 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=0 - inner_l3_len=40 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=114 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6  - sw ptype: L2_ETHER L3_IPV6 TUNNEL_IP INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=40 - tunnel_len=0 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=134 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6  - sw ptype: L2_ETHER L3_IPV6 TUNNEL_IP INNER_L3_IPV6 INNER_L4_UDP  - l2_len=14 - l3_len=40 - tunnel_len=0 - inner_l3_len=40 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=98 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_GRE INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=102 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4_EXT  - sw ptype: L2_ETHER L3_IPV4_EXT TUNNEL_GRE INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=24 - tunnel_len=4 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=102 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_GRE INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=8 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=118 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_GRE INNER_L3_IPV6 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l3_len=40 - inner_l4_len=8 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=112 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_NVGRE INNER_L2_ETHER INNER_L3_IPV4 INNER_L4_UDP  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l2_len=14 - inner_l3_len=20 - inner_l4_len=8 - Receive queue=0x0

L2 or L3 only
=============

# scapy
p = eh/IP()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/IPv6()/Raw("x"*32)
sendp(p, iface=eth)
p = eh/Raw("x"*32)
sendp(p, iface=eth)

port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=66 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4  - l2_len=14 - l3_len=20 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=86 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6  - sw ptype: L2_ETHER L3_IPV6  - l2_len=14 - l3_len=40 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0000 - length=60 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER  - l2_len=14 - Receive queue=0x0

fragments
=========

# scapy
p1, p2 = fragment(eh/IP()/UDP()/Raw("x"*32), 32)
sendp(p1, iface=eth)
sendp(p2, iface=eth)
p3, p4 = eh/IP()/GRE(proto=0x6558)/p1, eh/IP()/GRE(proto=0x6558)/p2
sendp(p3, iface=eth)
sendp(p4, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=66 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 L4_FRAG  - l2_len=14 - l3_len=20 - l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=60 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 L4_FRAG  - l2_len=14 - l3_len=20 - l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=104 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_NVGRE INNER_L2_ETHER INNER_L3_IPV4 INNER_L4_FRAG  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l2_len=14 - inner_l3_len=20 - inner_l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=80 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_NVGRE INNER_L2_ETHER INNER_L3_IPV4 INNER_L4_FRAG  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l2_len=14 - inner_l3_len=20 - inner_l4_len=0 - Receive queue=0x0

# scapy
p1, p2 = fragment6(eh/IPv6()/IPv6ExtHdrFragment()/UDP()/Raw("x"*32), 100)
sendp(p1, iface=eth)
sendp(p2, iface=eth)
p3, p4 = eh/IP()/GRE(proto=0x6558)/p1, eh/IP()/GRE(proto=0x6558)/p2
sendp(p3, iface=eth)
sendp(p4, iface=eth)

# displayed in testpmd
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=94 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6_EXT  - sw ptype: L2_ETHER L3_IPV6_EXT L4_FRAG  - l2_len=14 - l3_len=48 - l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x86dd - length=70 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV6_EXT  - sw ptype: L2_ETHER L3_IPV6_EXT L4_FRAG  - l2_len=14 - l3_len=48 - l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=132 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_NVGRE INNER_L2_ETHER INNER_L3_IPV6_EXT INNER_L4_FRAG  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l2_len=14 - inner_l3_len=48 - inner_l4_len=0 - Receive queue=0x0
port 0/queue 0: received 1 packets
  src=00:01:02:03:04:05 - dst=00:1B:21:AB:8F:10 - type=0x0800 - length=108 - nb_segs=1 - hw ptype: L2_ETHER L3_IPV4  - sw ptype: L2_ETHER L3_IPV4 TUNNEL_NVGRE INNER_L2_ETHER INNER_L3_IPV6_EXT INNER_L4_FRAG  - l2_len=14 - l3_len=20 - tunnel_len=4 - inner_l2_len=14 - inner_l3_len=48 - inner_l4_len=0 - Receive queue=0x0

-- 
2.8.1

^ permalink raw reply

* Re: [PATCH v4 4/5] app/test: added big data GMAC test for libcrypto
From: Mrozowicz, SlawomirX @ 2016-10-03  8:12 UTC (permalink / raw)
  To: Thomas Monjalon, Azarewicz, PiotrX T; +Cc: dev@dpdk.org, Dai, Wei
In-Reply-To: <4364051.h3faDOIdZz@xps13>



>-----Original Message-----
>From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
>Sent: Friday, September 30, 2016 7:19 PM
>To: Mrozowicz, SlawomirX <slawomirx.mrozowicz@intel.com>; Azarewicz,
>PiotrX T <piotrx.t.azarewicz@intel.com>
>Cc: dev@dpdk.org; Dai, Wei <wei.dai@intel.com>
>Subject: Re: [dpdk-dev] [PATCH v4 4/5] app/test: added big data GMAC test
>for libcrypto
>
>2016-09-30 18:32, Slawomir Mrozowicz:
>> This patch add big data AES-GMAC test for libcrypto PMD.
>>
>> Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
>> ---
>>  app/test/test_cryptodev.c                  |   18 +-
>>  app/test/test_cryptodev_gcm_test_vectors.h | 8245
>+++++++++++++++++++++++++++-
>>  2 files changed, 8242 insertions(+), 21 deletions(-)
>
>The test data are really too big.
>Is it possible to generate them as Wei Dai did for LPM?
>	http://dpdk.org/patch/16175
>	http://dpdk.org/patch/16253

Yes it is possible.
We will prepare new patch set with the changes which you proposed.
Sławek

^ permalink raw reply

* Re: [PATCH] l2fwd:mac learning
From: Thomas Monjalon @ 2016-10-03  6:45 UTC (permalink / raw)
  To: Rafat Jahan; +Cc: dev
In-Reply-To: <1475475478-29685-1-git-send-email-rafat.jahan@tcs.com>

Hi,

2016-10-03 11:47, Rafat Jahan:
> Added MAC learning to reduce load at l2

I'm sorry but I don't think it is worth adding a new example.
The examples are here to demonstrate the usage of the DPDK libraries.
And it would be valuable for project maintainability to reduce the
number of examples, not adding new ones.
Hope you'll understand.

^ permalink raw reply

* [PATCH] l2fwd:mac learning
From: Rafat Jahan @ 2016-10-03  6:17 UTC (permalink / raw)
  To: dev; +Cc: Rafat Jahan

Added MAC learning to reduce load at l2

Signed-off-by: Rafat Jahan <rafat.jahan@tcs.com>
---
 examples/l2fwd-mac/Makefile |   50 ++
 examples/l2fwd-mac/main.c   | 1325 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1375 insertions(+)
 create mode 100644 examples/l2fwd-mac/Makefile
 create mode 100644 examples/l2fwd-mac/main.c

diff --git a/examples/l2fwd-mac/Makefile b/examples/l2fwd-mac/Makefile
new file mode 100644
index 0000000..6ab93f4
--- /dev/null
+++ b/examples/l2fwd-mac/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-mac
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-mac/main.c b/examples/l2fwd-mac/main.c
new file mode 100644
index 0000000..33d6a6e
--- /dev/null
+++ b/examples/l2fwd-mac/main.c
@@ -0,0 +1,1325 @@
+/*-thread created and in which two seperate threads for updation and checking are created infinately
+
+	final working code
+
+
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_arp.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF   8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+ 
+#define default_aging_time 30
+pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * Work-around of a compilation error with ICC on invocations of the
+ * rte_be_to_cpu_16() function.
+ */
+#ifdef __GCC__
+#define RTE_BE_TO_CPU_16(be_16_v)  rte_be_to_cpu_16((be_16_v))
+#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v))
+#else
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+#define RTE_BE_TO_CPU_16(be_16_v)  (be_16_v)
+#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
+#else
+#define RTE_BE_TO_CPU_16(be_16_v) \
+        (uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
+#define RTE_CPU_TO_BE_16(cpu_16_v) \
+        (uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
+#endif
+#endif /* __GCC__ */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+static int64_t l2fwd_user_defined_dst_port = 0;
+static int16_t l2fwd_mac_learning_enabled = 0;
+uint64_t total_duplicate_packets_dropped = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port);
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport);
+static void l2fwd_mac_display(void);
+static void l2fwd_show_mac_entry(void);
+void source_mac_table(struct ether_hdr *eth,unsigned port);
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port);
+void update_aging(struct ether_hdr *eth);
+void *thread1(void);
+void *thread2(void);
+void *threadInit(void);
+
+
+struct node
+{
+        unsigned port;
+        struct ether_addr s_addr; /**< Source address. */
+	struct ether_addr d_addr; /**< Destination address. */
+	time_t starttime;
+        struct node *next;
+}*head = NULL;
+
+struct mac_list
+{
+        unsigned port;
+        struct ether_addr s_addr;
+	time_t rx_time;
+	char *buff;
+	int aging_time;
+        struct mac_list *next;
+}*start = NULL;
+
+
+struct mbuf_table {
+	unsigned len;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+void update_node(struct mac_list *ptr);
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+	unsigned n_rx_port;
+	unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+	struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static const struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+	uint64_t tx;
+	uint64_t rx;
+	uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+static inline void
+print_ether_addr(const char *what, struct ether_addr *eth_addr)
+{
+        char buf[ETHER_ADDR_FMT_SIZE];
+        ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
+        printf("%s%s", what, buf);
+}
+
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
+{
+        uint32_t ipv4_addr;
+
+        ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+        sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+                (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+                ipv4_addr & 0xFF);
+}
+
+static void
+ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
+{
+        char buf[16];
+
+        ipv4_addr_to_dot(be_ipv4_addr, buf);
+        if (what)
+                printf("%s", what);
+        printf("%s", buf);
+}
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+	struct node *new = NULL;
+	new = (struct node*)malloc(sizeof(struct node));
+	if(new == NULL)
+	{
+		printf("Memory not allocated for MAC database");
+	}
+
+	source_mac_table(eth,port);
+
+	new->port = port;
+	new->starttime = time(NULL);
+	ether_addr_copy(&eth->s_addr, &new->s_addr);
+	ether_addr_copy(&eth->d_addr, &new->d_addr);
+	if(head == NULL)
+	{
+		head = new;
+		head->next = NULL;
+		
+	}
+	else
+	{
+		new->next = head;
+		head = new;
+		
+	}
+}
+
+void source_mac_table(struct ether_hdr *eth,unsigned port)
+{
+
+        struct mac_list *ptr = NULL;
+        ptr = start;
+        if(start == NULL)
+        {
+                printf("Adding entry to the table\n");
+                add_src_mac_entry(eth,port);
+        }
+        else
+        {
+                while(ptr != NULL)
+                {
+                        if (memcmp(&eth->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+                        {
+							
+     				ptr->rx_time=time(NULL);
+				ptr->aging_time=default_aging_time;
+                                if(ptr->port != port )
+                                {
+                                        ptr->port = port;
+        	                           break;
+	                         }
+                                else
+                                        break; // received from same mac
+                        }
+                        ptr = ptr->next;
+                }
+                if(ptr == NULL)
+                {
+                        /*If the mac entry is not found in the table, then add the entry 
+                        to the mac table */
+                        printf("Adding MAC entry to table\n");
+                        add_src_mac_entry(eth,port);
+                }
+
+        }
+}
+
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+        struct mac_list *new = NULL;
+        new = (struct mac_list*)malloc(sizeof(struct mac_list));
+        if(new == NULL)
+        {
+                printf("Memory not allocated for MAC database");
+        }
+        new->port = port;
+        ether_addr_copy(&eth->s_addr, &new->s_addr);
+	new->rx_time=time(NULL);
+	new->aging_time=default_aging_time;
+	if(start == NULL)
+        {
+                start = new;
+                start->next = NULL;
+        }
+        else
+        {
+		new->next=start;
+		start=new;               
+        }
+
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+	unsigned portid;
+
+	total_packets_dropped = 0;
+	total_packets_tx = 0;
+	total_packets_rx = 0;
+
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+		/* Clear screen and move to top left */
+	printf("%s%s", clr, topLeft);
+
+	printf("\nPort statistics ====================================");
+
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+		/* skip disabled ports */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+		printf("\nStatistics for port %u ------------------------------"
+			   "\nPackets sent: %24"PRIu64
+			   "\nPackets received: %20"PRIu64
+			   "\nPackets dropped: %21"PRIu64,
+			   portid,
+			   port_statistics[portid].tx,
+			   port_statistics[portid].rx,
+			   port_statistics[portid].dropped);
+
+		total_packets_dropped += port_statistics[portid].dropped;
+		total_packets_tx += port_statistics[portid].tx;
+		total_packets_rx += port_statistics[portid].rx;
+	}
+	printf("\nAggregate statistics ==============================="
+		   "\nTotal packets sent: %18"PRIu64
+		   "\nTotal packets received: %14"PRIu64
+		   "\nTotal packets dropped: %15"PRIu64,
+		   total_packets_tx,
+		   total_packets_rx,
+		   total_packets_dropped);
+	printf("\nTotal duplicate packets dropped: %5"PRIu64,
+		   total_duplicate_packets_dropped);
+	printf("\n====================================================\n");
+}
+
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+	struct rte_mbuf **m_table;
+	unsigned ret;
+	unsigned queueid =0;
+
+	m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+	ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+	port_statistics[port].tx += ret;
+	if (unlikely(ret < n)) {
+		port_statistics[port].dropped += (n - ret);
+		do {
+			rte_pktmbuf_free(m_table[ret]);
+		} while (++ret < n);
+	}
+
+	return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+	unsigned lcore_id, len;
+	struct lcore_queue_conf *qconf;
+
+	lcore_id = rte_lcore_id();
+
+	qconf = &lcore_queue_conf[lcore_id];
+	len = qconf->tx_mbufs[port].len;
+	qconf->tx_mbufs[port].m_table[len] = m;
+	len++;
+
+	/* enough pkts to be sent */
+	if (unlikely(len == MAX_PKT_BURST)) {
+		l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+		len = 0;
+	}
+
+	qconf->tx_mbufs[port].len = len;
+	return 0;
+}
+static void l2fwd_mac_display(void)
+{
+	struct node *node = NULL;
+	printf("\n==============DEBUGGING MAC TABLE=================\n");
+        printf("        SMAC			DMAC			PORT \n");
+        node = head;
+        while(node != NULL)
+        {
+        	print_ether_addr("", &node->s_addr);
+                print_ether_addr("	",&node->d_addr);                
+		printf("		%d\n",node->port);
+		node = node->next;
+        }
+        printf("========================================\n");
+}
+static void l2fwd_show_mac_entry(void)
+{
+        struct mac_list *node = NULL;
+        printf("\n==============MAC TABLE=================\n");
+        printf("        MAC                     PORT\taging time\n");
+        node = start;
+        while(node != NULL)
+        {
+                print_ether_addr("", &node->s_addr);
+                printf("                %d\t",node->port);
+        	printf("%d\n",node->aging_time);
+		
+	        node = node->next;
+        }
+        printf("========================================\n");
+}
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport)
+{
+	struct node *ptr = NULL;
+	struct mac_list *ptr1 = NULL;
+	
+        ptr = head;
+        while(ptr != NULL)
+        {
+		if (memcmp(&eth->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+		{
+			ptr->port = rxport;
+		}
+                ptr = ptr->next;
+        }
+	
+	ptr1 = start;
+        while(ptr1 != NULL)
+        {
+		if (memcmp(&eth->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+		{
+			ptr1->port = rxport;
+			ptr1->rx_time=time(NULL);
+			ptr1->aging_time=default_aging_time;
+		}
+                ptr1 = ptr1->next;
+        }
+	
+}
+void update_aging(struct ether_hdr *eth)
+{
+	struct mac_list *ptr1=NULL;
+	ptr1 = start;
+        while(ptr1 != NULL)
+        {
+		if (memcmp(&eth->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+		{
+			ptr1->rx_time=time(NULL);
+			ptr1->aging_time=default_aging_time;
+		}
+                ptr1 = ptr1->next;
+        }
+}
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+	struct ether_hdr *eth;
+	void *tmp;
+	unsigned dst_port;
+	int currenttime,difference,timeout = 8;
+	//int err;
+	//pthread_t t1,t2;
+	dst_port = l2fwd_dst_ports[portid];
+        printf("---------- Forwarding Path ----------\n");
+        printf("Default forwarding dst port : %d\n",dst_port);
+	
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	
+	if(l2fwd_user_defined_dst_port > 0)
+	{
+		dst_port = l2fwd_user_defined_dst_port;
+        	printf("User defined dst Port       : %d\n",dst_port);
+		printf("----------------------------------------\n");
+		printf("Forwarding path has been modified from default to user defined\n");
+	}
+	else if(l2fwd_mac_learning_enabled)
+	{
+        	//l2fwd_mac_display();
+		//l2fwd_show_mac_entry();
+		//pthread_mutex_lock( &mutex1 );
+		struct node *ptr = NULL;
+		struct mac_list *temp = NULL;
+		ptr = head;
+		if(head == NULL)
+		{
+			printf("No MAC address exist in table , adding entry to the table\n");
+			add_mac_entry(eth,portid);
+		}
+		else
+		{
+			/* condition to check and overwrite the 'port' if the same mac address 
+			   was already received from another 'port' earlier*/
+			while(ptr != NULL)
+			{
+				if ((memcmp(&eth->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0) &&
+					 (memcmp(&eth->d_addr, &ptr->d_addr, ETHER_ADDR_LEN) == 0))
+				{
+				//	printf("----->same SMAC DMAC\n");
+					if(portid != ptr->port)
+					{
+						printf("port id is different %d\n",portid);
+						currenttime = time(NULL);
+						difference = currenttime - (ptr->starttime);
+						if(difference > timeout)
+						{
+							printf("----->difference %d\n",difference);
+							ptr->port = portid;
+							ptr->starttime = time(NULL);
+							l2fwd_mac_ports_update(eth,portid);
+						//	add_mac_entry(eth,portid);
+							break;
+						} else {
+							printf("Detected duplication,packet dropped \n");
+							//duplicate packet
+							total_duplicate_packets_dropped++;
+							//need to check whether break is needed
+						//	return;
+						}
+					}
+
+					ptr->starttime = time(NULL);
+					update_aging(eth);
+				//	printf("---->received from same mac diff %d\n",difference);
+					break;
+				}
+				ptr = ptr->next;
+			}
+			if(ptr == NULL)
+			{
+				/*If the mac entry is not found in the table, then add the entry 
+				  to the mac table */
+				printf("Adding MAC entry to table\n");
+				add_mac_entry(eth,portid);
+				//l2fwd_mac_ports_update(eth,portid);
+			}
+		}
+	
+
+		/* lookup to get the dst port if the mac entry is already present in the table*/
+		temp = start;
+		while(temp != NULL)
+		{
+			if (memcmp(&eth->d_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+			{
+				dst_port = temp->port;
+				printf("\n");
+        			printf("dst port from table : %d\n",dst_port);
+				break;
+			}
+			temp = temp->next;
+		}	
+		/*If the dst mac is not available,then forward the packet in dumping port*/
+		if(temp == NULL)
+		{
+			dst_port = 9;
+        		printf("Dumping port : %d\n",dst_port);
+		}
+	
+	}
+	else 
+	{
+//========================================================
+		/* 02:00:00:00:00:xx */
+		tmp = &eth->d_addr.addr_bytes[0];
+		*((uint64_t *)tmp) = 0xffffffffffff ;
+		//*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+	
+		/* src addr */
+		ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);
+	}
+
+	printf("========================================\n");
+       	l2fwd_mac_display();
+	l2fwd_show_mac_entry();
+	//pthread_mutex_unlock( &mutex1 );
+	l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *m;
+	unsigned lcore_id;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+	unsigned i, j, portid, nb_rx;
+	struct lcore_queue_conf *qconf;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+        struct ether_hdr *eth_hdr;
+        uint16_t eth_type;
+        struct ipv4_hdr *ip_h;
+        int l2_len;
+        struct arp_hdr  *arp_h;
+        uint32_t sip_addr,tip_addr;
+
+	prev_tsc = 0;
+	timer_tsc = 0;
+
+	lcore_id = rte_lcore_id();
+	qconf = &lcore_queue_conf[lcore_id];
+
+	if (qconf->n_rx_port == 0) {
+		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+		return;
+	}
+
+	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+	for (i = 0; i < qconf->n_rx_port; i++) {
+
+		portid = qconf->rx_port_list[i];
+		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+			portid);
+	}
+
+	while (1) {
+
+		cur_tsc = rte_rdtsc();
+
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+				if (qconf->tx_mbufs[portid].len == 0)
+					continue;
+				l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+						 qconf->tx_mbufs[portid].len,
+						 (uint8_t) portid);
+				qconf->tx_mbufs[portid].len = 0;
+			}
+
+			/* if timer is enabled */
+			if (timer_period > 0) {
+
+				/* advance the timer */
+				timer_tsc += diff_tsc;
+
+				/* if timer has reached its timeout */
+				if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+					/* do this only on master core */
+					if (lcore_id == rte_get_master_lcore()) {
+						print_stats();
+						/* reset the timer */
+						timer_tsc = 0;
+					}
+				}
+			}
+
+			prev_tsc = cur_tsc;
+		}
+
+		/*
+		 * Read packet from RX queues
+		 */
+		for (i = 0; i < qconf->n_rx_port; i++) {
+
+			portid = qconf->rx_port_list[i];
+			nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+						 pkts_burst, MAX_PKT_BURST);
+
+			if(nb_rx == 0)
+				continue;
+			port_statistics[portid].rx += nb_rx;
+
+			for (j = 0; j < nb_rx; j++) {
+				m = pkts_burst[j];
+				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+
+                                eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+                                eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
+                                l2_len = sizeof(struct ether_hdr);
+                			
+				//if (eth_type != ETHER_TYPE_IPv4) {
+                        	//	rte_pktmbuf_free(m);
+                        	//	continue;
+                		//}
+
+                                printf("========================================\n");
+                                printf("Packet received on port :%d\n",portid);
+                                printf("------------ L2 Details------------\n");
+                                print_ether_addr("   Source MAC         : ", &eth_hdr->s_addr);
+                                print_ether_addr("\n   Destination MAC    : ", &eth_hdr->d_addr);
+                                printf("\n   Port               : %d"
+                                	"\n   Ethernet Type      : 0x%04x"
+					"\n   Length             : %u "
+					"\n   Nb_segs            : %d",
+                                        portid,
+					eth_type,
+					(unsigned) m->pkt_len,
+					(int)m->nb_segs);
+                                printf("\n");
+
+                                if (eth_type == ETHER_TYPE_ARP)
+				{
+                                        arp_h = (struct arp_hdr *) ((char *)eth_hdr + l2_len);
+                                        sip_addr = arp_h->arp_data.arp_sip;
+                                        tip_addr = arp_h->arp_data.arp_tip;
+				} else
+				{
+                			if (eth_type != ETHER_TYPE_IPv4) {
+                        			rte_pktmbuf_free(m);
+                        			continue;
+                			}
+                                        ip_h = (struct ipv4_hdr *) ((char *)eth_hdr + l2_len);
+                                        sip_addr = ip_h->src_addr;
+                                        tip_addr = ip_h->dst_addr;
+				}
+				printf("------------ L3 Details------------\n");
+				ipv4_addr_dump("   Source IP          : ", sip_addr);
+                                ipv4_addr_dump("\n   Destination IP     : ", tip_addr);
+				printf("\n");
+	
+				l2fwd_simple_forward(m, portid);
+			}
+		}
+	}
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+	l2fwd_main_loop();
+	return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+		   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
+		"  -d DST PORT: user input to select the destination port\n"
+		"  -l MAC LEARNING: enable l2fwd mac learning 1-enable : 0 - disable(default) \n",
+	       prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+	char *end = NULL;
+	unsigned long n;
+
+	/* parse hexadecimal string */
+	n = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return 0;
+	if (n == 0)
+		return 0;
+	if (n >= MAX_RX_QUEUE_PER_LCORE)
+		return 0;
+
+	return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n >= MAX_TIMER_PERIOD)
+		return -1;
+
+	return n;
+}
+
+static int
+pktcap_parse_dst_port(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n > RTE_MAX_ETHPORTS)
+		return -1;
+
+	return n;
+}
+
+static int
+l2fwd_parse_mac_learning(const char *q_arg)
+{
+	char *end = NULL;
+	int n;
+
+	/* parse number string */
+	n = strtol(q_arg, &end, 0);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+		return -1;
+	if (n > 1)
+		return -1;
+
+	return n;
+}
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "p:q:T:d:l:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'p':
+			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+			if (l2fwd_enabled_port_mask == 0) {
+				printf("invalid portmask\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* nqueue */
+		case 'q':
+			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+			if (l2fwd_rx_queue_per_lcore == 0) {
+				printf("invalid queue number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* timer period */
+		case 'T':
+			timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+			if (timer_period < 0) {
+				printf("invalid timer period\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* user defined dst port*/
+		case 'd':
+			l2fwd_user_defined_dst_port = pktcap_parse_dst_port(optarg);
+			if (l2fwd_user_defined_dst_port < 0) {
+				printf("invalid port number\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+
+		/* l2 mac learning*/
+		case 'l':
+			l2fwd_mac_learning_enabled = l2fwd_parse_mac_learning(optarg);
+			if (l2fwd_mac_learning_enabled < 0) {
+				printf("invalid option\n");
+				l2fwd_usage(prgname);
+				return -1;
+			}
+			break;
+		/* long options */
+		case 0:
+			l2fwd_usage(prgname);
+			return -1;
+
+		default:
+			l2fwd_usage(prgname);
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+	uint8_t portid, count, all_ports_up, print_flag = 0;
+	struct rte_eth_link link;
+
+	printf("\nChecking link status");
+	fflush(stdout);
+	for (count = 0; count <= MAX_CHECK_TIME; count++) {
+		all_ports_up = 1;
+		for (portid = 0; portid < port_num; portid++) {
+			if ((port_mask & (1 << portid)) == 0)
+				continue;
+			memset(&link, 0, sizeof(link));
+			rte_eth_link_get_nowait(portid, &link);
+			/* print link status if flag set */
+			if (print_flag == 1) {
+				if (link.link_status)
+					printf("Port %d Link Up - speed %u "
+						"Mbps - %s\n", (uint8_t)portid,
+						(unsigned)link.link_speed,
+				(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+					("full-duplex") : ("half-duplex\n"));
+				else
+					printf("Port %d Link Down\n",
+						(uint8_t)portid);
+				continue;
+			}
+			/* clear all_ports_up flag if any link down */
+			if (link.link_status == 0) {
+				all_ports_up = 0;
+				break;
+			}
+		}
+		/* after finally printing all link status, get out */
+		if (print_flag == 1)
+			break;
+
+		if (all_ports_up == 0) {
+			printf(".");
+			fflush(stdout);
+			rte_delay_ms(CHECK_INTERVAL);
+		}
+
+		/* set the print_flag if all ports up or timeout */
+		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+			print_flag = 1;
+			printf("done\n");
+		}
+	}
+}
+
+void *thread2(void)
+{	
+	if(start!=NULL)
+                {
+
+                        pthread_mutex_lock( &mutex1 );
+                        struct mac_list *temp=start;
+                        while(temp!=NULL)
+                        {
+				if(temp->aging_time>0)
+                                        temp->aging_time=default_aging_time-(time(NULL)-temp->rx_time);
+                                //strcpy(temp->buff,"check");
+                                temp=temp->next;
+                        }
+                      pthread_mutex_unlock( &mutex1 );
+                }
+	pthread_exit(NULL);
+	return NULL;
+}
+
+void update_node(struct mac_list *l_temp)
+{
+	struct node *temp,*temp2,*prev;
+	if(head!=NULL)
+	{	
+		while(head!=NULL)
+		{	
+			if(memcmp(&l_temp->s_addr, &head->s_addr, ETHER_ADDR_LEN) == 0)
+			{
+				temp=head;
+				head=head->next;
+				free(temp);
+			}
+			else
+				break;
+		}
+	//	if(head!=NULL)
+		temp=head->next;
+		prev=head;
+		while(temp!=NULL && head!=NULL)
+		{
+			if(memcmp(&l_temp->s_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+			{
+				prev->next=temp->next;
+				temp2=temp;
+				temp=temp->next;
+				free(temp2);	
+			}
+			else
+			{
+				temp=temp->next;
+				prev=prev->next;
+			}
+		}
+	}
+	
+	
+}
+
+
+void *thread1(void)
+{
+	struct mac_list *temp,*temp2,*prev;
+	
+		if(start!=NULL)
+		{
+		
+			pthread_mutex_lock( &mutex1 );	
+			while(start!=NULL)
+			{	
+				if( start->aging_time==0)
+				{
+					temp = start;
+					update_node(temp);
+					start=start->next;
+					free(temp);
+				
+				}
+				else
+					break;		 
+			}
+	//		if(start!=NULL)
+			temp = start->next;
+			prev=start;
+			while(temp!= NULL && start!=NULL)
+        		{
+		            
+		        	if(temp->aging_time==0)
+			     {
+				update_node(temp);
+				prev->next=temp->next;
+				temp2=temp;
+				temp=temp->next;
+				if(temp2!=NULL)
+					free(temp2);
+		     	      }
+		     	      else
+	 		      {
+					temp = temp->next; 
+					prev=prev->next;
+	    	       		}
+	        	}
+			pthread_mutex_unlock( &mutex1 );
+		}
+	pthread_exit(NULL);
+	return NULL;
+}
+void *threadInit(void)
+{
+	pthread_t t1,t2;
+	int err;
+	while(1)
+		{
+		err=pthread_create(&t1, NULL,(void *)thread1,NULL);//for checking the mac table
+		pthread_join(t1,NULL);
+		
+		
+		err=pthread_create(&t2,NULL,(void *)thread2,NULL);//for updating the mac table
+		pthread_join(t2,NULL);
+		
+		if(err!=0)
+		{
+			printf("thread not created\n");
+			exit(0);
+		}
+	}
+	return NULL;	
+}
+
+int
+main(int argc, char **argv)
+{
+	struct lcore_queue_conf *qconf;
+	struct rte_eth_dev_info dev_info;
+	int ret,err;
+	uint8_t nb_ports;
+	uint8_t nb_ports_available;
+	uint8_t portid, last_port;
+	unsigned lcore_id, rx_lcore_id;
+	unsigned nb_ports_in_mask = 0;
+	pthread_t t3;
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = l2fwd_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+	/* create the mbuf pool */
+	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+		0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+	if (l2fwd_pktmbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports == 0)
+		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+	/* reset l2fwd_dst_ports */
+	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+		l2fwd_dst_ports[portid] = 0;
+	last_port = 0;
+		
+	printf("Entered port : %" PRId64 "\n",l2fwd_user_defined_dst_port);
+
+	/*
+	 * Each logical core is assigned a dedicated TX queue on each port.
+	 */
+	if(l2fwd_user_defined_dst_port == 0)
+	{
+		for (portid = 0; portid < nb_ports; portid++) {
+			/* skip ports that are not enabled */
+			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+				continue;
+	
+			if (nb_ports_in_mask % 2) {
+				l2fwd_dst_ports[portid] = last_port;
+				l2fwd_dst_ports[last_port] = portid;
+			}
+			else
+				last_port = portid;
+	
+				nb_ports_in_mask++;
+	
+			rte_eth_dev_info_get(portid, &dev_info);
+		}
+		if (nb_ports_in_mask % 2) {
+			printf("Notice: odd number of ports in portmask.\n");
+			l2fwd_dst_ports[last_port] = last_port;
+		}
+
+	}
+	rx_lcore_id = 0;
+	qconf = NULL;
+
+	/* Initialize the port/queue configuration of each logical core */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+			continue;
+
+		/* get the lcore_id for this port */
+		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+		       l2fwd_rx_queue_per_lcore) {
+			rx_lcore_id++;
+			if (rx_lcore_id >= RTE_MAX_LCORE)
+				rte_exit(EXIT_FAILURE, "Not enough cores\n");
+		}
+
+		if (qconf != &lcore_queue_conf[rx_lcore_id])
+			/* Assigned a new logical core in the loop above. */
+			qconf = &lcore_queue_conf[rx_lcore_id];
+
+		qconf->rx_port_list[qconf->n_rx_port] = portid;
+		qconf->n_rx_port++;
+		printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+	}
+
+	nb_ports_available = nb_ports;
+	
+	/* Initialise each port */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+			printf("Skipping disabled port %u\n", (unsigned) portid);
+			nb_ports_available--;
+			continue;
+		}
+		/* init port */
+		printf("Initializing port %u... ", (unsigned) portid);
+		fflush(stdout);
+		ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+		/* init one RX queue */
+		fflush(stdout);
+		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+					     rte_eth_dev_socket_id(portid),
+					     NULL,
+					     l2fwd_pktmbuf_pool);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		/* init one TX queue on each port */
+		fflush(stdout);
+		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+				rte_eth_dev_socket_id(portid),
+				NULL);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+				ret, (unsigned) portid);
+		/****************************************/
+		err=pthread_create(&t3,NULL,(void *)threadInit,NULL);
+		//thread for checking and updating the mac table
+		if(err!=0)
+		{
+			printf("thread not created\n");
+			exit(0);
+		}	
+		/****************************************/
+		/* Start device */
+		ret = rte_eth_dev_start(portid);
+		if (ret < 0)
+			rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
+				  ret, (unsigned) portid);
+
+		printf("done: \n");
+
+		rte_eth_promiscuous_enable(portid);
+
+		printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+				(unsigned) portid,
+				l2fwd_ports_eth_addr[portid].addr_bytes[0],
+				l2fwd_ports_eth_addr[portid].addr_bytes[1],
+				l2fwd_ports_eth_addr[portid].addr_bytes[2],
+				l2fwd_ports_eth_addr[portid].addr_bytes[3],
+				l2fwd_ports_eth_addr[portid].addr_bytes[4],
+				l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+		/* initialize port stats */
+		memset(&port_statistics, 0, sizeof(port_statistics));
+	}
+
+	if (!nb_ports_available) {
+		rte_exit(EXIT_FAILURE,
+			"All available ports are disabled. Please set portmask.\n");
+	}
+
+	check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+	/* launch per-lcore init on every lcore */
+	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (rte_eal_wait_lcore(lcore_id) < 0)
+			return -1;
+	}
+	//pthread_join(t1,NULL);
+        //pthread_join(t2,NULL);
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v1 0/4] Generalize PCI specific EAL function/structures
From: Shreyansh Jain @ 2016-10-03  5:37 UTC (permalink / raw)
  To: David Marchand; +Cc: dev@dpdk.org, Jan Viktorin, Thomas Monjalon
In-Reply-To: <CALwxeUtrswaOEBirUetWO+KWemgzySEBfC0cWPPKcP2VuKbZ8A@mail.gmail.com>

Hi David,

On Friday 30 September 2016 09:01 PM, David Marchand wrote:
> On Tue, Sep 27, 2016 at 4:12 PM, Shreyansh Jain <shreyansh.jain@nxp.com> wrote:
>> (I rebased these over HEAD 7b3c4f3)
>>
>> These patches were initially part of Jan's original series on SoC
>> Framework ([1],[2]). An update to that series, without these patches,
>> was posted here [3].
>>
>> Main motivation for these is aim of introducing a non-PCI centric
>> subsystem in EAL. As of now the first usecase is SoC, but not limited to
>> it.
>>
>> 4 patches in this series are independent of each other, as well as SoC
>> framework. All these focus on generalizing some structure or functions
>> present with the PCI specific code to EAL Common area (or splitting a
>> function to be more userful).
>
> Those patches move linux specifics (binding pci devices using sysfs)
> to common infrastucture.
> We have no proper hotplug support on bsd, but if we had some common
> code we should at least try to make the apis generic.
>

I am not sure if I understood your point well. Just to confirm - you are 
stating that the movement done in the patches might not suit BSD. 
Probably you are talking about (Patch 3/4 and 4/4).
Is my understanding correct?

So, movement to just Linux area is not enough?
I am not well versed with BSD way of doing something similar so if 
someone can point it out, I can integrate that. (I will investigate it 
at my end as well).

This patchset makes the PCI->EAL movement *only* for Linux for sysfs 
bind/unbind. (I should add this to cover letter, at the least).

-
Shreyansh

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox