1
2
3
4#include <stdint.h>
5#include <stdio.h>
6#include <inttypes.h>
7#include <unistd.h>
8#include <signal.h>
9#include <string.h>
10#include <getopt.h>
11
12#include <cmdline_parse_string.h>
13#include <cmdline_socket.h>
14#include <cmdline.h>
15#include <rte_common.h>
16#include <rte_rawdev.h>
17#include <rte_ethdev.h>
18#include <rte_malloc.h>
19#include <rte_lcore.h>
20#include <rte_cycles.h>
21#include <rte_pmd_ntb.h>
22#include <rte_mbuf_pool_ops.h>
23
24
25struct ntb_port_statistics {
26 uint64_t tx;
27 uint64_t rx;
28} __rte_cache_aligned;
29
30struct ntb_port_statistics ntb_port_stats[2];
31
32struct ntb_fwd_stream {
33 uint16_t tx_port;
34 uint16_t rx_port;
35 uint16_t qp_id;
36 uint8_t tx_ntb;
37};
38
39struct ntb_fwd_lcore_conf {
40 uint16_t stream_id;
41 uint16_t nb_stream;
42 uint8_t stopped;
43};
44
45enum ntb_fwd_mode {
46 FILE_TRANS = 0,
47 RXONLY,
48 TXONLY,
49 IOFWD,
50 MAX_FWD_MODE,
51};
52static const char *const fwd_mode_s[] = {
53 "file-trans",
54 "rxonly",
55 "txonly",
56 "iofwd",
57 NULL,
58};
59static enum ntb_fwd_mode fwd_mode = MAX_FWD_MODE;
60
61static struct ntb_fwd_lcore_conf fwd_lcore_conf[RTE_MAX_LCORE];
62static struct ntb_fwd_stream *fwd_streams;
63
64static struct rte_mempool *mbuf_pool;
65
66#define NTB_DRV_NAME_LEN 7
67#define MEMPOOL_CACHE_SIZE 256
68
69static uint8_t in_test;
70static uint8_t interactive = 1;
71static uint16_t eth_port_id = RTE_MAX_ETHPORTS;
72static uint16_t dev_id;
73
74
75static uint16_t num_queues = 1;
76static uint16_t ntb_buf_size = RTE_MBUF_DEFAULT_BUF_SIZE;
77
78
79#define NTB_DEFAULT_NUM_DESCS 1024
80static uint16_t nb_desc = NTB_DEFAULT_NUM_DESCS;
81
82static uint16_t tx_free_thresh;
83
84#define NTB_MAX_PKT_BURST 32
85#define NTB_DFLT_PKT_BURST 32
86static uint16_t pkt_burst = NTB_DFLT_PKT_BURST;
87
88#define BURST_TX_RETRIES 64
89
90static struct rte_eth_conf eth_port_conf = {
91 .rxmode = {
92 .mq_mode = ETH_MQ_RX_RSS,
93 .split_hdr_size = 0,
94 },
95 .rx_adv_conf = {
96 .rss_conf = {
97 .rss_key = NULL,
98 .rss_hf = ETH_RSS_IP,
99 },
100 },
101 .txmode = {
102 .mq_mode = ETH_MQ_TX_NONE,
103 },
104};
105
106
107struct cmd_help_result {
108 cmdline_fixed_string_t help;
109};
110
111static void
112cmd_help_parsed(__rte_unused void *parsed_result,
113 struct cmdline *cl,
114 __rte_unused void *data)
115{
116 cmdline_printf(
117 cl,
118 "\n"
119 "The following commands are currently available:\n\n"
120 "Control:\n"
121 " quit :"
122 " Quit the application.\n"
123 "\nTransmission:\n"
124 " send [path] :"
125 " Send [path] file. Only take effect in file-trans mode\n"
126 " start :"
127 " Start transmissions.\n"
128 " stop :"
129 " Stop transmissions.\n"
130 " clear/show port stats :"
131 " Clear/show port stats.\n"
132 " set fwd file-trans/rxonly/txonly/iofwd :"
133 " Set packet forwarding mode.\n"
134 );
135
136}
137
138cmdline_parse_token_string_t cmd_help_help =
139 TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
140
141cmdline_parse_inst_t cmd_help = {
142 .f = cmd_help_parsed,
143 .data = NULL,
144 .help_str = "show help",
145 .tokens = {
146 (void *)&cmd_help_help,
147 NULL,
148 },
149};
150
151
152struct cmd_quit_result {
153 cmdline_fixed_string_t quit;
154};
155
156static void
157cmd_quit_parsed(__rte_unused void *parsed_result,
158 struct cmdline *cl,
159 __rte_unused void *data)
160{
161 struct ntb_fwd_lcore_conf *conf;
162 uint32_t lcore_id;
163
164
165 RTE_LCORE_FOREACH_WORKER(lcore_id) {
166 conf = &fwd_lcore_conf[lcore_id];
167
168 if (!conf->nb_stream)
169 continue;
170
171 if (conf->stopped)
172 continue;
173
174 conf->stopped = 1;
175 }
176 printf("\nWaiting for lcores to finish...\n");
177 rte_eal_mp_wait_lcore();
178 in_test = 0;
179
180
181 rte_rawdev_stop(dev_id);
182 rte_rawdev_close(dev_id);
183 if (eth_port_id < RTE_MAX_ETHPORTS && fwd_mode == IOFWD) {
184 rte_eth_dev_stop(eth_port_id);
185 rte_eth_dev_close(eth_port_id);
186 }
187
188 cmdline_quit(cl);
189}
190
191cmdline_parse_token_string_t cmd_quit_quit =
192 TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
193
194cmdline_parse_inst_t cmd_quit = {
195 .f = cmd_quit_parsed,
196 .data = NULL,
197 .help_str = "exit application",
198 .tokens = {
199 (void *)&cmd_quit_quit,
200 NULL,
201 },
202};
203
204
205struct cmd_sendfile_result {
206 cmdline_fixed_string_t send_string;
207 char filepath[];
208};
209
210static void
211cmd_sendfile_parsed(void *parsed_result,
212 __rte_unused struct cmdline *cl,
213 __rte_unused void *data)
214{
215 struct cmd_sendfile_result *res = parsed_result;
216 struct rte_rawdev_buf *pkts_send[NTB_MAX_PKT_BURST];
217 struct rte_mbuf *mbuf_send[NTB_MAX_PKT_BURST];
218 uint64_t size, count, i, j, nb_burst;
219 uint16_t nb_tx, buf_size;
220 unsigned int nb_pkt;
221 size_t queue_id = 0;
222 uint16_t retry = 0;
223 uint32_t val;
224 FILE *file;
225 int ret;
226
227 if (num_queues != 1) {
228 printf("File transmission only supports 1 queue.\n");
229 num_queues = 1;
230 }
231
232 file = fopen(res->filepath, "r");
233 if (file == NULL) {
234 printf("Fail to open the file.\n");
235 return;
236 }
237
238 if (fseek(file, 0, SEEK_END) < 0) {
239 printf("Fail to get file size.\n");
240 fclose(file);
241 return;
242 }
243 size = ftell(file);
244 if (fseek(file, 0, SEEK_SET) < 0) {
245 printf("Fail to get file size.\n");
246 fclose(file);
247 return;
248 }
249
250
251 val = size >> 32;
252 rte_rawdev_set_attr(dev_id, "spad_user_0", val);
253 val = size;
254 rte_rawdev_set_attr(dev_id, "spad_user_1", val);
255 printf("Sending file, size is %"PRIu64"\n", size);
256
257 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
258 pkts_send[i] = (struct rte_rawdev_buf *)
259 malloc(sizeof(struct rte_rawdev_buf));
260
261 buf_size = ntb_buf_size - RTE_PKTMBUF_HEADROOM;
262 count = (size + buf_size - 1) / buf_size;
263 nb_burst = (count + pkt_burst - 1) / pkt_burst;
264
265 for (i = 0; i < nb_burst; i++) {
266 val = RTE_MIN(count, pkt_burst);
267 if (rte_mempool_get_bulk(mbuf_pool, (void **)mbuf_send,
268 val) == 0) {
269 for (nb_pkt = 0; nb_pkt < val; nb_pkt++) {
270 mbuf_send[nb_pkt]->port = dev_id;
271 mbuf_send[nb_pkt]->data_len =
272 fread(rte_pktmbuf_mtod(mbuf_send[nb_pkt],
273 void *), 1, buf_size, file);
274 mbuf_send[nb_pkt]->pkt_len =
275 mbuf_send[nb_pkt]->data_len;
276 pkts_send[nb_pkt]->buf_addr = mbuf_send[nb_pkt];
277 }
278 } else {
279 for (nb_pkt = 0; nb_pkt < val; nb_pkt++) {
280 mbuf_send[nb_pkt] =
281 rte_mbuf_raw_alloc(mbuf_pool);
282 if (mbuf_send[nb_pkt] == NULL)
283 break;
284 mbuf_send[nb_pkt]->port = dev_id;
285 mbuf_send[nb_pkt]->data_len =
286 fread(rte_pktmbuf_mtod(mbuf_send[nb_pkt],
287 void *), 1, buf_size, file);
288 mbuf_send[nb_pkt]->pkt_len =
289 mbuf_send[nb_pkt]->data_len;
290 pkts_send[nb_pkt]->buf_addr = mbuf_send[nb_pkt];
291 }
292 }
293
294 ret = rte_rawdev_enqueue_buffers(dev_id, pkts_send, nb_pkt,
295 (void *)queue_id);
296 if (ret < 0) {
297 printf("Enqueue failed with err %d\n", ret);
298 for (j = 0; j < nb_pkt; j++)
299 rte_pktmbuf_free(mbuf_send[j]);
300 goto clean;
301 }
302 nb_tx = ret;
303 while (nb_tx != nb_pkt && retry < BURST_TX_RETRIES) {
304 rte_delay_us(1);
305 ret = rte_rawdev_enqueue_buffers(dev_id,
306 &pkts_send[nb_tx], nb_pkt - nb_tx,
307 (void *)queue_id);
308 if (ret < 0) {
309 printf("Enqueue failed with err %d\n", ret);
310 for (j = nb_tx; j < nb_pkt; j++)
311 rte_pktmbuf_free(mbuf_send[j]);
312 goto clean;
313 }
314 nb_tx += ret;
315 }
316 count -= nb_pkt;
317 }
318
319
320 rte_rawdev_set_attr(dev_id, "spad_user_0", 0);
321 rte_rawdev_set_attr(dev_id, "spad_user_1", 0);
322 printf("Done sending file.\n");
323
324clean:
325 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
326 free(pkts_send[i]);
327 fclose(file);
328}
329
330cmdline_parse_token_string_t cmd_send_file_send =
331 TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, send_string,
332 "send");
333cmdline_parse_token_string_t cmd_send_file_filepath =
334 TOKEN_STRING_INITIALIZER(struct cmd_sendfile_result, filepath, NULL);
335
336
337cmdline_parse_inst_t cmd_send_file = {
338 .f = cmd_sendfile_parsed,
339 .data = NULL,
340 .help_str = "send <file_path>",
341 .tokens = {
342 (void *)&cmd_send_file_send,
343 (void *)&cmd_send_file_filepath,
344 NULL,
345 },
346};
347
348#define RECV_FILE_LEN 30
349static int
350start_polling_recv_file(void *param)
351{
352 struct rte_rawdev_buf *pkts_recv[NTB_MAX_PKT_BURST];
353 struct ntb_fwd_lcore_conf *conf = param;
354 struct rte_mbuf *mbuf;
355 char filepath[RECV_FILE_LEN];
356 uint64_t val, size, file_len;
357 uint16_t nb_rx, i, file_no;
358 size_t queue_id = 0;
359 FILE *file;
360 int ret;
361
362 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
363 pkts_recv[i] = (struct rte_rawdev_buf *)
364 malloc(sizeof(struct rte_rawdev_buf));
365
366 file_no = 0;
367 while (!conf->stopped) {
368 snprintf(filepath, RECV_FILE_LEN, "ntb_recv_file%d", file_no);
369 file = fopen(filepath, "w");
370 if (file == NULL) {
371 printf("Fail to open the file.\n");
372 return -EINVAL;
373 }
374
375 rte_rawdev_get_attr(dev_id, "spad_user_0", &val);
376 size = val << 32;
377 rte_rawdev_get_attr(dev_id, "spad_user_1", &val);
378 size |= val;
379
380 if (!size) {
381 fclose(file);
382 continue;
383 }
384
385 file_len = 0;
386 nb_rx = NTB_MAX_PKT_BURST;
387 while (file_len < size && !conf->stopped) {
388 ret = rte_rawdev_dequeue_buffers(dev_id, pkts_recv,
389 pkt_burst, (void *)queue_id);
390 if (ret < 0) {
391 printf("Dequeue failed with err %d\n", ret);
392 fclose(file);
393 goto clean;
394 }
395 nb_rx = ret;
396 ntb_port_stats[0].rx += nb_rx;
397 for (i = 0; i < nb_rx; i++) {
398 mbuf = pkts_recv[i]->buf_addr;
399 fwrite(rte_pktmbuf_mtod(mbuf, void *), 1,
400 mbuf->data_len, file);
401 file_len += mbuf->data_len;
402 rte_pktmbuf_free(mbuf);
403 pkts_recv[i]->buf_addr = NULL;
404 }
405 }
406
407 printf("Received file (size: %" PRIu64 ") from peer to %s.\n",
408 size, filepath);
409 fclose(file);
410 file_no++;
411 }
412
413clean:
414 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
415 free(pkts_recv[i]);
416 return 0;
417}
418
419static int
420start_iofwd_per_lcore(void *param)
421{
422 struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
423 struct rte_mbuf *pkts_burst[NTB_MAX_PKT_BURST];
424 struct ntb_fwd_lcore_conf *conf = param;
425 struct ntb_fwd_stream fs;
426 uint16_t nb_rx, nb_tx;
427 int i, j, ret;
428
429 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
430 ntb_buf[i] = (struct rte_rawdev_buf *)
431 malloc(sizeof(struct rte_rawdev_buf));
432
433 while (!conf->stopped) {
434 for (i = 0; i < conf->nb_stream; i++) {
435 fs = fwd_streams[conf->stream_id + i];
436 if (fs.tx_ntb) {
437 nb_rx = rte_eth_rx_burst(fs.rx_port,
438 fs.qp_id, pkts_burst,
439 pkt_burst);
440 if (unlikely(nb_rx == 0))
441 continue;
442 for (j = 0; j < nb_rx; j++)
443 ntb_buf[j]->buf_addr = pkts_burst[j];
444 ret = rte_rawdev_enqueue_buffers(fs.tx_port,
445 ntb_buf, nb_rx,
446 (void *)(size_t)fs.qp_id);
447 if (ret < 0) {
448 printf("Enqueue failed with err %d\n",
449 ret);
450 for (j = 0; j < nb_rx; j++)
451 rte_pktmbuf_free(pkts_burst[j]);
452 goto clean;
453 }
454 nb_tx = ret;
455 ntb_port_stats[0].tx += nb_tx;
456 ntb_port_stats[1].rx += nb_rx;
457 } else {
458 ret = rte_rawdev_dequeue_buffers(fs.rx_port,
459 ntb_buf, pkt_burst,
460 (void *)(size_t)fs.qp_id);
461 if (ret < 0) {
462 printf("Dequeue failed with err %d\n",
463 ret);
464 goto clean;
465 }
466 nb_rx = ret;
467 if (unlikely(nb_rx == 0))
468 continue;
469 for (j = 0; j < nb_rx; j++)
470 pkts_burst[j] = ntb_buf[j]->buf_addr;
471 nb_tx = rte_eth_tx_burst(fs.tx_port,
472 fs.qp_id, pkts_burst, nb_rx);
473 ntb_port_stats[1].tx += nb_tx;
474 ntb_port_stats[0].rx += nb_rx;
475 }
476 if (unlikely(nb_tx < nb_rx)) {
477 do {
478 rte_pktmbuf_free(pkts_burst[nb_tx]);
479 } while (++nb_tx < nb_rx);
480 }
481 }
482 }
483
484clean:
485 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
486 free(ntb_buf[i]);
487
488 return 0;
489}
490
491static int
492start_rxonly_per_lcore(void *param)
493{
494 struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
495 struct ntb_fwd_lcore_conf *conf = param;
496 struct ntb_fwd_stream fs;
497 uint16_t nb_rx;
498 int i, j, ret;
499
500 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
501 ntb_buf[i] = (struct rte_rawdev_buf *)
502 malloc(sizeof(struct rte_rawdev_buf));
503
504 while (!conf->stopped) {
505 for (i = 0; i < conf->nb_stream; i++) {
506 fs = fwd_streams[conf->stream_id + i];
507 ret = rte_rawdev_dequeue_buffers(fs.rx_port,
508 ntb_buf, pkt_burst, (void *)(size_t)fs.qp_id);
509 if (ret < 0) {
510 printf("Dequeue failed with err %d\n", ret);
511 goto clean;
512 }
513 nb_rx = ret;
514 if (unlikely(nb_rx == 0))
515 continue;
516 ntb_port_stats[0].rx += nb_rx;
517
518 for (j = 0; j < nb_rx; j++)
519 rte_pktmbuf_free(ntb_buf[j]->buf_addr);
520 }
521 }
522
523clean:
524 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
525 free(ntb_buf[i]);
526
527 return 0;
528}
529
530
531static int
532start_txonly_per_lcore(void *param)
533{
534 struct rte_rawdev_buf *ntb_buf[NTB_MAX_PKT_BURST];
535 struct rte_mbuf *pkts_burst[NTB_MAX_PKT_BURST];
536 struct ntb_fwd_lcore_conf *conf = param;
537 struct ntb_fwd_stream fs;
538 uint16_t nb_pkt, nb_tx;
539 int i, j, ret;
540
541 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
542 ntb_buf[i] = (struct rte_rawdev_buf *)
543 malloc(sizeof(struct rte_rawdev_buf));
544
545 while (!conf->stopped) {
546 for (i = 0; i < conf->nb_stream; i++) {
547 fs = fwd_streams[conf->stream_id + i];
548 if (rte_mempool_get_bulk(mbuf_pool, (void **)pkts_burst,
549 pkt_burst) == 0) {
550 for (nb_pkt = 0; nb_pkt < pkt_burst; nb_pkt++) {
551 pkts_burst[nb_pkt]->port = dev_id;
552 pkts_burst[nb_pkt]->data_len =
553 pkts_burst[nb_pkt]->buf_len -
554 RTE_PKTMBUF_HEADROOM;
555 pkts_burst[nb_pkt]->pkt_len =
556 pkts_burst[nb_pkt]->data_len;
557 ntb_buf[nb_pkt]->buf_addr =
558 pkts_burst[nb_pkt];
559 }
560 } else {
561 for (nb_pkt = 0; nb_pkt < pkt_burst; nb_pkt++) {
562 pkts_burst[nb_pkt] =
563 rte_pktmbuf_alloc(mbuf_pool);
564 if (pkts_burst[nb_pkt] == NULL)
565 break;
566 pkts_burst[nb_pkt]->port = dev_id;
567 pkts_burst[nb_pkt]->data_len =
568 pkts_burst[nb_pkt]->buf_len -
569 RTE_PKTMBUF_HEADROOM;
570 pkts_burst[nb_pkt]->pkt_len =
571 pkts_burst[nb_pkt]->data_len;
572 ntb_buf[nb_pkt]->buf_addr =
573 pkts_burst[nb_pkt];
574 }
575 }
576 ret = rte_rawdev_enqueue_buffers(fs.tx_port, ntb_buf,
577 nb_pkt, (void *)(size_t)fs.qp_id);
578 if (ret < 0) {
579 printf("Enqueue failed with err %d\n", ret);
580 for (j = 0; j < nb_pkt; j++)
581 rte_pktmbuf_free(pkts_burst[j]);
582 goto clean;
583 }
584 nb_tx = ret;
585 ntb_port_stats[0].tx += nb_tx;
586 if (unlikely(nb_tx < nb_pkt)) {
587 do {
588 rte_pktmbuf_free(pkts_burst[nb_tx]);
589 } while (++nb_tx < nb_pkt);
590 }
591 }
592 }
593
594clean:
595 for (i = 0; i < NTB_MAX_PKT_BURST; i++)
596 free(ntb_buf[i]);
597
598 return 0;
599}
600
601static int
602ntb_fwd_config_setup(void)
603{
604 uint16_t i;
605
606
607 if (fwd_mode == IOFWD && eth_port_id >= RTE_MAX_ETHPORTS) {
608 printf("No ethdev, cannot be in iofwd mode.");
609 return -EINVAL;
610 }
611
612 if (fwd_mode == IOFWD) {
613 fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
614 sizeof(struct ntb_fwd_stream) * num_queues * 2,
615 RTE_CACHE_LINE_SIZE);
616 for (i = 0; i < num_queues; i++) {
617 fwd_streams[i * 2].qp_id = i;
618 fwd_streams[i * 2].tx_port = dev_id;
619 fwd_streams[i * 2].rx_port = eth_port_id;
620 fwd_streams[i * 2].tx_ntb = 1;
621
622 fwd_streams[i * 2 + 1].qp_id = i;
623 fwd_streams[i * 2 + 1].tx_port = eth_port_id;
624 fwd_streams[i * 2 + 1].rx_port = dev_id;
625 fwd_streams[i * 2 + 1].tx_ntb = 0;
626 }
627 return 0;
628 }
629
630 if (fwd_mode == RXONLY || fwd_mode == FILE_TRANS) {
631
632 if (fwd_mode == FILE_TRANS)
633 num_queues = 1;
634
635 fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
636 sizeof(struct ntb_fwd_stream) * num_queues,
637 RTE_CACHE_LINE_SIZE);
638 for (i = 0; i < num_queues; i++) {
639 fwd_streams[i].qp_id = i;
640 fwd_streams[i].tx_port = RTE_MAX_ETHPORTS;
641 fwd_streams[i].rx_port = dev_id;
642 fwd_streams[i].tx_ntb = 0;
643 }
644 return 0;
645 }
646
647 if (fwd_mode == TXONLY) {
648 fwd_streams = rte_zmalloc("ntb_fwd: fwd_streams",
649 sizeof(struct ntb_fwd_stream) * num_queues,
650 RTE_CACHE_LINE_SIZE);
651 for (i = 0; i < num_queues; i++) {
652 fwd_streams[i].qp_id = i;
653 fwd_streams[i].tx_port = dev_id;
654 fwd_streams[i].rx_port = RTE_MAX_ETHPORTS;
655 fwd_streams[i].tx_ntb = 1;
656 }
657 }
658 return 0;
659}
660
661static void
662assign_stream_to_lcores(void)
663{
664 struct ntb_fwd_lcore_conf *conf;
665 struct ntb_fwd_stream *fs;
666 uint16_t nb_streams, sm_per_lcore, sm_id, i;
667 uint32_t lcore_id;
668 uint8_t lcore_num, nb_extra;
669
670 lcore_num = rte_lcore_count();
671
672 lcore_num--;
673
674 nb_streams = (fwd_mode == IOFWD) ? num_queues * 2 : num_queues;
675
676 sm_per_lcore = nb_streams / lcore_num;
677 nb_extra = nb_streams % lcore_num;
678 sm_id = 0;
679 i = 0;
680
681 RTE_LCORE_FOREACH_WORKER(lcore_id) {
682 conf = &fwd_lcore_conf[lcore_id];
683
684 if (i < nb_extra) {
685 conf->nb_stream = sm_per_lcore + 1;
686 conf->stream_id = sm_id;
687 sm_id = sm_id + sm_per_lcore + 1;
688 } else {
689 conf->nb_stream = sm_per_lcore;
690 conf->stream_id = sm_id;
691 sm_id = sm_id + sm_per_lcore;
692 }
693
694 i++;
695 if (sm_id >= nb_streams)
696 break;
697 }
698
699
700 RTE_LCORE_FOREACH_WORKER(lcore_id) {
701 conf = &fwd_lcore_conf[lcore_id];
702
703 if (!conf->nb_stream)
704 continue;
705
706 printf("Streams on Lcore %u :\n", lcore_id);
707 for (i = 0; i < conf->nb_stream; i++) {
708 fs = &fwd_streams[conf->stream_id + i];
709 if (fwd_mode == IOFWD)
710 printf(" + Stream %u : %s%u RX -> %s%u TX,"
711 " Q=%u\n", conf->stream_id + i,
712 fs->tx_ntb ? "Eth" : "NTB", fs->rx_port,
713 fs->tx_ntb ? "NTB" : "Eth", fs->tx_port,
714 fs->qp_id);
715 if (fwd_mode == FILE_TRANS || fwd_mode == RXONLY)
716 printf(" + Stream %u : %s%u RX only\n",
717 conf->stream_id, "NTB", fs->rx_port);
718 if (fwd_mode == TXONLY)
719 printf(" + Stream %u : %s%u TX only\n",
720 conf->stream_id, "NTB", fs->tx_port);
721 }
722 }
723}
724
725static void
726start_pkt_fwd(void)
727{
728 struct ntb_fwd_lcore_conf *conf;
729 struct rte_eth_link eth_link;
730 uint32_t lcore_id;
731 int ret, i;
732 char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
733
734 ret = ntb_fwd_config_setup();
735 if (ret < 0) {
736 printf("Cannot start traffic. Please reset fwd mode.\n");
737 return;
738 }
739
740
741 if (fwd_mode == IOFWD) {
742 printf("Checking eth link status...\n");
743
744 for (i = 0; i < 100; i++) {
745 ret = rte_eth_link_get(eth_port_id, ð_link);
746 if (ret < 0) {
747 printf("Link get failed with err %d\n", ret);
748 return;
749 }
750 if (eth_link.link_status) {
751 rte_eth_link_to_str(link_status_text,
752 sizeof(link_status_text),
753 ð_link);
754 printf("Eth%u %s\n", eth_port_id,
755 link_status_text);
756 break;
757 }
758 }
759 if (!eth_link.link_status) {
760 printf("Eth%u link down. Cannot start traffic.\n",
761 eth_port_id);
762 return;
763 }
764 }
765
766 assign_stream_to_lcores();
767 in_test = 1;
768
769 RTE_LCORE_FOREACH_WORKER(lcore_id) {
770 conf = &fwd_lcore_conf[lcore_id];
771
772 if (!conf->nb_stream)
773 continue;
774
775 conf->stopped = 0;
776 if (fwd_mode == FILE_TRANS)
777 rte_eal_remote_launch(start_polling_recv_file,
778 conf, lcore_id);
779 else if (fwd_mode == IOFWD)
780 rte_eal_remote_launch(start_iofwd_per_lcore,
781 conf, lcore_id);
782 else if (fwd_mode == RXONLY)
783 rte_eal_remote_launch(start_rxonly_per_lcore,
784 conf, lcore_id);
785 else if (fwd_mode == TXONLY)
786 rte_eal_remote_launch(start_txonly_per_lcore,
787 conf, lcore_id);
788 }
789}
790
791
792struct cmd_start_result {
793 cmdline_fixed_string_t start;
794};
795
796static void
797cmd_start_parsed(__rte_unused void *parsed_result,
798 __rte_unused struct cmdline *cl,
799 __rte_unused void *data)
800{
801 start_pkt_fwd();
802}
803
804cmdline_parse_token_string_t cmd_start_start =
805 TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
806
807cmdline_parse_inst_t cmd_start = {
808 .f = cmd_start_parsed,
809 .data = NULL,
810 .help_str = "start pkt fwd between ntb and ethdev",
811 .tokens = {
812 (void *)&cmd_start_start,
813 NULL,
814 },
815};
816
817
818struct cmd_stop_result {
819 cmdline_fixed_string_t stop;
820};
821
822static void
823cmd_stop_parsed(__rte_unused void *parsed_result,
824 __rte_unused struct cmdline *cl,
825 __rte_unused void *data)
826{
827 struct ntb_fwd_lcore_conf *conf;
828 uint32_t lcore_id;
829
830 RTE_LCORE_FOREACH_WORKER(lcore_id) {
831 conf = &fwd_lcore_conf[lcore_id];
832
833 if (!conf->nb_stream)
834 continue;
835
836 if (conf->stopped)
837 continue;
838
839 conf->stopped = 1;
840 }
841 printf("\nWaiting for lcores to finish...\n");
842 rte_eal_mp_wait_lcore();
843 in_test = 0;
844 printf("\nDone.\n");
845}
846
847cmdline_parse_token_string_t cmd_stop_stop =
848 TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
849
850cmdline_parse_inst_t cmd_stop = {
851 .f = cmd_stop_parsed,
852 .data = NULL,
853 .help_str = "stop: Stop packet forwarding",
854 .tokens = {
855 (void *)&cmd_stop_stop,
856 NULL,
857 },
858};
859
860static void
861ntb_stats_clear(void)
862{
863 int nb_ids, i;
864 uint32_t *ids;
865
866
867 nb_ids = rte_rawdev_xstats_names_get(dev_id, NULL, 0);
868 if (nb_ids < 0) {
869 printf("Error: Cannot get count of xstats\n");
870 return;
871 }
872 ids = malloc(sizeof(uint32_t) * nb_ids);
873 for (i = 0; i < nb_ids; i++)
874 ids[i] = i;
875 rte_rawdev_xstats_reset(dev_id, ids, nb_ids);
876 printf("\n statistics for NTB port %d cleared\n", dev_id);
877
878
879 if (fwd_mode == IOFWD && eth_port_id != RTE_MAX_ETHPORTS) {
880 rte_eth_stats_reset(eth_port_id);
881 printf("\n statistics for ETH port %d cleared\n", eth_port_id);
882 }
883}
884
885static inline void
886ntb_calculate_throughput(uint16_t port) {
887 uint64_t diff_pkts_rx, diff_pkts_tx, diff_cycles;
888 uint64_t mpps_rx, mpps_tx;
889 static uint64_t prev_pkts_rx[2];
890 static uint64_t prev_pkts_tx[2];
891 static uint64_t prev_cycles[2];
892
893 diff_cycles = prev_cycles[port];
894 prev_cycles[port] = rte_rdtsc();
895 if (diff_cycles > 0)
896 diff_cycles = prev_cycles[port] - diff_cycles;
897 diff_pkts_rx = (ntb_port_stats[port].rx > prev_pkts_rx[port]) ?
898 (ntb_port_stats[port].rx - prev_pkts_rx[port]) : 0;
899 diff_pkts_tx = (ntb_port_stats[port].tx > prev_pkts_tx[port]) ?
900 (ntb_port_stats[port].tx - prev_pkts_tx[port]) : 0;
901 prev_pkts_rx[port] = ntb_port_stats[port].rx;
902 prev_pkts_tx[port] = ntb_port_stats[port].tx;
903 mpps_rx = diff_cycles > 0 ?
904 diff_pkts_rx * rte_get_tsc_hz() / diff_cycles : 0;
905 mpps_tx = diff_cycles > 0 ?
906 diff_pkts_tx * rte_get_tsc_hz() / diff_cycles : 0;
907 printf(" Throughput (since last show)\n");
908 printf(" Rx-pps: %12"PRIu64"\n Tx-pps: %12"PRIu64"\n",
909 mpps_rx, mpps_tx);
910
911}
912
913static void
914ntb_stats_display(void)
915{
916 struct rte_rawdev_xstats_name *xstats_names;
917 struct rte_eth_stats stats;
918 uint64_t *values;
919 uint32_t *ids;
920 int nb_ids, i;
921
922 printf("###### statistics for NTB port %d #######\n", dev_id);
923
924
925 nb_ids = rte_rawdev_xstats_names_get(dev_id, NULL, 0);
926 if (nb_ids < 0) {
927 printf("Error: Cannot get count of xstats\n");
928 return;
929 }
930 xstats_names = malloc(sizeof(struct rte_rawdev_xstats_name) * nb_ids);
931 if (xstats_names == NULL) {
932 printf("Cannot allocate memory for xstats lookup\n");
933 return;
934 }
935 if (nb_ids != rte_rawdev_xstats_names_get(
936 dev_id, xstats_names, nb_ids)) {
937 printf("Error: Cannot get xstats lookup\n");
938 free(xstats_names);
939 return;
940 }
941 ids = malloc(sizeof(uint32_t) * nb_ids);
942 for (i = 0; i < nb_ids; i++)
943 ids[i] = i;
944 values = malloc(sizeof(uint64_t) * nb_ids);
945 if (nb_ids != rte_rawdev_xstats_get(dev_id, ids, values, nb_ids)) {
946 printf("Error: Unable to get xstats\n");
947 free(xstats_names);
948 free(values);
949 free(ids);
950 return;
951 }
952
953
954 for (i = 0; i < nb_ids; i++)
955 printf(" %s: %"PRIu64"\n", xstats_names[i].name, values[i]);
956 ntb_calculate_throughput(0);
957
958
959 if (fwd_mode == IOFWD && eth_port_id != RTE_MAX_ETHPORTS) {
960 printf("###### statistics for ETH port %d ######\n",
961 eth_port_id);
962 rte_eth_stats_get(eth_port_id, &stats);
963 printf(" RX-packets: %"PRIu64"\n", stats.ipackets);
964 printf(" RX-bytes: %"PRIu64"\n", stats.ibytes);
965 printf(" RX-errors: %"PRIu64"\n", stats.ierrors);
966 printf(" RX-missed: %"PRIu64"\n", stats.imissed);
967 printf(" TX-packets: %"PRIu64"\n", stats.opackets);
968 printf(" TX-bytes: %"PRIu64"\n", stats.obytes);
969 printf(" TX-errors: %"PRIu64"\n", stats.oerrors);
970 ntb_calculate_throughput(1);
971 }
972
973 free(xstats_names);
974 free(values);
975 free(ids);
976}
977
978
979struct cmd_stats_result {
980 cmdline_fixed_string_t show;
981 cmdline_fixed_string_t port;
982 cmdline_fixed_string_t stats;
983};
984
985static void
986cmd_stats_parsed(void *parsed_result,
987 __rte_unused struct cmdline *cl,
988 __rte_unused void *data)
989{
990 struct cmd_stats_result *res = parsed_result;
991 if (!strcmp(res->show, "clear"))
992 ntb_stats_clear();
993 else
994 ntb_stats_display();
995}
996
997cmdline_parse_token_string_t cmd_stats_show =
998 TOKEN_STRING_INITIALIZER(struct cmd_stats_result, show, "show#clear");
999cmdline_parse_token_string_t cmd_stats_port =
1000 TOKEN_STRING_INITIALIZER(struct cmd_stats_result, port, "port");
1001cmdline_parse_token_string_t cmd_stats_stats =
1002 TOKEN_STRING_INITIALIZER(struct cmd_stats_result, stats, "stats");
1003
1004
1005cmdline_parse_inst_t cmd_stats = {
1006 .f = cmd_stats_parsed,
1007 .data = NULL,
1008 .help_str = "show|clear port stats",
1009 .tokens = {
1010 (void *)&cmd_stats_show,
1011 (void *)&cmd_stats_port,
1012 (void *)&cmd_stats_stats,
1013 NULL,
1014 },
1015};
1016
1017
1018struct cmd_set_fwd_mode_result {
1019 cmdline_fixed_string_t set;
1020 cmdline_fixed_string_t fwd;
1021 cmdline_fixed_string_t mode;
1022};
1023
1024static void
1025cmd_set_fwd_mode_parsed(__rte_unused void *parsed_result,
1026 __rte_unused struct cmdline *cl,
1027 __rte_unused void *data)
1028{
1029 struct cmd_set_fwd_mode_result *res = parsed_result;
1030 int i;
1031
1032 if (in_test) {
1033 printf("Please stop traffic first.\n");
1034 return;
1035 }
1036
1037 for (i = 0; i < MAX_FWD_MODE; i++) {
1038 if (!strcmp(res->mode, fwd_mode_s[i])) {
1039 fwd_mode = i;
1040 return;
1041 }
1042 }
1043 printf("Invalid %s packet forwarding mode.\n", res->mode);
1044}
1045
1046cmdline_parse_token_string_t cmd_setfwd_set =
1047 TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, set, "set");
1048cmdline_parse_token_string_t cmd_setfwd_fwd =
1049 TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, fwd, "fwd");
1050cmdline_parse_token_string_t cmd_setfwd_mode =
1051 TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, mode,
1052 "file-trans#iofwd#txonly#rxonly");
1053
1054cmdline_parse_inst_t cmd_set_fwd_mode = {
1055 .f = cmd_set_fwd_mode_parsed,
1056 .data = NULL,
1057 .help_str = "set forwarding mode as file-trans|rxonly|txonly|iofwd",
1058 .tokens = {
1059 (void *)&cmd_setfwd_set,
1060 (void *)&cmd_setfwd_fwd,
1061 (void *)&cmd_setfwd_mode,
1062 NULL,
1063 },
1064};
1065
1066
1067cmdline_parse_ctx_t main_ctx[] = {
1068 (cmdline_parse_inst_t *)&cmd_help,
1069 (cmdline_parse_inst_t *)&cmd_send_file,
1070 (cmdline_parse_inst_t *)&cmd_start,
1071 (cmdline_parse_inst_t *)&cmd_stop,
1072 (cmdline_parse_inst_t *)&cmd_stats,
1073 (cmdline_parse_inst_t *)&cmd_set_fwd_mode,
1074 (cmdline_parse_inst_t *)&cmd_quit,
1075 NULL,
1076};
1077
1078
1079static void
1080prompt(void)
1081{
1082 struct cmdline *cl;
1083
1084 cl = cmdline_stdin_new(main_ctx, "ntb> ");
1085 if (cl == NULL)
1086 return;
1087
1088 cmdline_interact(cl);
1089 cmdline_stdin_exit(cl);
1090}
1091
1092static void
1093signal_handler(int signum)
1094{
1095 if (signum == SIGINT || signum == SIGTERM) {
1096 printf("\nSignal %d received, preparing to exit...\n", signum);
1097 signal(signum, SIG_DFL);
1098 kill(getpid(), signum);
1099 }
1100}
1101
1102#define OPT_BUF_SIZE "buf-size"
1103#define OPT_FWD_MODE "fwd-mode"
1104#define OPT_NB_DESC "nb-desc"
1105#define OPT_TXFREET "txfreet"
1106#define OPT_BURST "burst"
1107#define OPT_QP "qp"
1108
1109enum {
1110
1111 OPT_NO_ZERO_COPY_NUM = 1,
1112 OPT_BUF_SIZE_NUM,
1113 OPT_FWD_MODE_NUM,
1114 OPT_NB_DESC_NUM,
1115 OPT_TXFREET_NUM,
1116 OPT_BURST_NUM,
1117 OPT_QP_NUM,
1118};
1119
1120static const char short_options[] =
1121 "i"
1122 ;
1123
1124static const struct option lgopts[] = {
1125 {OPT_BUF_SIZE, 1, NULL, OPT_BUF_SIZE_NUM },
1126 {OPT_FWD_MODE, 1, NULL, OPT_FWD_MODE_NUM },
1127 {OPT_NB_DESC, 1, NULL, OPT_NB_DESC_NUM },
1128 {OPT_TXFREET, 1, NULL, OPT_TXFREET_NUM },
1129 {OPT_BURST, 1, NULL, OPT_BURST_NUM },
1130 {OPT_QP, 1, NULL, OPT_QP_NUM },
1131 {0, 0, NULL, 0 }
1132};
1133
1134static void
1135ntb_usage(const char *prgname)
1136{
1137 printf("%s [EAL options] -- [options]\n"
1138 "-i: run in interactive mode.\n"
1139 "-qp=N: set number of queues as N (N > 0, default: 1).\n"
1140 "--fwd-mode=N: set fwd mode (N: file-trans | rxonly | "
1141 "txonly | iofwd, default: file-trans)\n"
1142 "--buf-size=N: set mbuf dataroom size as N (0 < N < 65535,"
1143 " default: 2048).\n"
1144 "--nb-desc=N: set number of descriptors as N (%u <= N <= %u,"
1145 " default: 1024).\n"
1146 "--txfreet=N: set tx free thresh for NTB driver as N. (N >= 0)\n"
1147 "--burst=N: set pkt burst as N (0 < N <= %u default: 32).\n",
1148 prgname, NTB_MIN_DESC_SIZE, NTB_MAX_DESC_SIZE,
1149 NTB_MAX_PKT_BURST);
1150}
1151
1152static void
1153ntb_parse_args(int argc, char **argv)
1154{
1155 char *prgname = argv[0], **argvopt = argv;
1156 int opt, opt_idx, n, i;
1157
1158 while ((opt = getopt_long(argc, argvopt, short_options,
1159 lgopts, &opt_idx)) != EOF) {
1160 switch (opt) {
1161 case 'i':
1162 printf("Interactive-mode selected.\n");
1163 interactive = 1;
1164 break;
1165 case OPT_QP_NUM:
1166 n = atoi(optarg);
1167 if (n > 0)
1168 num_queues = n;
1169 else
1170 rte_exit(EXIT_FAILURE, "q must be > 0.\n");
1171 break;
1172 case OPT_BUF_SIZE_NUM:
1173 n = atoi(optarg);
1174 if (n > RTE_PKTMBUF_HEADROOM && n <= 0xFFFF)
1175 ntb_buf_size = n;
1176 else
1177 rte_exit(EXIT_FAILURE, "buf-size must be > "
1178 "%u and < 65536.\n",
1179 RTE_PKTMBUF_HEADROOM);
1180 break;
1181 case OPT_FWD_MODE_NUM:
1182 for (i = 0; i < MAX_FWD_MODE; i++) {
1183 if (!strcmp(optarg, fwd_mode_s[i])) {
1184 fwd_mode = i;
1185 break;
1186 }
1187 }
1188 if (i == MAX_FWD_MODE)
1189 rte_exit(EXIT_FAILURE, "Unsupported mode. "
1190 "(Should be: file-trans | rxonly | txonly "
1191 "| iofwd)\n");
1192 break;
1193 case OPT_NB_DESC_NUM:
1194 n = atoi(optarg);
1195 if (n >= NTB_MIN_DESC_SIZE && n <= NTB_MAX_DESC_SIZE)
1196 nb_desc = n;
1197 else
1198 rte_exit(EXIT_FAILURE, "nb-desc must be within"
1199 " [%u, %u].\n", NTB_MIN_DESC_SIZE,
1200 NTB_MAX_DESC_SIZE);
1201 break;
1202 case OPT_TXFREET_NUM:
1203 n = atoi(optarg);
1204 if (n >= 0)
1205 tx_free_thresh = n;
1206 else
1207 rte_exit(EXIT_FAILURE, "txfreet must be"
1208 " >= 0\n");
1209 break;
1210 case OPT_BURST_NUM:
1211 n = atoi(optarg);
1212 if (n > 0 && n <= NTB_MAX_PKT_BURST)
1213 pkt_burst = n;
1214 else
1215 rte_exit(EXIT_FAILURE, "burst must be within "
1216 "(0, %u].\n", NTB_MAX_PKT_BURST);
1217 break;
1218
1219 default:
1220 ntb_usage(prgname);
1221 rte_exit(EXIT_FAILURE,
1222 "Command line is incomplete or incorrect.\n");
1223 break;
1224 }
1225 }
1226}
1227
1228static void
1229ntb_mempool_mz_free(__rte_unused struct rte_mempool_memhdr *memhdr,
1230 void *opaque)
1231{
1232 const struct rte_memzone *mz = opaque;
1233 rte_memzone_free(mz);
1234}
1235
1236static struct rte_mempool *
1237ntb_mbuf_pool_create(uint16_t mbuf_seg_size, uint32_t nb_mbuf,
1238 struct ntb_dev_info ntb_info,
1239 struct ntb_dev_config *ntb_conf,
1240 unsigned int socket_id)
1241{
1242 size_t mz_len, total_elt_sz, max_mz_len, left_sz;
1243 struct rte_pktmbuf_pool_private mbp_priv;
1244 char pool_name[RTE_MEMPOOL_NAMESIZE];
1245 char mz_name[RTE_MEMZONE_NAMESIZE];
1246 const struct rte_memzone *mz;
1247 struct rte_mempool *mp;
1248 uint64_t align;
1249 uint32_t mz_id;
1250 int ret;
1251
1252 snprintf(pool_name, sizeof(pool_name), "ntb_mbuf_pool_%u", socket_id);
1253 mp = rte_mempool_create_empty(pool_name, nb_mbuf,
1254 (mbuf_seg_size + sizeof(struct rte_mbuf)),
1255 MEMPOOL_CACHE_SIZE,
1256 sizeof(struct rte_pktmbuf_pool_private),
1257 socket_id, 0);
1258 if (mp == NULL)
1259 return NULL;
1260
1261 if (rte_mempool_set_ops_byname(mp, rte_mbuf_best_mempool_ops(), NULL)) {
1262 printf("error setting mempool handler\n");
1263 goto fail;
1264 }
1265
1266 memset(&mbp_priv, 0, sizeof(mbp_priv));
1267 mbp_priv.mbuf_data_room_size = mbuf_seg_size;
1268 mbp_priv.mbuf_priv_size = 0;
1269 rte_pktmbuf_pool_init(mp, &mbp_priv);
1270
1271 ntb_conf->mz_list = rte_zmalloc("ntb_memzone_list",
1272 sizeof(struct rte_memzone *) *
1273 ntb_info.mw_cnt, 0);
1274 if (ntb_conf->mz_list == NULL)
1275 goto fail;
1276
1277
1278 if (ntb_info.mw_size[0] < ntb_info.ntb_hdr_size) {
1279 printf("mw0 (size: %" PRIu64 ") is not enough for ntb hdr"
1280 " (size: %u)\n", ntb_info.mw_size[0],
1281 ntb_info.ntb_hdr_size);
1282 goto fail;
1283 }
1284
1285 total_elt_sz = mp->header_size + mp->elt_size + mp->trailer_size;
1286 left_sz = total_elt_sz * nb_mbuf;
1287 for (mz_id = 0; mz_id < ntb_info.mw_cnt; mz_id++) {
1288
1289 if (!left_sz)
1290 break;
1291 snprintf(mz_name, sizeof(mz_name), "ntb_mw_%d", mz_id);
1292 align = ntb_info.mw_size_align ? ntb_info.mw_size[mz_id] :
1293 RTE_CACHE_LINE_SIZE;
1294
1295 max_mz_len = mz_id ? ntb_info.mw_size[mz_id] :
1296 ntb_info.mw_size[mz_id] - ntb_info.ntb_hdr_size;
1297 mz_len = left_sz <= max_mz_len ? left_sz :
1298 (max_mz_len / total_elt_sz * total_elt_sz);
1299 if (!mz_len)
1300 continue;
1301 mz = rte_memzone_reserve_aligned(mz_name, mz_len, socket_id,
1302 RTE_MEMZONE_IOVA_CONTIG, align);
1303 if (mz == NULL) {
1304 printf("Cannot allocate %" PRIu64 " aligned memzone"
1305 " %u\n", align, mz_id);
1306 goto fail;
1307 }
1308 left_sz -= mz_len;
1309
1310
1311 if (mz_id)
1312 ret = rte_mempool_populate_iova(mp, mz->addr, mz->iova,
1313 mz->len, ntb_mempool_mz_free,
1314 (void *)(uintptr_t)mz);
1315 else
1316 ret = rte_mempool_populate_iova(mp,
1317 (void *)((size_t)mz->addr +
1318 ntb_info.ntb_hdr_size),
1319 mz->iova + ntb_info.ntb_hdr_size,
1320 mz->len - ntb_info.ntb_hdr_size,
1321 ntb_mempool_mz_free,
1322 (void *)(uintptr_t)mz);
1323 if (ret <= 0) {
1324 rte_memzone_free(mz);
1325 rte_mempool_free(mp);
1326 return NULL;
1327 }
1328
1329 ntb_conf->mz_list[mz_id] = mz;
1330 }
1331 if (left_sz) {
1332 printf("mw space is not enough for mempool.\n");
1333 goto fail;
1334 }
1335
1336 ntb_conf->mz_num = mz_id;
1337 rte_mempool_obj_iter(mp, rte_pktmbuf_init, NULL);
1338
1339 return mp;
1340fail:
1341 rte_mempool_free(mp);
1342 return NULL;
1343}
1344
1345int
1346main(int argc, char **argv)
1347{
1348 struct rte_eth_conf eth_pconf = eth_port_conf;
1349 struct rte_rawdev_info ntb_rawdev_conf;
1350 struct rte_rawdev_info ntb_rawdev_info;
1351 struct rte_eth_dev_info ethdev_info;
1352 struct rte_eth_rxconf eth_rx_conf;
1353 struct rte_eth_txconf eth_tx_conf;
1354 struct ntb_queue_conf ntb_q_conf;
1355 struct ntb_dev_config ntb_conf;
1356 struct ntb_dev_info ntb_info;
1357 uint64_t ntb_link_status;
1358 uint32_t nb_mbuf;
1359 int ret, i;
1360
1361 signal(SIGINT, signal_handler);
1362 signal(SIGTERM, signal_handler);
1363
1364 ret = rte_eal_init(argc, argv);
1365 if (ret < 0)
1366 rte_exit(EXIT_FAILURE, "Error with EAL initialization.\n");
1367
1368 if (rte_lcore_count() < 2)
1369 rte_exit(EXIT_FAILURE, "Need at least 2 cores\n");
1370
1371
1372 for (i = 0; i < RTE_RAWDEV_MAX_DEVS; i++)
1373 if (rte_rawdevs[i].driver_name &&
1374 (strncmp(rte_rawdevs[i].driver_name, "raw_ntb",
1375 NTB_DRV_NAME_LEN) == 0) && (rte_rawdevs[i].attached == 1))
1376 break;
1377
1378 if (i == RTE_RAWDEV_MAX_DEVS)
1379 rte_exit(EXIT_FAILURE, "Cannot find any ntb device.\n");
1380
1381 dev_id = i;
1382
1383 argc -= ret;
1384 argv += ret;
1385
1386 ntb_parse_args(argc, argv);
1387
1388 rte_rawdev_set_attr(dev_id, NTB_QUEUE_SZ_NAME, nb_desc);
1389 printf("Set queue size as %u.\n", nb_desc);
1390 rte_rawdev_set_attr(dev_id, NTB_QUEUE_NUM_NAME, num_queues);
1391 printf("Set queue number as %u.\n", num_queues);
1392 ntb_rawdev_info.dev_private = (rte_rawdev_obj_t)(&ntb_info);
1393 rte_rawdev_info_get(dev_id, &ntb_rawdev_info, sizeof(ntb_info));
1394
1395 nb_mbuf = nb_desc * num_queues * 2 * 2 + rte_lcore_count() *
1396 MEMPOOL_CACHE_SIZE;
1397 mbuf_pool = ntb_mbuf_pool_create(ntb_buf_size, nb_mbuf, ntb_info,
1398 &ntb_conf, rte_socket_id());
1399 if (mbuf_pool == NULL)
1400 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool.\n");
1401
1402 ntb_conf.num_queues = num_queues;
1403 ntb_conf.queue_size = nb_desc;
1404 ntb_rawdev_conf.dev_private = (rte_rawdev_obj_t)(&ntb_conf);
1405 ret = rte_rawdev_configure(dev_id, &ntb_rawdev_conf, sizeof(ntb_conf));
1406 if (ret)
1407 rte_exit(EXIT_FAILURE, "Can't config ntb dev: err=%d, "
1408 "port=%u\n", ret, dev_id);
1409
1410 ntb_q_conf.tx_free_thresh = tx_free_thresh;
1411 ntb_q_conf.nb_desc = nb_desc;
1412 ntb_q_conf.rx_mp = mbuf_pool;
1413 for (i = 0; i < num_queues; i++) {
1414
1415 ret = rte_rawdev_queue_setup(dev_id, i, &ntb_q_conf,
1416 sizeof(ntb_q_conf));
1417 if (ret < 0)
1418 rte_exit(EXIT_FAILURE,
1419 "Failed to setup ntb queue %u.\n", i);
1420 }
1421
1422
1423 printf("Checking ntb link status...\n");
1424 for (i = 0; i < 1000; i++) {
1425 rte_rawdev_get_attr(dev_id, NTB_LINK_STATUS_NAME,
1426 &ntb_link_status);
1427 if (ntb_link_status) {
1428 printf("Peer dev ready, ntb link up.\n");
1429 break;
1430 }
1431 rte_delay_ms(100);
1432 }
1433 rte_rawdev_get_attr(dev_id, NTB_LINK_STATUS_NAME, &ntb_link_status);
1434 if (ntb_link_status == 0)
1435 printf("Expire 100s. Link is not up. Please restart app.\n");
1436
1437 ret = rte_rawdev_start(dev_id);
1438 if (ret < 0)
1439 rte_exit(EXIT_FAILURE, "rte_rawdev_start: err=%d, port=%u\n",
1440 ret, dev_id);
1441
1442
1443 eth_port_id = rte_eth_find_next(0);
1444
1445 if (eth_port_id < RTE_MAX_ETHPORTS) {
1446 rte_eth_dev_info_get(eth_port_id, ðdev_info);
1447 eth_pconf.rx_adv_conf.rss_conf.rss_hf &=
1448 ethdev_info.flow_type_rss_offloads;
1449 ret = rte_eth_dev_configure(eth_port_id, num_queues,
1450 num_queues, ð_pconf);
1451 if (ret)
1452 rte_exit(EXIT_FAILURE, "Can't config ethdev: err=%d, "
1453 "port=%u\n", ret, eth_port_id);
1454 eth_rx_conf = ethdev_info.default_rxconf;
1455 eth_rx_conf.offloads = eth_pconf.rxmode.offloads;
1456 eth_tx_conf = ethdev_info.default_txconf;
1457 eth_tx_conf.offloads = eth_pconf.txmode.offloads;
1458
1459
1460 for (i = 0; i < num_queues; i++) {
1461 ret = rte_eth_rx_queue_setup(eth_port_id, i, nb_desc,
1462 rte_eth_dev_socket_id(eth_port_id),
1463 ð_rx_conf, mbuf_pool);
1464 if (ret < 0)
1465 rte_exit(EXIT_FAILURE,
1466 "Failed to setup eth rxq %u.\n", i);
1467 ret = rte_eth_tx_queue_setup(eth_port_id, i, nb_desc,
1468 rte_eth_dev_socket_id(eth_port_id),
1469 ð_tx_conf);
1470 if (ret < 0)
1471 rte_exit(EXIT_FAILURE,
1472 "Failed to setup eth txq %u.\n", i);
1473 }
1474
1475 ret = rte_eth_dev_start(eth_port_id);
1476 if (ret < 0)
1477 rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
1478 "port=%u\n", ret, eth_port_id);
1479 }
1480
1481
1482 memset(&ntb_port_stats, 0, sizeof(ntb_port_stats));
1483
1484
1485 if (fwd_mode == MAX_FWD_MODE && eth_port_id < RTE_MAX_ETHPORTS) {
1486 printf("Set default fwd mode as iofwd.\n");
1487 fwd_mode = IOFWD;
1488 }
1489 if (fwd_mode == MAX_FWD_MODE) {
1490 printf("Set default fwd mode as file-trans.\n");
1491 fwd_mode = FILE_TRANS;
1492 }
1493
1494 if (interactive) {
1495 sleep(1);
1496 prompt();
1497 } else {
1498 start_pkt_fwd();
1499 }
1500
1501
1502 rte_eal_cleanup();
1503
1504 return 0;
1505}
1506