All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] software parser for packet type
@ 2016-07-05 15:41 Olivier Matz
  2016-07-05 15:41 ` [PATCH 01/18] doc: add template for release notes 16.11 Olivier Matz
                   ` (18 more replies)
  0 siblings, 19 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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.

Olivier Matz (18):
  doc: add template for release notes 16.11
  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
  mbuf: add function to get packet type from data
  mbuf: support Vlan in software packet type parser
  mbuf: support QinQ in software packet type parser
  net: add Mpls header structure
  mbuf: support Mpls in software packet type parser
  mbuf: support Ip tunnels in software packet type parser
  net: add Gre header structure
  mbuf: support Gre in software packet type parser
  mbuf: support Nvgre in software packet type parser
  mbuf: 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 sw packet type

 app/test-pmd/rxonly.c                  | 195 ++-------
 doc/guides/rel_notes/release_16_11.rst | 173 ++++++++
 lib/librte_ether/Makefile              |   3 +-
 lib/librte_ether/rte_ether.h           | 416 -------------------
 lib/librte_mbuf/Makefile               |   7 +-
 lib/librte_mbuf/rte_mbuf.c             |  36 ++
 lib/librte_mbuf/rte_mbuf.h             | 530 ++----------------------
 lib/librte_mbuf/rte_mbuf_ptype.c       | 735 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h       | 735 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |  16 +
 lib/librte_net/Makefile                |   4 +-
 lib/librte_net/rte_ether.h             | 419 +++++++++++++++++++
 lib/librte_net/rte_gre.h               |  71 ++++
 lib/librte_net/rte_mpls.h              |  64 +++
 14 files changed, 2317 insertions(+), 1087 deletions(-)
 create mode 100644 doc/guides/rel_notes/release_16_11.rst
 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_mpls.h

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

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"

class MPLS(Packet):
   name = "MPLS"
   fields_desc =  [ BitField("label", 3, 20),
     BitField("cos", 0, 3),
     BitField("bs", 1, 1),
     ByteField("ttl", 0)  ]

bind_layers(Ether, MPLS, type=0x8847)
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/MPLS(bs=1)/IP()/UDP()/Raw("x"*32)
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=0x8847 - length=78 - nb_segs=1 - hw ptype: L2_ETHER  - sw ptype: L2_ETHER_MPLS  - l2_len=18 - 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)
p = 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	[flat|nested] 71+ messages in thread

* [PATCH 01/18] doc: add template for release notes 16.11
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-06 11:48   ` Mcnamara, John
  2016-07-05 15:41 ` [PATCH 02/18] mbuf: add function to read packet data Olivier Matz
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 doc/guides/rel_notes/release_16_11.rst | 160 +++++++++++++++++++++++++++++++++
 1 file changed, 160 insertions(+)
 create mode 100644 doc/guides/rel_notes/release_16_11.rst

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
new file mode 100644
index 0000000..0106bc9
--- /dev/null
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -0,0 +1,160 @@
+DPDK Release 16.11
+==================
+
+.. **Read this first.**
+
+   The text below explains how to update the release notes.
+
+   Use proper spelling, capitalization and punctuation in all sections.
+
+   Variable and config names should be quoted as fixed width text: ``LIKE_THIS``.
+
+   Build the docs and view the output file to ensure the changes are correct::
+
+      make doc-guides-html
+
+      firefox build/doc/html/guides/rel_notes/release_16_11.html
+
+
+New Features
+------------
+
+.. This section should contain new features added in this release. Sample format:
+
+   * **Add a title in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description in the past tense. The description
+     should be enough to allow someone scanning the release notes to understand
+     the new feature.
+
+     If the feature adds a lot of sub-features you can use a bullet list like this.
+
+     * Added feature foo to do something.
+     * Enhanced feature bar to do something else.
+
+     Refer to the previous release notes for examples.
+
+
+Resolved Issues
+---------------
+
+.. This section should contain bug fixes added to the relevant sections. Sample format:
+
+   * **code/section Fixed issue in the past tense with a full stop.**
+
+     Add a short 1-2 sentence description of the resolved issue in the past tense.
+     The title should contain the code/lib section like a commit message.
+     Add the entries in alphabetic order in the relevant sections below.
+
+
+EAL
+~~~
+
+
+Drivers
+~~~~~~~
+
+
+Libraries
+~~~~~~~~~
+
+
+Examples
+~~~~~~~~
+
+
+Other
+~~~~~
+
+
+Known Issues
+------------
+
+.. This section should contain new known issues in this release. Sample format:
+
+   * **Add title in present tense with full stop.**
+
+     Add a short 1-2 sentence description of the known issue in the present
+     tense. Add information on any known workarounds.
+
+
+API Changes
+-----------
+
+.. This section should contain API changes. Sample format:
+
+   * Add a short 1-2 sentence description of the API change. Use fixed width
+     quotes for ``rte_function_names`` or ``rte_struct_names``. Use the past tense.
+
+
+ABI Changes
+-----------
+
+.. * Add a short 1-2 sentence description of the ABI change that was announced in
+     the previous releases and made in this release. Use fixed width quotes for
+     ``rte_function_names`` or ``rte_struct_names``. Use the past tense.
+
+
+Shared Library Versions
+-----------------------
+
+.. Update any library version updated in this release and prepend with a ``+`` sign.
+
+The libraries prepended with a plus sign were incremented in this version.
+
+.. code-block:: diff
+
+     libethdev.so.3
+     librte_acl.so.2
+     librte_cfgfile.so.2
+     librte_cmdline.so.2
+     librte_distributor.so.1
+     librte_eal.so.2
+     librte_hash.so.2
+     librte_ip_frag.so.1
+     librte_ivshmem.so.1
+     librte_jobstats.so.1
+     librte_kni.so.2
+     librte_kvargs.so.1
+     librte_lpm.so.2
+     librte_mbuf.so.2
+     librte_mempool.so.2
+     librte_meter.so.1
+     librte_pipeline.so.3
+     librte_pmd_bond.so.1
+     librte_pmd_ring.so.2
+     librte_port.so.2
+     librte_power.so.1
+     librte_reorder.so.1
+     librte_ring.so.1
+     librte_sched.so.1
+     librte_table.so.2
+     librte_timer.so.1
+     librte_vhost.so.2
+
+
+Tested Platforms
+----------------
+
+.. This section should contain a list of platforms that were tested with this
+   release.
+
+   The format is:
+
+   #. Platform name.
+
+      - Platform details.
+      - Platform details.
+
+
+Tested NICs
+-----------
+
+.. This section should contain a list of NICs that were tested with this release.
+
+   The format is:
+
+   #. NIC name.
+
+      - NIC details.
+      - NIC details.
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 02/18] mbuf: add function to read packet data
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
  2016-07-05 15:41 ` [PATCH 01/18] doc: add template for release notes 16.11 Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 03/18] net: move Ethernet header definitions to the net library Olivier Matz
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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             | 36 ++++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h             | 35 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |  7 +++++++
 4 files changed, 82 insertions(+)

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index 0106bc9..9b4d533 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -34,6 +34,10 @@ New Features
 
      Refer to the previous release notes for examples.
 
+* **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 601e528..a515ece 100644
--- a/lib/librte_mbuf/rte_mbuf.c
+++ b/lib/librte_mbuf/rte_mbuf.c
@@ -59,6 +59,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
@@ -259,6 +260,41 @@ 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) &&
+			rte_pktmbuf_data_len(seg) != 0) {
+		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 101485f..b76ee20 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -1958,6 +1958,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	[flat|nested] 71+ messages in thread

* [PATCH 03/18] net: move Ethernet header definitions to the net library
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
  2016-07-05 15:41 ` [PATCH 01/18] doc: add template for release notes 16.11 Olivier Matz
  2016-07-05 15:41 ` [PATCH 02/18] mbuf: add function to read packet data Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 04/18] mbuf: move packet type definitions in a new file Olivier Matz
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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	[flat|nested] 71+ messages in thread

* [PATCH 04/18] mbuf: move packet type definitions in a new file
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (2 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 03/18] net: move Ethernet header definitions to the net library Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 05/18] mbuf: add function to get packet type from data Olivier Matz
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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 b76ee20..ad6f660 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..4a34678
--- /dev/null
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -0,0 +1,552 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *   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	[flat|nested] 71+ messages in thread

* [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (3 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 04/18] mbuf: move packet type definitions in a new file Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-06  6:44   ` Liang, Cunming
  2016-07-05 15:41 ` [PATCH 06/18] mbuf: support Vlan in software packet type parser Olivier Matz
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
 lib/librte_mbuf/rte_mbuf_ptype.c       | 234 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
 lib/librte_mbuf/rte_mbuf_version.map   |   1 +
 5 files changed, 286 insertions(+), 2 deletions(-)
 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 9b4d533..0ef8a87 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -39,6 +39,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_pktmbuf_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_mbuf/Makefile b/lib/librte_mbuf/Makefile
index 27e037c..15bbc78 100644
--- a/lib/librte_mbuf/Makefile
+++ b/lib/librte_mbuf/Makefile
@@ -41,12 +41,13 @@ 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
 
 # this lib needs eal
-DEPDIRS-$(CONFIG_RTE_LIBRTE_MBUF) += lib/librte_eal lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_MBUF) += lib/librte_eal lib/librte_mempool \
+                                     lib/librte_net
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
new file mode 100644
index 0000000..73284ae
--- /dev/null
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -0,0 +1,234 @@
+/*-
+ *   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.
+ */
+
+#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>
+
+/* 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_pktmbuf_get_ptype(const struct rte_mbuf *m,
+	struct rte_mbuf_hdr_lens *hdr_lens)
+{
+	struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 4a34678..f468520 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -545,6 +545,49 @@ extern "C" {
 		RTE_PTYPE_INNER_L3_MASK |				\
 		RTE_PTYPE_INNER_L4_MASK))
 
+struct rte_mbuf;
+
+/**
+ * Structure containing header lengths associated to a packet.
+ */
+struct rte_mbuf_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_mbuf_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_pktmbuf_get_ptype(const struct rte_mbuf *m,
+	struct rte_mbuf_hdr_lens *hdr_lens);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map
index 79e4dd8..416af8e 100644
--- a/lib/librte_mbuf/rte_mbuf_version.map
+++ b/lib/librte_mbuf/rte_mbuf_version.map
@@ -23,5 +23,6 @@ DPDK_16.11 {
 	global:
 
 	__rte_pktmbuf_read;
+	rte_pktmbuf_get_ptype;
 
 } DPDK_2.1;
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 06/18] mbuf: support Vlan in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (4 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 05/18] mbuf: add function to get packet type from data Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 07/18] mbuf: support QinQ " Olivier Matz
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add a new RTE_PTYPE_L2_ETHER_VLAN packet type, and its support in
rte_pktmbuf_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.c | 13 +++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 73284ae..6bbb255 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -166,6 +166,19 @@ uint32_t rte_pktmbuf_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;
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index f468520..5f1325c 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.
  */
@@ -573,7 +580,7 @@ struct rte_mbuf_hdr_lens {
  * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
  *
  * Supported packet types are:
- *   L2: Ether
+ *   L2: Ether, Vlan
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
  *
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 07/18] mbuf: support QinQ in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (5 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 06/18] mbuf: support Vlan in software packet type parser Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 08/18] net: add Mpls header structure Olivier Matz
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add a new RTE_PTYPE_L2_ETHER_QINQ packet type, and its support in
rte_pktmbuf_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.c | 12 ++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
 lib/librte_net/rte_ether.h       |  1 +
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 6bbb255..5d46608 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -177,6 +177,18 @@ uint32_t rte_pktmbuf_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;
 	}
 
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 5f1325c..e2e92d0 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.
  */
@@ -580,7 +587,7 @@ struct rte_mbuf_hdr_lens {
  * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
  *
  * Supported packet types are:
- *   L2: Ether, Vlan
+ *   L2: Ether, Vlan, QinQ
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
  *
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. */
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 08/18] net: add Mpls header structure
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (6 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 07/18] mbuf: support QinQ " Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 09/18] mbuf: support Mpls in software packet type parser Olivier Matz
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
---
 lib/librte_net/rte_mpls.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 lib/librte_net/rte_mpls.h

diff --git a/lib/librte_net/rte_mpls.h b/lib/librte_net/rte_mpls.h
new file mode 100644
index 0000000..bf8c6cc
--- /dev/null
+++ b/lib/librte_net/rte_mpls.h
@@ -0,0 +1,64 @@
+/*-
+ *   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_MPLS_H_
+#define _RTE_MPLS_H_
+
+#include <stdint.h>
+#include <rte_byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * MPLS Header
+ */
+struct mpls_hdr {
+	uint16_t tag_msb;   /**< Label(msb). */
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	uint8_t tag_lsb:4;  /**< Label(lsb). */
+	uint8_t tc:3;       /**< Traffic class. */
+	uint8_t bs:1;       /**< Bottom of stack. */
+#else
+	uint8_t bs:1;       /**< Bottom of stack. */
+	uint8_t tc:3;       /**< Traffic class. */
+	uint8_t tag_lsb:4;  /**< label(lsb) */
+#endif
+	uint8_t  ttl;       /**< Time to live. */
+} __attribute__((__packed__));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_MPLS_H_ */
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 09/18] mbuf: support Mpls in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (7 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 08/18] net: add Mpls header structure Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-06  7:08   ` Liang, Cunming
  2016-07-05 15:41 ` [PATCH 10/18] mbuf: support Ip tunnels " Olivier Matz
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add a new RTE_PTYPE_L2_ETHER_MPLS packet type, and its support in
rte_pktmbuf_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.c | 25 +++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
 lib/librte_net/Makefile          |  4 +++-
 lib/librte_net/rte_ether.h       |  2 ++
 4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 5d46608..0dea600 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -41,6 +41,7 @@
 #include <rte_tcp.h>
 #include <rte_udp.h>
 #include <rte_sctp.h>
+#include <rte_mpls.h>
 
 /* get l3 packet type from ip6 next protocol */
 static uint32_t
@@ -166,6 +167,9 @@ uint32_t rte_pktmbuf_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;
@@ -189,8 +193,29 @@ uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
 		off += 2 * sizeof(*vh);
 		hdr_lens->l2_len += 2 * sizeof(*vh);
 		proto = vh->eth_proto;
+	} else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
+			(proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
+		unsigned int i;
+		const struct mpls_hdr *mh;
+		struct mpls_hdr mh_copy;
+
+#define MAX_MPLS_HDR 5
+		for (i = 0; i < MAX_MPLS_HDR; i++) {
+			mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
+				sizeof(*mh), &mh_copy);
+			if (unlikely(mh == NULL))
+				return pkt_type;
+			if (mh->bs)
+				break;
+		}
+		if (i == MAX_MPLS_HDR)
+			return pkt_type;
+		pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
+		hdr_lens->l2_len += (sizeof(*mh) * (i + 1));
+		return pkt_type;
 	}
 
+ 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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index e2e92d0..adc4c03 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -150,6 +150,13 @@ extern "C" {
  */
 #define RTE_PTYPE_L2_ETHER_QINQ             0x00000007
 /**
+ * MPLS packet type.
+ *
+ * Packet format:
+ * <'ether type'=[0x8847|0x0x8848]>
+ */
+#define RTE_PTYPE_L2_ETHER_MPLS             0x00000008
+/**
  * Mask of layer 2 packet types.
  * It is used for outer packet for tunneling cases.
  */
@@ -587,7 +594,7 @@ struct rte_mbuf_hdr_lens {
  * (retval & RTE_PTYPE_L2_MASK) != RTE_PTYPE_UNKNOWN.
  *
  * Supported packet types are:
- *   L2: Ether, Vlan, QinQ
+ *   L2: Ether, Vlan, QinQ, Mpls
  *   L3: IPv4, IPv6
  *   L4: TCP, UDP, SCTP
  *
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index fc332ff..af57f40 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -34,7 +34,9 @@ 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 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_mpls.h
 
 
 include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_net/rte_ether.h b/lib/librte_net/rte_ether.h
index ff3d065..254cb2d 100644
--- a/lib/librte_net/rte_ether.h
+++ b/lib/librte_net/rte_ether.h
@@ -333,6 +333,8 @@ struct vxlan_hdr {
 #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_TYPE_MPLS 0x8847 /**< MPLS ethertype. */
+#define ETHER_TYPE_MPLSM 0x8848 /**< MPLS multicast ethertype. */
 
 #define ETHER_VXLAN_HLEN (sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr))
 /**< VXLAN tunnel header length. */
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 10/18] mbuf: support Ip tunnels in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (8 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 09/18] mbuf: support Mpls in software packet type parser Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 11/18] net: add Gre header structure Olivier Matz
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add support of IP and IP6 tunnels in rte_pktmbuf_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_mbuf/rte_mbuf_ptype.c | 158 ++++++++++++++++++++++++++++++++++++++-
 lib/librte_mbuf/rte_mbuf_ptype.h |   1 +
 2 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 0dea600..1fddbc3 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.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)
@@ -227,9 +300,8 @@ uint32_t rte_pktmbuf_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;
@@ -265,6 +337,7 @@ uint32_t rte_pktmbuf_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;
@@ -274,10 +347,89 @@ uint32_t rte_pktmbuf_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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index adc4c03..87749b0 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -597,6 +597,7 @@ struct rte_mbuf_hdr_lens {
  *   L2: Ether, Vlan, QinQ, Mpls
  *   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	[flat|nested] 71+ messages in thread

* [PATCH 11/18] net: add Gre header structure
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (9 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 10/18] mbuf: support Ip tunnels " Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 12/18] mbuf: support Gre in software packet type parser Olivier Matz
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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 af57f40..ffbef58 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -36,7 +36,7 @@ CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 # 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_mpls.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include += rte_ether.h rte_mpls.h rte_gre.h
 
 
 include $(RTE_SDK)/mk/rte.install.mk
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	[flat|nested] 71+ messages in thread

* [PATCH 12/18] mbuf: support Gre in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (10 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 11/18] net: add Gre header structure Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 13/18] mbuf: support Nvgre " Olivier Matz
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add support of Gre tunnels in rte_pktmbuf_get_ptype().

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

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 1fddbc3..f681a42 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -42,6 +42,7 @@
 #include <rte_udp.h>
 #include <rte_sctp.h>
 #include <rte_mpls.h>
+#include <rte_gre.h>
 
 /* get l3 packet type from ip6 next protocol */
 static uint32_t
@@ -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;
@@ -352,9 +382,11 @@ uint32_t rte_pktmbuf_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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 87749b0..d037504 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -597,7 +597,7 @@ struct rte_mbuf_hdr_lens {
  *   L2: Ether, Vlan, QinQ, Mpls
  *   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	[flat|nested] 71+ messages in thread

* [PATCH 13/18] mbuf: support Nvgre in software packet type parser
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (11 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 12/18] mbuf: support Gre in software packet type parser Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 14/18] mbuf: get ptype for the first layers only Olivier Matz
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add support of Nvgre tunnels in rte_pktmbuf_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.c | 48 ++++++++++++++++++++++++++++++++++++++--
 lib/librte_mbuf/rte_mbuf_ptype.h | 20 ++++++++++++++++-
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index f681a42..e5be308 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.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);
@@ -392,7 +395,48 @@ uint32_t rte_pktmbuf_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;
+	} else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
+			(proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
+		pkt_type &= ~RTE_PTYPE_INNER_L2_MASK;
+		pkt_type |= RTE_PTYPE_INNER_L2_ETHER_MPLS;
+		hdr_lens->inner_l2_len += 4;
+		return pkt_type;
+	}
 
 	if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
 		const struct ipv4_hdr *ip4h;
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index d037504..be3ad96 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -403,6 +403,24 @@ 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
+/**
+ * MPLS packet type.
+ *
+ * Packet format:
+ * <'ether type'=[0x8847|0x0x8848]>
+ */
+#define RTE_PTYPE_INNER_L2_ETHER_MPLS       0x00040000
+/**
+ * Mask of layer 2 packet types.
+ * It is used for outer packet for tunneling cases.
+ */
+/**
  * Mask of inner layer 2 packet types.
  */
 #define RTE_PTYPE_INNER_L2_MASK             0x000f0000
@@ -597,7 +615,7 @@ struct rte_mbuf_hdr_lens {
  *   L2: Ether, Vlan, QinQ, Mpls
  *   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	[flat|nested] 71+ messages in thread

* [PATCH 14/18] mbuf: get ptype for the first layers only
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (12 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 13/18] mbuf: support Nvgre " Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 15/18] mbuf: add functions to dump packet type Olivier Matz
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

Add a parameter to rte_pktmbuf_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_mbuf/rte_mbuf_ptype.c | 33 ++++++++++++++++++++++++++++++++-
 lib/librte_mbuf/rte_mbuf_ptype.h |  7 ++++++-
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index e5be308..2abb896 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.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_pktmbuf_get_ptype(const struct rte_mbuf *m,
-	struct rte_mbuf_hdr_lens *hdr_lens)
+	struct rte_mbuf_hdr_lens *hdr_lens, uint32_t layers)
 {
 	struct rte_mbuf_hdr_lens local_hdr_lens;
 	const struct ether_hdr *eh;
@@ -273,6 +273,9 @@ uint32_t rte_pktmbuf_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 */
 
@@ -322,6 +325,9 @@ uint32_t rte_pktmbuf_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;
@@ -333,6 +339,10 @@ uint32_t rte_pktmbuf_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;
@@ -360,6 +370,10 @@ uint32_t rte_pktmbuf_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;
@@ -388,6 +402,10 @@ uint32_t rte_pktmbuf_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;
 	}
@@ -395,6 +413,9 @@ uint32_t rte_pktmbuf_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))
@@ -438,6 +459,9 @@ uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
 		return pkt_type;
 	}
 
+	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;
@@ -449,6 +473,9 @@ uint32_t rte_pktmbuf_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)) {
@@ -481,6 +508,10 @@ uint32_t rte_pktmbuf_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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index be3ad96..9af52b4 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -622,11 +622,16 @@ struct rte_mbuf_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_pktmbuf_get_ptype(const struct rte_mbuf *m,
-	struct rte_mbuf_hdr_lens *hdr_lens);
+	struct rte_mbuf_hdr_lens *hdr_lens, uint32_t layers);
 
 #ifdef __cplusplus
 }
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 15/18] mbuf: add functions to dump packet type
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (13 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 14/18] mbuf: get ptype for the first layers only Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 16/18] mbuf: clarify definition of fragment packet types Olivier Matz
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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/rte_mbuf_ptype.c       | 192 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_ptype.h       |  89 +++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |   8 ++
 4 files changed, 293 insertions(+)

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index 0ef8a87..7ce201b 100644
--- a/doc/guides/rel_notes/release_16_11.rst
+++ b/doc/guides/rel_notes/release_16_11.rst
@@ -44,6 +44,10 @@ New Features
   Added a new function ``rte_pktmbuf_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/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
index 2abb896..848b622 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.c
+++ b/lib/librte_mbuf/rte_mbuf_ptype.c
@@ -44,6 +44,198 @@
 #include <rte_mpls.h>
 #include <rte_gre.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";
+	case RTE_PTYPE_L2_ETHER_MPLS: return "L2_ETHER_MPLS";
+	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";
+	case RTE_PTYPE_INNER_L2_ETHER_MPLS: return "INNER_L2_ETHER_MPLS";
+	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;
+}
+
 /* get l3 packet type from ip6 next protocol */
 static uint32_t
 ptype_l3_ip6(uint8_t ip6_proto)
diff --git a/lib/librte_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
index 9af52b4..21bba37 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -562,6 +562,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
@@ -587,6 +591,91 @@ extern "C" {
 struct rte_mbuf;
 
 /**
+ * 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);
+
+/**
  * Structure containing header lengths associated to a packet.
  */
 struct rte_mbuf_hdr_lens {
diff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map
index 416af8e..0f04b02 100644
--- a/lib/librte_mbuf/rte_mbuf_version.map
+++ b/lib/librte_mbuf/rte_mbuf_version.map
@@ -23,6 +23,14 @@ 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;
 	rte_pktmbuf_get_ptype;
 
 } DPDK_2.1;
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 16/18] mbuf: clarify definition of fragment packet types
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (14 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 15/18] mbuf: add functions to dump packet type Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 17/18] app/testpmd: dump ptype using the new function Olivier Matz
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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 21bba37..55ee24f 100644
--- a/lib/librte_mbuf/rte_mbuf_ptype.h
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -234,7 +234,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>
@@ -246,7 +246,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>
@@ -265,6 +265,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>
  */
@@ -275,7 +278,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>
@@ -287,7 +290,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>
@@ -303,7 +306,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]>
@@ -491,7 +494,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>
@@ -503,7 +506,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>
@@ -517,6 +520,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>
  */
@@ -527,7 +533,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>
@@ -539,7 +545,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>
@@ -552,7 +558,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	[flat|nested] 71+ messages in thread

* [PATCH 17/18] app/testpmd: dump ptype using the new function
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (15 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 16/18] mbuf: clarify definition of fragment packet types Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-07-05 15:41 ` [PATCH 18/18] app/testpmd: display sw packet type Olivier Matz
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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 fbf287d..aba07ee 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -92,6 +92,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;
@@ -162,177 +163,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	[flat|nested] 71+ messages in thread

* [PATCH 18/18] app/testpmd: display sw packet type
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (16 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 17/18] app/testpmd: dump ptype using the new function Olivier Matz
@ 2016-07-05 15:41 ` Olivier Matz
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
  18 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-05 15:41 UTC (permalink / raw)
  To: dev

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 | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/app/test-pmd/rxonly.c b/app/test-pmd/rxonly.c
index aba07ee..00da1a2 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -93,6 +93,8 @@ pkt_burst_receive(struct fwd_stream *fs)
 	uint16_t i, packet_type;
 	uint16_t is_encapsulation;
 	char buf[256];
+	struct rte_mbuf_hdr_lens hdr_lens;
+	uint32_t sw_packet_type;
 
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
 	uint64_t start_tsc;
@@ -164,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_pktmbuf_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	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-05 15:41 ` [PATCH 05/18] mbuf: add function to get packet type from data Olivier Matz
@ 2016-07-06  6:44   ` Liang, Cunming
  2016-07-06  7:42     ` Olivier MATZ
  0 siblings, 1 reply; 71+ messages in thread
From: Liang, Cunming @ 2016-07-06  6:44 UTC (permalink / raw)
  To: Olivier Matz, dev

Hi Olivier,

On 7/5/2016 11:41 PM, Olivier Matz wrote:
> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234 +++++++++++++++++++++++++++++++++
>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
>   5 files changed, 286 insertions(+), 2 deletions(-)
>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
>
> [...]
> +
> +/* parse mbuf data to get packet type */
> +uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
> +	struct rte_mbuf_hdr_lens *hdr_lens)
> +{
> +	struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h b/lib/librte_mbuf/rte_mbuf_ptype.h
> index 4a34678..f468520 100644
> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
> @@ -545,6 +545,49 @@ extern "C" {
>   		RTE_PTYPE_INNER_L3_MASK |				\
>   		RTE_PTYPE_INNER_L4_MASK))
>   
> +struct rte_mbuf;
> +
> +/**
> + * Structure containing header lengths associated to a packet.
> + */
> +struct rte_mbuf_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;
> +};
[LC] The header parsing graph usually is not unique. The definition 
maybe nice for the basic IP and L4 tunnel.
However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls 
l2/l3 tunnel.
The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of 
"struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
In this case, the fixed function is to support below.

+ * Supported packet types are:
+ *   L2: Ether
+ *   L3: IPv4, IPv6
+ *   L4: TCP, UDP, SCTP

Of course, it can add more packet type detection logic in future. But 
the more support, the higher the cost.

One of the alternative way is to allow registering parser pair. APP 
decides to choose the predefined scheme(by DPDK LIB), or to self-define 
the parsing logic.
In this way, the scheme can do some assumption for the specific case and 
ignore some useless graph detection.
In addition, besides the SW parser, the HW parser(identified by 
packet_type in mbuf) can be turn on/off by leveraging the same manner.

Thanks.
> +
> +/**
> + * 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_mbuf_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_pktmbuf_get_ptype(const struct rte_mbuf *m,
> +	struct rte_mbuf_hdr_lens *hdr_lens);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map
> index 79e4dd8..416af8e 100644
> --- a/lib/librte_mbuf/rte_mbuf_version.map
> +++ b/lib/librte_mbuf/rte_mbuf_version.map
> @@ -23,5 +23,6 @@ DPDK_16.11 {
>   	global:
>   
>   	__rte_pktmbuf_read;
> +	rte_pktmbuf_get_ptype;
>   
>   } DPDK_2.1;

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 09/18] mbuf: support Mpls in software packet type parser
  2016-07-05 15:41 ` [PATCH 09/18] mbuf: support Mpls in software packet type parser Olivier Matz
@ 2016-07-06  7:08   ` Liang, Cunming
  2016-07-06  8:00     ` Olivier MATZ
  0 siblings, 1 reply; 71+ messages in thread
From: Liang, Cunming @ 2016-07-06  7:08 UTC (permalink / raw)
  To: Olivier Matz, dev

Hi Olivier,

On 7/5/2016 11:41 PM, Olivier Matz wrote:
> Add a new RTE_PTYPE_L2_ETHER_MPLS packet type, and its support in
> rte_pktmbuf_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.c | 25 +++++++++++++++++++++++++
>   lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
>   lib/librte_net/Makefile          |  4 +++-
>   lib/librte_net/rte_ether.h       |  2 ++
>   4 files changed, 38 insertions(+), 2 deletions(-)
>
> diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c b/lib/librte_mbuf/rte_mbuf_ptype.c
> index 5d46608..0dea600 100644
> --- a/lib/librte_mbuf/rte_mbuf_ptype.c
> +++ b/lib/librte_mbuf/rte_mbuf_ptype.c
> @@ -41,6 +41,7 @@
>   #include <rte_tcp.h>
>   #include <rte_udp.h>
>   #include <rte_sctp.h>
> +#include <rte_mpls.h>
>   
>   /* get l3 packet type from ip6 next protocol */
>   static uint32_t
> @@ -166,6 +167,9 @@ uint32_t rte_pktmbuf_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;
> @@ -189,8 +193,29 @@ uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
>   		off += 2 * sizeof(*vh);
>   		hdr_lens->l2_len += 2 * sizeof(*vh);
>   		proto = vh->eth_proto;
> +	} else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
> +			(proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
> +		unsigned int i;
> +		const struct mpls_hdr *mh;
> +		struct mpls_hdr mh_copy;
> +
> +#define MAX_MPLS_HDR 5
> +		for (i = 0; i < MAX_MPLS_HDR; i++) {
> +			mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
> +				sizeof(*mh), &mh_copy);
> +			if (unlikely(mh == NULL))
> +				return pkt_type;
> +			if (mh->bs)
> +				break;
> +		}
> +		if (i == MAX_MPLS_HDR)
> +			return pkt_type;
> +		pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
> +		hdr_lens->l2_len += (sizeof(*mh) * (i + 1));
[LC] l2_len includes Eth, Vlan(opt.), MPLS(opt.). For VLAN and MPLS, it 
may include #n times overlay.
These layer recognition knowledge are lost after the detection logic. 
Once the APP takes the ptype, for the layer(L2, L3, L4) which has more 
shim-layer, the xxx_len can't help to avoid the re-parse cost.
> +		return pkt_type;
>   	}
>   
> [...]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-06  6:44   ` Liang, Cunming
@ 2016-07-06  7:42     ` Olivier MATZ
  2016-07-06 11:59       ` Chilikin, Andrey
  2016-07-07  8:19       ` Liang, Cunming
  0 siblings, 2 replies; 71+ messages in thread
From: Olivier MATZ @ 2016-07-06  7:42 UTC (permalink / raw)
  To: Liang, Cunming, dev

Hi Cunming,

On 07/06/2016 08:44 AM, Liang, Cunming wrote:
> Hi Olivier,
> 
> On 7/5/2016 11:41 PM, Olivier Matz wrote:
>> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
>>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
>> +++++++++++++++++++++++++++++++++
>>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
>>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
>>   5 files changed, 286 insertions(+), 2 deletions(-)
>>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
>>
>> [...]
>> +
>> +/* parse mbuf data to get packet type */
>> +uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
>> +    struct rte_mbuf_hdr_lens *hdr_lens)
>> +{
>> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
>> b/lib/librte_mbuf/rte_mbuf_ptype.h
>> index 4a34678..f468520 100644
>> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
>> @@ -545,6 +545,49 @@ extern "C" {
>>           RTE_PTYPE_INNER_L3_MASK |                \
>>           RTE_PTYPE_INNER_L4_MASK))
>>   +struct rte_mbuf;
>> +
>> +/**
>> + * Structure containing header lengths associated to a packet.
>> + */
>> +struct rte_mbuf_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;
>> +};
> [LC] The header parsing graph usually is not unique. The definition
> maybe nice for the basic IP and L4 tunnel.
> However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
> l2/l3 tunnel.
> The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
> "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
> In this case, the fixed function is to support below.
> 
> + * Supported packet types are:
> + *   L2: Ether
> + *   L3: IPv4, IPv6
> + *   L4: TCP, UDP, SCTP
> 
> Of course, it can add more packet type detection logic in future. But
> the more support, the higher the cost.
> 
> One of the alternative way is to allow registering parser pair. APP
> decides to choose the predefined scheme(by DPDK LIB), or to self-define
> the parsing logic.
> In this way, the scheme can do some assumption for the specific case and
> ignore some useless graph detection.
> In addition, besides the SW parser, the HW parser(identified by
> packet_type in mbuf) can be turn on/off by leveraging the same manner.


Sorry, I'm not sure I'm fully getting what you are saying. If I
understand well, you would like to have something more flexible that
supports the registration of protocol to be recognized?

I'm not sure having a function with a dynamic registration method would
really increase the performance compared to a static complete function.
Actually, we will never support a tons of protocols since each layer
packet type is 4 bits, and since it requires that at least one hw
supports it.

As described in the cover letter, the 2 main goals of this patchset are
to provide a reference implementation for packet type recognition, and
enable the support of virtio offloads (I'll send the patchset soon).
This function is adapted to these 2 usages. Are you thinking of another
use-case that would not be covered?

Regards,
Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 09/18] mbuf: support Mpls in software packet type parser
  2016-07-06  7:08   ` Liang, Cunming
@ 2016-07-06  8:00     ` Olivier MATZ
  2016-07-07  8:48       ` Liang, Cunming
  0 siblings, 1 reply; 71+ messages in thread
From: Olivier MATZ @ 2016-07-06  8:00 UTC (permalink / raw)
  To: Liang, Cunming, dev

Hi Cunming,

On 07/06/2016 09:08 AM, Liang, Cunming wrote:
> Hi Olivier,
> 
> On 7/5/2016 11:41 PM, Olivier Matz wrote:
>> Add a new RTE_PTYPE_L2_ETHER_MPLS packet type, and its support in
>> rte_pktmbuf_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.c | 25 +++++++++++++++++++++++++
>>   lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
>>   lib/librte_net/Makefile          |  4 +++-
>>   lib/librte_net/rte_ether.h       |  2 ++
>>   4 files changed, 38 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c
>> b/lib/librte_mbuf/rte_mbuf_ptype.c
>> index 5d46608..0dea600 100644
>> --- a/lib/librte_mbuf/rte_mbuf_ptype.c
>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.c
>> @@ -41,6 +41,7 @@
>>   #include <rte_tcp.h>
>>   #include <rte_udp.h>
>>   #include <rte_sctp.h>
>> +#include <rte_mpls.h>
>>     /* get l3 packet type from ip6 next protocol */
>>   static uint32_t
>> @@ -166,6 +167,9 @@ uint32_t rte_pktmbuf_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;
>> @@ -189,8 +193,29 @@ uint32_t rte_pktmbuf_get_ptype(const struct
>> rte_mbuf *m,
>>           off += 2 * sizeof(*vh);
>>           hdr_lens->l2_len += 2 * sizeof(*vh);
>>           proto = vh->eth_proto;
>> +    } else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
>> +            (proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
>> +        unsigned int i;
>> +        const struct mpls_hdr *mh;
>> +        struct mpls_hdr mh_copy;
>> +
>> +#define MAX_MPLS_HDR 5
>> +        for (i = 0; i < MAX_MPLS_HDR; i++) {
>> +            mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
>> +                sizeof(*mh), &mh_copy);
>> +            if (unlikely(mh == NULL))
>> +                return pkt_type;
>> +            if (mh->bs)
>> +                break;
>> +        }
>> +        if (i == MAX_MPLS_HDR)
>> +            return pkt_type;
>> +        pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
>> +        hdr_lens->l2_len += (sizeof(*mh) * (i + 1));
> [LC] l2_len includes Eth, Vlan(opt.), MPLS(opt.). For VLAN and MPLS, it
> may include #n times overlay.
> These layer recognition knowledge are lost after the detection logic.
> Once the APP takes the ptype, for the layer(L2, L3, L4) which has more
> shim-layer, the xxx_len can't help to avoid the re-parse cost.

This is linked with the definition of packet type. Each layer has a
type, and here we associate it to a length (by the way the length is
something we may consider integrate inside the packet type in the future).

The packet_type model allows to describe many packets kinds. Some will
be difficult to represent (ex: a packet with several different L2 or
L3). But I think this is a good compromise that could help the
application to get some information without looking inside the packet.

Changing the packet type structure to something more flexible/complex
would probably imply to loose time filling it in drivers and parse it in
the application. And we already have a structure that contains all the
information needed by the application: the packet data ;)

In any case, this is not really the topic of the patchset, which just
provide a helper to parse a packet by software and get a packet_type (as
it is defined today).

Regards,
Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 01/18] doc: add template for release notes 16.11
  2016-07-05 15:41 ` [PATCH 01/18] doc: add template for release notes 16.11 Olivier Matz
@ 2016-07-06 11:48   ` Mcnamara, John
  2016-07-06 12:00     ` Olivier MATZ
  0 siblings, 1 reply; 71+ messages in thread
From: Mcnamara, John @ 2016-07-06 11:48 UTC (permalink / raw)
  To: Olivier Matz, dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier Matz
> Sent: Tuesday, July 5, 2016 4:42 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 01/18] doc: add template for release notes
> 16.11

Hi,

This is useful but it is probably a little bit early since it should include the shared lib versions from the final 16.07 release notes.

Also, is it intentionally part of a patchset for a "software parser for packet type"? It should probably be separate.

John

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-06  7:42     ` Olivier MATZ
@ 2016-07-06 11:59       ` Chilikin, Andrey
  2016-07-06 12:08         ` Olivier MATZ
  2016-07-07  8:19       ` Liang, Cunming
  1 sibling, 1 reply; 71+ messages in thread
From: Chilikin, Andrey @ 2016-07-06 11:59 UTC (permalink / raw)
  To: Olivier MATZ, Liang, Cunming, dev; +Cc: Ananyev, Konstantin

Hi Oliver,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier MATZ
> Sent: Wednesday, July 6, 2016 8:43 AM
> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
> from data
> 
> Hi Cunming,
> 
> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
> > Hi Olivier,
> >
> > On 7/5/2016 11:41 PM, Olivier Matz wrote:
> >> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
> >>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
> >> +++++++++++++++++++++++++++++++++
> >>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
> >>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
> >>   5 files changed, 286 insertions(+), 2 deletions(-)
> >>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
> >>
> >> [...]
> >> +
> >> +/* parse mbuf data to get packet type */ uint32_t
> >> +rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
> >> +    struct rte_mbuf_hdr_lens *hdr_lens) {
> >> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
> >> b/lib/librte_mbuf/rte_mbuf_ptype.h
> >> index 4a34678..f468520 100644
> >> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
> >> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
> >> @@ -545,6 +545,49 @@ extern "C" {
> >>           RTE_PTYPE_INNER_L3_MASK |                \
> >>           RTE_PTYPE_INNER_L4_MASK))
> >>   +struct rte_mbuf;
> >> +
> >> +/**
> >> + * Structure containing header lengths associated to a packet.
> >> + */
> >> +struct rte_mbuf_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;
> >> +};
> > [LC] The header parsing graph usually is not unique. The definition
> > maybe nice for the basic IP and L4 tunnel.
> > However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
> > l2/l3 tunnel.
> > The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
> > "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
> > In this case, the fixed function is to support below.
> >
> > + * Supported packet types are:
> > + *   L2: Ether
> > + *   L3: IPv4, IPv6
> > + *   L4: TCP, UDP, SCTP
> >
> > Of course, it can add more packet type detection logic in future. But
> > the more support, the higher the cost.
> >
> > One of the alternative way is to allow registering parser pair. APP
> > decides to choose the predefined scheme(by DPDK LIB), or to
> > self-define the parsing logic.
> > In this way, the scheme can do some assumption for the specific case
> > and ignore some useless graph detection.
> > In addition, besides the SW parser, the HW parser(identified by
> > packet_type in mbuf) can be turn on/off by leveraging the same manner.
> 
> Sorry, I'm not sure I'm fully getting what you are saying. If I understand well,
> you would like to have something more flexible that supports the registration of
> protocol to be recognized?
> 
> I'm not sure having a function with a dynamic registration method would really
> increase the performance compared to a static complete function.
> Actually, we will never support a tons of protocols since each layer packet type
> is 4 bits, and since it requires that at least one hw supports it.

This patch will be very useful as a reference implementation, but it also highlights an issue with the current implementation of packet types reporting by HW and SW - as you just mentioned there are only 4 bits per each layer. As these 4 bit are used as a enumeration it is impossible to reports multiple headers located on the same layer. MPLS is one example, different packets could have different numbers of MPLS labels, but it is impossible to report using current packet_type structure.

It is possible, however, to  program HW to report user (application) specific packet types. For example, for IPoMPLS with one MPLS label, HW will report packet type A, but for IPoMPLS with two MPLS labels HW will reports packet type B. In this case, instead of defining and supporting tons of statically defined (or enumerated) protocol headers combinations, application will register packet types it expects from HW in addition to standard packet types. At the moment we  have high bits of packet_type reserved, so one possible solution would be to use the highest bit to indicate that this is user defined packet_type, specific to the application. Then it could be used with HW and with SW parser. For example, packet_type 0x8000000A is IPoMPLS with one MPLS label, 0x8000000B is IPoMPLS with two MPLS labels and so on.

Regards,
Andrey
> 
> As described in the cover letter, the 2 main goals of this patchset are to provide
> a reference implementation for packet type recognition, and enable the
> support of virtio offloads (I'll send the patchset soon).
> This function is adapted to these 2 usages. Are you thinking of another use-case
> that would not be covered?

> 
> Regards,
> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 01/18] doc: add template for release notes 16.11
  2016-07-06 11:48   ` Mcnamara, John
@ 2016-07-06 12:00     ` Olivier MATZ
  0 siblings, 0 replies; 71+ messages in thread
From: Olivier MATZ @ 2016-07-06 12:00 UTC (permalink / raw)
  To: Mcnamara, John, dev

Hi John,

On 07/06/2016 01:48 PM, Mcnamara, John wrote:
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier Matz
>> Sent: Tuesday, July 5, 2016 4:42 PM
>> To: dev@dpdk.org
>> Subject: [dpdk-dev] [PATCH 01/18] doc: add template for release notes
>> 16.11
> 
> Hi,
> 
> This is useful but it is probably a little bit early since it should include the shared lib versions from the final 16.07 release notes.
> 
> Also, is it intentionally part of a patchset for a "software parser for packet type"? It should probably be separate.

Sorry, I should have add an explanation: I just wanted to have the
patchset applying on current head (16.07-rc1) without conflicts. Indeed
some commits add some entries in the release note.

I agree, at the end, this commit should not be part of the patchset.

Regards,
Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-06 11:59       ` Chilikin, Andrey
@ 2016-07-06 12:08         ` Olivier MATZ
  2016-07-06 12:21           ` Chilikin, Andrey
  0 siblings, 1 reply; 71+ messages in thread
From: Olivier MATZ @ 2016-07-06 12:08 UTC (permalink / raw)
  To: Chilikin, Andrey, Liang, Cunming, dev; +Cc: Ananyev, Konstantin

Hi Andrey,

On 07/06/2016 01:59 PM, Chilikin, Andrey wrote:
> Hi Oliver,
> 
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier MATZ
>> Sent: Wednesday, July 6, 2016 8:43 AM
>> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
>> from data
>>
>> Hi Cunming,
>>
>> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
>>> Hi Olivier,
>>>
>>> On 7/5/2016 11:41 PM, Olivier Matz wrote:
>>>> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
>>>>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
>>>> +++++++++++++++++++++++++++++++++
>>>>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
>>>>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
>>>>   5 files changed, 286 insertions(+), 2 deletions(-)
>>>>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
>>>>
>>>> [...]
>>>> +
>>>> +/* parse mbuf data to get packet type */ uint32_t
>>>> +rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
>>>> +    struct rte_mbuf_hdr_lens *hdr_lens) {
>>>> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
>>>> b/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> index 4a34678..f468520 100644
>>>> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> @@ -545,6 +545,49 @@ extern "C" {
>>>>           RTE_PTYPE_INNER_L3_MASK |                \
>>>>           RTE_PTYPE_INNER_L4_MASK))
>>>>   +struct rte_mbuf;
>>>> +
>>>> +/**
>>>> + * Structure containing header lengths associated to a packet.
>>>> + */
>>>> +struct rte_mbuf_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;
>>>> +};
>>> [LC] The header parsing graph usually is not unique. The definition
>>> maybe nice for the basic IP and L4 tunnel.
>>> However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
>>> l2/l3 tunnel.
>>> The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
>>> "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
>>> In this case, the fixed function is to support below.
>>>
>>> + * Supported packet types are:
>>> + *   L2: Ether
>>> + *   L3: IPv4, IPv6
>>> + *   L4: TCP, UDP, SCTP
>>>
>>> Of course, it can add more packet type detection logic in future. But
>>> the more support, the higher the cost.
>>>
>>> One of the alternative way is to allow registering parser pair. APP
>>> decides to choose the predefined scheme(by DPDK LIB), or to
>>> self-define the parsing logic.
>>> In this way, the scheme can do some assumption for the specific case
>>> and ignore some useless graph detection.
>>> In addition, besides the SW parser, the HW parser(identified by
>>> packet_type in mbuf) can be turn on/off by leveraging the same manner.
>>
>> Sorry, I'm not sure I'm fully getting what you are saying. If I understand well,
>> you would like to have something more flexible that supports the registration of
>> protocol to be recognized?
>>
>> I'm not sure having a function with a dynamic registration method would really
>> increase the performance compared to a static complete function.
>> Actually, we will never support a tons of protocols since each layer packet type
>> is 4 bits, and since it requires that at least one hw supports it.
> 
> This patch will be very useful as a reference implementation, but it also highlights an issue with the current implementation of packet types reporting by HW and SW - as you just mentioned there are only 4 bits per each layer. As these 4 bit are used as a enumeration it is impossible to reports multiple headers located on the same layer. MPLS is one example, different packets could have different numbers of MPLS labels, but it is impossible to report using current packet_type structure.
> 
> It is possible, however, to  program HW to report user (application) specific packet types. For example, for IPoMPLS with one MPLS label, HW will report packet type A, but for IPoMPLS with two MPLS labels HW will reports packet type B. In this case, instead of defining and supporting tons of statically defined (or enumerated) protocol headers combinations, application will register packet types it expects from HW in addition to standard packet types. At the moment we  have high bits of packet_type reserved, so one possible solution would be to use the highest bit to indicate that this is user defined packet_type, specific to the application. Then it could be used with HW and with SW parser. For example, packet_type 0x8000000A is IPoMPLS with one MPLS label, 0x8000000B is IPoMPLS with two
  MPLS labels and so on.

Thank you for the explanation. From your description, I wonder if the
flow director API recently [1] proposed by Adrien wouldn't solve this issue?

[1] http://dpdk.org/ml/archives/dev/2016-July/043365.html

Regards,
Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-06 12:08         ` Olivier MATZ
@ 2016-07-06 12:21           ` Chilikin, Andrey
  0 siblings, 0 replies; 71+ messages in thread
From: Chilikin, Andrey @ 2016-07-06 12:21 UTC (permalink / raw)
  To: Olivier MATZ, Liang, Cunming, dev; +Cc: Ananyev, Konstantin, Zhang, Helin

Hi Oliver,

> -----Original Message-----
> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
> Sent: Wednesday, July 6, 2016 1:09 PM
> To: Chilikin, Andrey <andrey.chilikin@intel.com>; Liang, Cunming
> <cunming.liang@intel.com>; dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
> from data
> 
> Hi Andrey,
> 
> On 07/06/2016 01:59 PM, Chilikin, Andrey wrote:
> > Hi Oliver,
> >
> >> -----Original Message-----
> >> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Olivier MATZ
> >> Sent: Wednesday, July 6, 2016 8:43 AM
> >> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> >> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get
> >> packet type from data
> >>
> >> Hi Cunming,
> >>
> >> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
> >>> Hi Olivier,
> >>>
> >>> On 7/5/2016 11:41 PM, Olivier Matz wrote:
> >>>> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
> >>>>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
> >>>> +++++++++++++++++++++++++++++++++
> >>>>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
> >>>>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
> >>>>   5 files changed, 286 insertions(+), 2 deletions(-)
> >>>>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
> >>>>
> >>>> [...]
> >>>> +
> >>>> +/* parse mbuf data to get packet type */ uint32_t
> >>>> +rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
> >>>> +    struct rte_mbuf_hdr_lens *hdr_lens) {
> >>>> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
> >>>> b/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> index 4a34678..f468520 100644
> >>>> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> @@ -545,6 +545,49 @@ extern "C" {
> >>>>           RTE_PTYPE_INNER_L3_MASK |                \
> >>>>           RTE_PTYPE_INNER_L4_MASK))
> >>>>   +struct rte_mbuf;
> >>>> +
> >>>> +/**
> >>>> + * Structure containing header lengths associated to a packet.
> >>>> + */
> >>>> +struct rte_mbuf_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;
> >>>> +};
> >>> [LC] The header parsing graph usually is not unique. The definition
> >>> maybe nice for the basic IP and L4 tunnel.
> >>> However it can't scale out to other cases, e.g. qinq, mac-in-mac,
> >>> mpls
> >>> l2/l3 tunnel.
> >>> The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
> >>> "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
> >>> In this case, the fixed function is to support below.
> >>>
> >>> + * Supported packet types are:
> >>> + *   L2: Ether
> >>> + *   L3: IPv4, IPv6
> >>> + *   L4: TCP, UDP, SCTP
> >>>
> >>> Of course, it can add more packet type detection logic in future.
> >>> But the more support, the higher the cost.
> >>>
> >>> One of the alternative way is to allow registering parser pair. APP
> >>> decides to choose the predefined scheme(by DPDK LIB), or to
> >>> self-define the parsing logic.
> >>> In this way, the scheme can do some assumption for the specific case
> >>> and ignore some useless graph detection.
> >>> In addition, besides the SW parser, the HW parser(identified by
> >>> packet_type in mbuf) can be turn on/off by leveraging the same manner.
> >>
> >> Sorry, I'm not sure I'm fully getting what you are saying. If I
> >> understand well, you would like to have something more flexible that
> >> supports the registration of protocol to be recognized?
> >>
> >> I'm not sure having a function with a dynamic registration method
> >> would really increase the performance compared to a static complete
> function.
> >> Actually, we will never support a tons of protocols since each layer
> >> packet type is 4 bits, and since it requires that at least one hw supports it.
> >
> > This patch will be very useful as a reference implementation, but it also
> highlights an issue with the current implementation of packet types reporting
> by HW and SW - as you just mentioned there are only 4 bits per each layer. As
> these 4 bit are used as a enumeration it is impossible to reports multiple
> headers located on the same layer. MPLS is one example, different packets
> could have different numbers of MPLS labels, but it is impossible to report
> using current packet_type structure.
> >
> > It is possible, however, to  program HW to report user (application) specific
> packet types. For example, for IPoMPLS with one MPLS label, HW will report
> packet type A, but for IPoMPLS with two MPLS labels HW will reports packet
> type B. In this case, instead of defining and supporting tons of statically defined
> (or enumerated) protocol headers combinations, application will register
> packet types it expects from HW in addition to standard packet types. At the
> moment we  have high bits of packet_type reserved, so one possible solution
> would be to use the highest bit to indicate that this is user defined packet_type,
> specific to the application. Then it could be used with HW and with SW parser.
> For example, packet_type 0x8000000A is IPoMPLS with one MPLS label,
> 0x8000000B is IPoMPLS with two MPLS labels and so on.
> 
> Thank you for the explanation. From your description, I wonder if the flow
> director API recently [1] proposed by Adrien wouldn't solve this issue?
> 
> [1] http://dpdk.org/ml/archives/dev/2016-July/043365.html

I'm reviewing Adrien's proposal (it is a big document :)) and reply with my comment after reviewing.

Regards,
Andrey  

> Regards,
> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-06  7:42     ` Olivier MATZ
  2016-07-06 11:59       ` Chilikin, Andrey
@ 2016-07-07  8:19       ` Liang, Cunming
  2016-07-07 15:48         ` Olivier Matz
  1 sibling, 1 reply; 71+ messages in thread
From: Liang, Cunming @ 2016-07-07  8:19 UTC (permalink / raw)
  To: Olivier MATZ, dev

Hi Olivier,

> -----Original Message-----
> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
> Sent: Wednesday, July 06, 2016 3:43 PM
> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
> from data
> 
> Hi Cunming,
> 
> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
> > Hi Olivier,
> >
> > On 7/5/2016 11:41 PM, Olivier Matz wrote:
> >> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
> >>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
> >> +++++++++++++++++++++++++++++++++
> >>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
> >>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
> >>   5 files changed, 286 insertions(+), 2 deletions(-)
> >>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
> >>
> >> [...]
> >> +
> >> +/* parse mbuf data to get packet type */
> >> +uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
> >> +    struct rte_mbuf_hdr_lens *hdr_lens)
> >> +{
> >> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
> >> b/lib/librte_mbuf/rte_mbuf_ptype.h
> >> index 4a34678..f468520 100644
> >> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
> >> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
> >> @@ -545,6 +545,49 @@ extern "C" {
> >>           RTE_PTYPE_INNER_L3_MASK |                \
> >>           RTE_PTYPE_INNER_L4_MASK))
> >>   +struct rte_mbuf;
> >> +
> >> +/**
> >> + * Structure containing header lengths associated to a packet.
> >> + */
> >> +struct rte_mbuf_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;
> >> +};
> > [LC] The header parsing graph usually is not unique. The definition
> > maybe nice for the basic IP and L4 tunnel.
> > However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
> > l2/l3 tunnel.
> > The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
> > "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
> > In this case, the fixed function is to support below.
> >
> > + * Supported packet types are:
> > + *   L2: Ether
> > + *   L3: IPv4, IPv6
> > + *   L4: TCP, UDP, SCTP
> >
> > Of course, it can add more packet type detection logic in future. But
> > the more support, the higher the cost.
> >
> > One of the alternative way is to allow registering parser pair. APP
> > decides to choose the predefined scheme(by DPDK LIB), or to self-define
> > the parsing logic.
> > In this way, the scheme can do some assumption for the specific case and
> > ignore some useless graph detection.
> > In addition, besides the SW parser, the HW parser(identified by
> > packet_type in mbuf) can be turn on/off by leveraging the same manner.
> 
> 
> Sorry, I'm not sure I'm fully getting what you are saying. If I
> understand well, you would like to have something more flexible that
> supports the registration of protocol to be recognized?
[LC] Not on that granularity, but on the entire parsing routine.
rte_pktmbuf_get_ptype() as the common API, and can present in different behavior.
Usually in different scenario, the interested packet set is different.
For the specific case, can do some speculation pre-checking on the optimization perspective.

> 
> I'm not sure having a function with a dynamic registration method would
> really increase the performance compared to a static complete function.
[LC] No, it won't. But the overhead is not much, refer to rx_pkt_burst(is a callback either).
If someone only interest for IPv4-NoFrag-TCP stream, the easiest way maybe not layer by layer detection.
The straight forward way maybe, 1) load n bytes 2) compare mask 3) update ptype.
We require a normal way to do SW detection, current version is perfect.
My point is, we can provide a simple mechanism to allow other way, and under the same unified API.

> Actually, we will never support a tons of protocols since each layer
> packet type is 4 bits, and since it requires that at least one hw
> supports it.
[LC] Agree, it is today. But maybe dynamic in future, packet type definition as a template.
> 
> As described in the cover letter, the 2 main goals of this patchset are
> to provide a reference implementation for packet type recognition, and
> enable the support of virtio offloads (I'll send the patchset soon).
> This function is adapted to these 2 usages. Are you thinking of another
> use-case that would not be covered?
[LC] That's excellent work.  Furthermore I believe it can cover all ethdev actually.
When HW can't report some demand packet type, then fallback to your SW parser version.
If the auto-switch can be transparent, that's perfect. Maybe rx callback and update ptype in mbuf?

Thanks
> 
> Regards,
> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 09/18] mbuf: support Mpls in software packet type parser
  2016-07-06  8:00     ` Olivier MATZ
@ 2016-07-07  8:48       ` Liang, Cunming
  2016-07-07 16:01         ` Olivier Matz
  0 siblings, 1 reply; 71+ messages in thread
From: Liang, Cunming @ 2016-07-07  8:48 UTC (permalink / raw)
  To: Olivier MATZ, dev

Hi Olivier,

> -----Original Message-----
> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
> Sent: Wednesday, July 06, 2016 4:00 PM
> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 09/18] mbuf: support Mpls in software packet
> type parser
> 
> Hi Cunming,
> 
> On 07/06/2016 09:08 AM, Liang, Cunming wrote:
> > Hi Olivier,
> >
> > On 7/5/2016 11:41 PM, Olivier Matz wrote:
> >> Add a new RTE_PTYPE_L2_ETHER_MPLS packet type, and its support in
> >> rte_pktmbuf_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.c | 25 +++++++++++++++++++++++++
> >>   lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
> >>   lib/librte_net/Makefile          |  4 +++-
> >>   lib/librte_net/rte_ether.h       |  2 ++
> >>   4 files changed, 38 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c
> >> b/lib/librte_mbuf/rte_mbuf_ptype.c
> >> index 5d46608..0dea600 100644
> >> --- a/lib/librte_mbuf/rte_mbuf_ptype.c
> >> +++ b/lib/librte_mbuf/rte_mbuf_ptype.c
> >> @@ -41,6 +41,7 @@
> >>   #include <rte_tcp.h>
> >>   #include <rte_udp.h>
> >>   #include <rte_sctp.h>
> >> +#include <rte_mpls.h>
> >>     /* get l3 packet type from ip6 next protocol */
> >>   static uint32_t
> >> @@ -166,6 +167,9 @@ uint32_t rte_pktmbuf_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;
> >> @@ -189,8 +193,29 @@ uint32_t rte_pktmbuf_get_ptype(const struct
> >> rte_mbuf *m,
> >>           off += 2 * sizeof(*vh);
> >>           hdr_lens->l2_len += 2 * sizeof(*vh);
> >>           proto = vh->eth_proto;
> >> +    } else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
> >> +            (proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
> >> +        unsigned int i;
> >> +        const struct mpls_hdr *mh;
> >> +        struct mpls_hdr mh_copy;
> >> +
> >> +#define MAX_MPLS_HDR 5
> >> +        for (i = 0; i < MAX_MPLS_HDR; i++) {
> >> +            mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
> >> +                sizeof(*mh), &mh_copy);
> >> +            if (unlikely(mh == NULL))
> >> +                return pkt_type;
> >> +            if (mh->bs)
> >> +                break;
> >> +        }
> >> +        if (i == MAX_MPLS_HDR)
> >> +            return pkt_type;
> >> +        pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
> >> +        hdr_lens->l2_len += (sizeof(*mh) * (i + 1));
> > [LC] l2_len includes Eth, Vlan(opt.), MPLS(opt.). For VLAN and MPLS, it
> > may include #n times overlay.
> > These layer recognition knowledge are lost after the detection logic.
> > Once the APP takes the ptype, for the layer(L2, L3, L4) which has more
> > shim-layer, the xxx_len can't help to avoid the re-parse cost.
> 
> This is linked with the definition of packet type. Each layer has a
> type, and here we associate it to a length (by the way the length is
> something we may consider integrate inside the packet type in the future).
[LC] Yes, I see. 
My point is in some case, the length can represent for different layer.
For who interests on L2 MPLS, the length layer scheme maybe can define as {L2/MPLS/inner_L2/inner_L3}.
The rte_mbuf_hdr_lens likes a meta data which associates with the specific parser(assuming customized runtime instance provided by rte_pktmbuf_get_ptype).
The provider understand the meaning and layout.
 
> 
> The packet_type model allows to describe many packets kinds. Some will
> be difficult to represent (ex: a packet with several different L2 or
> L3). But I think this is a good compromise that could help the
> application to get some information without looking inside the packet.
> 
> Changing the packet type structure to something more flexible/complex
> would probably imply to loose time filling it in drivers and parse it in
> the application. And we already have a structure that contains all the
> information needed by the application: the packet data ;)
[LC] Fully agree. Sometimes it's a tradeoff, if the offering meta data by parser is 
not enough for further processing, the duplication packet data walking through may happen.
It's hard to define a meta data format for all cases. Probably the raw META is a good choice, which is recognized by the parser provider.

> 
> In any case, this is not really the topic of the patchset, which just
> provide a helper to parse a packet by software and get a packet_type (as
> it is defined today).
[LC] Maybe the conversation is a little beyond. Hope you get my point.

Thanks.

> 
> Regards,
> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-07  8:19       ` Liang, Cunming
@ 2016-07-07 15:48         ` Olivier Matz
  2016-07-08 10:08           ` Liang, Cunming
  0 siblings, 1 reply; 71+ messages in thread
From: Olivier Matz @ 2016-07-07 15:48 UTC (permalink / raw)
  To: Liang, Cunming, dev

Hi Cunming,

Thank you for your feedback.

On 07/07/2016 10:19 AM, Liang, Cunming wrote:
> Hi Olivier,
> 
>> -----Original Message-----
>> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
>> Sent: Wednesday, July 06, 2016 3:43 PM
>> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
>> from data
>>
>> Hi Cunming,
>>
>> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
>>> Hi Olivier,
>>>
>>> On 7/5/2016 11:41 PM, Olivier Matz wrote:
>>>> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
>>>>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
>>>> +++++++++++++++++++++++++++++++++
>>>>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
>>>>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
>>>>   5 files changed, 286 insertions(+), 2 deletions(-)
>>>>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
>>>>
>>>> [...]
>>>> +
>>>> +/* parse mbuf data to get packet type */
>>>> +uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
>>>> +    struct rte_mbuf_hdr_lens *hdr_lens)
>>>> +{
>>>> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
>>>> b/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> index 4a34678..f468520 100644
>>>> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
>>>> @@ -545,6 +545,49 @@ extern "C" {
>>>>           RTE_PTYPE_INNER_L3_MASK |                \
>>>>           RTE_PTYPE_INNER_L4_MASK))
>>>>   +struct rte_mbuf;
>>>> +
>>>> +/**
>>>> + * Structure containing header lengths associated to a packet.
>>>> + */
>>>> +struct rte_mbuf_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;
>>>> +};
>>> [LC] The header parsing graph usually is not unique. The definition
>>> maybe nice for the basic IP and L4 tunnel.
>>> However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
>>> l2/l3 tunnel.
>>> The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
>>> "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
>>> In this case, the fixed function is to support below.
>>>
>>> + * Supported packet types are:
>>> + *   L2: Ether
>>> + *   L3: IPv4, IPv6
>>> + *   L4: TCP, UDP, SCTP
>>>
>>> Of course, it can add more packet type detection logic in future. But
>>> the more support, the higher the cost.
>>>
>>> One of the alternative way is to allow registering parser pair. APP
>>> decides to choose the predefined scheme(by DPDK LIB), or to self-define
>>> the parsing logic.
>>> In this way, the scheme can do some assumption for the specific case and
>>> ignore some useless graph detection.
>>> In addition, besides the SW parser, the HW parser(identified by
>>> packet_type in mbuf) can be turn on/off by leveraging the same manner.
>>
>>
>> Sorry, I'm not sure I'm fully getting what you are saying. If I
>> understand well, you would like to have something more flexible that
>> supports the registration of protocol to be recognized?
> [LC] Not on that granularity, but on the entire parsing routine.
> rte_pktmbuf_get_ptype() as the common API, and can present in different behavior.
> Usually in different scenario, the interested packet set is different.
> For the specific case, can do some speculation pre-checking on the optimization perspective.
> 
>>
>> I'm not sure having a function with a dynamic registration method would
>> really increase the performance compared to a static complete function.
> [LC] No, it won't. But the overhead is not much, refer to rx_pkt_burst(is a callback either).
> If someone only interest for IPv4-NoFrag-TCP stream, the easiest way maybe not layer by layer detection.
> The straight forward way maybe, 1) load n bytes 2) compare mask 3) update ptype.
> We require a normal way to do SW detection, current version is perfect.
> My point is, we can provide a simple mechanism to allow other way, and under the same unified API.

Again, sorry, I'm not perfectly sure I understand what you are saying.

What you describe (mask packet data, then compare with a value) seems
very similar to what ovs does. Do you mean we should have an API for that?

I think once we have masked+compared the data, we may know much more
than just a packet_type.



> 
>> Actually, we will never support a tons of protocols since each layer
>> packet type is 4 bits, and since it requires that at least one hw
>> supports it.
> [LC] Agree, it is today. But maybe dynamic in future, packet type definition as a template.
>>
>> As described in the cover letter, the 2 main goals of this patchset are
>> to provide a reference implementation for packet type recognition, and
>> enable the support of virtio offloads (I'll send the patchset soon).
>> This function is adapted to these 2 usages. Are you thinking of another
>> use-case that would not be covered?
> [LC] That's excellent work.  Furthermore I believe it can cover all ethdev actually.
> When HW can't report some demand packet type, then fallback to your SW parser version.
> If the auto-switch can be transparent, that's perfect. Maybe rx callback and update ptype in mbuf?

I was also thinking about calling rte_pktmbuf_get_ptype() from a driver.
I think drivers should not access to mbuf data if it's not absolutely
required.
Calling rte_pktmbuf_get_ptype() from inside a rx callback seems easily
feasible, it may be useful for applications that mostly relies on
packet_type to select an action.


Regards,
Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 09/18] mbuf: support Mpls in software packet type parser
  2016-07-07  8:48       ` Liang, Cunming
@ 2016-07-07 16:01         ` Olivier Matz
  0 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-07-07 16:01 UTC (permalink / raw)
  To: Liang, Cunming, dev

Hi Cunming,

On 07/07/2016 10:48 AM, Liang, Cunming wrote:
> Hi Olivier,
> 
>> -----Original Message-----
>> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
>> Sent: Wednesday, July 06, 2016 4:00 PM
>> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH 09/18] mbuf: support Mpls in software packet
>> type parser
>>
>> Hi Cunming,
>>
>> On 07/06/2016 09:08 AM, Liang, Cunming wrote:
>>> Hi Olivier,
>>>
>>> On 7/5/2016 11:41 PM, Olivier Matz wrote:
>>>> Add a new RTE_PTYPE_L2_ETHER_MPLS packet type, and its support in
>>>> rte_pktmbuf_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.c | 25 +++++++++++++++++++++++++
>>>>   lib/librte_mbuf/rte_mbuf_ptype.h |  9 ++++++++-
>>>>   lib/librte_net/Makefile          |  4 +++-
>>>>   lib/librte_net/rte_ether.h       |  2 ++
>>>>   4 files changed, 38 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/lib/librte_mbuf/rte_mbuf_ptype.c
>>>> b/lib/librte_mbuf/rte_mbuf_ptype.c
>>>> index 5d46608..0dea600 100644
>>>> --- a/lib/librte_mbuf/rte_mbuf_ptype.c
>>>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.c
>>>> @@ -41,6 +41,7 @@
>>>>   #include <rte_tcp.h>
>>>>   #include <rte_udp.h>
>>>>   #include <rte_sctp.h>
>>>> +#include <rte_mpls.h>
>>>>     /* get l3 packet type from ip6 next protocol */
>>>>   static uint32_t
>>>> @@ -166,6 +167,9 @@ uint32_t rte_pktmbuf_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;
>>>> @@ -189,8 +193,29 @@ uint32_t rte_pktmbuf_get_ptype(const struct
>>>> rte_mbuf *m,
>>>>           off += 2 * sizeof(*vh);
>>>>           hdr_lens->l2_len += 2 * sizeof(*vh);
>>>>           proto = vh->eth_proto;
>>>> +    } else if ((proto == rte_cpu_to_be_16(ETHER_TYPE_MPLS)) ||
>>>> +            (proto == rte_cpu_to_be_16(ETHER_TYPE_MPLSM))) {
>>>> +        unsigned int i;
>>>> +        const struct mpls_hdr *mh;
>>>> +        struct mpls_hdr mh_copy;
>>>> +
>>>> +#define MAX_MPLS_HDR 5
>>>> +        for (i = 0; i < MAX_MPLS_HDR; i++) {
>>>> +            mh = rte_pktmbuf_read(m, off + (i * sizeof(*mh)),
>>>> +                sizeof(*mh), &mh_copy);
>>>> +            if (unlikely(mh == NULL))
>>>> +                return pkt_type;
>>>> +            if (mh->bs)
>>>> +                break;
>>>> +        }
>>>> +        if (i == MAX_MPLS_HDR)
>>>> +            return pkt_type;
>>>> +        pkt_type = RTE_PTYPE_L2_ETHER_MPLS;
>>>> +        hdr_lens->l2_len += (sizeof(*mh) * (i + 1));
>>> [LC] l2_len includes Eth, Vlan(opt.), MPLS(opt.). For VLAN and MPLS, it
>>> may include #n times overlay.
>>> These layer recognition knowledge are lost after the detection logic.
>>> Once the APP takes the ptype, for the layer(L2, L3, L4) which has more
>>> shim-layer, the xxx_len can't help to avoid the re-parse cost.
>>
>> This is linked with the definition of packet type. Each layer has a
>> type, and here we associate it to a length (by the way the length is
>> something we may consider integrate inside the packet type in the future).
> [LC] Yes, I see. 
> My point is in some case, the length can represent for different layer.
> For who interests on L2 MPLS, the length layer scheme maybe can define as {L2/MPLS/inner_L2/inner_L3}.
> The rte_mbuf_hdr_lens likes a meta data which associates with the specific parser(assuming customized runtime instance provided by rte_pktmbuf_get_ptype).
> The provider understand the meaning and layout.

OK, I see.

For VLAN or QinQ, we could consider that it is the same L2 than the
Ethernet header.
But maybe MPLS should not be part of this patchset, because it's
actually a bit different. The choice I've made was to represent MPLS in
packet_type like this:

  Ether - MPLS - IP - TCP
  \         /     |    |
      L2         L3    L4

Another way to represent it would be:

  Ether - MPLS - IP - TCP
    |      |      |    |
   L2   INNER_L2    INNER_L4
              INNER_L3

If it's too confusing, we may remove MPLS from this patchset.


Regards,
Olivier



>  
>>
>> The packet_type model allows to describe many packets kinds. Some will
>> be difficult to represent (ex: a packet with several different L2 or
>> L3). But I think this is a good compromise that could help the
>> application to get some information without looking inside the packet.
>>
>> Changing the packet type structure to something more flexible/complex
>> would probably imply to loose time filling it in drivers and parse it in
>> the application. And we already have a structure that contains all the
>> information needed by the application: the packet data ;)
> [LC] Fully agree. Sometimes it's a tradeoff, if the offering meta data by parser is 
> not enough for further processing, the duplication packet data walking through may happen.
> It's hard to define a meta data format for all cases. Probably the raw META is a good choice, which is recognized by the parser provider.
> 
>>
>> In any case, this is not really the topic of the patchset, which just
>> provide a helper to parse a packet by software and get a packet_type (as
>> it is defined today).
> [LC] Maybe the conversation is a little beyond. Hope you get my point.
> 
> Thanks.
> 
>>
>> Regards,
>> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/18] mbuf: add function to get packet type from data
  2016-07-07 15:48         ` Olivier Matz
@ 2016-07-08 10:08           ` Liang, Cunming
  0 siblings, 0 replies; 71+ messages in thread
From: Liang, Cunming @ 2016-07-08 10:08 UTC (permalink / raw)
  To: Olivier Matz, dev

Hi Olivier,

> -----Original Message-----
> From: Olivier Matz [mailto:olivier.matz@6wind.com]
> Sent: Thursday, July 07, 2016 11:49 PM
> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
> from data
> 
> Hi Cunming,
> 
> Thank you for your feedback.
> 
> On 07/07/2016 10:19 AM, Liang, Cunming wrote:
> > Hi Olivier,
> >
> >> -----Original Message-----
> >> From: Olivier MATZ [mailto:olivier.matz@6wind.com]
> >> Sent: Wednesday, July 06, 2016 3:43 PM
> >> To: Liang, Cunming <cunming.liang@intel.com>; dev@dpdk.org
> >> Subject: Re: [dpdk-dev] [PATCH 05/18] mbuf: add function to get packet type
> >> from data
> >>
> >> Hi Cunming,
> >>
> >> On 07/06/2016 08:44 AM, Liang, Cunming wrote:
> >>> Hi Olivier,
> >>>
> >>> On 7/5/2016 11:41 PM, Olivier Matz wrote:
> >>>> Introduce the function rte_pktmbuf_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_mbuf/Makefile               |   5 +-
> >>>>   lib/librte_mbuf/rte_mbuf_ptype.c       | 234
> >>>> +++++++++++++++++++++++++++++++++
> >>>>   lib/librte_mbuf/rte_mbuf_ptype.h       |  43 ++++++
> >>>>   lib/librte_mbuf/rte_mbuf_version.map   |   1 +
> >>>>   5 files changed, 286 insertions(+), 2 deletions(-)
> >>>>   create mode 100644 lib/librte_mbuf/rte_mbuf_ptype.c
> >>>>
> >>>> [...]
> >>>> +
> >>>> +/* parse mbuf data to get packet type */
> >>>> +uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
> >>>> +    struct rte_mbuf_hdr_lens *hdr_lens)
> >>>> +{
> >>>> +    struct rte_mbuf_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_mbuf/rte_mbuf_ptype.h
> >>>> b/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> index 4a34678..f468520 100644
> >>>> --- a/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> +++ b/lib/librte_mbuf/rte_mbuf_ptype.h
> >>>> @@ -545,6 +545,49 @@ extern "C" {
> >>>>           RTE_PTYPE_INNER_L3_MASK |                \
> >>>>           RTE_PTYPE_INNER_L4_MASK))
> >>>>   +struct rte_mbuf;
> >>>> +
> >>>> +/**
> >>>> + * Structure containing header lengths associated to a packet.
> >>>> + */
> >>>> +struct rte_mbuf_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;
> >>>> +};
> >>> [LC] The header parsing graph usually is not unique. The definition
> >>> maybe nice for the basic IP and L4 tunnel.
> >>> However it can't scale out to other cases, e.g. qinq, mac-in-mac, mpls
> >>> l2/l3 tunnel.
> >>> The parsing logic of "rte_pktmbuf_get_ptype()" and the definition of
> >>> "struct rte_mbuf_hdr_lens" consist a pair for one specific parser scheme.
> >>> In this case, the fixed function is to support below.
> >>>
> >>> + * Supported packet types are:
> >>> + *   L2: Ether
> >>> + *   L3: IPv4, IPv6
> >>> + *   L4: TCP, UDP, SCTP
> >>>
> >>> Of course, it can add more packet type detection logic in future. But
> >>> the more support, the higher the cost.
> >>>
> >>> One of the alternative way is to allow registering parser pair. APP
> >>> decides to choose the predefined scheme(by DPDK LIB), or to self-define
> >>> the parsing logic.
> >>> In this way, the scheme can do some assumption for the specific case and
> >>> ignore some useless graph detection.
> >>> In addition, besides the SW parser, the HW parser(identified by
> >>> packet_type in mbuf) can be turn on/off by leveraging the same manner.
> >>
> >>
> >> Sorry, I'm not sure I'm fully getting what you are saying. If I
> >> understand well, you would like to have something more flexible that
> >> supports the registration of protocol to be recognized?
> > [LC] Not on that granularity, but on the entire parsing routine.
> > rte_pktmbuf_get_ptype() as the common API, and can present in different
> behavior.
> > Usually in different scenario, the interested packet set is different.
> > For the specific case, can do some speculation pre-checking on the optimization
> perspective.
> >
> >>
> >> I'm not sure having a function with a dynamic registration method would
> >> really increase the performance compared to a static complete function.
> > [LC] No, it won't. But the overhead is not much, refer to rx_pkt_burst(is a
> callback either).
> > If someone only interest for IPv4-NoFrag-TCP stream, the easiest way maybe
> not layer by layer detection.
> > The straight forward way maybe, 1) load n bytes 2) compare mask 3) update
> ptype.
> > We require a normal way to do SW detection, current version is perfect.
> > My point is, we can provide a simple mechanism to allow other way, and under
> the same unified API.
> 
> Again, sorry, I'm not perfectly sure I understand what you are saying.
> 
> What you describe (mask packet data, then compare with a value) seems
> very similar to what ovs does. Do you mean we should have an API for that?
[LC] No. Sorry to make you confused.
If there's one function can well detect all kinds of packet in low cost, it's perfect.
But from case to case, the packet detection interest is difficult(IPDC, wireless, metro Ethernet and etc).
Considering the possible tradeoff of performance and completeness, to
allow dedicated parser tuned for special purpose is an alternative way.

> 
> I think once we have masked+compared the data, we may know much more
> than just a packet_type.
[LC] Detection packet layer by layer is the normal way. In some case, it doesn't have to.
For example, we assume there's one network using VXLAN-GPE..
To detect the packet layer by layer, need to walk through two step, UDP Port and VXLAN NP.
In fact, UDP+VXLAN(16B) as a whole to compare mask once, you can know it's a VXLAN w/ inner Ethernet or not.

Probably it's not a perfect cases. SW Parser is not a low cost stuff, from cases to cases, if there are some special, it has potential space to optimize. One possible pseudo code as below.

struct rte_ptype_parser {
	char name[128];
	uint32_t (*get_ptype)(const struct rte_mbuf *m, void *hdr_lens);
};

struct rte_ptype_parser def_parser = 
{
	.name = "ipdc"; 
	.get_ptype = ipdc_get_ptype;
};

uint32_t rte_pktmbuf_get_ptype(const struct rte_mbuf *m,
		void *hdr_lens)
{
	struct rte_ptype_parser parser = def_parser;
	
	[...]
	parser->get_ptype(m, hdr_lens);
	[...]
}

/* scheme for ipdc */
struct ipdc_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;
};
uint32_t ipdc_get_ptype(const struct rte_mbuf *m, void *hdr_lens)
{
	struct ipdc_hdr_lens ihl = (struct ipdc_hdr_lens*)hdr_lens;

	/* parser logic optimized for typical IP datacenter packet */
	[...]
}

/* scheme for l2mpls */
struct l2mpls_hdr_lens {
	uint8_t l2_len;
	uint8_t mpls_len;            /* total length for multi-layer */
	uint8_t inner_l2_len;
	uint8_t inner_l3_len;
};
uint32_t l2mpls_get_ptype(const struct rte_mbuf *m, void *hdr_lens)
{
	struct l2mpls_hdr_lens ihl = (struct l2mpls_hdr_lens*)hdr_lens;

	/* parser logic optimized for typical L2MPLS */
	[...]
}

> 
> 
> 
> >
> >> Actually, we will never support a tons of protocols since each layer
> >> packet type is 4 bits, and since it requires that at least one hw
> >> supports it.
> > [LC] Agree, it is today. But maybe dynamic in future, packet type definition as a
> template.
> >>
> >> As described in the cover letter, the 2 main goals of this patchset are
> >> to provide a reference implementation for packet type recognition, and
> >> enable the support of virtio offloads (I'll send the patchset soon).
> >> This function is adapted to these 2 usages. Are you thinking of another
> >> use-case that would not be covered?
> > [LC] That's excellent work.  Furthermore I believe it can cover all ethdev actually.
> > When HW can't report some demand packet type, then fallback to your SW
> parser version.
> > If the auto-switch can be transparent, that's perfect. Maybe rx callback and
> update ptype in mbuf?
> 
> I was also thinking about calling rte_pktmbuf_get_ptype() from a driver.
> I think drivers should not access to mbuf data if it's not absolutely
> required.
> Calling rte_pktmbuf_get_ptype() from inside a rx callback seems easily
> feasible, it may be useful for applications that mostly relies on
> packet_type to select an action.
> 
> 
> Regards,
> Olivier

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [PATCH v2 00/16] software parser for packet type
  2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
                   ` (17 preceding siblings ...)
  2016-07-05 15:41 ` [PATCH 18/18] app/testpmd: display sw packet type Olivier Matz
@ 2016-08-29 14:35 ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 01/16] mbuf: add function to read packet data Olivier Matz
                     ` (16 more replies)
  18 siblings, 17 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 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             |  36 ++
 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 +
 18 files changed, 2143 insertions(+), 1087 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 v2, 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	[flat|nested] 71+ messages in thread

* [PATCH v2 01/16] mbuf: add function to read packet data
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 02/16] net: move Ethernet header definitions to the net library Olivier Matz
                     ` (15 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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             | 36 ++++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h             | 35 +++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf_version.map   |  7 +++++++
 4 files changed, 82 insertions(+)

diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst
index 66916af..280f298 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 4846b89..fb2b962 100644
--- a/lib/librte_mbuf/rte_mbuf.c
+++ b/lib/librte_mbuf/rte_mbuf.c
@@ -59,6 +59,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
@@ -262,6 +263,41 @@ 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) &&
+			rte_pktmbuf_data_len(seg) != 0) {
+		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 7ea66ed..7d94f82 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -1951,6 +1951,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	[flat|nested] 71+ messages in thread

* [PATCH v2 02/16] net: move Ethernet header definitions to the net library
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 01/16] mbuf: add function to read packet data Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 03/16] mbuf: move packet type definitions in a new file Olivier Matz
                     ` (14 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v2 03/16] mbuf: move packet type definitions in a new file
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 01/16] mbuf: add function to read packet data Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 02/16] net: move Ethernet header definitions to the net library Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 04/16] net: introduce net library Olivier Matz
                     ` (13 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 7d94f82..758af23 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..4a34678
--- /dev/null
+++ b/lib/librte_mbuf/rte_mbuf_ptype.h
@@ -0,0 +1,552 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *   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	[flat|nested] 71+ messages in thread

* [PATCH v2 04/16] net: introduce net library
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (2 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 03/16] mbuf: move packet type definitions in a new file Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 05/16] net: add function to get packet type from data Olivier Matz
                     ` (12 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 +
 5 files changed, 15 insertions(+), 1 deletion(-)
 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 bc9aa02..20ffff8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -436,6 +436,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
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH v2 05/16] net: add function to get packet type from data
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (3 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 04/16] net: introduce net library Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 06/16] net: support Vlan in software packet type parser Olivier Matz
                     ` (11 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 280f298..489ed40 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..a542fb5 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 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 <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	[flat|nested] 71+ messages in thread

* [PATCH v2 06/16] net: support Vlan in software packet type parser
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (4 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 05/16] net: add function to get packet type from data Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 07/16] net: support QinQ " Olivier Matz
                     ` (10 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 4a34678..101e7fa 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 a542fb5..7d34532 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	[flat|nested] 71+ messages in thread

* [PATCH v2 07/16] net: support QinQ in software packet type parser
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (5 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 06/16] net: support Vlan in software packet type parser Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 08/16] net: support Ip tunnels " Olivier Matz
                     ` (9 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 101e7fa..7084259 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 7d34532..d20cc65 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	[flat|nested] 71+ messages in thread

* [PATCH v2 08/16] net: support Ip tunnels in software packet type parser
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (6 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 07/16] net: support QinQ " Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 09/16] net: add Gre header structure Olivier Matz
                     ` (8 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 d20cc65..d921db8 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	[flat|nested] 71+ messages in thread

* [PATCH v2 09/16] net: add Gre header structure
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (7 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 08/16] net: support Ip tunnels " Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 10/16] net: support Gre in software packet type parser Olivier Matz
                     ` (7 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v2 10/16] net: support Gre in software packet type parser
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (8 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 09/16] net: add Gre header structure Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 11/16] net: support Nvgre " Olivier Matz
                     ` (6 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 d921db8..0840126 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	[flat|nested] 71+ messages in thread

* [PATCH v2 11/16] net: support Nvgre in software packet type parser
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (9 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 10/16] net: support Gre in software packet type parser Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 12/16] net: get ptype for the first layers only Olivier Matz
                     ` (5 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 7084259..3490fa1 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 0840126..2b57ac1 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	[flat|nested] 71+ messages in thread

* [PATCH v2 12/16] net: get ptype for the first layers only
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (10 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 11/16] net: support Nvgre " Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 13/16] mbuf: add functions to dump packet type Olivier Matz
                     ` (4 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 2b57ac1..a5fe07e 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	[flat|nested] 71+ messages in thread

* [PATCH v2 13/16] mbuf: add functions to dump packet type
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (11 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 12/16] net: get ptype for the first layers only Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
                     ` (3 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 489ed40..36111f3 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..bc84bea
--- /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 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 <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 3490fa1..c56965a 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	[flat|nested] 71+ messages in thread

* [PATCH v2 14/16] mbuf: clarify definition of fragment packet types
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (12 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 13/16] mbuf: add functions to dump packet type Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 15/16] app/testpmd: dump ptype using the new function Olivier Matz
                     ` (2 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 c56965a..72f2d18 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	[flat|nested] 71+ messages in thread

* [PATCH v2 15/16] app/testpmd: dump ptype using the new function
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (13 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-08-29 14:35   ` [PATCH v2 16/16] app/testpmd: display software packet type Olivier Matz
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 fbf287d..aba07ee 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -92,6 +92,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;
@@ -162,177 +163,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	[flat|nested] 71+ messages in thread

* [PATCH v2 16/16] app/testpmd: display software packet type
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (14 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 15/16] app/testpmd: dump ptype using the new function Olivier Matz
@ 2016-08-29 14:35   ` Olivier Matz
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-08-29 14:35 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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 aba07ee..b83d0c7 100644
--- a/app/test-pmd/rxonly.c
+++ b/app/test-pmd/rxonly.c
@@ -67,6 +67,7 @@
 #include <rte_string_fns.h>
 #include <rte_ip.h>
 #include <rte_udp.h>
+#include <rte_net.h>
 
 #include "testpmd.h"
 
@@ -93,6 +94,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;
@@ -164,8 +167,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	[flat|nested] 71+ messages in thread

* [PATCH v3 00/16] software parser for packet type
  2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
                     ` (15 preceding siblings ...)
  2016-08-29 14:35   ` [PATCH v2 16/16] app/testpmd: display software packet type Olivier Matz
@ 2016-10-03  8:38   ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 01/16] mbuf: add function to read packet data Olivier Matz
                       ` (16 more replies)
  16 siblings, 17 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 01/16] mbuf: add function to read packet data
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 02/16] net: move Ethernet header definitions to the net library Olivier Matz
                       ` (15 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 02/16] net: move Ethernet header definitions to the net library
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 01/16] mbuf: add function to read packet data Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 03/16] mbuf: move packet type definitions in a new file Olivier Matz
                       ` (14 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Didier Pallard

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	[flat|nested] 71+ messages in thread

* [PATCH v3 03/16] mbuf: move packet type definitions in a new file
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 01/16] mbuf: add function to read packet data Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 02/16] net: move Ethernet header definitions to the net library Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-10 14:52       ` Thomas Monjalon
  2016-10-03  8:38     ` [PATCH v3 04/16] net: introduce net library Olivier Matz
                       ` (13 subsequent siblings)
  16 siblings, 1 reply; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 04/16] net: introduce net library
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (2 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 03/16] mbuf: move packet type definitions in a new file Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 05/16] net: add function to get packet type from data Olivier Matz
                       ` (12 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 05/16] net: add function to get packet type from data
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (3 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 04/16] net: introduce net library Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 06/16] net: support Vlan in software packet type parser Olivier Matz
                       ` (11 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
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

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	[flat|nested] 71+ messages in thread

* [PATCH v3 06/16] net: support Vlan in software packet type parser
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (4 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 05/16] net: add function to get packet type from data Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 07/16] net: support QinQ " Olivier Matz
                       ` (10 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Didier Pallard

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	[flat|nested] 71+ messages in thread

* [PATCH v3 07/16] net: support QinQ in software packet type parser
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (5 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 06/16] net: support Vlan in software packet type parser Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 08/16] net: support Ip tunnels " Olivier Matz
                       ` (9 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Didier Pallard

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	[flat|nested] 71+ messages in thread

* [PATCH v3 08/16] net: support Ip tunnels in software packet type parser
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (6 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 07/16] net: support QinQ " Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 09/16] net: add Gre header structure Olivier Matz
                       ` (8 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Jean Dao

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	[flat|nested] 71+ messages in thread

* [PATCH v3 09/16] net: add Gre header structure
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (7 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 08/16] net: support Ip tunnels " Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 10/16] net: support Gre in software packet type parser Olivier Matz
                       ` (7 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Jean Dao

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	[flat|nested] 71+ messages in thread

* [PATCH v3 10/16] net: support Gre in software packet type parser
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (8 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 09/16] net: add Gre header structure Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 11/16] net: support Nvgre " Olivier Matz
                       ` (6 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Jean Dao

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	[flat|nested] 71+ messages in thread

* [PATCH v3 11/16] net: support Nvgre in software packet type parser
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (9 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 10/16] net: support Gre in software packet type parser Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 12/16] net: get ptype for the first layers only Olivier Matz
                       ` (5 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev
  Cc: cunming.liang, john.mcnamara, andrey.chilikin,
	konstantin.ananyev, Jean Dao

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	[flat|nested] 71+ messages in thread

* [PATCH v3 12/16] net: get ptype for the first layers only
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (10 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 11/16] net: support Nvgre " Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 13/16] mbuf: add functions to dump packet type Olivier Matz
                       ` (4 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 13/16] mbuf: add functions to dump packet type
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (11 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 12/16] net: get ptype for the first layers only Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
                       ` (3 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 14/16] mbuf: clarify definition of fragment packet types
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (12 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 13/16] mbuf: add functions to dump packet type Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 15/16] app/testpmd: dump ptype using the new function Olivier Matz
                       ` (2 subsequent siblings)
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 15/16] app/testpmd: dump ptype using the new function
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (13 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-03  8:38     ` [PATCH v3 16/16] app/testpmd: display software packet type Olivier Matz
  2016-10-11 16:24     ` [PATCH v3 00/16] software parser for " Thomas Monjalon
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* [PATCH v3 16/16] app/testpmd: display software packet type
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (14 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 15/16] app/testpmd: dump ptype using the new function Olivier Matz
@ 2016-10-03  8:38     ` Olivier Matz
  2016-10-11 16:24     ` [PATCH v3 00/16] software parser for " Thomas Monjalon
  16 siblings, 0 replies; 71+ messages in thread
From: Olivier Matz @ 2016-10-03  8:38 UTC (permalink / raw)
  To: dev; +Cc: cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

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	[flat|nested] 71+ messages in thread

* Re: [PATCH v3 03/16] mbuf: move packet type definitions in a new file
  2016-10-03  8:38     ` [PATCH v3 03/16] mbuf: move packet type definitions in a new file Olivier Matz
@ 2016-10-10 14:52       ` Thomas Monjalon
  2016-10-11  9:01         ` Olivier MATZ
  0 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2016-10-10 14:52 UTC (permalink / raw)
  To: Olivier Matz
  Cc: dev, cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

2016-10-03 10:38, Olivier Matz:
> 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 +++++++++++++++++++++++++++++++++++++++

Why not moving packet type and other packet flags in librte_net?

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH v3 03/16] mbuf: move packet type definitions in a new file
  2016-10-10 14:52       ` Thomas Monjalon
@ 2016-10-11  9:01         ` Olivier MATZ
  2016-10-11 15:51           ` Thomas Monjalon
  0 siblings, 1 reply; 71+ messages in thread
From: Olivier MATZ @ 2016-10-11  9:01 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: dev, cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

Hi Thomas,

On 10/10/2016 04:52 PM, Thomas Monjalon wrote:
> 2016-10-03 10:38, Olivier Matz:
>> 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 +++++++++++++++++++++++++++++++++++++++
>
> Why not moving packet type and other packet flags in librte_net?
>

These are mbuf features.
I can reverse the question: why moving them in librte_net? :)

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH v3 03/16] mbuf: move packet type definitions in a new file
  2016-10-11  9:01         ` Olivier MATZ
@ 2016-10-11 15:51           ` Thomas Monjalon
  0 siblings, 0 replies; 71+ messages in thread
From: Thomas Monjalon @ 2016-10-11 15:51 UTC (permalink / raw)
  To: Olivier MATZ
  Cc: dev, cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

2016-10-11 11:01, Olivier MATZ:
> Hi Thomas,
> 
> On 10/10/2016 04:52 PM, Thomas Monjalon wrote:
> > 2016-10-03 10:38, Olivier Matz:
> >> 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 +++++++++++++++++++++++++++++++++++++++
> >
> > Why not moving packet type and other packet flags in librte_net?
> 
> These are mbuf features.

Yes there is some space reserved in the mbuf for these bits.

> I can reverse the question: why moving them in librte_net? :)

Fair enough :)
I was thinking to group protocol-related definitions in librte_net.
But both approaches are acceptable.

OK to keep the packet types in mbuf lib.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH v3 00/16] software parser for packet type
  2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
                       ` (15 preceding siblings ...)
  2016-10-03  8:38     ` [PATCH v3 16/16] app/testpmd: display software packet type Olivier Matz
@ 2016-10-11 16:24     ` Thomas Monjalon
  16 siblings, 0 replies; 71+ messages in thread
From: Thomas Monjalon @ 2016-10-11 16:24 UTC (permalink / raw)
  To: Olivier Matz
  Cc: dev, cunming.liang, john.mcnamara, andrey.chilikin, konstantin.ananyev

2016-10-03 10:38, Olivier Matz:
> 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.

Applied, thanks

^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2016-10-11 16:24 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-05 15:41 [PATCH 00/18] software parser for packet type Olivier Matz
2016-07-05 15:41 ` [PATCH 01/18] doc: add template for release notes 16.11 Olivier Matz
2016-07-06 11:48   ` Mcnamara, John
2016-07-06 12:00     ` Olivier MATZ
2016-07-05 15:41 ` [PATCH 02/18] mbuf: add function to read packet data Olivier Matz
2016-07-05 15:41 ` [PATCH 03/18] net: move Ethernet header definitions to the net library Olivier Matz
2016-07-05 15:41 ` [PATCH 04/18] mbuf: move packet type definitions in a new file Olivier Matz
2016-07-05 15:41 ` [PATCH 05/18] mbuf: add function to get packet type from data Olivier Matz
2016-07-06  6:44   ` Liang, Cunming
2016-07-06  7:42     ` Olivier MATZ
2016-07-06 11:59       ` Chilikin, Andrey
2016-07-06 12:08         ` Olivier MATZ
2016-07-06 12:21           ` Chilikin, Andrey
2016-07-07  8:19       ` Liang, Cunming
2016-07-07 15:48         ` Olivier Matz
2016-07-08 10:08           ` Liang, Cunming
2016-07-05 15:41 ` [PATCH 06/18] mbuf: support Vlan in software packet type parser Olivier Matz
2016-07-05 15:41 ` [PATCH 07/18] mbuf: support QinQ " Olivier Matz
2016-07-05 15:41 ` [PATCH 08/18] net: add Mpls header structure Olivier Matz
2016-07-05 15:41 ` [PATCH 09/18] mbuf: support Mpls in software packet type parser Olivier Matz
2016-07-06  7:08   ` Liang, Cunming
2016-07-06  8:00     ` Olivier MATZ
2016-07-07  8:48       ` Liang, Cunming
2016-07-07 16:01         ` Olivier Matz
2016-07-05 15:41 ` [PATCH 10/18] mbuf: support Ip tunnels " Olivier Matz
2016-07-05 15:41 ` [PATCH 11/18] net: add Gre header structure Olivier Matz
2016-07-05 15:41 ` [PATCH 12/18] mbuf: support Gre in software packet type parser Olivier Matz
2016-07-05 15:41 ` [PATCH 13/18] mbuf: support Nvgre " Olivier Matz
2016-07-05 15:41 ` [PATCH 14/18] mbuf: get ptype for the first layers only Olivier Matz
2016-07-05 15:41 ` [PATCH 15/18] mbuf: add functions to dump packet type Olivier Matz
2016-07-05 15:41 ` [PATCH 16/18] mbuf: clarify definition of fragment packet types Olivier Matz
2016-07-05 15:41 ` [PATCH 17/18] app/testpmd: dump ptype using the new function Olivier Matz
2016-07-05 15:41 ` [PATCH 18/18] app/testpmd: display sw packet type Olivier Matz
2016-08-29 14:35 ` [PATCH v2 00/16] software parser for " Olivier Matz
2016-08-29 14:35   ` [PATCH v2 01/16] mbuf: add function to read packet data Olivier Matz
2016-08-29 14:35   ` [PATCH v2 02/16] net: move Ethernet header definitions to the net library Olivier Matz
2016-08-29 14:35   ` [PATCH v2 03/16] mbuf: move packet type definitions in a new file Olivier Matz
2016-08-29 14:35   ` [PATCH v2 04/16] net: introduce net library Olivier Matz
2016-08-29 14:35   ` [PATCH v2 05/16] net: add function to get packet type from data Olivier Matz
2016-08-29 14:35   ` [PATCH v2 06/16] net: support Vlan in software packet type parser Olivier Matz
2016-08-29 14:35   ` [PATCH v2 07/16] net: support QinQ " Olivier Matz
2016-08-29 14:35   ` [PATCH v2 08/16] net: support Ip tunnels " Olivier Matz
2016-08-29 14:35   ` [PATCH v2 09/16] net: add Gre header structure Olivier Matz
2016-08-29 14:35   ` [PATCH v2 10/16] net: support Gre in software packet type parser Olivier Matz
2016-08-29 14:35   ` [PATCH v2 11/16] net: support Nvgre " Olivier Matz
2016-08-29 14:35   ` [PATCH v2 12/16] net: get ptype for the first layers only Olivier Matz
2016-08-29 14:35   ` [PATCH v2 13/16] mbuf: add functions to dump packet type Olivier Matz
2016-08-29 14:35   ` [PATCH v2 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
2016-08-29 14:35   ` [PATCH v2 15/16] app/testpmd: dump ptype using the new function Olivier Matz
2016-08-29 14:35   ` [PATCH v2 16/16] app/testpmd: display software packet type Olivier Matz
2016-10-03  8:38   ` [PATCH v3 00/16] software parser for " Olivier Matz
2016-10-03  8:38     ` [PATCH v3 01/16] mbuf: add function to read packet data Olivier Matz
2016-10-03  8:38     ` [PATCH v3 02/16] net: move Ethernet header definitions to the net library Olivier Matz
2016-10-03  8:38     ` [PATCH v3 03/16] mbuf: move packet type definitions in a new file Olivier Matz
2016-10-10 14:52       ` Thomas Monjalon
2016-10-11  9:01         ` Olivier MATZ
2016-10-11 15:51           ` Thomas Monjalon
2016-10-03  8:38     ` [PATCH v3 04/16] net: introduce net library Olivier Matz
2016-10-03  8:38     ` [PATCH v3 05/16] net: add function to get packet type from data Olivier Matz
2016-10-03  8:38     ` [PATCH v3 06/16] net: support Vlan in software packet type parser Olivier Matz
2016-10-03  8:38     ` [PATCH v3 07/16] net: support QinQ " Olivier Matz
2016-10-03  8:38     ` [PATCH v3 08/16] net: support Ip tunnels " Olivier Matz
2016-10-03  8:38     ` [PATCH v3 09/16] net: add Gre header structure Olivier Matz
2016-10-03  8:38     ` [PATCH v3 10/16] net: support Gre in software packet type parser Olivier Matz
2016-10-03  8:38     ` [PATCH v3 11/16] net: support Nvgre " Olivier Matz
2016-10-03  8:38     ` [PATCH v3 12/16] net: get ptype for the first layers only Olivier Matz
2016-10-03  8:38     ` [PATCH v3 13/16] mbuf: add functions to dump packet type Olivier Matz
2016-10-03  8:38     ` [PATCH v3 14/16] mbuf: clarify definition of fragment packet types Olivier Matz
2016-10-03  8:38     ` [PATCH v3 15/16] app/testpmd: dump ptype using the new function Olivier Matz
2016-10-03  8:38     ` [PATCH v3 16/16] app/testpmd: display software packet type Olivier Matz
2016-10-11 16:24     ` [PATCH v3 00/16] software parser for " Thomas Monjalon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.