port.h revision aa97dd1c
1/*
2 * Copyright (c) 2016  Intel Corporation.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef PORT_H_
17#define PORT_H_
18
19static void
20prepare_hash_key(struct netbe_port *uprt, uint8_t key_size, uint16_t family)
21{
22	uint32_t align_nb_q;
23
24	align_nb_q = rte_align32pow2(uprt->nb_lcore);
25	memset(uprt->hash_key, 0, RSS_HASH_KEY_LENGTH);
26	uprt->hash_key_size = key_size;
27	if (family == AF_INET)
28		uprt->hash_key[RSS_HASH_KEY_DEST_PORT_LOC_IPV4] = align_nb_q;
29	else
30		uprt->hash_key[RSS_HASH_KEY_DEST_PORT_LOC_IPV6] = align_nb_q;
31}
32
33static int
34update_rss_conf(struct netbe_port *uprt,
35	const struct rte_eth_dev_info *dev_info,
36	struct rte_eth_conf *port_conf, uint32_t proto)
37{
38	uint8_t hash_key_size;
39
40	if (uprt->nb_lcore > 1) {
41		if (dev_info->hash_key_size > 0)
42			hash_key_size = dev_info->hash_key_size;
43		else {
44			RTE_LOG(ERR, USER1,
45				"%s: dev_info did not provide a valid hash "
46				"key size\n", __func__);
47			return -EINVAL;
48		}
49
50		if (uprt->ipv4 != INADDR_ANY &&
51				memcmp(&uprt->ipv6, &in6addr_any,
52				sizeof(uprt->ipv6)) != 0) {
53			RTE_LOG(ERR, USER1,
54				"%s: RSS for both IPv4 and IPv6 not "
55				"supported!\n", __func__);
56			return -EINVAL;
57		} else if (uprt->ipv4 != INADDR_ANY) {
58			prepare_hash_key(uprt, hash_key_size, AF_INET);
59		} else if (memcmp(&uprt->ipv6, &in6addr_any, sizeof(uprt->ipv6))
60				!= 0) {
61			prepare_hash_key(uprt, hash_key_size, AF_INET6);
62		} else {
63			RTE_LOG(ERR, USER1,
64				"%s: No IPv4 or IPv6 address is found!\n",
65				__func__);
66			return -EINVAL;
67		}
68		port_conf->rxmode.mq_mode = ETH_MQ_RX_RSS;
69		if (proto == TLE_PROTO_TCP)
70			port_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_TCP;
71		else
72			port_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_UDP;
73		port_conf->rx_adv_conf.rss_conf.rss_key_len = hash_key_size;
74		port_conf->rx_adv_conf.rss_conf.rss_key = uprt->hash_key;
75	}
76
77	return 0;
78}
79
80static uint32_t
81qidx_from_hash_index(uint32_t hash, uint32_t align_nb_q)
82{
83	uint32_t i, nb_bit, q;
84
85	nb_bit = (sizeof(uint32_t) * CHAR_BIT) - __builtin_clz(align_nb_q - 1);
86	q = (hash & 1);
87	for (i = 1; i < nb_bit; i++) {
88		hash >>= 1;
89		q <<= 1;
90		q |= (hash & 1);
91	}
92
93	return q;
94}
95
96static int
97update_rss_reta(struct netbe_port *uprt,
98	const struct rte_eth_dev_info *dev_info)
99{
100	struct rte_eth_rss_reta_entry64 reta_conf[RSS_RETA_CONF_ARRAY_SIZE];
101	int32_t i, rc, align_nb_q;
102	int32_t q_index, idx, shift;
103
104	if (uprt->nb_lcore > 1) {
105		if (dev_info->reta_size == 0) {
106			RTE_LOG(ERR, USER1,
107				"%s: Redirection table size 0 is invalid for "
108				"RSS\n", __func__);
109			return -EINVAL;
110		}
111		RTE_LOG(NOTICE, USER1,
112			"%s: The reta size of port %d is %u\n",
113			__func__, uprt->id, dev_info->reta_size);
114
115		if (dev_info->reta_size > ETH_RSS_RETA_SIZE_512) {
116			RTE_LOG(ERR, USER1,
117				"%s: More than %u entries of Reta not supported\n",
118				__func__, ETH_RSS_RETA_SIZE_512);
119			return -EINVAL;
120		}
121
122		memset(reta_conf, 0, sizeof(reta_conf));
123		align_nb_q = rte_align32pow2(uprt->nb_lcore);
124		for (i = 0; i < align_nb_q; i++) {
125			q_index = qidx_from_hash_index(i, align_nb_q) %
126						uprt->nb_lcore;
127
128			idx = i / RTE_RETA_GROUP_SIZE;
129			shift = i % RTE_RETA_GROUP_SIZE;
130			reta_conf[idx].mask |= (1ULL << shift);
131			reta_conf[idx].reta[shift] = q_index;
132			RTE_LOG(NOTICE, USER1,
133				"%s: port=%u RSS reta conf: hash=%u, q=%u\n",
134				__func__, uprt->id, i, q_index);
135		}
136
137		rc = rte_eth_dev_rss_reta_update(uprt->id,
138				reta_conf, dev_info->reta_size);
139		if (rc != 0) {
140			RTE_LOG(ERR, USER1,
141				"%s: Bad redirection table parameter, "
142				"rc = %d\n", __func__, rc);
143			return rc;
144		}
145	}
146
147	return 0;
148}
149
150/*
151 * Initilise DPDK port.
152 * In current version, multi-queue per port is used.
153 */
154static int
155port_init(struct netbe_port *uprt, uint32_t proto)
156{
157	int32_t rc;
158	struct rte_eth_conf port_conf;
159	struct rte_eth_dev_info dev_info;
160
161	rte_eth_dev_info_get(uprt->id, &dev_info);
162	if ((dev_info.rx_offload_capa & uprt->rx_offload) != uprt->rx_offload) {
163		RTE_LOG(ERR, USER1,
164			"port#%u supported/requested RX offloads don't match, "
165			"supported: %#x, requested: %#x;\n",
166			uprt->id, dev_info.rx_offload_capa, uprt->rx_offload);
167		return -EINVAL;
168	}
169	if ((dev_info.tx_offload_capa & uprt->tx_offload) != uprt->tx_offload) {
170		RTE_LOG(ERR, USER1,
171			"port#%u supported/requested TX offloads don't match, "
172			"supported: %#x, requested: %#x;\n",
173			uprt->id, dev_info.tx_offload_capa, uprt->tx_offload);
174		return -EINVAL;
175	}
176
177	port_conf = port_conf_default;
178	if ((uprt->rx_offload & RX_CSUM_OFFLOAD) != 0) {
179		RTE_LOG(ERR, USER1, "%s(%u): enabling RX csum offload;\n",
180			__func__, uprt->id);
181		port_conf.rxmode.hw_ip_checksum = 1;
182	}
183	port_conf.rxmode.max_rx_pkt_len = uprt->mtu + ETHER_CRC_LEN;
184
185	rc = update_rss_conf(uprt, &dev_info, &port_conf, proto);
186	if (rc != 0)
187		return rc;
188
189	rc = rte_eth_dev_configure(uprt->id, uprt->nb_lcore, uprt->nb_lcore,
190			&port_conf);
191	RTE_LOG(NOTICE, USER1,
192		"%s: rte_eth_dev_configure(prt_id=%u, nb_rxq=%u, nb_txq=%u) "
193		"returns %d;\n", __func__, uprt->id, uprt->nb_lcore,
194		uprt->nb_lcore, rc);
195	if (rc != 0)
196		return rc;
197
198	return 0;
199}
200
201static int
202queue_init(struct netbe_port *uprt, struct rte_mempool *mp)
203{
204	int32_t socket, rc;
205	uint16_t q;
206	struct rte_eth_dev_info dev_info;
207
208	rte_eth_dev_info_get(uprt->id, &dev_info);
209
210	socket = rte_eth_dev_socket_id(uprt->id);
211
212	dev_info.default_rxconf.rx_drop_en = 1;
213
214	dev_info.default_txconf.tx_free_thresh = TX_RING_SIZE / 2;
215	if (uprt->tx_offload != 0) {
216		RTE_LOG(ERR, USER1, "%s(%u): enabling full featured TX;\n",
217			__func__, uprt->id);
218		dev_info.default_txconf.txq_flags = 0;
219	}
220
221	for (q = 0; q < uprt->nb_lcore; q++) {
222		rc = rte_eth_rx_queue_setup(uprt->id, q, RX_RING_SIZE,
223			socket, &dev_info.default_rxconf, mp);
224		if (rc < 0) {
225			RTE_LOG(ERR, USER1,
226				"%s: rx queue=%u setup failed with error "
227				"code: %d\n", __func__, q, rc);
228			return rc;
229		}
230	}
231
232	for (q = 0; q < uprt->nb_lcore; q++) {
233		rc = rte_eth_tx_queue_setup(uprt->id, q, TX_RING_SIZE,
234			socket, &dev_info.default_txconf);
235		if (rc < 0) {
236			RTE_LOG(ERR, USER1,
237				"%s: tx queue=%u setup failed with error "
238				"code: %d\n", __func__, q, rc);
239			return rc;
240		}
241	}
242	return 0;
243}
244
245/*
246 * Check that lcore is enabled, not master, and not in use already.
247 */
248static int
249check_lcore(uint32_t lc)
250{
251	if (rte_lcore_is_enabled(lc) == 0) {
252		RTE_LOG(ERR, USER1, "lcore %u is not enabled\n", lc);
253		return -EINVAL;
254	}
255	if (rte_eal_get_lcore_state(lc) == RUNNING) {
256		RTE_LOG(ERR, USER1, "lcore %u already running %p\n",
257			lc, lcore_config[lc].f);
258		return -EINVAL;
259	}
260	return 0;
261}
262
263static void
264log_netbe_prt(const struct netbe_port *uprt)
265{
266	uint32_t i;
267	char corelist[2 * RTE_MAX_LCORE + 1];
268	char hashkey[2 * RSS_HASH_KEY_LENGTH];
269
270	memset(corelist, 0, sizeof(corelist));
271	memset(hashkey, 0, sizeof(hashkey));
272	for (i = 0; i < uprt->nb_lcore; i++)
273		if (i < uprt->nb_lcore - 1)
274			sprintf(corelist + (2 * i), "%u,", uprt->lcore_id[i]);
275		else
276			sprintf(corelist + (2 * i), "%u", uprt->lcore_id[i]);
277
278	for (i = 0; i < uprt->hash_key_size; i++)
279		sprintf(hashkey + (2 * i), "%02x", uprt->hash_key[i]);
280
281	RTE_LOG(NOTICE, USER1,
282		"uprt %p = <id = %u, lcore = <%s>, mtu = %u, "
283		"rx_offload = %u, tx_offload = %u,\n"
284		"ipv4 = %#x, "
285		"ipv6 = %04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx, "
286		"mac = %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx>;\n"
287		"hashkey = %s;\n",
288		uprt, uprt->id, corelist,
289		uprt->mtu, uprt->rx_offload, uprt->tx_offload,
290		uprt->ipv4,
291		uprt->ipv6.s6_addr16[0], uprt->ipv6.s6_addr16[1],
292		uprt->ipv6.s6_addr16[2], uprt->ipv6.s6_addr16[3],
293		uprt->ipv6.s6_addr16[4], uprt->ipv6.s6_addr16[5],
294		uprt->ipv6.s6_addr16[6], uprt->ipv6.s6_addr16[7],
295		uprt->mac.addr_bytes[0], uprt->mac.addr_bytes[1],
296		uprt->mac.addr_bytes[2], uprt->mac.addr_bytes[3],
297		uprt->mac.addr_bytes[4], uprt->mac.addr_bytes[5],
298		hashkey);
299}
300
301static void
302log_netbe_cfg(const struct netbe_cfg *ucfg)
303{
304	uint32_t i;
305
306	RTE_LOG(NOTICE, USER1,
307		"ucfg @ %p, prt_num = %u\n", ucfg, ucfg->prt_num);
308
309	for (i = 0; i != ucfg->prt_num; i++)
310		log_netbe_prt(ucfg->prt + i);
311}
312
313static int
314pool_init(uint32_t sid)
315{
316	int32_t rc;
317	struct rte_mempool *mp;
318	char name[RTE_MEMPOOL_NAMESIZE];
319
320	snprintf(name, sizeof(name), "MP%u", sid);
321	mp = rte_pktmbuf_pool_create(name, MPOOL_NB_BUF, MPOOL_CACHE_SIZE, 0,
322		RTE_MBUF_DEFAULT_BUF_SIZE, sid - 1);
323	if (mp == NULL) {
324		rc = -rte_errno;
325		RTE_LOG(ERR, USER1, "%s(%d) failed with error code: %d\n",
326			__func__, sid - 1, rc);
327		return rc;
328	}
329
330	mpool[sid] = mp;
331	return 0;
332}
333
334static int
335frag_pool_init(uint32_t sid)
336{
337	int32_t rc;
338	struct rte_mempool *frag_mp;
339	char frag_name[RTE_MEMPOOL_NAMESIZE];
340
341	snprintf(frag_name, sizeof(frag_name), "frag_MP%u", sid);
342	frag_mp = rte_pktmbuf_pool_create(frag_name, MPOOL_NB_BUF,
343		MPOOL_CACHE_SIZE, 0, FRAG_MBUF_BUF_SIZE, sid - 1);
344	if (frag_mp == NULL) {
345		rc = -rte_errno;
346		RTE_LOG(ERR, USER1, "%s(%d) failed with error code: %d\n",
347			__func__, sid - 1, rc);
348		return rc;
349	}
350
351	frag_mpool[sid] = frag_mp;
352	return 0;
353}
354
355static struct netbe_lcore *
356find_initilized_lcore(struct netbe_cfg *cfg, uint32_t lc_num)
357{
358	uint32_t i;
359
360	for (i = 0; i < cfg->cpu_num; i++)
361		if (cfg->cpu[i].id == lc_num)
362			return &cfg->cpu[i];
363
364	return NULL;
365}
366
367/*
368 * Setup all enabled ports.
369 */
370static int
371netbe_port_init(struct netbe_cfg *cfg)
372{
373	int32_t rc;
374	uint32_t i, sid, j;
375	struct netbe_port *prt;
376	struct netbe_lcore *lc;
377
378	for (i = 0; i != cfg->prt_num; i++) {
379		prt = cfg->prt + i;
380		rc = port_init(prt, cfg->proto);
381		if (rc != 0) {
382			RTE_LOG(ERR, USER1,
383				"%s: port=%u init failed with error code: %d\n",
384				__func__, prt->id, rc);
385			return rc;
386		}
387		rte_eth_macaddr_get(prt->id, &prt->mac);
388		if (cfg->promisc)
389			rte_eth_promiscuous_enable(prt->id);
390
391		for (j = 0; j < prt->nb_lcore; j++) {
392			rc = check_lcore(prt->lcore_id[j]);
393			if (rc != 0) {
394				RTE_LOG(ERR, USER1,
395					"%s: processing failed with err: %d\n",
396					__func__, rc);
397				return rc;
398			}
399
400			sid = rte_lcore_to_socket_id(prt->lcore_id[j]) + 1;
401			assert(sid < RTE_DIM(mpool));
402
403			if (mpool[sid] == NULL) {
404				rc = pool_init(sid);
405				if (rc != 0)
406					return rc;
407			}
408
409			if (frag_mpool[sid] == NULL) {
410				rc = frag_pool_init(sid);
411				if (rc != 0)
412					return rc;
413			}
414
415			rc = queue_init(prt, mpool[sid]);
416			if (rc != 0) {
417				RTE_LOG(ERR, USER1,
418					"%s: lcore=%u queue init failed with "
419					"err: %d\n",
420					__func__, prt->lcore_id[j], rc);
421				return rc;
422			}
423
424			/* calculate number of queues and assign queue id
425			 * per lcore. */
426			lc = find_initilized_lcore(cfg, prt->lcore_id[j]);
427			if (lc == NULL) {
428				lc = &cfg->cpu[cfg->cpu_num];
429				lc->id = prt->lcore_id[j];
430				lc->proto = becfg.proto;
431				cfg->cpu_num++;
432			}
433
434			lc->prtq = rte_realloc(lc->prtq, sizeof(*(lc->prtq)) *
435				(lc->prtq_num + 1), RTE_CACHE_LINE_SIZE);
436			if (lc->prtq == NULL) {
437				RTE_LOG(ERR, USER1,
438					"%s: failed to reallocate memory\n",
439					__func__);
440				return -ENOMEM;
441			}
442			lc->prtq[lc->prtq_num].rxqid = j;
443			lc->prtq[lc->prtq_num].txqid = j;
444			lc->prtq[lc->prtq_num].port = *prt;
445			lc->prtq_num++;
446		}
447	}
448	log_netbe_cfg(cfg);
449
450	return 0;
451}
452
453#endif /* PORT_H_ */
454