• 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 ");
    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 ");
    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 ");
    33. nb_ports = rte_eth_dev_count(); //获得当初可用的最大网口数,是从PCI中获得的。
    34. if(nb_ports ==0)
    35. rte_exit(EXIT_FAILURE,"No Ethernet ports - bye ");
    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. ");
    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 ");
    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 ", 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 ",(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 ",
    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 ",
    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 ",
    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 ",
    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 ",(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 ",
    134. ret,(unsigned) portid);
    135. printf("done: ");
    136. rte_eth_promiscuous_enable(portid);//设置该网口为混杂模式,就是接收所有的报文。
    137. printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X ",//初使化报文统计
    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. ");
    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 ");
    169. }
    170. printf("Bye... ");
    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 ", lcore_id);
    20. return;
    21. }
    22. RTE_LOG(INFO, L2FWD,"entering main loop on lcore %u ", 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 ", 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. }
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     





  • 相关阅读:
    Sort-20191304商苏赫
    Myod-20191304商苏赫
    Linux C语言编程基础-20191304商苏赫
    《Unix/Linux系统编程》第十章学习笔记-20191304商苏赫
    《Unix/Linux系统编程》第九章学习笔记 --20191304商苏赫
    《Unix/Linux系统编程》第一、二章学习笔记,知识点归纳及收获
    20191325学习笔记6
    20191325学习笔记5
    20191325第七八章学习笔记
    2021.10.9测试二20191325
  • 原文地址:https://www.cnblogs.com/yml435/p/6286162.html
Copyright © 2020-2023  润新知