aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-dpdk/odp_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-dpdk/odp_packet.c')
-rw-r--r--platform/linux-dpdk/odp_packet.c301
1 files changed, 174 insertions, 127 deletions
diff --git a/platform/linux-dpdk/odp_packet.c b/platform/linux-dpdk/odp_packet.c
index 7cb294eb1..74864138c 100644
--- a/platform/linux-dpdk/odp_packet.c
+++ b/platform/linux-dpdk/odp_packet.c
@@ -75,12 +75,13 @@ ODP_STATIC_ASSERT(sizeof(dummy.ol_flags) == sizeof(uint64_t),
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;
@@ -194,6 +195,7 @@ int odp_packet_reset(odp_packet_t pkt, uint32_t len)
ODP_OFFSETOF(odp_packet_hdr_t, uarea_size) -
ODP_OFFSETOF(odp_packet_hdr_t, input));
+ pkt_hdr->p.parsed_layers = LAYER_NONE;
pkt_hdr->p.l3_offset = (uint32_t)ODP_PACKET_OFFSET_INVALID;
pkt_hdr->p.l4_offset = (uint32_t)ODP_PACKET_OFFSET_INVALID;
pkt_hdr->buf_hdr.next = NULL;
@@ -643,8 +645,8 @@ void *odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L3)
+ packet_parse_layer(pkt_hdr, LAYER_L3);
return packet_offset_to_ptr(pkt, len, pkt_hdr->p.l3_offset);
}
@@ -652,8 +654,8 @@ uint32_t odp_packet_l3_offset(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L3)
+ packet_parse_layer(pkt_hdr, LAYER_L3);
return pkt_hdr->p.l3_offset;
}
@@ -664,8 +666,8 @@ int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
if (odp_unlikely(offset >= (odp_packet_len(pkt) - 1)))
return -1;
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L3)
+ packet_parse_layer(pkt_hdr, LAYER_L3);
pkt_hdr->p.l3_offset = offset;
return 0;
}
@@ -674,8 +676,8 @@ void *odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L4)
+ packet_parse_layer(pkt_hdr, LAYER_L4);
return packet_offset_to_ptr(pkt, len, pkt_hdr->p.l4_offset);
}
@@ -683,8 +685,8 @@ uint32_t odp_packet_l4_offset(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L4)
+ packet_parse_layer(pkt_hdr, LAYER_L4);
return pkt_hdr->p.l4_offset;
}
@@ -695,8 +697,8 @@ int odp_packet_l4_offset_set(odp_packet_t pkt, uint32_t offset)
if (odp_unlikely(offset >= (odp_packet_len(pkt) - 1)))
return -1;
- if (packet_parse_not_complete(pkt_hdr))
- packet_parse_full(pkt_hdr);
+ if (pkt_hdr->p.parsed_layers < LAYER_L4)
+ packet_parse_layer(pkt_hdr, LAYER_L4);
pkt_hdr->p.l4_offset = offset;
return 0;
}
@@ -1303,162 +1305,207 @@ static inline void parse_udp(packet_parser_t *prs,
}
/**
- * 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);
+ switch (prs->parsed_layers) {
+ case LAYER_NONE:
+ /* Fall through */
+
+ 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;
+ }
+
+ /* Get Ethertype */
+ prs->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;
+ /* 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;
}
- 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;
+ 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);
+ }
- vlan = (const _odp_vlanhdr_t *)parseptr;
- ethtype = odp_be_to_cpu_16(vlan->type);
- offset += sizeof(_odp_vlanhdr_t);
- parseptr += sizeof(_odp_vlanhdr_t);
- }
+ /* 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;
- 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);
- }
+ 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);
+ }
- /* Set l3_offset+flag only for known ethtypes */
- prs->input_flags.l3 = 1;
- prs->l3_offset = offset;
+ prs->l3_offset = offset;
+ prs->parsed_layers = LAYER_L2;
+ if (layer == LAYER_L2)
+ return prs->error_flags.all != 0;
+ }
+ /* Fall through */
+
+ 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;
- /* 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;
+ 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_IPV6:
- prs->input_flags.ipv6 = 1;
- 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;
- case _ODP_ETHTYPE_ARP:
- prs->input_flags.arp = 1;
- 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 */
+ }
- default:
- prs->input_flags.l3 = 0;
- prs->l3_offset = ODP_PACKET_OFFSET_INVALID;
- ip_proto = 255; /* Reserved invalid by IANA */
+ /* 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;
}
+ /* Fall through */
+
+ 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;
- /* Set l4_offset+flag only for known ip_proto */
- prs->input_flags.l4 = 1;
- prs->l4_offset = offset;
+ 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;
- /* Parse Layer 4 headers */
- switch (ip_proto) {
- case _ODP_IPPROTO_ICMP:
- prs->input_flags.icmp = 1;
- 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_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_AH:
+ prs->input_flags.ipsec = 1;
+ prs->input_flags.ipsec_ah = 1;
+ 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_ESP:
+ prs->input_flags.ipsec = 1;
+ prs->input_flags.ipsec_esp = 1;
+ break;
+
+ case _ODP_IPPROTO_SCTP:
+ prs->input_flags.sctp = 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;
}
/**
* Simple packet parser
*/
-int packet_parse_full(odp_packet_hdr_t *pkt_hdr)
+int packet_parse_layer(odp_packet_hdr_t *pkt_hdr, layer_t layer)
{
uint32_t seg_len = odp_packet_seg_len((odp_packet_t)pkt_hdr);
uint32_t len = packet_len(pkt_hdr);
void *base = odp_packet_data((odp_packet_t)pkt_hdr);
- return packet_parse_common(&pkt_hdr->p, base, len, seg_len);
+ return packet_parse_common(&pkt_hdr->p, base, len, seg_len, layer);
}