Enable parsing packet headers up to a given protocol layer.

Signed-off-by: Matias Elo <matias....@nokia.com>
---
 .../linux-generic/include/odp_packet_internal.h    |  24 +-
 platform/linux-generic/odp_classification.c        |   2 +-
 platform/linux-generic/odp_packet.c                | 293 ++++++++++++---------
 3 files changed, 193 insertions(+), 126 deletions(-)

diff --git a/platform/linux-generic/include/odp_packet_internal.h 
b/platform/linux-generic/include/odp_packet_internal.h
index 392d670..9b4f59e 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -41,7 +41,6 @@ typedef union {
 
        struct {
                uint64_t parsed_l2:1; /**< L2 parsed */
-               uint64_t parsed_all:1;/**< Parsing complete */
                uint64_t dst_queue:1; /**< Dst queue present */
 
                uint64_t flow_hash:1; /**< Flow hash present */
@@ -131,6 +130,18 @@ ODP_STATIC_ASSERT(sizeof(output_flags_t) == 
sizeof(uint32_t),
                  "OUTPUT_FLAGS_SIZE_ERROR");
 
 /**
+ * Protocol stack layers
+ */
+typedef enum {
+       LAYER_NONE = 0,
+       LAYER_L1,
+       LAYER_L2,
+       LAYER_L3,
+       LAYER_L4,
+       LAYER_ALL
+} layer_t;
+
+/**
  * Packet parser metadata
  */
 typedef struct {
@@ -145,6 +156,10 @@ typedef struct {
        uint32_t l3_len;    /**< Layer 3 length */
        uint32_t l4_len;    /**< Layer 4 length */
 
+       layer_t parsed_layers;  /**< Highest parsed protocol stack layer */
+       uint16_t ethtype;       /**< EtherType */
+       uint8_t ip_proto;       /**< IP protocol */
+
 } packet_parser_t;
 
 /**
@@ -300,7 +315,7 @@ static inline int packet_parse_l2_not_done(packet_parser_t 
*prs)
 
 static inline int packet_parse_not_complete(odp_packet_hdr_t *pkt_hdr)
 {
-       return !pkt_hdr->p.input_flags.parsed_all;
+       return pkt_hdr->p.parsed_layers != LAYER_ALL;
 }
 
 /* Forward declarations */
@@ -316,6 +331,9 @@ void packet_parse_l2(packet_parser_t *prs, uint32_t 
frame_len);
 /* Perform full packet parse */
 int packet_parse_full(odp_packet_hdr_t *pkt_hdr);
 
+/* Perform packet parse up to a given protocol layer */
+int packet_parse_layer(odp_packet_hdr_t *pkt_hdr, layer_t layer);
+
 /* Reset parser metadata for a new parse */
 void packet_parse_reset(odp_packet_hdr_t *pkt_hdr);
 
@@ -349,7 +367,7 @@ static inline void packet_set_ts(odp_packet_hdr_t *pkt_hdr, 
odp_time_t *ts)
 }
 
 int packet_parse_common(packet_parser_t *pkt_hdr, const uint8_t *ptr,
-                       uint32_t pkt_len, uint32_t seg_len);
+                       uint32_t pkt_len, uint32_t seg_len, layer_t layer);
 
 int _odp_cls_parse(odp_packet_hdr_t *pkt_hdr, const uint8_t *parseptr);
 
diff --git a/platform/linux-generic/odp_classification.c 
b/platform/linux-generic/odp_classification.c
index ea223bf..868058d 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -821,7 +821,7 @@ int cls_classify_packet(pktio_entry_t *entry, const uint8_t 
*base,
        packet_parse_reset(pkt_hdr);
        packet_set_len(pkt_hdr, pkt_len);
 
-       packet_parse_common(&pkt_hdr->p, base, pkt_len, seg_len);
+       packet_parse_common(&pkt_hdr->p, base, pkt_len, seg_len, LAYER_ALL);
        cos = cls_select_cos(entry, base, pkt_hdr);
 
        if (cos == NULL)
diff --git a/platform/linux-generic/odp_packet.c 
b/platform/linux-generic/odp_packet.c
index c4cf324..5f84869 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -30,12 +30,13 @@
 static inline void packet_parse_disable(odp_packet_hdr_t *pkt_hdr)
 {
        pkt_hdr->p.input_flags.parsed_l2  = 1;
-       pkt_hdr->p.input_flags.parsed_all = 1;
+       pkt_hdr->p.parsed_layers = LAYER_ALL;
 }
 
 void packet_parse_reset(odp_packet_hdr_t *pkt_hdr)
 {
        /* Reset parser metadata before new parse */
+       pkt_hdr->p.parsed_layers    = LAYER_NONE;
        pkt_hdr->p.error_flags.all  = 0;
        pkt_hdr->p.input_flags.all  = 0;
        pkt_hdr->p.output_flags.all = 0;
@@ -50,6 +51,8 @@ void packet_parse_reset(odp_packet_hdr_t *pkt_hdr)
 static void packet_init(pool_entry_t *pool, odp_packet_hdr_t *pkt_hdr,
                        size_t size, int parse)
 {
+       pkt_hdr->p.parsed_layers    = LAYER_NONE;
+
        pkt_hdr->p.input_flags.all  = 0;
        pkt_hdr->p.output_flags.all = 0;
        pkt_hdr->p.error_flags.all  = 0;
@@ -1166,151 +1169,185 @@ void packet_parse_l2(packet_parser_t *prs, uint32_t 
frame_len)
 }
 
 /**
- * Parse common packet headers
+ * Parse common packet headers up to given layer
  *
  * The function expects at least PACKET_PARSE_SEG_LEN bytes of data to be
  * available from the ptr.
  */
 int packet_parse_common(packet_parser_t *prs, const uint8_t *ptr,
-                       uint32_t frame_len, uint32_t seg_len)
+                       uint32_t frame_len, uint32_t seg_len, layer_t layer)
 {
-       const _odp_ethhdr_t *eth;
-       const _odp_vlanhdr_t *vlan;
-       uint16_t ethtype;
        uint32_t offset;
-       uint8_t ip_proto = 0;
        const uint8_t *parseptr;
-       uint16_t macaddr0, macaddr2, macaddr4;
-
-       offset = sizeof(_odp_ethhdr_t);
-       if (packet_parse_l2_not_done(prs))
-               packet_parse_l2(prs, frame_len);
-
-       eth = (const _odp_ethhdr_t *)ptr;
-
-       /* Handle Ethernet broadcast/multicast addresses */
-       macaddr0 = odp_be_to_cpu_16(*((const uint16_t *)(const void *)eth));
-       prs->input_flags.eth_mcast = (macaddr0 & 0x0100) == 0x0100;
-
-       if (macaddr0 == 0xffff) {
-               macaddr2 =
-                       odp_be_to_cpu_16(*((const uint16_t *)
-                                          (const void *)eth + 1));
-               macaddr4 =
-                       odp_be_to_cpu_16(*((const uint16_t *)
-                                          (const void *)eth + 2));
-               prs->input_flags.eth_bcast =
-                       (macaddr2 == 0xffff) && (macaddr4 == 0xffff);
-       } else {
-               prs->input_flags.eth_bcast = 0;
-       }
-
-       /* Get Ethertype */
-       ethtype = odp_be_to_cpu_16(eth->type);
-       parseptr = (const uint8_t *)(eth + 1);
 
-       /* Check for SNAP vs. DIX */
-       if (ethtype < _ODP_ETH_LEN_MAX) {
-               prs->input_flags.snap = 1;
-               if (ethtype > frame_len - offset) {
-                       prs->error_flags.snap_len = 1;
-                       goto parse_exit;
+       switch (prs->parsed_layers) {
+       case LAYER_NONE:
+       case LAYER_L2:
+       {
+               const _odp_ethhdr_t *eth;
+               uint16_t macaddr0, macaddr2, macaddr4;
+               const _odp_vlanhdr_t *vlan;
+
+               offset = sizeof(_odp_ethhdr_t);
+               if (packet_parse_l2_not_done(prs))
+                       packet_parse_l2(prs, frame_len);
+
+               eth = (const _odp_ethhdr_t *)ptr;
+
+               /* Handle Ethernet broadcast/multicast addresses */
+               macaddr0 = odp_be_to_cpu_16(*((const uint16_t *)
+                                           (const void *)eth));
+               prs->input_flags.eth_mcast = (macaddr0 & 0x0100) == 0x0100;
+
+               if (macaddr0 == 0xffff) {
+                       macaddr2 =
+                               odp_be_to_cpu_16(*((const uint16_t *)
+                                                  (const void *)eth + 1));
+                       macaddr4 =
+                               odp_be_to_cpu_16(*((const uint16_t *)
+                                                  (const void *)eth + 2));
+                       prs->input_flags.eth_bcast =
+                               (macaddr2 == 0xffff) && (macaddr4 == 0xffff);
+               } else {
+                       prs->input_flags.eth_bcast = 0;
                }
-               ethtype = odp_be_to_cpu_16(*((const uint16_t *)
-                                            (uintptr_t)(parseptr + 6)));
-               offset   += 8;
-               parseptr += 8;
-       }
-
-       /* Parse the VLAN header(s), if present */
-       if (ethtype == _ODP_ETHTYPE_VLAN_OUTER) {
-               prs->input_flags.vlan_qinq = 1;
-               prs->input_flags.vlan = 1;
-
-               vlan = (const _odp_vlanhdr_t *)parseptr;
-               ethtype = odp_be_to_cpu_16(vlan->type);
-               offset += sizeof(_odp_vlanhdr_t);
-               parseptr += sizeof(_odp_vlanhdr_t);
-       }
-
-       if (ethtype == _ODP_ETHTYPE_VLAN) {
-               prs->input_flags.vlan = 1;
-               vlan = (const _odp_vlanhdr_t *)parseptr;
-               ethtype = odp_be_to_cpu_16(vlan->type);
-               offset += sizeof(_odp_vlanhdr_t);
-               parseptr += sizeof(_odp_vlanhdr_t);
-       }
 
-       /* Set l3_offset+flag only for known ethtypes */
-       prs->input_flags.l3 = 1;
-       prs->l3_offset = offset;
+               /* Get Ethertype */
+               prs->ethtype = odp_be_to_cpu_16(eth->type);
+               parseptr = (const uint8_t *)(eth + 1);
+
+               /* Check for SNAP vs. DIX */
+               if (prs->ethtype < _ODP_ETH_LEN_MAX) {
+                       prs->input_flags.snap = 1;
+                       if (prs->ethtype > frame_len - offset) {
+                               prs->error_flags.snap_len = 1;
+                               goto parse_exit;
+                       }
+                       prs->ethtype = odp_be_to_cpu_16(*((const uint16_t *)
+                                                       (uintptr_t)
+                                                       (parseptr + 6)));
+                       offset   += 8;
+                       parseptr += 8;
+               }
 
-       /* Parse Layer 3 headers */
-       switch (ethtype) {
-       case _ODP_ETHTYPE_IPV4:
-               prs->input_flags.ipv4 = 1;
-               ip_proto = parse_ipv4(prs, &parseptr, &offset, frame_len);
-               break;
+               /* Parse the VLAN header(s), if present */
+               if (prs->ethtype == _ODP_ETHTYPE_VLAN_OUTER) {
+                       prs->input_flags.vlan_qinq = 1;
+                       prs->input_flags.vlan = 1;
 
-       case _ODP_ETHTYPE_IPV6:
-               prs->input_flags.ipv6 = 1;
-               ip_proto = parse_ipv6(prs, &parseptr, &offset, frame_len,
-                                     seg_len);
-               break;
+                       vlan = (const _odp_vlanhdr_t *)parseptr;
+                       prs->ethtype = odp_be_to_cpu_16(vlan->type);
+                       offset += sizeof(_odp_vlanhdr_t);
+                       parseptr += sizeof(_odp_vlanhdr_t);
+               }
 
-       case _ODP_ETHTYPE_ARP:
-               prs->input_flags.arp = 1;
-               ip_proto = 255;  /* Reserved invalid by IANA */
-               break;
+               if (prs->ethtype == _ODP_ETHTYPE_VLAN) {
+                       prs->input_flags.vlan = 1;
+                       vlan = (const _odp_vlanhdr_t *)parseptr;
+                       prs->ethtype = odp_be_to_cpu_16(vlan->type);
+                       offset += sizeof(_odp_vlanhdr_t);
+                       parseptr += sizeof(_odp_vlanhdr_t);
+               }
 
-       default:
-               prs->input_flags.l3 = 0;
-               prs->l3_offset = ODP_PACKET_OFFSET_INVALID;
-               ip_proto = 255;  /* Reserved invalid by IANA */
+               prs->l3_offset = offset;
+               prs->parsed_layers = LAYER_L2;
+               if (layer == LAYER_L2)
+                       return prs->error_flags.all != 0;
        }
+       case LAYER_L3:
+       {
+               offset = prs->l3_offset;
+               parseptr = (const uint8_t *)(ptr + offset);
+               /* Set l3_offset+flag only for known ethtypes */
+               prs->input_flags.l3 = 1;
+
+               /* Parse Layer 3 headers */
+               switch (prs->ethtype) {
+               case _ODP_ETHTYPE_IPV4:
+                       prs->input_flags.ipv4 = 1;
+                       prs->ip_proto = parse_ipv4(prs, &parseptr, &offset,
+                                                  frame_len);
+                       break;
+
+               case _ODP_ETHTYPE_IPV6:
+                       prs->input_flags.ipv6 = 1;
+                       prs->ip_proto = parse_ipv6(prs, &parseptr, &offset,
+                                                  frame_len, seg_len);
+                       break;
+
+               case _ODP_ETHTYPE_ARP:
+                       prs->input_flags.arp = 1;
+                       prs->ip_proto = 255;  /* Reserved invalid by IANA */
+                       break;
+
+               default:
+                       prs->input_flags.l3 = 0;
+                       prs->l3_offset = ODP_PACKET_OFFSET_INVALID;
+                       prs->ip_proto = 255;  /* Reserved invalid by IANA */
+               }
 
-       /* Set l4_offset+flag only for known ip_proto */
-       prs->input_flags.l4 = 1;
-       prs->l4_offset = offset;
-
-       /* Parse Layer 4 headers */
-       switch (ip_proto) {
-       case _ODP_IPPROTO_ICMP:
-               prs->input_flags.icmp = 1;
-               break;
-
-       case _ODP_IPPROTO_TCP:
-               if (odp_unlikely(offset + _ODP_TCPHDR_LEN > seg_len))
-                       return -1;
-               prs->input_flags.tcp = 1;
-               parse_tcp(prs, &parseptr, NULL);
-               break;
-
-       case _ODP_IPPROTO_UDP:
-               if (odp_unlikely(offset + _ODP_UDPHDR_LEN > seg_len))
-                       return -1;
-               prs->input_flags.udp = 1;
-               parse_udp(prs, &parseptr, NULL);
-               break;
+               /* Set l4_offset+flag only for known ip_proto */
+               prs->l4_offset = offset;
+               prs->parsed_layers = LAYER_L3;
+               if (layer == LAYER_L3)
+                       return prs->error_flags.all != 0;
+       }
+       case LAYER_L4:
+       {
+               offset = prs->l4_offset;
+               parseptr = (const uint8_t *)(ptr + offset);
+               prs->input_flags.l4 = 1;
+
+               /* Parse Layer 4 headers */
+               switch (prs->ip_proto) {
+               case _ODP_IPPROTO_ICMP:
+                       prs->input_flags.icmp = 1;
+                       break;
+
+               case _ODP_IPPROTO_TCP:
+                       if (odp_unlikely(offset + _ODP_TCPHDR_LEN > seg_len))
+                               return -1;
+                       prs->input_flags.tcp = 1;
+                       parse_tcp(prs, &parseptr, NULL);
+                       break;
+
+               case _ODP_IPPROTO_UDP:
+                       if (odp_unlikely(offset + _ODP_UDPHDR_LEN > seg_len))
+                               return -1;
+                       prs->input_flags.udp = 1;
+                       parse_udp(prs, &parseptr, NULL);
+                       break;
+
+               case _ODP_IPPROTO_AH:
+                       prs->input_flags.ipsec = 1;
+                       prs->input_flags.ipsec_ah = 1;
+                       break;
+
+               case _ODP_IPPROTO_ESP:
+                       prs->input_flags.ipsec = 1;
+                       prs->input_flags.ipsec_esp = 1;
+                       break;
+
+               default:
+                       prs->input_flags.l4 = 0;
+                       prs->l4_offset = ODP_PACKET_OFFSET_INVALID;
+                       break;
+               }
 
-       case _ODP_IPPROTO_AH:
-               prs->input_flags.ipsec = 1;
-               prs->input_flags.ipsec_ah = 1;
+               prs->parsed_layers = LAYER_L4;
                break;
-
-       case _ODP_IPPROTO_ESP:
-               prs->input_flags.ipsec = 1;
-               prs->input_flags.ipsec_esp = 1;
+       }
+       case LAYER_ALL:
                break;
 
        default:
-               prs->input_flags.l4 = 0;
-               prs->l4_offset = ODP_PACKET_OFFSET_INVALID;
-               break;
+               ODP_ERR("Invalid parse layer: %d\n", (int)layer);
+               return -1;
        }
 
+       prs->parsed_layers = LAYER_ALL;
+
 parse_exit:
-       prs->input_flags.parsed_all = 1;
        return prs->error_flags.all != 0;
 }
 
@@ -1323,5 +1360,17 @@ int packet_parse_full(odp_packet_hdr_t *pkt_hdr)
        void *base = packet_map(pkt_hdr, 0, &seg_len);
 
        return packet_parse_common(&pkt_hdr->p, base, pkt_hdr->frame_len,
-                                  seg_len);
+                                  seg_len, LAYER_ALL);
+}
+
+/**
+ * Simple packet parser
+ */
+int packet_parse_layer(odp_packet_hdr_t *pkt_hdr, layer_t layer)
+{
+       uint32_t seg_len;
+       void *base = packet_map(pkt_hdr, 0, &seg_len);
+
+       return packet_parse_common(&pkt_hdr->p, base, pkt_hdr->frame_len,
+                                  seg_len, layer);
 }
-- 
2.7.4

Reply via email to