For this series:

Reviewed-and-tested-by: Bill Fischofer <bill.fischo...@linaro.org>

On Tue, Sep 13, 2016 at 9:30 AM, Matias Elo <matias....@nokia.com> wrote:

> 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