DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注
DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注DPDK l2fwd 浅注

l2fwd是DPDK中的非常经典的例子。二层转发模型。
就是在相邻的网卡接口间互相传递报文。
网口0和网口1之间报文互传。
网口2和网口3之间报文互传。
。。。。。。。。。。。。

运行参数 .
在目录/home/yml/dpdk/dpdk-stable-16.07.2/examples/l2fwd/build 下面(当然要先编译这个例子 make)
  1. ./l2fwd [EAL options]---p PORTMASK [-q NQ]--[no-]mac-updating
EAL options : 就是EAL的参数 ,我这里设成
  1. -c 3-n 2
  1. -c 表示的是整个程序会使用哪些核
  2. 例如:-c f 表示 20+21+22+23
  3. 表示 四个核都会用上。
 
-n 表示内存的通道数。
 
-- -p  : 表示使用哪些网口, 
  1. ---p 3
表示使用网口0和1 。
  1. -q 1
表示每个逻辑核(lcore线程)上分配一个网口。
 
我这里直接用下面的参数运行。
  1. ./l2fwd -c3 -n2 ---p 3-q 1
 

 
  1. int
  2. main(int argc,char**argv)
  3. {
  4. struct lcore_queue_conf *qconf;
  5. struct rte_eth_dev_info dev_info;
  6. int ret;
  7. uint8_t nb_ports;
  8. uint8_t nb_ports_available;
  9. uint8_t portid, last_port;
  10. unsigned lcore_id, rx_lcore_id;
  11. unsigned nb_ports_in_mask =0;
  12. /* init EAL */
  13. ret = rte_eal_init(argc, argv); //EAL的初使化。
  14. if(ret <0)
  15. rte_exit(EXIT_FAILURE,"Invalid EAL arguments\n");
  16. argc -= ret;
  17. argv += ret;
  18. force_quit =false;
  19. signal(SIGINT, signal_handler);
  20. signal(SIGTERM, signal_handler);
  21. /* parse application arguments (after the EAL ones) */
  22. ret = l2fwd_parse_args(argc, argv);//这里是解析后面的---p 3-q 1 参数,用于获得这些参数的值。
  23. if(ret <0)
  24. rte_exit(EXIT_FAILURE,"Invalid L2FWD arguments\n");
  25. /* convert to number of cycles */
  26. timer_period *= rte_get_timer_hz();
  27. /* create the mbuf pool */
  28. l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF,
  29. MEMPOOL_CACHE_SIZE,0, RTE_MBUF_DEFAULT_BUF_SIZE, //创建内存池,
  30. rte_socket_id());
  31. if(l2fwd_pktmbuf_pool == NULL)
  32. rte_exit(EXIT_FAILURE,"Cannot init mbuf pool\n");
  33. nb_ports = rte_eth_dev_count(); //获得当初可用的最大网口数,是从PCI中获得的。
  34. if(nb_ports ==0)
  35. rte_exit(EXIT_FAILURE,"No Ethernet ports - bye\n");
  36. /* reset l2fwd_dst_ports */
  37. for(portid =0; portid < RTE_MAX_ETHPORTS; portid++)
  38. l2fwd_dst_ports[portid]=0;
  39. last_port =0;
  40. /*
  41. * Each logical core is assigned a dedicated TX queue on each port.
  42. */
  43. for(portid =0; portid < nb_ports; portid++){ //这里其实就是确定每个网口的发包对象。如网口0的报文传给网口1,。。。。这里就是初使化一个数组。
  44. /* skip ports that are not enabled */
  45. if((l2fwd_enabled_port_mask &(1<< portid))==0)
  46. continue;
  47. if(nb_ports_in_mask %2){
  48. l2fwd_dst_ports[portid]= last_port;
  49. l2fwd_dst_ports[last_port]= portid;
  50. }
  51. else
  52. last_port = portid;
  53. nb_ports_in_mask++;
  54. rte_eth_dev_info_get(portid,&dev_info);
  55. }
  56. if(nb_ports_in_mask %2){
  57. printf("Notice: odd number of ports in portmask.\n");
  58. l2fwd_dst_ports[last_port]= last_port;
  59. }
  60. rx_lcore_id =0;
  61. qconf = NULL;
  62. /* Initialize the port/queue configuration of each logical core */
  63. for(portid =0; portid < nb_ports; portid++){//给每一个网口分配一个可用的,你配置过的逻辑核
  64. /* skip ports that are not enabled */
  65. if((l2fwd_enabled_port_mask &(1<< portid))==0)
  66. continue;
  67. /* get the lcore_id for this port */
  68. while(rte_lcore_is_enabled(rx_lcore_id)==0||
  69. lcore_queue_conf[rx_lcore_id].n_rx_port ==
  70. l2fwd_rx_queue_per_lcore){
  71. rx_lcore_id++;
  72. if(rx_lcore_id >= RTE_MAX_LCORE)
  73. rte_exit(EXIT_FAILURE,"Not enough cores\n");
  74. }
  75. if(qconf !=&lcore_queue_conf[rx_lcore_id])
  76. /* Assigned a new logical core in the loop above. */
  77. qconf =&lcore_queue_conf[rx_lcore_id];
  78. qconf->rx_port_list[qconf->n_rx_port]= portid;
  79. qconf->n_rx_port++;
  80. printf("Lcore %u: RX port %u\n", rx_lcore_id,(unsigned) portid);
  81. }
  82. nb_ports_available = nb_ports;
  83. /* Initialise each port */
  84. for(portid =0; portid < nb_ports; portid++){//就是初使化网口,给每个网口分配接收的缓存,分配接收和发送的队列。
  85. /* skip ports that are not enabled */
  86. if((l2fwd_enabled_port_mask &(1<< portid))==0){
  87. printf("Skipping disabled port %u\n",(unsigned) portid);
  88. nb_ports_available--;
  89. continue;
  90. }
  91. /* init port */
  92. printf("Initializing port %u... ",(unsigned) portid);
  93. fflush(stdout);
  94. ret = rte_eth_dev_configure(portid,1,1,&port_conf);//设置portid这个网口一个接收和一个发送的队列。
  95. if(ret <0)
  96. rte_exit(EXIT_FAILURE,"Cannot configure device: err=%d, port=%u\n",
  97. ret,(unsigned) portid);
  98. rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
  99. /* init one RX queue */
  100. fflush(stdout);
  101. ret = rte_eth_rx_queue_setup(portid,0, nb_rxd, //给对应的网口分配接收队列。
  102. rte_eth_dev_socket_id(portid),
  103. NULL,
  104. l2fwd_pktmbuf_pool);
  105. if(ret <0)
  106. rte_exit(EXIT_FAILURE,"rte_eth_rx_queue_setup:err=%d, port=%u\n",
  107. ret,(unsigned) portid);
  108. /* init one TX queue on each port */
  109. fflush(stdout);
  110. ret = rte_eth_tx_queue_setup(portid,0, nb_txd,//给对应的网口分配发送队列。
  111. rte_eth_dev_socket_id(portid),
  112. NULL);
  113. if(ret <0)
  114. rte_exit(EXIT_FAILURE,"rte_eth_tx_queue_setup:err=%d, port=%u\n",
  115. ret,(unsigned) portid);
  116. /* Initialize TX buffers */
  117. tx_buffer[portid]= rte_zmalloc_socket("tx_buffer",//分配接收缓存空间,就是收包的缓存。
  118. RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST),0,
  119. rte_eth_dev_socket_id(portid));
  120. if(tx_buffer[portid]== NULL)
  121. rte_exit(EXIT_FAILURE,"Cannot allocate buffer for tx on port %u\n",
  122. (unsigned) portid);
  123. rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
  124. ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],//当报文发送失败后要调用的回调函数
  125. rte_eth_tx_buffer_count_callback,
  126. &port_statistics[portid].dropped);
  127. if(ret <0)
  128. rte_exit(EXIT_FAILURE,"Cannot set error callback for "
  129. "tx buffer on port %u\n",(unsigned) portid);
  130. /* Start device */
  131. ret = rte_eth_dev_start(portid);
  132. if(ret <0)
  133. rte_exit(EXIT_FAILURE,"rte_eth_dev_start:err=%d, port=%u\n",
  134. ret,(unsigned) portid);
  135. printf("done: \n");
  136. rte_eth_promiscuous_enable(portid);//设置该网口为混杂模式,就是接收所有的报文。
  137. printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",//初使化报文统计
  138. (unsigned) portid,
  139. l2fwd_ports_eth_addr[portid].addr_bytes[0],
  140. l2fwd_ports_eth_addr[portid].addr_bytes[1],
  141. l2fwd_ports_eth_addr[portid].addr_bytes[2],
  142. l2fwd_ports_eth_addr[portid].addr_bytes[3],
  143. l2fwd_ports_eth_addr[portid].addr_bytes[4],
  144. l2fwd_ports_eth_addr[portid].addr_bytes[5]);
  145. /* initialize port stats */
  146. memset(&port_statistics,0,sizeof(port_statistics));
  147. }
  148. if(!nb_ports_available){
  149. rte_exit(EXIT_FAILURE,
  150. "All available ports are disabled. Please set portmask.\n");
  151. }
  152. check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);//检查这些网口是否可以用。
  153. ret =0;
  154. /* launch per-lcore init on every lcore */
  155. rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);//在所有的逻辑核(包括管理核,一般DPDK会默认将第一个可用的逻辑核当管理核)上执行l2fwd_launch_one_lcore这个函数。
  156. RTE_LCORE_FOREACH_SLAVE(lcore_id){
  157. if(rte_eal_wait_lcore(lcore_id)<0){//等待从逻辑核的结束。
  158. ret =-1;
  159. break;
  160. }
  161. }
  162. for(portid =0; portid < nb_ports; portid++){ //down掉网口,结束。
  163. if((l2fwd_enabled_port_mask &(1<< portid))==0)
  164. continue;
  165. printf("Closing port %d...", portid);
  166. rte_eth_dev_stop(portid);
  167. rte_eth_dev_close(portid);
  168. printf(" Done\n");
  169. }
  170. printf("Bye...\n");
  171. return ret;
  172. }
 
  1. staticvoid
  2. l2fwd_main_loop(void)
  3. {
  4. struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
  5. struct rte_mbuf *m;
  6. int sent;
  7. unsigned lcore_id;
  8. uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
  9. unsigned i, j, portid, nb_rx;
  10. struct lcore_queue_conf *qconf;
  11. constuint64_t drain_tsc =(rte_get_tsc_hz()+ US_PER_S -1)/ US_PER_S *
  12. BURST_TX_DRAIN_US;
  13. struct rte_eth_dev_tx_buffer *buffer;
  14. prev_tsc =0;
  15. timer_tsc =0;
  16. lcore_id = rte_lcore_id();
  17. qconf =&lcore_queue_conf[lcore_id];//获得我们初使化的时候配置的逻辑核与网口的对应关系列表。
  18. if(qconf->n_rx_port ==0){
  19. RTE_LOG(INFO, L2FWD,"lcore %u has nothing to do\n", lcore_id);
  20. return;
  21. }
  22. RTE_LOG(INFO, L2FWD,"entering main loop on lcore %u\n", lcore_id);
  23. for(i =0; i < qconf->n_rx_port; i++){
  24. portid = qconf->rx_port_list[i];
  25. RTE_LOG(INFO, L2FWD," -- lcoreid=%u portid=%u\n", lcore_id,
  26. portid);
  27. }
  28. while(!force_quit){
  29. cur_tsc = rte_rdtsc();
  30. /*
  31. * TX burst queue drain
  32. */
  33. diff_tsc = cur_tsc - prev_tsc;
  34. if(unlikely(diff_tsc > drain_tsc)){//时间时隔到了就刷新发送所有网口上的待发送的报文。
  35. for(i =0; i < qconf->n_rx_port; i++){
  36. portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
  37. buffer = tx_buffer[portid];
  38. sent = rte_eth_tx_buffer_flush(portid,0, buffer);
  39. if(sent)
  40. port_statistics[portid].tx += sent;
  41. }
  42. /* if timer is enabled */
  43. if(timer_period >0){
  44. /* advance the timer */
  45. timer_tsc += diff_tsc;
  46. /* if timer has reached its timeout */
  47. if(unlikely(timer_tsc >= timer_period)){
  48. /* do this only on master core */
  49. if(lcore_id == rte_get_master_lcore()){//如果是在逻辑核上,且符合条件,就打印统计信息。
  50. print_stats();
  51. /* reset the timer */
  52. timer_tsc =0;
  53. }
  54. }
  55. }
  56. prev_tsc = cur_tsc;
  57. }
  58. /*
  59. * Read packet from RX queues
  60. */
  61. for(i =0; i < qconf->n_rx_port; i++){//轮询每个网口,进行接收报文。
  62. portid = qconf->rx_port_list[i];
  63. nb_rx = rte_eth_rx_burst((uint8_t) portid,0,
  64. pkts_burst, MAX_PKT_BURST);
  65. port_statistics[portid].rx += nb_rx;
  66. for(j =0; j < nb_rx; j++){
  67. m = pkts_burst[j];
  68. rte_prefetch0(rte_pktmbuf_mtod(m,void*));
  69. l2fwd_simple_forward(m, portid);
  70. }
  71. }
  72. }
  73. }
  1. staticvoid
  2. l2fwd_simple_forward(struct rte_mbuf *m,unsigned portid)
  3. {
  4. struct ether_hdr *eth;
  5. void*tmp;
  6. unsigned dst_port;
  7. int sent;
  8. struct rte_eth_dev_tx_buffer *buffer;
  9. dst_port = l2fwd_dst_ports[portid];//获得发送的网口,相当于就是做转发。
  10. eth = rte_pktmbuf_mtod(m,struct ether_hdr *);
  11. /* 02:00:00:00:00:xx */
  12. tmp =&eth->d_addr.addr_bytes[0];
  13. *((uint64_t*)tmp)=0x000000000002+((uint64_t)dst_port <<40);
  14. /* src addr */
  15. ether_addr_copy(&l2fwd_ports_eth_addr[dst_port],&eth->s_addr);
  16. buffer = tx_buffer[dst_port];//获得初使化的时候配置的发送缓存。
  17. sent = rte_eth_tx_buffer(dst_port,0, buffer, m);//预发送,其实并没有真正的发送。
  18. if(sent)
  19. port_statistics[dst_port].tx += sent;
  20. }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





相关文章:

  • 2021-12-16
  • 2021-04-01
  • 2021-09-16
  • 2022-12-23
  • 2021-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-09-27
  • 2022-12-23
  • 2021-06-09
  • 2022-12-23
  • 2021-11-25
  • 2021-04-18
  • 2021-10-21
相关资源
相似解决方案