1aa97dd1cSKonstantin Ananyev/*
2aa97dd1cSKonstantin Ananyev * Copyright (c) 2016  Intel Corporation.
3aa97dd1cSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
4aa97dd1cSKonstantin Ananyev * you may not use this file except in compliance with the License.
5aa97dd1cSKonstantin Ananyev * You may obtain a copy of the License at:
6aa97dd1cSKonstantin Ananyev *
7aa97dd1cSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
8aa97dd1cSKonstantin Ananyev *
9aa97dd1cSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
10aa97dd1cSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
11aa97dd1cSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12aa97dd1cSKonstantin Ananyev * See the License for the specific language governing permissions and
13aa97dd1cSKonstantin Ananyev * limitations under the License.
14aa97dd1cSKonstantin Ananyev */
15aa97dd1cSKonstantin Ananyev
16aa97dd1cSKonstantin Ananyev#include <netinet/ip6.h>
17aa97dd1cSKonstantin Ananyev#include <rte_arp.h>
18aa97dd1cSKonstantin Ananyev
19aa97dd1cSKonstantin Ananyev#include "netbe.h"
205c795f7bSKonstantin Ananyev#include "dpdk_legacy.h"
21aa97dd1cSKonstantin Ananyev
22fbba0a3bSMohammad Abdul Awalstruct ptype2cb {
23fbba0a3bSMohammad Abdul Awal	uint32_t mask;
24fbba0a3bSMohammad Abdul Awal	const char *name;
25fbba0a3bSMohammad Abdul Awal	rte_rx_callback_fn fn;
26fbba0a3bSMohammad Abdul Awal};
27fbba0a3bSMohammad Abdul Awal
28fbba0a3bSMohammad Abdul Awalenum {
29fbba0a3bSMohammad Abdul Awal	ETHER_PTYPE = 0x1,
30fbba0a3bSMohammad Abdul Awal	IPV4_PTYPE = 0x2,
31fbba0a3bSMohammad Abdul Awal	IPV4_EXT_PTYPE = 0x4,
32fbba0a3bSMohammad Abdul Awal	IPV6_PTYPE = 0x8,
33fbba0a3bSMohammad Abdul Awal	IPV6_EXT_PTYPE = 0x10,
34fbba0a3bSMohammad Abdul Awal	TCP_PTYPE = 0x20,
35fbba0a3bSMohammad Abdul Awal	UDP_PTYPE = 0x40,
36fbba0a3bSMohammad Abdul Awal};
37fbba0a3bSMohammad Abdul Awal
38aa97dd1cSKonstantin Ananyevstatic inline uint64_t
39aa97dd1cSKonstantin Ananyev_mbuf_tx_offload(uint64_t il2, uint64_t il3, uint64_t il4, uint64_t tso,
40aa97dd1cSKonstantin Ananyev	uint64_t ol3, uint64_t ol2)
41aa97dd1cSKonstantin Ananyev{
42aa97dd1cSKonstantin Ananyev	return il2 | il3 << 7 | il4 << 16 | tso << 24 | ol3 << 40 | ol2 << 49;
43aa97dd1cSKonstantin Ananyev}
44aa97dd1cSKonstantin Ananyev
45aa97dd1cSKonstantin Ananyevstatic inline void
46aa97dd1cSKonstantin Ananyevfill_pkt_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t l3, uint32_t l4)
47aa97dd1cSKonstantin Ananyev{
48aa97dd1cSKonstantin Ananyev	m->tx_offload = _mbuf_tx_offload(l2, l3, l4, 0, 0, 0);
49aa97dd1cSKonstantin Ananyev}
50aa97dd1cSKonstantin Ananyev
51aa97dd1cSKonstantin Ananyevstatic inline int
52aa97dd1cSKonstantin Ananyevis_ipv4_frag(const struct ipv4_hdr *iph)
53aa97dd1cSKonstantin Ananyev{
54aa97dd1cSKonstantin Ananyev	const uint16_t mask = rte_cpu_to_be_16(~IPV4_HDR_DF_FLAG);
55aa97dd1cSKonstantin Ananyev
56aa97dd1cSKonstantin Ananyev	return ((mask & iph->fragment_offset) != 0);
57aa97dd1cSKonstantin Ananyev}
58aa97dd1cSKonstantin Ananyev
59aa97dd1cSKonstantin Ananyevstatic inline uint32_t
60aa97dd1cSKonstantin Ananyevget_tcp_header_size(struct rte_mbuf *m, uint32_t l2_len, uint32_t l3_len)
61aa97dd1cSKonstantin Ananyev{
62aa97dd1cSKonstantin Ananyev	const struct tcp_hdr *tcp;
63aa97dd1cSKonstantin Ananyev
64aa97dd1cSKonstantin Ananyev	tcp = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *, l2_len + l3_len);
65aa97dd1cSKonstantin Ananyev	return (tcp->data_off >> 4) * 4;
66aa97dd1cSKonstantin Ananyev}
67aa97dd1cSKonstantin Ananyev
68aa97dd1cSKonstantin Ananyevstatic inline void
69aa97dd1cSKonstantin Ananyevadjust_ipv4_pktlen(struct rte_mbuf *m, uint32_t l2_len)
70aa97dd1cSKonstantin Ananyev{
71aa97dd1cSKonstantin Ananyev	uint32_t plen, trim;
72aa97dd1cSKonstantin Ananyev	const struct ipv4_hdr *iph;
73aa97dd1cSKonstantin Ananyev
74aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2_len);
75aa97dd1cSKonstantin Ananyev	plen = rte_be_to_cpu_16(iph->total_length) + l2_len;
76aa97dd1cSKonstantin Ananyev	if (plen < m->pkt_len) {
77aa97dd1cSKonstantin Ananyev		trim = m->pkt_len - plen;
78aa97dd1cSKonstantin Ananyev		rte_pktmbuf_trim(m, trim);
79aa97dd1cSKonstantin Ananyev	}
80aa97dd1cSKonstantin Ananyev}
81aa97dd1cSKonstantin Ananyev
82aa97dd1cSKonstantin Ananyevstatic inline void
83aa97dd1cSKonstantin Ananyevadjust_ipv6_pktlen(struct rte_mbuf *m, uint32_t l2_len)
84aa97dd1cSKonstantin Ananyev{
85aa97dd1cSKonstantin Ananyev	uint32_t plen, trim;
86aa97dd1cSKonstantin Ananyev	const struct ipv6_hdr *iph;
87aa97dd1cSKonstantin Ananyev
88aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *, l2_len);
89aa97dd1cSKonstantin Ananyev	plen = rte_be_to_cpu_16(iph->payload_len) + sizeof(*iph) + l2_len;
90aa97dd1cSKonstantin Ananyev	if (plen < m->pkt_len) {
91aa97dd1cSKonstantin Ananyev		trim = m->pkt_len - plen;
92aa97dd1cSKonstantin Ananyev		rte_pktmbuf_trim(m, trim);
93aa97dd1cSKonstantin Ananyev	}
94aa97dd1cSKonstantin Ananyev}
95aa97dd1cSKonstantin Ananyev
96aa97dd1cSKonstantin Ananyevstatic inline void
97aa97dd1cSKonstantin Ananyevtcp_stat_update(struct netbe_lcore *lc, const struct rte_mbuf *m,
98aa97dd1cSKonstantin Ananyev	uint32_t l2_len, uint32_t l3_len)
99aa97dd1cSKonstantin Ananyev{
100aa97dd1cSKonstantin Ananyev	const struct tcp_hdr *th;
101aa97dd1cSKonstantin Ananyev
102aa97dd1cSKonstantin Ananyev	th = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *, l2_len + l3_len);
103aa97dd1cSKonstantin Ananyev	lc->tcp_stat.flags[th->tcp_flags]++;
104aa97dd1cSKonstantin Ananyev}
105aa97dd1cSKonstantin Ananyev
106aa97dd1cSKonstantin Ananyevstatic inline uint32_t
107aa97dd1cSKonstantin Ananyevget_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto, uint32_t frag)
108aa97dd1cSKonstantin Ananyev{
109aa97dd1cSKonstantin Ananyev	const struct ipv4_hdr *iph;
110aa97dd1cSKonstantin Ananyev	int32_t dlen, len;
111aa97dd1cSKonstantin Ananyev
112aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
113aa97dd1cSKonstantin Ananyev	dlen -= l2;
114aa97dd1cSKonstantin Ananyev
115aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2);
116aa97dd1cSKonstantin Ananyev	len = (iph->version_ihl & IPV4_HDR_IHL_MASK) * IPV4_IHL_MULTIPLIER;
117aa97dd1cSKonstantin Ananyev
118aa97dd1cSKonstantin Ananyev	if (frag != 0 && is_ipv4_frag(iph)) {
119aa97dd1cSKonstantin Ananyev		m->packet_type &= ~RTE_PTYPE_L4_MASK;
120aa97dd1cSKonstantin Ananyev		m->packet_type |= RTE_PTYPE_L4_FRAG;
121aa97dd1cSKonstantin Ananyev	}
122aa97dd1cSKonstantin Ananyev
123aa97dd1cSKonstantin Ananyev	if (len > dlen || (proto <= IPPROTO_MAX && iph->next_proto_id != proto))
124aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
125aa97dd1cSKonstantin Ananyev
126aa97dd1cSKonstantin Ananyev	return len;
127aa97dd1cSKonstantin Ananyev}
128aa97dd1cSKonstantin Ananyev
129aa97dd1cSKonstantin Ananyevstatic inline void
130aa97dd1cSKonstantin Ananyevfill_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto,
131aa97dd1cSKonstantin Ananyev	uint32_t frag, uint32_t l4_len)
132aa97dd1cSKonstantin Ananyev{
133aa97dd1cSKonstantin Ananyev	uint32_t len;
134aa97dd1cSKonstantin Ananyev
135aa97dd1cSKonstantin Ananyev	len = get_ipv4_hdr_len(m, l2, proto, frag);
136aa97dd1cSKonstantin Ananyev	fill_pkt_hdr_len(m, l2, len, l4_len);
137aa97dd1cSKonstantin Ananyev	adjust_ipv4_pktlen(m, l2);
138aa97dd1cSKonstantin Ananyev}
139aa97dd1cSKonstantin Ananyev
140aa97dd1cSKonstantin Ananyevstatic inline int
141aa97dd1cSKonstantin Ananyevipv6x_hdr(uint32_t proto)
142aa97dd1cSKonstantin Ananyev{
143aa97dd1cSKonstantin Ananyev	return (proto == IPPROTO_HOPOPTS ||
144aa97dd1cSKonstantin Ananyev		proto == IPPROTO_ROUTING ||
145aa97dd1cSKonstantin Ananyev		proto == IPPROTO_FRAGMENT ||
146aa97dd1cSKonstantin Ananyev		proto == IPPROTO_AH ||
147aa97dd1cSKonstantin Ananyev		proto == IPPROTO_NONE ||
148aa97dd1cSKonstantin Ananyev		proto == IPPROTO_DSTOPTS);
149aa97dd1cSKonstantin Ananyev}
150aa97dd1cSKonstantin Ananyev
151aa97dd1cSKonstantin Ananyevstatic inline uint32_t
152aa97dd1cSKonstantin Ananyevget_ipv6x_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t nproto,
153aa97dd1cSKonstantin Ananyev	uint32_t fproto)
154aa97dd1cSKonstantin Ananyev{
155aa97dd1cSKonstantin Ananyev	const struct ip6_ext *ipx;
156aa97dd1cSKonstantin Ananyev	int32_t dlen, len, ofs;
157aa97dd1cSKonstantin Ananyev
158aa97dd1cSKonstantin Ananyev	len = sizeof(struct ipv6_hdr);
159aa97dd1cSKonstantin Ananyev
160aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
161aa97dd1cSKonstantin Ananyev	dlen -= l2;
162aa97dd1cSKonstantin Ananyev
163aa97dd1cSKonstantin Ananyev	ofs = l2 + len;
164aa97dd1cSKonstantin Ananyev	ipx = rte_pktmbuf_mtod_offset(m, const struct ip6_ext *, ofs);
165aa97dd1cSKonstantin Ananyev
166aa97dd1cSKonstantin Ananyev	while (ofs > 0 && len < dlen) {
167aa97dd1cSKonstantin Ananyev
168aa97dd1cSKonstantin Ananyev		switch (nproto) {
169aa97dd1cSKonstantin Ananyev		case IPPROTO_HOPOPTS:
170aa97dd1cSKonstantin Ananyev		case IPPROTO_ROUTING:
171aa97dd1cSKonstantin Ananyev		case IPPROTO_DSTOPTS:
172aa97dd1cSKonstantin Ananyev			ofs = (ipx->ip6e_len + 1) << 3;
173aa97dd1cSKonstantin Ananyev			break;
174aa97dd1cSKonstantin Ananyev		case IPPROTO_AH:
175aa97dd1cSKonstantin Ananyev			ofs = (ipx->ip6e_len + 2) << 2;
176aa97dd1cSKonstantin Ananyev			break;
177aa97dd1cSKonstantin Ananyev		case IPPROTO_FRAGMENT:
178aa97dd1cSKonstantin Ananyev			/*
179aa97dd1cSKonstantin Ananyev			 * tso_segsz is not used by RX, so use it as temporary
180aa97dd1cSKonstantin Ananyev			 * buffer to store the fragment offset.
181aa97dd1cSKonstantin Ananyev			 */
182aa97dd1cSKonstantin Ananyev			m->tso_segsz = ofs;
183aa97dd1cSKonstantin Ananyev			ofs = sizeof(struct ip6_frag);
184aa97dd1cSKonstantin Ananyev			m->packet_type &= ~RTE_PTYPE_L4_MASK;
185aa97dd1cSKonstantin Ananyev			m->packet_type |= RTE_PTYPE_L4_FRAG;
186aa97dd1cSKonstantin Ananyev			break;
187aa97dd1cSKonstantin Ananyev		default:
188aa97dd1cSKonstantin Ananyev			ofs = 0;
189aa97dd1cSKonstantin Ananyev		}
190aa97dd1cSKonstantin Ananyev
191aa97dd1cSKonstantin Ananyev		if (ofs > 0) {
192aa97dd1cSKonstantin Ananyev			nproto = ipx->ip6e_nxt;
193aa97dd1cSKonstantin Ananyev			len += ofs;
194aa97dd1cSKonstantin Ananyev			ipx += ofs / sizeof(*ipx);
195aa97dd1cSKonstantin Ananyev		}
196aa97dd1cSKonstantin Ananyev	}
197aa97dd1cSKonstantin Ananyev
198aa97dd1cSKonstantin Ananyev	/* unrecognized or invalid packet. */
199aa97dd1cSKonstantin Ananyev	if ((ofs == 0 && nproto != fproto) || len > dlen)
200aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
201aa97dd1cSKonstantin Ananyev
202aa97dd1cSKonstantin Ananyev	return len;
203aa97dd1cSKonstantin Ananyev}
204aa97dd1cSKonstantin Ananyev
205aa97dd1cSKonstantin Ananyevstatic inline uint32_t
206aa97dd1cSKonstantin Ananyevget_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto)
207aa97dd1cSKonstantin Ananyev{
208aa97dd1cSKonstantin Ananyev	const struct ipv6_hdr *iph;
209aa97dd1cSKonstantin Ananyev
210aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *,
211aa97dd1cSKonstantin Ananyev		sizeof(struct ether_hdr));
212aa97dd1cSKonstantin Ananyev
213aa97dd1cSKonstantin Ananyev	if (iph->proto == fproto)
214aa97dd1cSKonstantin Ananyev		return sizeof(struct ipv6_hdr);
215aa97dd1cSKonstantin Ananyev	else if (ipv6x_hdr(iph->proto) != 0)
216aa97dd1cSKonstantin Ananyev		return get_ipv6x_hdr_len(m, l2, iph->proto, fproto);
217aa97dd1cSKonstantin Ananyev
218aa97dd1cSKonstantin Ananyev	m->packet_type = RTE_PTYPE_UNKNOWN;
219aa97dd1cSKonstantin Ananyev	return 0;
220aa97dd1cSKonstantin Ananyev}
221aa97dd1cSKonstantin Ananyev
222aa97dd1cSKonstantin Ananyevstatic inline void
223aa97dd1cSKonstantin Ananyevfill_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto,
224aa97dd1cSKonstantin Ananyev	uint32_t l4_len)
225aa97dd1cSKonstantin Ananyev{
226aa97dd1cSKonstantin Ananyev	uint32_t len;
227aa97dd1cSKonstantin Ananyev
228aa97dd1cSKonstantin Ananyev	len = get_ipv6_hdr_len(m, l2, fproto);
229aa97dd1cSKonstantin Ananyev	fill_pkt_hdr_len(m, l2, len, l4_len);
230aa97dd1cSKonstantin Ananyev	adjust_ipv6_pktlen(m, l2);
231aa97dd1cSKonstantin Ananyev}
232aa97dd1cSKonstantin Ananyev
233aa97dd1cSKonstantin Ananyevstatic inline struct rte_mbuf *
2345c795f7bSKonstantin Ananyevhandle_arp(struct rte_mbuf *m, struct netbe_lcore *lc, dpdk_port_t port,
235aa97dd1cSKonstantin Ananyev	uint32_t l2len)
236aa97dd1cSKonstantin Ananyev{
237aa97dd1cSKonstantin Ananyev	const struct arp_hdr *ahdr;
238aa97dd1cSKonstantin Ananyev	struct pkt_buf *abuf;
239aa97dd1cSKonstantin Ananyev
240aa97dd1cSKonstantin Ananyev	ahdr = rte_pktmbuf_mtod_offset(m, const struct arp_hdr *, l2len);
241aa97dd1cSKonstantin Ananyev
242aa97dd1cSKonstantin Ananyev	if (ahdr->arp_hrd != rte_be_to_cpu_16(ARP_HRD_ETHER) ||
243aa97dd1cSKonstantin Ananyev		ahdr->arp_pro != rte_be_to_cpu_16(ETHER_TYPE_IPv4) ||
244aa97dd1cSKonstantin Ananyev		ahdr->arp_op != rte_be_to_cpu_16(ARP_OP_REQUEST)) {
245aa97dd1cSKonstantin Ananyev
246aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
247aa97dd1cSKonstantin Ananyev		return m;
248aa97dd1cSKonstantin Ananyev	}
249aa97dd1cSKonstantin Ananyev
250aa97dd1cSKonstantin Ananyev	m->l2_len = l2len;
251aa97dd1cSKonstantin Ananyev	abuf = &lc->prtq[port].arp_buf;
252aa97dd1cSKonstantin Ananyev	if (abuf->num >= RTE_DIM(abuf->pkt))
253aa97dd1cSKonstantin Ananyev		return m;
254aa97dd1cSKonstantin Ananyev
255aa97dd1cSKonstantin Ananyev	abuf->pkt[abuf->num++] = m;
256aa97dd1cSKonstantin Ananyev
257aa97dd1cSKonstantin Ananyev	return NULL;
258aa97dd1cSKonstantin Ananyev}
259aa97dd1cSKonstantin Ananyev
260aa97dd1cSKonstantin Ananyevstatic inline struct rte_mbuf *
261aa97dd1cSKonstantin Ananyevfill_eth_tcp_arp_hdr_len(struct rte_mbuf *m, struct netbe_lcore *lc,
2625c795f7bSKonstantin Ananyev	dpdk_port_t port)
263aa97dd1cSKonstantin Ananyev{
264aa97dd1cSKonstantin Ananyev	uint32_t dlen, l2_len, l3_len, l4_len;
265aa97dd1cSKonstantin Ananyev	uint16_t etp;
266aa97dd1cSKonstantin Ananyev	const struct ether_hdr *eth;
267aa97dd1cSKonstantin Ananyev
268aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
269aa97dd1cSKonstantin Ananyev
270aa97dd1cSKonstantin Ananyev	/* check that first segment is at least 54B long. */
271aa97dd1cSKonstantin Ananyev	if (dlen < sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
272aa97dd1cSKonstantin Ananyev			sizeof(struct tcp_hdr)) {
273aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
274aa97dd1cSKonstantin Ananyev		return m;
275aa97dd1cSKonstantin Ananyev	}
276aa97dd1cSKonstantin Ananyev
277aa97dd1cSKonstantin Ananyev	l2_len = sizeof(*eth);
278aa97dd1cSKonstantin Ananyev
279aa97dd1cSKonstantin Ananyev	eth = rte_pktmbuf_mtod(m, const struct ether_hdr *);
280aa97dd1cSKonstantin Ananyev	etp = eth->ether_type;
281aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_VLAN))
282aa97dd1cSKonstantin Ananyev		l2_len += sizeof(struct vlan_hdr);
283aa97dd1cSKonstantin Ananyev
284aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_ARP))
285aa97dd1cSKonstantin Ananyev		return handle_arp(m, lc, port, l2_len);
286aa97dd1cSKonstantin Ananyev
287aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) {
288aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_TCP |
289aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
290aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
291aa97dd1cSKonstantin Ananyev		l3_len = get_ipv4_hdr_len(m, l2_len, IPPROTO_TCP, 1);
292aa97dd1cSKonstantin Ananyev		l4_len = get_tcp_header_size(m, l2_len, l3_len);
293aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
294aa97dd1cSKonstantin Ananyev		adjust_ipv4_pktlen(m, l2_len);
295aa97dd1cSKonstantin Ananyev	} else if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv6) &&
296aa97dd1cSKonstantin Ananyev			dlen >= l2_len + sizeof(struct ipv6_hdr) +
297aa97dd1cSKonstantin Ananyev			sizeof(struct tcp_hdr)) {
298aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_TCP |
299aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
300aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
301aa97dd1cSKonstantin Ananyev		l3_len = get_ipv6_hdr_len(m, l2_len, IPPROTO_TCP);
302aa97dd1cSKonstantin Ananyev		l4_len = get_tcp_header_size(m, l2_len, l3_len);
303aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
304aa97dd1cSKonstantin Ananyev		adjust_ipv6_pktlen(m, l2_len);
305aa97dd1cSKonstantin Ananyev	} else
306aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
307aa97dd1cSKonstantin Ananyev
308aa97dd1cSKonstantin Ananyev	return m;
309aa97dd1cSKonstantin Ananyev}
310aa97dd1cSKonstantin Ananyev
311aa97dd1cSKonstantin Ananyevstatic inline void
312aa97dd1cSKonstantin Ananyevfill_eth_tcp_hdr_len(struct rte_mbuf *m)
313aa97dd1cSKonstantin Ananyev{
314aa97dd1cSKonstantin Ananyev	uint32_t dlen, l2_len, l3_len, l4_len;
315aa97dd1cSKonstantin Ananyev	uint16_t etp;
316aa97dd1cSKonstantin Ananyev	const struct ether_hdr *eth;
317aa97dd1cSKonstantin Ananyev
318aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
319aa97dd1cSKonstantin Ananyev
320aa97dd1cSKonstantin Ananyev	/* check that first segment is at least 54B long. */
321aa97dd1cSKonstantin Ananyev	if (dlen < sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
322aa97dd1cSKonstantin Ananyev			sizeof(struct tcp_hdr)) {
323aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
324aa97dd1cSKonstantin Ananyev		return;
325aa97dd1cSKonstantin Ananyev	}
326aa97dd1cSKonstantin Ananyev
327aa97dd1cSKonstantin Ananyev	l2_len = sizeof(*eth);
328aa97dd1cSKonstantin Ananyev
329aa97dd1cSKonstantin Ananyev	eth = rte_pktmbuf_mtod(m, const struct ether_hdr *);
330aa97dd1cSKonstantin Ananyev	etp = eth->ether_type;
331aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_VLAN))
332aa97dd1cSKonstantin Ananyev		l2_len += sizeof(struct vlan_hdr);
333aa97dd1cSKonstantin Ananyev
334aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) {
335aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_TCP |
336aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
337aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
338aa97dd1cSKonstantin Ananyev		l3_len = get_ipv4_hdr_len(m, l2_len, IPPROTO_TCP, 1);
339aa97dd1cSKonstantin Ananyev		l4_len = get_tcp_header_size(m, l2_len, l3_len);
340aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
341aa97dd1cSKonstantin Ananyev		adjust_ipv4_pktlen(m, l2_len);
342aa97dd1cSKonstantin Ananyev	} else if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv6) &&
343aa97dd1cSKonstantin Ananyev			dlen >= l2_len + sizeof(struct ipv6_hdr) +
344aa97dd1cSKonstantin Ananyev			sizeof(struct tcp_hdr)) {
345aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_TCP |
346aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
347aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
348aa97dd1cSKonstantin Ananyev		l3_len = get_ipv6_hdr_len(m, l2_len, IPPROTO_TCP);
349aa97dd1cSKonstantin Ananyev		l4_len = get_tcp_header_size(m, l2_len, l3_len);
350aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
351aa97dd1cSKonstantin Ananyev		adjust_ipv6_pktlen(m, l2_len);
352aa97dd1cSKonstantin Ananyev	} else
353aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
354aa97dd1cSKonstantin Ananyev}
355aa97dd1cSKonstantin Ananyev
356aa97dd1cSKonstantin Ananyevstatic inline void
357aa97dd1cSKonstantin Ananyevfill_eth_udp_hdr_len(struct rte_mbuf *m)
358aa97dd1cSKonstantin Ananyev{
359aa97dd1cSKonstantin Ananyev	uint32_t dlen, l2_len;
360aa97dd1cSKonstantin Ananyev	uint16_t etp;
361aa97dd1cSKonstantin Ananyev	const struct ether_hdr *eth;
362aa97dd1cSKonstantin Ananyev
363aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
364aa97dd1cSKonstantin Ananyev
365aa97dd1cSKonstantin Ananyev	/* check that first segment is at least 42B long. */
366aa97dd1cSKonstantin Ananyev	if (dlen < sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
367aa97dd1cSKonstantin Ananyev			sizeof(struct udp_hdr)) {
368aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
369aa97dd1cSKonstantin Ananyev		return;
370aa97dd1cSKonstantin Ananyev	}
371aa97dd1cSKonstantin Ananyev
372aa97dd1cSKonstantin Ananyev	l2_len = sizeof(*eth);