aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatias Elo <matias.elo@nokia.com>2016-09-13 17:30:10 +0300
committerMaxim Uvarov <maxim.uvarov@linaro.org>2016-10-24 15:49:56 +0300
commit144a1d8c4d0265ff3ff6ae740b4e99045645e59d (patch)
tree3a5c3febbb4db9257589fbe46673c1ef8bbc3803
parente89d5d15852b9a64e3aaf115b59c87d07092717d (diff)
linux-gen: packet: enable parsing only selected packet header layers
Enable parsing packet headers up to a given protocol layer. Signed-off-by: Matias Elo <matias.elo@nokia.com> Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
-rw-r--r--platform/linux-generic/include/odp_packet_internal.h24
-rw-r--r--platform/linux-generic/odp_classification.c2
-rw-r--r--platform/linux-generic/odp_packet.c293
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 392d67052..9b4f59e98 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 ea223bfb2..868058da5 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 c4cf32467..5f84869c4 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);
}