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 "test_common.h"
17aa97dd1cSKonstantin Ananyev
18aa97dd1cSKonstantin Ananyevint
195c795f7bSKonstantin Ananyevport_init(dpdk_port_t port, struct rte_mempool *mbuf_pool)
20aa97dd1cSKonstantin Ananyev{
21aa97dd1cSKonstantin Ananyev	struct rte_eth_conf port_conf;
22aa97dd1cSKonstantin Ananyev	const uint16_t rx_rings = 1, tx_rings = 1;
23aa97dd1cSKonstantin Ananyev	uint16_t q;
24aa97dd1cSKonstantin Ananyev	int retval;
25aa97dd1cSKonstantin Ananyev	int socket_id;
26aa97dd1cSKonstantin Ananyev
27aa97dd1cSKonstantin Ananyev	socket_id = rte_eth_dev_socket_id(port);
28aa97dd1cSKonstantin Ananyev
29aa97dd1cSKonstantin Ananyev	memset(&port_conf, 0, sizeof(struct rte_eth_conf));
30aa97dd1cSKonstantin Ananyev	port_conf.rxmode.max_rx_pkt_len = ETHER_MAX_LEN;
31aa97dd1cSKonstantin Ananyev
32aa97dd1cSKonstantin Ananyev	/* Configure the Ethernet device. */
33aa97dd1cSKonstantin Ananyev	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
34aa97dd1cSKonstantin Ananyev	if (retval != 0)
35aa97dd1cSKonstantin Ananyev		return retval;
36aa97dd1cSKonstantin Ananyev
37aa97dd1cSKonstantin Ananyev	/* Allocate and set up 1 RX queue per Ethernet port. */
38aa97dd1cSKonstantin Ananyev	for (q = 0; q < rx_rings; q++) {
39aa97dd1cSKonstantin Ananyev		retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
40aa97dd1cSKonstantin Ananyev				socket_id, NULL, mbuf_pool);
41aa97dd1cSKonstantin Ananyev		if (retval < 0)
42aa97dd1cSKonstantin Ananyev			return retval;
43aa97dd1cSKonstantin Ananyev	}
44aa97dd1cSKonstantin Ananyev
45aa97dd1cSKonstantin Ananyev	/* Allocate and set up 1 TX queue per Ethernet port. */
46aa97dd1cSKonstantin Ananyev	for (q = 0; q < tx_rings; q++) {
47aa97dd1cSKonstantin Ananyev		retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
48aa97dd1cSKonstantin Ananyev				socket_id, NULL);
49aa97dd1cSKonstantin Ananyev		if (retval < 0)
50aa97dd1cSKonstantin Ananyev			return retval;
51aa97dd1cSKonstantin Ananyev	}
52aa97dd1cSKonstantin Ananyev
53aa97dd1cSKonstantin Ananyev	/* Start the Ethernet port. */
54aa97dd1cSKonstantin Ananyev	retval = rte_eth_dev_start(port);
55aa97dd1cSKonstantin Ananyev	if (retval < 0)
56aa97dd1cSKonstantin Ananyev		return retval;
57aa97dd1cSKonstantin Ananyev
58aa97dd1cSKonstantin Ananyev	/* Enable RX in promiscuous mode for the Ethernet device. */
59aa97dd1cSKonstantin Ananyev	rte_eth_promiscuous_enable(port);
60aa97dd1cSKonstantin Ananyev
61aa97dd1cSKonstantin Ananyev	return 0;
62aa97dd1cSKonstantin Ananyev}
63aa97dd1cSKonstantin Ananyev
64aa97dd1cSKonstantin Ananyev/* TODO: Shameless rip of examples/udpfwd/pkt.c below. Sorry Would like to
65aa97dd1cSKonstantin Ananyev * move these funcions to separate lib so all future created apps could
66aa97dd1cSKonstantin Ananyev * re-use that code.
67aa97dd1cSKonstantin Ananyev */
68aa97dd1cSKonstantin Ananyevvoid
69aa97dd1cSKonstantin Ananyevfill_pkt_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t l3, uint32_t l4)
70aa97dd1cSKonstantin Ananyev{
71aa97dd1cSKonstantin Ananyev	m->l2_len = l2;
72aa97dd1cSKonstantin Ananyev	m->l3_len = l3;
73aa97dd1cSKonstantin Ananyev	m->l4_len = l4;
74aa97dd1cSKonstantin Ananyev	m->tso_segsz = 0;
75aa97dd1cSKonstantin Ananyev	m->outer_l2_len = 0;
76aa97dd1cSKonstantin Ananyev	m->outer_l3_len = 0;
77aa97dd1cSKonstantin Ananyev}
78aa97dd1cSKonstantin Ananyev
79aa97dd1cSKonstantin Ananyevint
80aa97dd1cSKonstantin Ananyevis_ipv4_frag(const struct ipv4_hdr *iph)
81aa97dd1cSKonstantin Ananyev{
82aa97dd1cSKonstantin Ananyev	const uint16_t mask = rte_cpu_to_be_16(~IPV4_HDR_DF_FLAG);
83aa97dd1cSKonstantin Ananyev
84aa97dd1cSKonstantin Ananyev	return ((mask & iph->fragment_offset) != 0);
85aa97dd1cSKonstantin Ananyev}
86aa97dd1cSKonstantin Ananyev
87aa97dd1cSKonstantin Ananyevvoid
88aa97dd1cSKonstantin Ananyevfill_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto,
89aa97dd1cSKonstantin Ananyev	uint32_t frag)
90aa97dd1cSKonstantin Ananyev{
91aa97dd1cSKonstantin Ananyev	const struct ipv4_hdr *iph;
92aa97dd1cSKonstantin Ananyev	int32_t dlen, len;
93aa97dd1cSKonstantin Ananyev
94aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
95aa97dd1cSKonstantin Ananyev	dlen -= l2 + sizeof(struct udp_hdr);
96aa97dd1cSKonstantin Ananyev
97aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2);
98aa97dd1cSKonstantin Ananyev	len = (iph->version_ihl & IPV4_HDR_IHL_MASK) * IPV4_IHL_MULTIPLIER;
99aa97dd1cSKonstantin Ananyev
100aa97dd1cSKonstantin Ananyev	if (frag != 0 && is_ipv4_frag(iph)) {
101aa97dd1cSKonstantin Ananyev		m->packet_type &= ~RTE_PTYPE_L4_MASK;
102aa97dd1cSKonstantin Ananyev		m->packet_type |= RTE_PTYPE_L4_FRAG;
103aa97dd1cSKonstantin Ananyev	}
104aa97dd1cSKonstantin Ananyev
105aa97dd1cSKonstantin Ananyev	if (len > dlen || (proto <= IPPROTO_MAX && iph->next_proto_id != proto))
106aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
107aa97dd1cSKonstantin Ananyev	else
108aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2, len, sizeof(struct udp_hdr));
109aa97dd1cSKonstantin Ananyev}
110aa97dd1cSKonstantin Ananyev
111aa97dd1cSKonstantin Ananyevint
112aa97dd1cSKonstantin Ananyevipv6x_hdr(uint32_t proto)
113aa97dd1cSKonstantin Ananyev{
114aa97dd1cSKonstantin Ananyev	return (proto == IPPROTO_HOPOPTS ||
115aa97dd1cSKonstantin Ananyev		proto == IPPROTO_ROUTING ||
116aa97dd1cSKonstantin Ananyev		proto == IPPROTO_FRAGMENT ||
117aa97dd1cSKonstantin Ananyev		proto == IPPROTO_AH ||
118aa97dd1cSKonstantin Ananyev		proto == IPPROTO_NONE ||
119aa97dd1cSKonstantin Ananyev		proto == IPPROTO_DSTOPTS);
120aa97dd1cSKonstantin Ananyev}
121aa97dd1cSKonstantin Ananyev
122aa97dd1cSKonstantin Ananyevuint16_t
123aa97dd1cSKonstantin Ananyevipv4x_cksum(const void *iph, size_t len)
124aa97dd1cSKonstantin Ananyev{
125aa97dd1cSKonstantin Ananyev        uint16_t cksum;
126aa97dd1cSKonstantin Ananyev
127aa97dd1cSKonstantin Ananyev        cksum = rte_raw_cksum(iph, len);
128aa97dd1cSKonstantin Ananyev        return (cksum == 0xffff) ? cksum : ~cksum;
129aa97dd1cSKonstantin Ananyev}
130aa97dd1cSKonstantin Ananyev
131aa97dd1cSKonstantin Ananyevvoid
132aa97dd1cSKonstantin Ananyevfill_ipv6x_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t nproto,
133aa97dd1cSKonstantin Ananyev	uint32_t fproto)
134aa97dd1cSKonstantin Ananyev{
135aa97dd1cSKonstantin Ananyev	const struct ip6_ext *ipx;
136aa97dd1cSKonstantin Ananyev	int32_t dlen, len, ofs;
137aa97dd1cSKonstantin Ananyev
138aa97dd1cSKonstantin Ananyev	len = sizeof(struct ipv6_hdr);
139aa97dd1cSKonstantin Ananyev
140aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
141aa97dd1cSKonstantin Ananyev	dlen -= l2 + sizeof(struct udp_hdr);
142aa97dd1cSKonstantin Ananyev
143aa97dd1cSKonstantin Ananyev	ofs = l2 + len;
144aa97dd1cSKonstantin Ananyev	ipx = rte_pktmbuf_mtod_offset(m, const struct ip6_ext *, ofs);
145aa97dd1cSKonstantin Ananyev
146aa97dd1cSKonstantin Ananyev	while (ofs > 0 && len < dlen) {
147aa97dd1cSKonstantin Ananyev
148aa97dd1cSKonstantin Ananyev		switch (nproto) {
149aa97dd1cSKonstantin Ananyev		case IPPROTO_HOPOPTS:
150aa97dd1cSKonstantin Ananyev		case IPPROTO_ROUTING:
151aa97dd1cSKonstantin Ananyev		case IPPROTO_DSTOPTS:
152aa97dd1cSKonstantin Ananyev			ofs = (ipx->ip6e_len + 1) << 3;
153aa97dd1cSKonstantin Ananyev			break;
154aa97dd1cSKonstantin Ananyev		case IPPROTO_AH:
155aa97dd1cSKonstantin Ananyev			ofs = (ipx->ip6e_len + 2) << 2;
156aa97dd1cSKonstantin Ananyev			break;
157aa97dd1cSKonstantin Ananyev		case IPPROTO_FRAGMENT:
158aa97dd1cSKonstantin Ananyev			/*
159aa97dd1cSKonstantin Ananyev			 * tso_segsz is not used by RX, so suse it as temporary
160aa97dd1cSKonstantin Ananyev			 * buffer to store the fragment offset.
161aa97dd1cSKonstantin Ananyev			 */
162aa97dd1cSKonstantin Ananyev			m->tso_segsz = ofs;
163aa97dd1cSKonstantin Ananyev			ofs = sizeof(struct ip6_frag);
164aa97dd1cSKonstantin Ananyev			m->packet_type &= ~RTE_PTYPE_L4_MASK;
165aa97dd1cSKonstantin Ananyev			m->packet_type |= RTE_PTYPE_L4_FRAG;
166aa97dd1cSKonstantin Ananyev			break;
167aa97dd1cSKonstantin Ananyev		default:
168aa97dd1cSKonstantin Ananyev			ofs = 0;
169aa97dd1cSKonstantin Ananyev		}
170aa97dd1cSKonstantin Ananyev
171aa97dd1cSKonstantin Ananyev		if (ofs > 0) {
172aa97dd1cSKonstantin Ananyev			nproto = ipx->ip6e_nxt;
173aa97dd1cSKonstantin Ananyev			len += ofs;
174aa97dd1cSKonstantin Ananyev			ipx += ofs / sizeof(*ipx);
175aa97dd1cSKonstantin Ananyev		}
176aa97dd1cSKonstantin Ananyev	}
177aa97dd1cSKonstantin Ananyev
178aa97dd1cSKonstantin Ananyev	/* undercognised or invalid packet. */
179aa97dd1cSKonstantin Ananyev	if ((ofs == 0 && nproto != fproto) || len > dlen)
180aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
181aa97dd1cSKonstantin Ananyev	else
182aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2, len, sizeof(struct udp_hdr));
183aa97dd1cSKonstantin Ananyev}
184aa97dd1cSKonstantin Ananyev
185aa97dd1cSKonstantin Ananyevvoid
186aa97dd1cSKonstantin Ananyevfill_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto)
187aa97dd1cSKonstantin Ananyev{
188aa97dd1cSKonstantin Ananyev	const struct ipv6_hdr *iph;
189aa97dd1cSKonstantin Ananyev
190aa97dd1cSKonstantin Ananyev	iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *,
191aa97dd1cSKonstantin Ananyev		sizeof(struct ether_hdr));
192aa97dd1cSKonstantin Ananyev
193aa97dd1cSKonstantin Ananyev	if (iph->proto == fproto)
194aa97dd1cSKonstantin Ananyev		fill_pkt_hdr_len(m, l2, sizeof(struct ipv6_hdr),
195aa97dd1cSKonstantin Ananyev			sizeof(struct udp_hdr));
196aa97dd1cSKonstantin Ananyev	else if (ipv6x_hdr(iph->proto) != 0)
197aa97dd1cSKonstantin Ananyev		fill_ipv6x_hdr_len(m, l2, iph->proto, fproto);
198aa97dd1cSKonstantin Ananyev}
199aa97dd1cSKonstantin Ananyev
200aa97dd1cSKonstantin Ananyevvoid
201aa97dd1cSKonstantin Ananyevfill_eth_hdr_len(struct rte_mbuf *m)
202aa97dd1cSKonstantin Ananyev{
203aa97dd1cSKonstantin Ananyev	uint32_t dlen, l2;
204aa97dd1cSKonstantin Ananyev	uint16_t etp;
205aa97dd1cSKonstantin Ananyev	const struct ether_hdr *eth;
206aa97dd1cSKonstantin Ananyev
207aa97dd1cSKonstantin Ananyev	dlen = rte_pktmbuf_data_len(m);
208aa97dd1cSKonstantin Ananyev
209aa97dd1cSKonstantin Ananyev	/* check that first segment is at least 42B long. */
210aa97dd1cSKonstantin Ananyev	if (dlen < sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
211aa97dd1cSKonstantin Ananyev			sizeof(struct udp_hdr)) {
212aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
213aa97dd1cSKonstantin Ananyev		return;
214aa97dd1cSKonstantin Ananyev	}
215aa97dd1cSKonstantin Ananyev
216aa97dd1cSKonstantin Ananyev	l2 = sizeof(*eth);
217aa97dd1cSKonstantin Ananyev
218aa97dd1cSKonstantin Ananyev	eth = rte_pktmbuf_mtod(m, const struct ether_hdr *);
219aa97dd1cSKonstantin Ananyev	etp = eth->ether_type;
220aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_VLAN))
221aa97dd1cSKonstantin Ananyev		l2 += sizeof(struct vlan_hdr);
222aa97dd1cSKonstantin Ananyev
223aa97dd1cSKonstantin Ananyev	if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) {
224aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_UDP |
225aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
226aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
227aa97dd1cSKonstantin Ananyev		fill_ipv4_hdr_len(m, l2, IPPROTO_UDP, 1);
228aa97dd1cSKonstantin Ananyev	} else if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv6) &&
229aa97dd1cSKonstantin Ananyev			dlen >= l2 + sizeof(struct ipv6_hdr) +
230aa97dd1cSKonstantin Ananyev			sizeof(struct udp_hdr)) {
231aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_L4_UDP |
232aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
233aa97dd1cSKonstantin Ananyev			RTE_PTYPE_L2_ETHER;
234aa97dd1cSKonstantin Ananyev			fill_ipv6_hdr_len(m, l2, IPPROTO_UDP);
235aa97dd1cSKonstantin Ananyev	} else
236aa97dd1cSKonstantin Ananyev		m->packet_type = RTE_PTYPE_UNKNOWN;
237aa97dd1cSKonstantin Ananyev}
238aa97dd1cSKonstantin Ananyev
239aa97dd1cSKonstantin Ananyev/*
240aa97dd1cSKonstantin Ananyev * generic, assumes HW doesn't recognise any packet type.
241aa97dd1cSKonstantin Ananyev */
242aa97dd1cSKonstantin Ananyevuint16_t
2435c795f7bSKonstantin Ananyevtypen_rx_callback(dpdk_port_t port, __rte_unused uint16_t queue,
244aa97dd1cSKonstantin Ananyev	struct rte_mbuf *pkt[], uint16_t nb_pkts,
245aa97dd1cSKonstantin Ananyev	__rte_unused uint16_t max_pkts, void *user_param)
246aa97dd1cSKonstantin Ananyev{
247aa97dd1cSKonstantin Ananyev	uint32_t j;
248aa97dd1cSKonstantin Ananyev
249aa97dd1cSKonstantin Ananyev	for (j = 0; j != nb_pkts; j++) {
250aa97dd1cSKonstantin Ananyev		fill_eth_hdr_len(pkt[j]);
251aa97dd1cSKonstantin Ananyev
252aa97dd1cSKonstantin Ananyev	}
253aa97dd1cSKonstantin Ananyev
254aa97dd1cSKonstantin Ananyev	return nb_pkts;
255aa97dd1cSKonstantin Ananyev}
256aa97dd1cSKonstantin Ananyev
257aa97dd1cSKonstantin Ananyevint
258aa97dd1cSKonstantin Ananyevdummy_lookup4(void *opaque, const struct in_addr *addr, struct tle_dest *res)
259aa97dd1cSKonstantin Ananyev{
260aa97dd1cSKonstantin Ananyev	RTE_SET_USED(opaque);
261aa97dd1cSKonstantin Ananyev	RTE_SET_USED(addr);
262aa97dd1cSKonstantin Ananyev	RTE_SET_USED(res);
263aa97dd1cSKonstantin Ananyev	return -ENOENT;
264aa97dd1cSKonstantin Ananyev}
265aa97dd1cSKonstantin Ananyev
266aa97dd1cSKonstantin Ananyevint
267aa97dd1cSKonstantin Ananyevdummy_lookup6(void *opaque, const struct in6_addr *addr, struct tle_dest *res)
268aa97dd1cSKonstantin Ananyev{
269aa97dd1cSKonstantin Ananyev	RTE_SET_USED(opaque);
270aa97dd1cSKonstantin Ananyev	RTE_SET_USED(addr);
271aa97dd1cSKonstantin Ananyev	RTE_SET_USED(res);
272aa97dd1cSKonstantin Ananyev	return -ENOENT;
273aa97dd1cSKonstantin Ananyev}