aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJere Leppänen <jere.leppanen@nokia.com>2022-02-02 17:01:59 +0200
committerPetri Savolainen <petri.savolainen@nokia.com>2022-03-10 09:33:44 +0200
commit3924507d7a375c1ac48760586971d3b488d54aae (patch)
tree16cd4d416457019725316ee59da4905afe121220
parent37072db5ae3644223769ce9ea65d93ff25c9fe81 (diff)
linux-gen: packet: move parse functions to new source files
Move packet parsing functions to new odp_parse.c and odp_parse_internal.h files. Signed-off-by: Jere Leppänen <jere.leppanen@nokia.com> Reviewed-by: Matias Elo <matias.elo@nokia.com> Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
-rw-r--r--platform/linux-generic/Makefile.am2
-rw-r--r--platform/linux-generic/include/odp_macros_internal.h2
-rw-r--r--platform/linux-generic/include/odp_packet_internal.h42
-rw-r--r--platform/linux-generic/include/odp_parse_internal.h104
-rw-r--r--platform/linux-generic/odp_packet.c541
-rw-r--r--platform/linux-generic/odp_parse.c496
-rw-r--r--platform/linux-generic/pktio/loop.c1
-rw-r--r--platform/linux-generic/pktio/netmap.c1
-rw-r--r--platform/linux-generic/pktio/pcap.c1
-rw-r--r--platform/linux-generic/pktio/socket.c1
-rw-r--r--platform/linux-generic/pktio/socket_mmap.c1
-rw-r--r--platform/linux-generic/pktio/tap.c1
12 files changed, 632 insertions, 561 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index fc73925e5..0e95d96a9 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -126,6 +126,7 @@ noinst_HEADERS = \
include/odp_packet_dpdk.h \
include/odp_packet_internal.h \
include/odp_packet_io_internal.h \
+ include/odp_parse_internal.h \
include/odp_socket_common.h \
include/odp_packet_io_stats_common.h \
include/odp_packet_io_stats.h \
@@ -202,6 +203,7 @@ __LIB__libodp_linux_la_SOURCES = \
odp_packet_vector.c \
odp_packet_flags.c \
odp_packet_io.c \
+ odp_parse.c \
odp_pkt_queue.c \
odp_pool.c \
odp_queue_basic.c \
diff --git a/platform/linux-generic/include/odp_macros_internal.h b/platform/linux-generic/include/odp_macros_internal.h
index 997e0fd5b..b8be7f938 100644
--- a/platform/linux-generic/include/odp_macros_internal.h
+++ b/platform/linux-generic/include/odp_macros_internal.h
@@ -35,6 +35,8 @@ extern "C" {
tmp_a > tmp_b ? tmp_a : tmp_b; \
})
+#define MAX3(a, b, c) (MAX(MAX((a), (b)), (c)))
+
#define odp_container_of(pointer, type, member) \
((type *)(void *)(((char *)pointer) - offsetof(type, member)))
diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index 6a557943c..868b4ef56 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -38,15 +38,23 @@ extern "C" {
#include <stdint.h>
#include <string.h>
-/** Minimum segment length expected by _odp_packet_parse_common() */
-#define PACKET_PARSE_SEG_LEN 96
-
ODP_STATIC_ASSERT(sizeof(_odp_packet_input_flags_t) == sizeof(uint64_t),
"INPUT_FLAGS_SIZE_ERROR");
ODP_STATIC_ASSERT(sizeof(_odp_packet_flags_t) == sizeof(uint32_t),
"PACKET_FLAGS_SIZE_ERROR");
+/* Packet extra data length */
+#define PKT_EXTRA_LEN 128
+
+/* Packet extra data types */
+#define PKT_EXTRA_TYPE_DPDK 1
+
+/* Maximum number of segments per packet */
+#define PKT_MAX_SEGS 255
+
+ODP_STATIC_ASSERT(PKT_MAX_SEGS < UINT16_MAX, "PACKET_MAX_SEGS_ERROR");
+
/**
* Packet parser metadata
*/
@@ -67,17 +75,6 @@ typedef struct {
uint16_t l4_offset;
} packet_parser_t;
-/* Packet extra data length */
-#define PKT_EXTRA_LEN 128
-
-/* Packet extra data types */
-#define PKT_EXTRA_TYPE_DPDK 1
-
-/* Maximum number of segments per packet */
-#define PKT_MAX_SEGS 255
-
-ODP_STATIC_ASSERT(PKT_MAX_SEGS < UINT16_MAX, "PACKET_MAX_SEGS_ERROR");
-
/**
* Internal Packet header
*
@@ -198,6 +195,11 @@ static inline odp_packet_t packet_from_event_hdr(_odp_event_hdr_t *event_hdr)
return (odp_packet_t)(uintptr_t)event_hdr;
}
+static inline uint32_t packet_first_seg_len(odp_packet_hdr_t *pkt_hdr)
+{
+ return pkt_hdr->seg_len;
+}
+
static inline odp_packet_hdr_t *packet_last_seg(odp_packet_hdr_t *hdr)
{
while (hdr->seg_next != NULL)
@@ -404,11 +406,6 @@ static inline void packet_set_len(odp_packet_hdr_t *pkt_hdr, uint32_t len)
int _odp_packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
odp_packet_t pkt[], int max_num);
-/* Perform packet parse up to a given protocol layer */
-int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
- odp_proto_layer_t layer,
- odp_proto_chksums_t chksums);
-
/* Reset parser metadata for a new parse */
static inline void packet_parse_reset(odp_packet_hdr_t *pkt_hdr, int all)
{
@@ -458,10 +455,6 @@ static inline void packet_set_ts(odp_packet_hdr_t *pkt_hdr, odp_time_t *ts)
}
}
-int _odp_packet_parse_common(packet_parser_t *pkt_hdr, const uint8_t *ptr,
- uint32_t pkt_len, uint32_t seg_len, int layer,
- odp_proto_chksums_t chksums);
-
int _odp_cls_parse(odp_packet_hdr_t *pkt_hdr, const uint8_t *parseptr);
int _odp_packet_set_data(odp_packet_t pkt, uint32_t offset,
@@ -475,6 +468,9 @@ int _odp_packet_tcp_chksum_insert(odp_packet_t pkt);
int _odp_packet_udp_chksum_insert(odp_packet_t pkt);
int _odp_packet_sctp_chksum_insert(odp_packet_t pkt);
+int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, odp_proto_chksums_t chksums,
+ uint64_t l4_part_sum);
+
#ifdef __cplusplus
}
#endif
diff --git a/platform/linux-generic/include/odp_parse_internal.h b/platform/linux-generic/include/odp_parse_internal.h
new file mode 100644
index 000000000..99b730a58
--- /dev/null
+++ b/platform/linux-generic/include/odp_parse_internal.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2013-2018, Linaro Limited
+ * Copyright (c) 2019-2022, Nokia
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ODP_PARSE_INTERNAL_H_
+#define ODP_PARSE_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_packet_internal.h>
+#include <odp_macros_internal.h>
+#include <protocols/eth.h>
+#include <protocols/ip.h>
+#include <protocols/sctp.h>
+#include <protocols/tcp.h>
+#include <protocols/udp.h>
+#include <odp/api/plat/packet_inline_types.h>
+#include <odp/api/hints.h>
+#include <odp/api/packet_io.h>
+#include <odp/api/packet_types.h>
+#include <stdint.h>
+
+/** Minimum segment length expected by _odp_packet_parse_common() */
+#define PACKET_PARSE_SEG_LEN 96
+/*
+ * In the worst case we look at the Ethernet header, 8 bytes of LLC/SNAP
+ * header and two VLAN tags in the same packet.
+ */
+#define PARSE_ETH_BYTES (sizeof(_odp_ethhdr_t) + 8 + 2 * sizeof(_odp_vlanhdr_t))
+#define PARSE_IPV4_BYTES (0xfU * 4) /* max IPv4 header length with options */
+/*
+ * Peeks 2 bytes beyond IPv6 base header without length check if there
+ * are extension headers.
+ */
+#define PARSE_IPV6_BYTES (sizeof(_odp_ipv6hdr_t) + 2)
+#define PARSE_TCP_BYTES (sizeof(_odp_tcphdr_t))
+/*
+ * In the worst case we look at the UDP header and 4 bytes of the UDP
+ * payload (the non-ESP marker to distinguish IKE packets from ESP packets).
+ */
+#define PARSE_UDP_BYTES (sizeof(_odp_udphdr_t) + 4)
+#define PARSE_SCTP_BYTES (sizeof(_odp_sctphdr_t))
+
+#define PARSE_L3_L4_BYTES (MAX(PARSE_IPV4_BYTES, PARSE_IPV6_BYTES) + \
+ MAX3(PARSE_TCP_BYTES, PARSE_UDP_BYTES, PARSE_SCTP_BYTES))
+
+uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
+ uint32_t *offset, uint32_t frame_len);
+
+int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
+ uint32_t offset,
+ uint32_t frame_len, uint32_t seg_len,
+ int layer, uint16_t ethtype,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum);
+
+/**
+ * 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. Also parse metadata must be already initialized.
+ */
+static inline int _odp_packet_parse_common(packet_parser_t *prs,
+ const uint8_t *ptr,
+ uint32_t frame_len, uint32_t seg_len,
+ int layer,
+ odp_proto_chksums_t chksums)
+{
+ uint32_t offset;
+ uint16_t ethtype;
+ const uint8_t *parseptr;
+ uint64_t l4_part_sum;
+
+ parseptr = ptr;
+ offset = 0;
+
+ if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE))
+ return 0;
+
+ /* Assume valid L2 header, no CRC/FCS check in SW */
+ prs->l2_offset = offset;
+
+ ethtype = parse_eth(prs, &parseptr, &offset, frame_len);
+
+ return packet_parse_common_l3_l4(prs, parseptr, offset, frame_len,
+ seg_len, layer, ethtype, chksums,
+ &l4_part_sum);
+}
+
+/* Perform packet parse up to a given protocol layer */
+int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
+ odp_proto_layer_t layer,
+ odp_proto_chksums_t chksums);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index d89beeee3..a49c8911b 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -16,6 +16,7 @@
#include <odp/api/proto_stats.h>
#include <odp/api/timer.h>
+#include <odp_parse_internal.h>
#include <odp_chksum_internal.h>
#include <odp_debug_internal.h>
#include <odp_errno_define.h>
@@ -131,11 +132,6 @@ static inline uint32_t packet_seg_len(odp_packet_hdr_t *pkt_hdr,
return pkt_hdr->seg_len;
}
-static inline uint32_t packet_first_seg_len(odp_packet_hdr_t *pkt_hdr)
-{
- return pkt_hdr->seg_len;
-}
-
static inline void *packet_tail(odp_packet_hdr_t *pkt_hdr)
{
odp_packet_hdr_t *last_seg = packet_last_seg(pkt_hdr);
@@ -1771,500 +1767,6 @@ static uint32_t packet_sum_crc32c(odp_packet_hdr_t *pkt_hdr,
return sum;
}
-/*
- * In the worst case we look at the Ethernet header, 8 bytes of LLC/SNAP
- * header and two VLAN tags in the same packet.
- */
-#define PARSE_ETH_BYTES (sizeof(_odp_ethhdr_t) + 8 + 2 * sizeof(_odp_vlanhdr_t))
-/** Parser helper function for Ethernet packets
- *
- * Requires up to PARSE_ETH_BYTES bytes of contiguous packet data.
- */
-static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
- uint32_t *offset, uint32_t frame_len)
-{
- uint16_t ethtype;
- const _odp_ethhdr_t *eth;
- uint16_t macaddr0, macaddr2, macaddr4;
- const _odp_vlanhdr_t *vlan;
- _odp_packet_input_flags_t input_flags;
-
- input_flags.all = 0;
- input_flags.l2 = 1;
- input_flags.eth = 1;
-
- eth = (const _odp_ethhdr_t *)*parseptr;
-
- /* Detect jumbo frames */
- if (odp_unlikely(frame_len - *offset > _ODP_ETH_LEN_MAX))
- input_flags.jumbo = 1;
-
- /* Handle Ethernet broadcast/multicast addresses */
- macaddr0 = odp_be_to_cpu_16(*((const uint16_t *)(const void *)eth));
- if (odp_unlikely((macaddr0 & 0x0100) == 0x0100))
- input_flags.eth_mcast = 1;
-
- if (odp_unlikely(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));
-
- if ((macaddr2 == 0xffff) && (macaddr4 == 0xffff))
- input_flags.eth_bcast = 1;
- }
-
- /* Get Ethertype */
- ethtype = odp_be_to_cpu_16(eth->type);
- *offset += sizeof(*eth);
- *parseptr += sizeof(*eth);
-
- /* Check for SNAP vs. DIX */
- if (odp_unlikely(ethtype < _ODP_ETH_LEN_MAX)) {
- input_flags.snap = 1;
- if (ethtype > frame_len - *offset) {
- prs->flags.snap_len_err = 1;
- ethtype = 0;
- goto error;
- }
- 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 (odp_unlikely(ethtype == _ODP_ETHTYPE_VLAN_OUTER)) {
- input_flags.vlan_qinq = 1;
- 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) {
- 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);
- }
-
- /*
- * The packet was too short for what we parsed. We just give up
- * entirely without trying to parse what fits in the packet.
- */
- if (odp_unlikely(*offset > frame_len)) {
- input_flags.all = 0;
- input_flags.l2 = 1;
- ethtype = 0;
- }
-
-error:
- prs->input_flags.all |= input_flags.all;
-
- return ethtype;
-}
-
-#define PARSE_IPV4_BYTES (0xfU * 4) /* max IPv4 header length with options */
-/**
- * Parser helper function for IPv4
- *
- * Requires up to PARSE_IPV4_BYTES bytes of contiguous packet data.
- */
-static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
- uint32_t *offset, uint32_t frame_len,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- const _odp_ipv4hdr_t *ipv4 = (const _odp_ipv4hdr_t *)*parseptr;
- uint32_t dstaddr = odp_be_to_cpu_32(ipv4->dst_addr);
- uint32_t l3_len = odp_be_to_cpu_16(ipv4->tot_len);
- uint16_t frag_offset = odp_be_to_cpu_16(ipv4->frag_offset);
- uint8_t ver = _ODP_IPV4HDR_VER(ipv4->ver_ihl);
- uint8_t ihl = _ODP_IPV4HDR_IHL(ipv4->ver_ihl);
-
- if (odp_unlikely(ihl < _ODP_IPV4HDR_IHL_MIN ||
- ver != 4 ||
- sizeof(*ipv4) > frame_len - *offset ||
- (l3_len > frame_len - *offset))) {
- prs->flags.ip_err = 1;
- return 0;
- }
-
- if (chksums.chksum.ipv4) {
- prs->input_flags.l3_chksum_done = 1;
- if (chksum_finalize(chksum_partial(ipv4, ihl * 4, 0)) != 0xffff) {
- prs->flags.ip_err = 1;
- prs->flags.l3_chksum_err = 1;
- return 0;
- }
- }
-
- *offset += ihl * 4;
- *parseptr += ihl * 4;
-
- if (chksums.chksum.udp || chksums.chksum.tcp)
- *l4_part_sum = chksum_partial((const uint8_t *)&ipv4->src_addr,
- 2 * _ODP_IPV4ADDR_LEN, 0);
-
- if (odp_unlikely(ihl > _ODP_IPV4HDR_IHL_MIN))
- prs->input_flags.ipopt = 1;
-
- /* A packet is a fragment if:
- * "more fragments" flag is set (all fragments except the last)
- * OR
- * "fragment offset" field is nonzero (all fragments except the first)
- */
- if (odp_unlikely(_ODP_IPV4HDR_IS_FRAGMENT(frag_offset)))
- prs->input_flags.ipfrag = 1;
-
- /* Handle IPv4 broadcast / multicast */
- if (odp_unlikely(dstaddr == 0xffffffff))
- prs->input_flags.ip_bcast = 1;
-
- if (odp_unlikely((dstaddr >> 28) == 0xe))
- prs->input_flags.ip_mcast = 1;
-
- return ipv4->proto;
-}
-
-/*
- * Peeks 2 bytes beyond IPv6 base header without length check if there
- * are extension headers.
- */
-#define PARSE_IPV6_BYTES (sizeof(_odp_ipv6hdr_t) + 2)
-/**
- * Parser helper function for IPv6
- *
- * Requires at least PARSE_IPV6_BYTES bytes of contiguous packet data.
- */
-static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
- uint32_t *offset, uint32_t frame_len,
- uint32_t seg_len,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr;
- const _odp_ipv6hdr_ext_t *ipv6ext;
- uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr.u8[0]);
- uint32_t l3_len = odp_be_to_cpu_16(ipv6->payload_len) +
- _ODP_IPV6HDR_LEN;
-
- /* Basic sanity checks on IPv6 header */
- if (odp_unlikely((odp_be_to_cpu_32(ipv6->ver_tc_flow) >> 28) != 6 ||
- sizeof(*ipv6) > frame_len - *offset ||
- l3_len > frame_len - *offset)) {
- prs->flags.ip_err = 1;
- return 0;
- }
-
- /* IPv6 broadcast / multicast flags */
- prs->input_flags.ip_mcast = (dstaddr0 & 0xff000000) == 0xff000000;
- prs->input_flags.ip_bcast = 0;
-
- /* Skip past IPv6 header */
- *offset += sizeof(_odp_ipv6hdr_t);
- *parseptr += sizeof(_odp_ipv6hdr_t);
-
- if (chksums.chksum.udp || chksums.chksum.tcp)
- *l4_part_sum = chksum_partial((const uint8_t *)&ipv6->src_addr,
- 2 * _ODP_IPV6ADDR_LEN, 0);
-
- /* Skip past any IPv6 extension headers */
- if (ipv6->next_hdr == _ODP_IPPROTO_HOPOPTS ||
- ipv6->next_hdr == _ODP_IPPROTO_ROUTE) {
- prs->input_flags.ipopt = 1;
-
- do {
- ipv6ext = (const _odp_ipv6hdr_ext_t *)*parseptr;
- uint16_t extlen = 8 + ipv6ext->ext_len * 8;
-
- *offset += extlen;
- *parseptr += extlen;
- } while ((ipv6ext->next_hdr == _ODP_IPPROTO_HOPOPTS ||
- ipv6ext->next_hdr == _ODP_IPPROTO_ROUTE) &&
- *offset < seg_len);
-
- if (*offset >= prs->l3_offset +
- odp_be_to_cpu_16(ipv6->payload_len)) {
- prs->flags.ip_err = 1;
- return 0;
- }
-
- if (ipv6ext->next_hdr == _ODP_IPPROTO_FRAG)
- prs->input_flags.ipfrag = 1;
-
- return ipv6ext->next_hdr;
- }
-
- if (odp_unlikely(ipv6->next_hdr == _ODP_IPPROTO_FRAG)) {
- prs->input_flags.ipopt = 1;
- prs->input_flags.ipfrag = 1;
- }
-
- return ipv6->next_hdr;
-}
-
-#define PARSE_TCP_BYTES (sizeof(_odp_tcphdr_t))
-/**
- * Parser helper function for TCP
- *
- * Requires PARSE_TCP_BYTES bytes of contiguous packet data.
- */
-static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr,
- uint16_t tcp_len,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- const _odp_tcphdr_t *tcp = (const _odp_tcphdr_t *)*parseptr;
- uint32_t len = tcp->hl * 4;
-
- if (odp_unlikely(tcp->hl < sizeof(_odp_tcphdr_t) / sizeof(uint32_t)))
- prs->flags.tcp_err = 1;
-
- if (chksums.chksum.tcp &&
- !prs->input_flags.ipfrag) {
- *l4_part_sum += odp_cpu_to_be_16(tcp_len);
-#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
- *l4_part_sum += _ODP_IPPROTO_TCP;
-#else
- *l4_part_sum += _ODP_IPPROTO_TCP << 8;
-#endif
- }
-
- *parseptr += len;
-}
-
-/*
- * In the worst case we look at the UDP header and 4 bytes of the UDP
- * payload (the non-ESP marker to distinguish IKE packets from ESP packets).
- */
-#define PARSE_UDP_BYTES (sizeof(_odp_udphdr_t) + 4)
-/**
- * Parser helper function for UDP
- *
- * Requires PARSE_UDP_BYTES bytes of contiguous packet data.
- */
-static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- const _odp_udphdr_t *udp = (const _odp_udphdr_t *)*parseptr;
- uint32_t udplen = odp_be_to_cpu_16(udp->length);
- uint16_t ipsec_port = odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT);
-
- if (odp_unlikely(udplen < sizeof(_odp_udphdr_t))) {
- prs->flags.udp_err = 1;
- return;
- }
-
- if (chksums.chksum.udp &&
- !prs->input_flags.ipfrag) {
- if (udp->chksum == 0) {
- prs->input_flags.l4_chksum_done = 1;
- prs->flags.l4_chksum_err =
- (prs->input_flags.ipv4 != 1);
- } else {
- *l4_part_sum += udp->length;
-#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
- *l4_part_sum += _ODP_IPPROTO_UDP;
-#else
- *l4_part_sum += _ODP_IPPROTO_UDP << 8;
-#endif
- }
- prs->input_flags.udp_chksum_zero = (udp->chksum == 0);
- }
-
- if (odp_unlikely(ipsec_port == udp->dst_port && udplen > 4)) {
- uint32_t val;
-
- memcpy(&val, udp + 1, 4);
- if (val != 0) {
- prs->input_flags.ipsec = 1;
- prs->input_flags.ipsec_udp = 1;
- }
- }
-
- *parseptr += sizeof(_odp_udphdr_t);
-}
-
-#define PARSE_SCTP_BYTES (sizeof(_odp_sctphdr_t))
-/**
- * Parser helper function for SCTP
- *
- * Requires PARSE_SCTP_BYTES bytes of contiguous packet data.
- */
-static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr,
- uint16_t sctp_len,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- if (odp_unlikely(sctp_len < sizeof(_odp_sctphdr_t))) {
- prs->flags.sctp_err = 1;
- return;
- }
-
- if (chksums.chksum.sctp &&
- !prs->input_flags.ipfrag) {
- const _odp_sctphdr_t *sctp =
- (const _odp_sctphdr_t *)*parseptr;
- uint32_t crc = ~0;
- uint32_t zero = 0;
-
- crc = odp_hash_crc32c(sctp, sizeof(*sctp) - 4, crc);
- crc = odp_hash_crc32c(&zero, 4, crc);
- *l4_part_sum = crc;
- }
-
- *parseptr += sizeof(_odp_sctphdr_t);
-}
-
-#define MAX3(a, b, c) (MAX(MAX((a), (b)), (c)))
-#define PARSE_L3_L4_BYTES (MAX(PARSE_IPV4_BYTES, PARSE_IPV6_BYTES) + \
- MAX3(PARSE_TCP_BYTES, PARSE_UDP_BYTES, PARSE_SCTP_BYTES))
-/* Requires up to PARSE_L3_L4_BYTES bytes of contiguous packet data. */
-static inline
-int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
- uint32_t offset,
- uint32_t frame_len, uint32_t seg_len,
- int layer, uint16_t ethtype,
- odp_proto_chksums_t chksums,
- uint64_t *l4_part_sum)
-{
- uint8_t ip_proto;
-
- prs->l3_offset = offset;
-
- if (odp_unlikely(layer <= ODP_PROTO_LAYER_L2))
- return prs->flags.all.error != 0;
-
- /* Set l3 flag only for known ethtypes */
- prs->input_flags.l3 = 1;
-
- /* Parse Layer 3 headers */
- switch (ethtype) {
- case _ODP_ETHTYPE_IPV4:
- prs->input_flags.ipv4 = 1;
- ip_proto = parse_ipv4(prs, &parseptr, &offset, frame_len,
- chksums, l4_part_sum);
- prs->l4_offset = offset;
- break;
-
- case _ODP_ETHTYPE_IPV6:
- prs->input_flags.ipv6 = 1;
- ip_proto = parse_ipv6(prs, &parseptr, &offset, frame_len,
- seg_len, chksums, l4_part_sum);
- prs->l4_offset = offset;
- break;
-
- case _ODP_ETHTYPE_ARP:
- prs->input_flags.arp = 1;
- ip_proto = 255; /* Reserved invalid by IANA */
- break;
-
- default:
- prs->input_flags.l3 = 0;
- ip_proto = 255; /* Reserved invalid by IANA */
- }
-
- if (layer == ODP_PROTO_LAYER_L3)
- return prs->flags.all.error != 0;
-
- /* Set l4 flag only for known ip_proto */
- prs->input_flags.l4 = 1;
-
- /* Parse Layer 4 headers */
- switch (ip_proto) {
- case _ODP_IPPROTO_ICMPV4:
- /* Fall through */
-
- case _ODP_IPPROTO_ICMPV6:
- prs->input_flags.icmp = 1;
- break;
-
- case _ODP_IPPROTO_IPIP:
- /* Do nothing */
- 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, frame_len - prs->l4_offset, chksums,
- l4_part_sum);
- 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, chksums, l4_part_sum);
- 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;
-
- case _ODP_IPPROTO_SCTP:
- prs->input_flags.sctp = 1;
- parse_sctp(prs, &parseptr, frame_len - prs->l4_offset, chksums,
- l4_part_sum);
- break;
-
- case _ODP_IPPROTO_NO_NEXT:
- prs->input_flags.no_next_hdr = 1;
- break;
-
- default:
- prs->input_flags.l4 = 0;
- break;
- }
-
- return prs->flags.all.error != 0;
-}
-
-/**
- * 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. Also parse metadata must be already initialized.
- */
-int _odp_packet_parse_common(packet_parser_t *prs, const uint8_t *ptr,
- uint32_t frame_len, uint32_t seg_len,
- int layer, odp_proto_chksums_t chksums)
-{
- uint32_t offset;
- uint16_t ethtype;
- const uint8_t *parseptr;
- uint64_t l4_part_sum;
-
- parseptr = ptr;
- offset = 0;
-
- if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE))
- return 0;
-
- /* Assume valid L2 header, no CRC/FCS check in SW */
- prs->l2_offset = offset;
-
- ethtype = parse_eth(prs, &parseptr, &offset, frame_len);
-
- return packet_parse_common_l3_l4(prs, parseptr, offset, frame_len,
- seg_len, layer, ethtype, chksums,
- &l4_part_sum);
-}
-
static inline int packet_ipv4_chksum(odp_packet_t pkt,
uint32_t offset,
_odp_ipv4hdr_t *ip,
@@ -2442,9 +1944,8 @@ int _odp_packet_sctp_chksum_insert(odp_packet_t pkt)
return odp_packet_copy_from_mem(pkt, pkt_hdr->p.l4_offset + 8, 4, &sum);
}
-static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr,
- odp_proto_chksums_t chksums,
- uint64_t l4_part_sum)
+int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr, odp_proto_chksums_t chksums,
+ uint64_t l4_part_sum)
{
/* UDP chksum == 0 case is covered in parse_udp() */
if (chksums.chksum.udp &&
@@ -2518,42 +2019,6 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr,
return pkt_hdr->p.flags.all.error != 0;
}
-/**
- * Simple packet parser
- */
-int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
- odp_proto_layer_t layer,
- odp_proto_chksums_t chksums)
-{
- uint32_t seg_len = packet_first_seg_len(pkt_hdr);
- const uint8_t *base = packet_data(pkt_hdr);
- uint32_t offset = 0;
- uint16_t ethtype;
- uint64_t l4_part_sum = 0;
- int rc;
-
- if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE))
- return 0;
-
- /* Assume valid L2 header, no CRC/FCS check in SW */
- pkt_hdr->p.l2_offset = offset;
-
- ethtype = parse_eth(&pkt_hdr->p, &base, &offset, pkt_hdr->frame_len);
-
- rc = packet_parse_common_l3_l4(&pkt_hdr->p, base, offset,
- pkt_hdr->frame_len,
- seg_len, layer, ethtype, chksums,
- &l4_part_sum);
-
- if (rc != 0)
- return rc;
-
- if (layer >= ODP_PROTO_LAYER_L4)
- return packet_l4_chksum(pkt_hdr, chksums, l4_part_sum);
- else
- return 0;
-}
-
int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
const odp_packet_parse_param_t *param)
{
diff --git a/platform/linux-generic/odp_parse.c b/platform/linux-generic/odp_parse.c
new file mode 100644
index 000000000..c89ed6dfb
--- /dev/null
+++ b/platform/linux-generic/odp_parse.c
@@ -0,0 +1,496 @@
+/* Copyright (c) 2013-2018, Linaro Limited
+ * Copyright (c) 2019-2022, Nokia
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp_parse_internal.h>
+#include <odp_chksum_internal.h>
+#include <protocols/eth.h>
+#include <protocols/ip.h>
+#include <protocols/sctp.h>
+#include <protocols/tcp.h>
+#include <protocols/udp.h>
+#include <odp/api/hash.h>
+#include <odp/api/packet_io.h>
+#include <odp/api/packet_types.h>
+#include <stdint.h>
+#include <string.h>
+
+/** Parser helper function for Ethernet packets
+ *
+ * Requires up to PARSE_ETH_BYTES bytes of contiguous packet data.
+ */
+uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
+ uint32_t *offset, uint32_t frame_len)
+{
+ uint16_t ethtype;
+ const _odp_ethhdr_t *eth;
+ uint16_t macaddr0, macaddr2, macaddr4;
+ const _odp_vlanhdr_t *vlan;
+ _odp_packet_input_flags_t input_flags;
+
+ input_flags.all = 0;
+ input_flags.l2 = 1;
+ input_flags.eth = 1;
+
+ eth = (const _odp_ethhdr_t *)*parseptr;
+
+ /* Detect jumbo frames */
+ if (odp_unlikely(frame_len - *offset > _ODP_ETH_LEN_MAX))
+ input_flags.jumbo = 1;
+
+ /* Handle Ethernet broadcast/multicast addresses */
+ macaddr0 = odp_be_to_cpu_16(*((const uint16_t *)(const void *)eth));
+ if (odp_unlikely((macaddr0 & 0x0100) == 0x0100))
+ input_flags.eth_mcast = 1;
+
+ if (odp_unlikely(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));
+
+ if ((macaddr2 == 0xffff) && (macaddr4 == 0xffff))
+ input_flags.eth_bcast = 1;
+ }
+
+ /* Get Ethertype */
+ ethtype = odp_be_to_cpu_16(eth->type);
+ *offset += sizeof(*eth);
+ *parseptr += sizeof(*eth);
+
+ /* Check for SNAP vs. DIX */
+ if (odp_unlikely(ethtype < _ODP_ETH_LEN_MAX)) {
+ input_flags.snap = 1;
+ if (ethtype > frame_len - *offset) {
+ prs->flags.snap_len_err = 1;
+ ethtype = 0;
+ goto error;
+ }
+ 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 (odp_unlikely(ethtype == _ODP_ETHTYPE_VLAN_OUTER)) {
+ input_flags.vlan_qinq = 1;
+ 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) {
+ 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);
+ }
+
+ /*
+ * The packet was too short for what we parsed. We just give up
+ * entirely without trying to parse what fits in the packet.
+ */
+ if (odp_unlikely(*offset > frame_len)) {
+ input_flags.all = 0;
+ input_flags.l2 = 1;
+ ethtype = 0;
+ }
+
+error:
+ prs->input_flags.all |= input_flags.all;
+
+ return ethtype;
+}
+
+/**
+ * Parser helper function for IPv4
+ *
+ * Requires up to PARSE_IPV4_BYTES bytes of contiguous packet data.
+ */
+static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
+ uint32_t *offset, uint32_t frame_len,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ const _odp_ipv4hdr_t *ipv4 = (const _odp_ipv4hdr_t *)*parseptr;
+ uint32_t dstaddr = odp_be_to_cpu_32(ipv4->dst_addr);
+ uint32_t l3_len = odp_be_to_cpu_16(ipv4->tot_len);
+ uint16_t frag_offset = odp_be_to_cpu_16(ipv4->frag_offset);
+ uint8_t ver = _ODP_IPV4HDR_VER(ipv4->ver_ihl);
+ uint8_t ihl = _ODP_IPV4HDR_IHL(ipv4->ver_ihl);
+
+ if (odp_unlikely(ihl < _ODP_IPV4HDR_IHL_MIN ||
+ ver != 4 ||
+ sizeof(*ipv4) > frame_len - *offset ||
+ (l3_len > frame_len - *offset))) {
+ prs->flags.ip_err = 1;
+ return 0;
+ }
+
+ if (chksums.chksum.ipv4) {
+ prs->input_flags.l3_chksum_done = 1;
+ if (chksum_finalize(chksum_partial(ipv4, ihl * 4, 0)) != 0xffff) {
+ prs->flags.ip_err = 1;
+ prs->flags.l3_chksum_err = 1;
+ return 0;
+ }
+ }
+
+ *offset += ihl * 4;
+ *parseptr += ihl * 4;
+
+ if (chksums.chksum.udp || chksums.chksum.tcp)
+ *l4_part_sum = chksum_partial((const uint8_t *)&ipv4->src_addr,
+ 2 * _ODP_IPV4ADDR_LEN, 0);
+
+ if (odp_unlikely(ihl > _ODP_IPV4HDR_IHL_MIN))
+ prs->input_flags.ipopt = 1;
+
+ /* A packet is a fragment if:
+ * "more fragments" flag is set (all fragments except the last)
+ * OR
+ * "fragment offset" field is nonzero (all fragments except the first)
+ */
+ if (odp_unlikely(_ODP_IPV4HDR_IS_FRAGMENT(frag_offset)))
+ prs->input_flags.ipfrag = 1;
+
+ /* Handle IPv4 broadcast / multicast */
+ if (odp_unlikely(dstaddr == 0xffffffff))
+ prs->input_flags.ip_bcast = 1;
+
+ if (odp_unlikely((dstaddr >> 28) == 0xe))
+ prs->input_flags.ip_mcast = 1;
+
+ return ipv4->proto;
+}
+
+/**
+ * Parser helper function for IPv6
+ *
+ * Requires at least PARSE_IPV6_BYTES bytes of contiguous packet data.
+ */
+static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
+ uint32_t *offset, uint32_t frame_len,
+ uint32_t seg_len,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr;
+ const _odp_ipv6hdr_ext_t *ipv6ext;
+ uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr.u8[0]);
+ uint32_t l3_len = odp_be_to_cpu_16(ipv6->payload_len) +
+ _ODP_IPV6HDR_LEN;
+
+ /* Basic sanity checks on IPv6 header */
+ if (odp_unlikely((odp_be_to_cpu_32(ipv6->ver_tc_flow) >> 28) != 6 ||
+ sizeof(*ipv6) > frame_len - *offset ||
+ l3_len > frame_len - *offset)) {
+ prs->flags.ip_err = 1;
+ return 0;
+ }
+
+ /* IPv6 broadcast / multicast flags */
+ prs->input_flags.ip_mcast = (dstaddr0 & 0xff000000) == 0xff000000;
+ prs->input_flags.ip_bcast = 0;
+
+ /* Skip past IPv6 header */
+ *offset += sizeof(_odp_ipv6hdr_t);
+ *parseptr += sizeof(_odp_ipv6hdr_t);
+
+ if (chksums.chksum.udp || chksums.chksum.tcp)
+ *l4_part_sum = chksum_partial((const uint8_t *)&ipv6->src_addr,
+ 2 * _ODP_IPV6ADDR_LEN, 0);
+
+ /* Skip past any IPv6 extension headers */
+ if (ipv6->next_hdr == _ODP_IPPROTO_HOPOPTS ||
+ ipv6->next_hdr == _ODP_IPPROTO_ROUTE) {
+ prs->input_flags.ipopt = 1;
+
+ do {
+ ipv6ext = (const _odp_ipv6hdr_ext_t *)*parseptr;
+ uint16_t extlen = 8 + ipv6ext->ext_len * 8;
+
+ *offset += extlen;
+ *parseptr += extlen;
+ } while ((ipv6ext->next_hdr == _ODP_IPPROTO_HOPOPTS ||
+ ipv6ext->next_hdr == _ODP_IPPROTO_ROUTE) &&
+ *offset < seg_len);
+
+ if (*offset >= prs->l3_offset +
+ odp_be_to_cpu_16(ipv6->payload_len)) {
+ prs->flags.ip_err = 1;
+ return 0;
+ }
+
+ if (ipv6ext->next_hdr == _ODP_IPPROTO_FRAG)
+ prs->input_flags.ipfrag = 1;
+
+ return ipv6ext->next_hdr;
+ }
+
+ if (odp_unlikely(ipv6->next_hdr == _ODP_IPPROTO_FRAG)) {
+ prs->input_flags.ipopt = 1;
+ prs->input_flags.ipfrag = 1;
+ }
+
+ return ipv6->next_hdr;
+}
+
+/**
+ * Parser helper function for TCP
+ *
+ * Requires PARSE_TCP_BYTES bytes of contiguous packet data.
+ */
+static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr,
+ uint16_t tcp_len,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ const _odp_tcphdr_t *tcp = (const _odp_tcphdr_t *)*parseptr;
+ uint32_t len = tcp->hl * 4;
+
+ if (odp_unlikely(tcp->hl < sizeof(_odp_tcphdr_t) / sizeof(uint32_t)))
+ prs->flags.tcp_err = 1;
+
+ if (chksums.chksum.tcp &&
+ !prs->input_flags.ipfrag) {
+ *l4_part_sum += odp_cpu_to_be_16(tcp_len);
+#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
+ *l4_part_sum += _ODP_IPPROTO_TCP;
+#else
+ *l4_part_sum += _ODP_IPPROTO_TCP << 8;
+#endif
+ }
+
+ *parseptr += len;
+}
+
+/**
+ * Parser helper function for UDP
+ *
+ * Requires PARSE_UDP_BYTES bytes of contiguous packet data.
+ */
+static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ const _odp_udphdr_t *udp = (const _odp_udphdr_t *)*parseptr;
+ uint32_t udplen = odp_be_to_cpu_16(udp->length);
+ uint16_t ipsec_port = odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT);
+
+ if (odp_unlikely(udplen < sizeof(_odp_udphdr_t))) {
+ prs->flags.udp_err = 1;
+ return;
+ }
+
+ if (chksums.chksum.udp &&
+ !prs->input_flags.ipfrag) {
+ if (udp->chksum == 0) {
+ prs->input_flags.l4_chksum_done = 1;
+ prs->flags.l4_chksum_err =
+ (prs->input_flags.ipv4 != 1);
+ } else {
+ *l4_part_sum += udp->length;
+#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
+ *l4_part_sum += _ODP_IPPROTO_UDP;
+#else
+ *l4_part_sum += _ODP_IPPROTO_UDP << 8;
+#endif
+ }
+ prs->input_flags.udp_chksum_zero = (udp->chksum == 0);
+ }
+
+ if (odp_unlikely(ipsec_port == udp->dst_port && udplen > 4)) {
+ uint32_t val;
+
+ memcpy(&val, udp + 1, 4);
+ if (val != 0) {
+ prs->input_flags.ipsec = 1;
+ prs->input_flags.ipsec_udp = 1;
+ }
+ }
+
+ *parseptr += sizeof(_odp_udphdr_t);
+}
+
+/**
+ * Parser helper function for SCTP
+ *
+ * Requires PARSE_SCTP_BYTES bytes of contiguous packet data.
+ */
+static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr,
+ uint16_t sctp_len,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ if (odp_unlikely(sctp_len < sizeof(_odp_sctphdr_t))) {
+ prs->flags.sctp_err = 1;
+ return;
+ }
+
+ if (chksums.chksum.sctp &&
+ !prs->input_flags.ipfrag) {
+ const _odp_sctphdr_t *sctp =
+ (const _odp_sctphdr_t *)*parseptr;
+ uint32_t crc = ~0;
+ uint32_t zero = 0;
+
+ crc = odp_hash_crc32c(sctp, sizeof(*sctp) - 4, crc);
+ crc = odp_hash_crc32c(&zero, 4, crc);
+ *l4_part_sum = crc;
+ }
+
+ *parseptr += sizeof(_odp_sctphdr_t);
+}
+
+/* Requires up to PARSE_L3_L4_BYTES bytes of contiguous packet data. */
+int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
+ uint32_t offset,
+ uint32_t frame_len, uint32_t seg_len,
+ int layer, uint16_t ethtype,
+ odp_proto_chksums_t chksums,
+ uint64_t *l4_part_sum)
+{
+ uint8_t ip_proto;
+
+ prs->l3_offset = offset;
+
+ if (odp_unlikely(layer <= ODP_PROTO_LAYER_L2))
+ return prs->flags.all.error != 0;
+
+ /* Set l3 flag only for known ethtypes */
+ prs->input_flags.l3 = 1;
+
+ /* Parse Layer 3 headers */
+ switch (ethtype) {
+ case _ODP_ETHTYPE_IPV4:
+ prs->input_flags.ipv4 = 1;
+ ip_proto = parse_ipv4(prs, &parseptr, &offset, frame_len,
+ chksums, l4_part_sum);
+ prs->l4_offset = offset;
+ break;
+
+ case _ODP_ETHTYPE_IPV6:
+ prs->input_flags.ipv6 = 1;
+ ip_proto = parse_ipv6(prs, &parseptr, &offset, frame_len,
+ seg_len, chksums, l4_part_sum);
+ prs->l4_offset = offset;
+ break;
+
+ case _ODP_ETHTYPE_ARP:
+ prs->input_flags.arp = 1;
+ ip_proto = 255; /* Reserved invalid by IANA */
+ break;
+
+ default:
+ prs->input_flags.l3 = 0;
+ ip_proto = 255; /* Reserved invalid by IANA */
+ }
+
+ if (layer == ODP_PROTO_LAYER_L3)
+ return prs->flags.all.error != 0;
+
+ /* Set l4 flag only for known ip_proto */
+ prs->input_flags.l4 = 1;
+
+ /* Parse Layer 4 headers */
+ switch (ip_proto) {
+ case _ODP_IPPROTO_ICMPV4:
+ /* Fall through */
+
+ case _ODP_IPPROTO_ICMPV6:
+ prs->input_flags.icmp = 1;
+ break;
+
+ case _ODP_IPPROTO_IPIP:
+ /* Do nothing */
+ 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, frame_len - prs->l4_offset, chksums,
+ l4_part_sum);
+ 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, chksums, l4_part_sum);
+ 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;
+
+ case _ODP_IPPROTO_SCTP:
+ prs->input_flags.sctp = 1;
+ parse_sctp(prs, &parseptr, frame_len - prs->l4_offset, chksums,
+ l4_part_sum);
+ break;
+
+ case _ODP_IPPROTO_NO_NEXT:
+ prs->input_flags.no_next_hdr = 1;
+ break;
+
+ default:
+ prs->input_flags.l4 = 0;
+ break;
+ }
+
+ return prs->flags.all.error != 0;
+}
+
+/**
+ * Simple packet parser
+ */
+int _odp_packet_parse_layer(odp_packet_hdr_t *pkt_hdr,
+ odp_proto_layer_t layer,
+ odp_proto_chksums_t chksums)
+{
+ uint32_t seg_len = packet_first_seg_len(pkt_hdr);
+ const uint8_t *base = packet_data(pkt_hdr);
+ uint32_t offset = 0;
+ uint16_t ethtype;
+ uint64_t l4_part_sum = 0;
+ int rc;
+
+ if (odp_unlikely(layer == ODP_PROTO_LAYER_NONE))
+ return 0;
+
+ /* Assume valid L2 header, no CRC/FCS check in SW */
+ pkt_hdr->p.l2_offset = offset;
+
+ ethtype = parse_eth(&pkt_hdr->p, &base, &offset, pkt_hdr->frame_len);
+
+ rc = packet_parse_common_l3_l4(&pkt_hdr->p, base, offset,
+ pkt_hdr->frame_len,
+ seg_len, layer, ethtype, chksums,
+ &l4_part_sum);
+
+ if (rc != 0)
+ return rc;
+
+ if (layer >= ODP_PROTO_LAYER_L4)
+ return packet_l4_chksum(pkt_hdr, chksums, l4_part_sum);
+ else
+ return 0;
+}
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index 0a81e7085..208d71d8b 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -18,6 +18,7 @@
#include <odp/api/plat/packet_flag_inlines.h>
#include <odp/api/plat/queue_inlines.h>
+#include <odp_parse_internal.h>
#include <odp_classification_internal.h>
#include <odp_debug_internal.h>
#include <odp_errno_define.h>
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c
index a3cde2f90..22312f79b 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -16,6 +16,7 @@
#include <odp/api/time.h>
#include <odp/api/plat/time_inlines.h>
+#include <odp_parse_internal.h>
#include <odp_packet_io_internal.h>
#include <odp_packet_io_stats.h>
#include <odp_ethtool_stats.h>
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
index 5dd58259a..6efe0c22b 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -46,6 +46,7 @@
#include <odp/api/plat/packet_inlines.h>
+#include <odp_parse_internal.h>
#include <odp_classification_internal.h>
#include <odp_debug_internal.h>
#include <odp_global_data.h>
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index e2f0cbaae..0b46f2a33 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -15,6 +15,7 @@
#include <odp/api/ticketlock.h>
#include <odp_socket_common.h>
+#include <odp_parse_internal.h>
#include <odp_packet_internal.h>
#include <odp_packet_io_internal.h>
#include <odp_packet_io_stats.h>
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index 7710fe1dc..c3c73851f 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -16,6 +16,7 @@
#include <odp/api/plat/packet_inlines.h>
#include <odp_socket_common.h>
+#include <odp_parse_internal.h>
#include <odp_packet_internal.h>
#include <odp_packet_io_internal.h>
#include <odp_packet_io_stats.h>
diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c
index 43676d0f9..67b893417 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -38,6 +38,7 @@
#include <odp/api/plat/packet_inlines.h>
+#include <odp_parse_internal.h>
#include <odp_debug_internal.h>
#include <odp_socket_common.h>
#include <odp_packet_internal.h>