Advertisement
Guest User

Untitled

a guest
Oct 12th, 2024
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.41 KB | None | 0 0
  1. #include <iostream>
  2. #include <rte_eal.h>
  3. #include <rte_ethdev.h>
  4. #include <rte_vhost.h>
  5. #include <cstring>
  6. #include <thread>
  7. #include <unistd.h>
  8. #include <algorithm>
  9. #include <arpa/inet.h>
  10. #include <sys/epoll.h>
  11.  
  12. #define NUM_MBUFS 8192
  13. #define NUM_RXTX_QUEUES 37
  14.  
  15. static int get_portid_by_name(const char* if_name) {
  16. uint16_t portid;
  17. RTE_ETH_FOREACH_DEV(portid) {
  18. char name[RTE_ETH_NAME_MAX_LEN];
  19. rte_eth_dev_get_name_by_port(portid, name);
  20. if (strcmp(name, if_name) == 0)
  21. return portid;
  22. }
  23. return -1; // Interface não encontrada
  24. }
  25.  
  26. static rte_spinlock_t locks[RTE_MAX_ETHPORTS];
  27.  
  28. static void turn_on_intr(const int epfd, const uint16_t port_id, const uint16_t queue) {
  29. rte_spinlock_lock(&locks[port_id]);
  30.  
  31. if (rte_eth_dev_rx_intr_ctl_q(port_id, queue, epfd, RTE_INTR_EVENT_ADD, nullptr) != 0)
  32. std::cerr << "Erro ao configurar a interrupção RX para a porta " << port_id << " fila " << queue << std::endl;
  33.  
  34. rte_spinlock_unlock(&locks[port_id]);
  35. }
  36.  
  37. static void configure_port(rte_mempool* mempool, const uint16_t port_id, bool has_interrupt = true) {
  38. rte_eth_dev_info dev_info {};
  39. if (rte_eth_dev_info_get(port_id, &dev_info) != 0) {
  40. std::cerr << "Erro ao obter informações da porta: " << port_id << std::endl;
  41. exit(0);
  42. }
  43.  
  44. rte_eth_conf port_conf {
  45. .rxmode = {
  46. .mq_mode = RTE_ETH_MQ_RX_RSS,
  47. .offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM
  48. },
  49. .intr_conf = {
  50. .rxq = has_interrupt
  51. }
  52. };
  53.  
  54. uint16_t max_queues = NUM_RXTX_QUEUES;
  55. uint16_t nb_rx_queues = std::min(dev_info.max_rx_queues, max_queues);
  56. uint16_t nb_tx_queues = std::min(dev_info.max_tx_queues, max_queues);
  57.  
  58. if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
  59. port_conf.txmode.offloads |=
  60. RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
  61.  
  62. if (rte_eth_dev_configure(port_id, nb_rx_queues, nb_tx_queues, &port_conf) != 0) {
  63. std::cerr << "Erro ao configurar a porta: " << port_id << std::endl;
  64. exit(0);
  65. }
  66.  
  67. uint16_t max_descs = NUM_MBUFS;
  68. uint16_t nb_rx_desc = std::min(dev_info.rx_desc_lim.nb_max, max_descs);
  69. uint16_t nb_tx_desc = std::min(dev_info.tx_desc_lim.nb_max, max_descs);
  70. if (rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rx_desc, &nb_tx_desc) != 0) {
  71. std::cerr << "Erro ao ajustar descritores RX/TX: " << port_id << std::endl;
  72. exit(0);
  73. }
  74.  
  75. for (uint16_t q = 0; q < nb_rx_queues; q++) {
  76. auto rxq_conf = dev_info.default_rxconf;
  77. rxq_conf.rx_thresh.pthresh = 8;
  78. rxq_conf.rx_thresh.hthresh = 8;
  79. rxq_conf.rx_thresh.wthresh = 4;
  80. rxq_conf.rx_drop_en = 0;
  81.  
  82. if (rte_eth_rx_queue_setup(port_id, q, nb_rx_desc,
  83. rte_eth_dev_socket_id(port_id), &rxq_conf, mempool) != 0) {
  84. std::cerr << "Erro ao configurar fila RX: " << q << " na porta: " << port_id << std::endl;
  85. exit(0);
  86. }
  87. }
  88.  
  89. for (uint16_t q = 0; q < nb_tx_queues; q++) {
  90. auto txq_conf = dev_info.default_txconf;
  91. txq_conf.tx_thresh.pthresh = 8;
  92. txq_conf.tx_thresh.hthresh = 8;
  93. txq_conf.tx_thresh.wthresh = 4;
  94.  
  95. if (rte_eth_tx_queue_setup(port_id, q, nb_tx_desc,
  96. rte_eth_dev_socket_id(port_id), &txq_conf) != 0) {
  97. std::cerr << "Erro ao configurar fila TX: " << q << " na porta: " << port_id << std::endl;
  98. exit(0);
  99. }
  100. }
  101.  
  102. if (rte_eth_dev_start(port_id) != 0) {
  103. std::cerr << "Erro ao iniciar a porta: " << port_id << std::endl;
  104. exit(0);
  105. }
  106. }
  107.  
  108. static void net_to_virtio_queue(const int port_id, const int queue) {
  109. std::string virtio_net = std::string("virtio_user") + std::to_string(port_id);
  110. auto virtio_port_id = get_portid_by_name(virtio_net.c_str());
  111.  
  112. if (virtio_port_id == -1) {
  113. std::cerr << "Erro: Interface " << virtio_net << " não encontrada" << std::endl;
  114. return;
  115. }
  116.  
  117. rte_epoll_event event {};
  118.  
  119. turn_on_intr(RTE_EPOLL_PER_THREAD, port_id, queue);
  120.  
  121. while (true) {
  122. assert(rte_eth_dev_rx_intr_enable(port_id, queue) == 0);
  123. int nfds = rte_epoll_wait(RTE_EPOLL_PER_THREAD, &event, 1, -1);
  124. if (nfds == 0) continue;
  125.  
  126. rte_mbuf* rx_packets[2048];
  127. uint16_t num_rx = rte_eth_rx_burst(port_id, queue, rx_packets, 2048);
  128. if (num_rx == 0) continue;
  129.  
  130. rte_eth_tx_burst(virtio_port_id, 0, rx_packets, num_rx);
  131.  
  132. rte_pktmbuf_free_bulk(rx_packets, num_rx);
  133. }
  134. }
  135.  
  136. static void virtio_to_net_queue(const int port_id) {
  137. std::string virtio_net = std::string("virtio_user") + std::to_string(port_id);
  138. auto virtio_port_id = get_portid_by_name(virtio_net.c_str());
  139.  
  140. if (virtio_port_id == -1) {
  141. std::cerr << "Erro: Interface " << virtio_net << " não encontrada" << std::endl;
  142. return;
  143. }
  144.  
  145. while (true) {
  146. rte_mbuf* rx_packets[2048];
  147. uint16_t num_rx = rte_eth_rx_burst(virtio_port_id, 0, rx_packets, 2048);
  148. if (num_rx == 0) {
  149. usleep(100);
  150. continue;
  151. }
  152.  
  153. rte_eth_tx_burst(port_id, NUM_RXTX_QUEUES-1, rx_packets, num_rx);
  154.  
  155. rte_pktmbuf_free_bulk(rx_packets, num_rx);
  156. }
  157. }
  158.  
  159. static void redirect_to_virtio(const int port_id) {
  160. rte_eth_dev_info dev_info {};
  161. rte_eth_dev_info_get(port_id, &dev_info);
  162.  
  163. uint16_t nb_rx_queues = dev_info.nb_rx_queues;
  164.  
  165. for (uint16_t q = 0; q < nb_rx_queues; q++) {
  166. std::thread thread(net_to_virtio_queue, port_id, q);
  167.  
  168. cpu_set_t cpuset;
  169. CPU_ZERO(&cpuset);
  170. CPU_SET(q, &cpuset);
  171. pthread_setaffinity_np(thread.native_handle(),
  172. sizeof(cpu_set_t), &cpuset);
  173.  
  174. thread.detach();
  175. }
  176.  
  177. std::thread (virtio_to_net_queue, port_id).detach();
  178. }
  179.  
  180. int main(int argc, char **argv) {
  181. int ret = rte_eal_init(argc, argv);
  182. if (ret < 0) {
  183. std::cerr << "Erro na inicialização do EAL" << std::endl;
  184. return -1;
  185. }
  186.  
  187. uint16_t nb_ports = rte_eth_dev_count_avail();
  188. uint16_t port_id;
  189.  
  190. int port_count = 0;
  191.  
  192. rte_mempool *mempool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * (NUM_RXTX_QUEUES * 2) * nb_ports,
  193. 256, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
  194.  
  195. if (mempool == nullptr) {
  196. std::cerr << "Erro ao alocar mempool: " << rte_strerror(rte_errno) << std::endl;
  197. return 0;
  198. }
  199.  
  200. RTE_ETH_FOREACH_DEV(port_id) {
  201. char portname[32];
  202. char portargs[256];
  203. rte_ether_addr addr {};
  204.  
  205. if (++port_count > nb_ports)
  206. break;
  207.  
  208. rte_eth_macaddr_get(port_id, &addr);
  209.  
  210. snprintf(portname, sizeof(portname), "virtio_user%u", port_id);
  211. snprintf(portargs, sizeof(portargs),
  212. "path=/dev/vhost-net,queues=1,queue_size=%u,iface=%s,mac=" RTE_ETHER_ADDR_PRT_FMT,
  213. 1024, portname, RTE_ETHER_ADDR_BYTES(&addr));
  214.  
  215. if (rte_eal_hotplug_add("vdev", portname, portargs) < 0) {
  216. rte_exit(EXIT_FAILURE, "Cannot create paired port for port %u\n", port_id);
  217. }
  218.  
  219. // Atribuir IP e ativar a interface
  220. system("ifconfig virtio_user0 67.159.40.18/24 up");
  221. system("ip route add default via 67.159.40.17 dev virtio_user0");
  222.  
  223. rte_spinlock_init(&locks[port_id]);
  224.  
  225. configure_port(mempool, port_id, true);
  226.  
  227. std::string virtio_net = std::string("virtio_user") + std::to_string(port_id);
  228. auto virtio_port_id = get_portid_by_name(virtio_net.c_str());
  229.  
  230. if (virtio_port_id == -1) {
  231. std::cerr << "Erro: Interface " << virtio_net << " não encontrada" << std::endl;
  232. return 0;
  233. }
  234.  
  235. configure_port(mempool, virtio_port_id, false);
  236.  
  237. redirect_to_virtio(port_id);
  238. }
  239.  
  240. while (true) {
  241. sleep(1);
  242. }
  243.  
  244. return 0;
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement