netmap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /*
  2. * Copyright (c) 2013 Fred Klassen <fklassen at appneta dot com> - AppNeta
  3. *
  4. * The Tcpreplay Suite of tools is free software: you can redistribute it
  5. * and/or modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or with the authors permission any later version.
  8. *
  9. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <string.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #include <stdlib.h>
  21. #include <dirent.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/file.h>
  24. #include <sys/socket.h>
  25. #include <errno.h>
  26. #include "config.h"
  27. #include "defines.h"
  28. #include "common.h"
  29. #include "tcpreplay_api.h"
  30. #include "netmap.h"
  31. #ifdef DEBUG
  32. extern int debug;
  33. #endif
  34. #include <sys/mman.h>
  35. static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd);
  36. /**
  37. * Method takes an open "/dev/netmap" file descriptor and returns
  38. * the netmap version.
  39. *
  40. * Returns -1 on error
  41. */
  42. int
  43. get_netmap_version()
  44. {
  45. u_int32_t netmap_version = -1;
  46. nmreq_t nmr;
  47. int fd;
  48. if ((fd = open ("/dev/netmap", O_RDWR)) < 0)
  49. return -1;
  50. /* netmap version discovery */
  51. bzero (&nmr, sizeof(nmr));
  52. nmr.nr_version = NETMAP_API;
  53. /* attempt using the netmap API version that this was compiled under */
  54. if(ioctl(fd, NIOCGINFO, &nmr) == 0) {
  55. netmap_version = nmr.nr_version;
  56. dbgx(1, "netmap detected API version %d which matches compiled version\n",
  57. netmap_version);
  58. } else {
  59. /* failed.
  60. *
  61. * Try other versions in an attempt to find the version
  62. * that matches this system.
  63. */
  64. int x;
  65. for (x = 0; x < 50; ++x) {
  66. bzero (&nmr, sizeof(nmr));
  67. nmr.nr_version = x;
  68. if(ioctl(fd, NIOCGINFO, &nmr) == 0) {
  69. netmap_version = nmr.nr_version;
  70. dbgx(1, "netmap detected API version %d which doesn't match compiled version %d\n",
  71. netmap_version, NETMAP_API);
  72. break;
  73. }
  74. }
  75. }
  76. close(fd);
  77. return netmap_version;
  78. }
  79. /**
  80. * ioctl support for netmap
  81. */
  82. static int nm_do_ioctl (sendpacket_t *sp, u_long what, int subcmd) {
  83. struct ifreq ifr;
  84. int error;
  85. int fd;
  86. #ifdef linux
  87. struct ethtool_value eval;
  88. #endif
  89. assert(sp);
  90. fd = socket (AF_INET, SOCK_DGRAM, 0);
  91. if (fd < 0) {
  92. dbg(1, "ioctl error: cannot get device control socket.\n");
  93. return -1;
  94. }
  95. bzero (&ifr, sizeof(ifr));
  96. strncpy (ifr.ifr_name, sp->device, sizeof(ifr.ifr_name));
  97. switch (what) {
  98. case SIOCSIFFLAGS:
  99. ifr.ifr_flags = sp->if_flags >> 16;
  100. ifr.ifr_flags = sp->if_flags & 0xffff;
  101. break;
  102. #ifdef linux
  103. case SIOCETHTOOL:
  104. eval.cmd = subcmd;
  105. eval.data = sp->data;
  106. ifr.ifr_data = (caddr_t)&eval;
  107. dbgx(1, "ioctl SIOCETHTOOL subcmd=%d data=%u", subcmd, eval.data);
  108. break;
  109. #endif
  110. }
  111. error = ioctl (fd, what, &ifr);
  112. if (error)
  113. goto done;
  114. switch (what) {
  115. case SIOCGIFFLAGS:
  116. sp->if_flags = (ifr.ifr_flags << 16) | (0xffff & ifr.ifr_flags);
  117. dbgx(1, "SIOCGIFFLAGS flags are 0x%x", sp->if_flags);
  118. break;
  119. #ifdef linux
  120. case SIOCETHTOOL:
  121. switch (subcmd) {
  122. case ETHTOOL_GGSO:
  123. sp->gso = eval.data;
  124. dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GGSO=%u", eval.data);
  125. break;
  126. case ETHTOOL_GTSO:
  127. sp->tso = eval.data;
  128. dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTSO=%u", eval.data);
  129. break;
  130. case ETHTOOL_GRXCSUM:
  131. sp->rxcsum = eval.data;
  132. dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GRXCSUM=%u", eval.data);
  133. break;
  134. case ETHTOOL_GTXCSUM:
  135. sp->txcsum = eval.data;
  136. dbgx(1, "ioctl SIOCETHTOOL ETHTOOL_GTXCSUM=%u", eval.data);
  137. break;
  138. }
  139. break;
  140. #endif
  141. }
  142. done:
  143. close (fd);
  144. if (error)
  145. warnx("ioctl error %d %lu:%d", error, what, subcmd);
  146. return error;
  147. }
  148. /**
  149. * Inner sendpacket_open() method for using netmap
  150. */
  151. void *
  152. sendpacket_open_netmap(const char *device, char *errbuf, void *arg) {
  153. tcpreplay_t *ctx = (tcpreplay_t*)arg;
  154. sendpacket_t *sp = NULL;
  155. nmreq_t nmr;
  156. char ifname_buf[MAX_IFNAMELEN];
  157. const char *ifname;
  158. const char *port = NULL;
  159. size_t namelen;
  160. u_int32_t nr_ringid = 0;
  161. u_int32_t nr_flags = NR_REG_DEFAULT;
  162. int is_default = 0;
  163. assert(device);
  164. assert(errbuf);
  165. dbg(1, "sendpacket_open_netmap: using netmap");
  166. bzero(&nmr, sizeof(nmr));
  167. /* prep & return our sp handle */
  168. sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
  169. if (strlen(device) > MAX_IFNAMELEN - 8) {
  170. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device);
  171. goto IFACENAME_INVALID;
  172. }
  173. /* get the version of the netmap driver. If < 0, driver is not installed */
  174. sp->netmap_version = get_netmap_version();
  175. if (sp->netmap_version < 0) {
  176. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to determine the running netmap version.\n"
  177. "See INSTALL document for details on installing or upgrading netmap.");
  178. goto NETMAP_NOT_INSTALLED;
  179. }
  180. /*
  181. * Sort out interface names
  182. *
  183. * ifname (foo, netmap:foo or vale:foo) is the port name
  184. * foo bind to a single NIC hardware queue
  185. * netmap:foo bind to a single NIC hardware queue
  186. * vale:foo bind to the Vale virtual interface
  187. *
  188. * for netmap version 10+ a suffix can indicate the following:
  189. * netmap:foo! bind to all NIC hardware queues (may cause TX reordering)
  190. * netmap:foo^ bind to the host (sw) ring pair
  191. * netmap:foo* bind to the host (sw) and NIC ring pairs (transparent)
  192. * netmap:foo-NN bind to the individual NIC ring pair (queue) where NN = the ring number
  193. * netmap:foo{NN bind to the master side of pipe NN
  194. * netmap:foo}NN bind to the slave side of pipe NN
  195. */
  196. if (strncmp(device, "netmap:", 7) && strncmp(device, "vale", 4)) {
  197. snprintf(ifname_buf, sizeof(ifname_buf), "netmap:%s", device);
  198. ifname = ifname_buf;
  199. } else {
  200. ifname = device;
  201. }
  202. if (!strncmp("vale", device, 4))
  203. sp->is_vale = 1;
  204. if (ifname[0] == 'n')
  205. ifname += 7;
  206. /* scan for a separator */
  207. for (port = ifname; *port && !index("!-*^{}", *port); port++)
  208. ;
  209. namelen = port - ifname;
  210. if (namelen > sizeof(nmr.nr_name)) {
  211. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Interface name is to long: %s\n", device);
  212. goto IFACENAME_INVALID;
  213. }
  214. /*
  215. * Open the netmap device to fetch the number of queues of our
  216. * interface.
  217. *
  218. * The first NIOCREGIF also detaches the card from the
  219. * protocol stack and may cause a reset of the card,
  220. * which in turn may take some time for the PHY to
  221. * reconfigure.
  222. */
  223. if ((sp->handle.fd = open("/dev/netmap", O_RDWR)) < 0) {
  224. dbg(1, "sendpacket_open_netmap: Unable to access netmap");
  225. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Unable to access netmap.\n"
  226. "See INSTALL to learn which NICs are supported and\n"
  227. "how to set up netmap-capable network drivers.");
  228. goto OPEN_FAILED;
  229. }
  230. /*
  231. * The nmreq structure must have the NETMAP_API version for the running machine.
  232. * However the binary may have been compiled on a different machine than the
  233. * running machine. Discover the true netmap API version, and be careful to call
  234. * functions that are available on all netmap versions.
  235. */
  236. if (sp->netmap_version >= 10) {
  237. switch (*port) {
  238. case '-': /* one NIC */
  239. nr_flags = NR_REG_ONE_NIC;
  240. nr_ringid = atoi(port + 1);
  241. break;
  242. case '*': /* NIC and SW, ignore port */
  243. nr_flags = NR_REG_NIC_SW;
  244. if (port[1]) {
  245. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid netmap port for nic+sw");
  246. goto NETMAP_IF_PARSE_FAIL;
  247. }
  248. break;
  249. case '^': /* only sw ring */
  250. nr_flags = NR_REG_SW;
  251. if (port[1]) {
  252. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid port for sw ring");
  253. goto NETMAP_IF_PARSE_FAIL;
  254. }
  255. break;
  256. case '{':
  257. nr_flags = NR_REG_PIPE_MASTER;
  258. nr_ringid = atoi(port + 1);
  259. break;
  260. case '}':
  261. nr_flags = NR_REG_PIPE_SLAVE;
  262. nr_ringid = atoi(port + 1);
  263. break;
  264. case '!':
  265. nr_flags = NR_REG_ALL_NIC;
  266. break;
  267. default: /* '\0', no suffix */
  268. nr_flags = NR_REG_ALL_NIC;
  269. is_default = 1;
  270. break;
  271. }
  272. if (nr_ringid >= NETMAP_RING_MASK) {
  273. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "invalid ringid");
  274. goto NETMAP_IF_PARSE_FAIL;
  275. }
  276. nmr.nr_ringid = nr_ringid;
  277. nmr.nr_flags = nr_flags;
  278. }
  279. nmr.nr_version = sp->netmap_version;
  280. memcpy(nmr.nr_name, ifname, namelen);
  281. nmr.nr_name[namelen] = '\0';
  282. strlcpy(sp->device, nmr.nr_name, sizeof(sp->device));
  283. /*
  284. * Register the interface on the netmap device: from now on,
  285. * we can operate on the network interface without any
  286. * interference from the legacy network stack.
  287. *
  288. * Cards take a long time to reset the PHY.
  289. */
  290. fprintf(stderr, "Switching network driver for %s to netmap bypass mode... ",
  291. sp->device);
  292. fflush(NULL);
  293. sleep(1); /* ensure message prints when user is connected via ssh */
  294. if (ioctl (sp->handle.fd, NIOCREGIF, &nmr)) {
  295. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Failure accessing netmap.\n"
  296. "\tRequest for netmap version %d failed.\n\tCompiled netmap driver is version %d.\n\tError=%s\n",
  297. sp->netmap_version, NETMAP_API, strerror(errno));
  298. goto NETMAP_IF_FAILED;
  299. }
  300. if (!nmr.nr_memsize) {
  301. snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "Netmap interface '%s' not configured.\n",
  302. device);
  303. goto NETMAP_IF_FAILED;
  304. }
  305. sp->mmap_size = nmr.nr_memsize;
  306. sp->mmap_addr = (struct netmap_d *)mmap (0, sp->mmap_size,
  307. PROT_WRITE | PROT_READ, MAP_SHARED, sp->handle.fd, 0);
  308. if (!sp->mmap_addr || sp->mmap_addr == MAP_FAILED) {
  309. snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "mmap: %s", strerror (errno));
  310. goto MMAP_FAILED;
  311. }
  312. dbgx(1, "sendpacket_open_netmap: mapping %d Kbytes queues=%d",
  313. sp->mmap_size >> 10, nmr.nr_tx_rings);
  314. sp->nm_if = NETMAP_IF(sp->mmap_addr, nmr.nr_offset);
  315. sp->nmr = nmr;
  316. sp->handle_type = SP_TYPE_NETMAP;
  317. /* set up ring IDs */
  318. sp->cur_tx_ring = 0;
  319. switch(nr_flags) {
  320. case NR_REG_DEFAULT: /* only use one queue to prevent TX reordering */
  321. sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0;
  322. break;
  323. case NR_REG_ALL_NIC:
  324. if (is_default) {
  325. sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0;
  326. } else {
  327. sp->first_tx_ring = sp->cur_tx_ring = 0;
  328. sp->last_tx_ring = nmr.nr_tx_rings - 1;
  329. }
  330. break;
  331. case NR_REG_SW:
  332. sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nmr.nr_tx_rings;
  333. break;
  334. case NR_REG_NIC_SW:
  335. sp->first_tx_ring = sp->cur_tx_ring = 0;
  336. sp->last_tx_ring = nmr.nr_tx_rings;
  337. break;
  338. case NR_REG_ONE_NIC:
  339. sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = nr_ringid;
  340. break;
  341. default:
  342. sp->first_tx_ring = sp->last_tx_ring = sp->cur_tx_ring = 0;
  343. }
  344. {
  345. /* debugging code */
  346. int i;
  347. dbgx(1, "%s tx first=%d last=%d num=%d", ifname,
  348. sp->first_tx_ring, sp->last_tx_ring, sp->nmr.nr_tx_rings);
  349. for (i = 0; i <= sp->nmr.nr_tx_rings; i++) {
  350. #ifdef HAVE_NETMAP_RING_HEAD_TAIL
  351. dbgx(1, "TX%d 0x%p head=%d cur=%d tail=%d", i, NETMAP_TXRING(sp->nm_if, i),
  352. (NETMAP_TXRING(sp->nm_if, i))->head,
  353. (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->tail);
  354. #else
  355. dbgx(1, "TX%d 0x%p cur=%d avail=%d", i, NETMAP_TXRING(sp->nm_if, i),
  356. (NETMAP_TXRING(sp->nm_if, i))->cur, (NETMAP_TXRING(sp->nm_if, i))->avail);
  357. #endif
  358. }
  359. }
  360. dbgx(2, "Waiting %d seconds for phy reset...", ctx->options->netmap_delay);
  361. sleep(ctx->options->netmap_delay);
  362. dbg(2, "Ready!");
  363. if (!sp->is_vale) {
  364. if (nm_do_ioctl(sp, SIOCGIFFLAGS, 0) < 0)
  365. goto NM_DO_IOCTL_FAILED;
  366. if ((sp->if_flags & IFF_RUNNING) == 0) {
  367. dbgx(1, "sendpacket_open_netmap: %s is not running", sp->device);
  368. snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "interface %s is not running - check cables\n", sp->device);
  369. goto NETMAP_IF_NOT_RUNNING;
  370. }
  371. if ((sp->if_flags & IFF_UP) == 0) {
  372. dbgx(1, "%s is down, bringing up...", sp->device);
  373. sp->if_flags |= IFF_UP;
  374. }
  375. /* set promiscuous mode */
  376. sp->if_flags |= IFF_PROMISC;
  377. if (nm_do_ioctl(sp, SIOCSIFFLAGS, 0) < 0)
  378. goto NM_DO_IOCTL_FAILED;
  379. #ifdef linux
  380. /* disable:
  381. * - generic-segmentation-offload
  382. * - tcp-segmentation-offload
  383. * - rx-checksumming
  384. * - tx-checksumming
  385. */
  386. if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GGSO) < 0 ||
  387. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTSO) < 0 ||
  388. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GRXCSUM) < 0 ||
  389. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_GTXCSUM) < 0)
  390. goto NM_DO_IOCTL_FAILED;
  391. sp->data = 0;
  392. if (nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO) < 0 ||
  393. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO) < 0 ||
  394. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM) < 0 ||
  395. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM))
  396. goto NM_DO_IOCTL_FAILED;
  397. #endif
  398. }
  399. if(sp->abort)
  400. goto NETMAP_ABORT;
  401. notice("done!");
  402. return sp;
  403. NM_DO_IOCTL_FAILED:
  404. snprintf (errbuf, SENDPACKET_ERRBUF_SIZE, "nm_do_ioctl: %s", strerror (errno));
  405. NETMAP_IF_NOT_RUNNING:
  406. notice("failed!");
  407. NETMAP_ABORT:
  408. fprintf(stderr, " Switching network driver for %s to normal mode... ",
  409. sp->device);
  410. fflush(NULL);
  411. munmap(sp->mmap_addr, sp->mmap_size);
  412. MMAP_FAILED:
  413. #if NETMAP_API < 10
  414. ioctl(sp->handle.fd, NIOCUNREGIF, NULL);
  415. #endif
  416. NETMAP_IF_FAILED:
  417. NETMAP_IF_PARSE_FAIL:
  418. close (sp->handle.fd);
  419. OPEN_FAILED:
  420. safe_free(sp);
  421. IFACENAME_INVALID:
  422. NETMAP_NOT_INSTALLED:
  423. return NULL;
  424. }
  425. void sendpacket_close_netmap(void *p)
  426. {
  427. sendpacket_t *sp = p;
  428. fprintf(stderr, "Switching network driver for %s to normal mode... ",
  429. sp->device);
  430. fflush(NULL);
  431. /* flush any remaining packets */
  432. ioctl(sp->handle.fd, NIOCTXSYNC, NULL);
  433. /* wait for traffic to be sent */
  434. dbgx(2, "Waiting %d seconds for phy reset...", sp->netmap_delay);
  435. sleep(sp->netmap_delay);
  436. dbg(2, "Ready!");
  437. #ifdef linux
  438. if (!sp->is_vale) {
  439. /* restore original settings:
  440. * - generic-segmentation-offload
  441. * - tcp-segmentation-offload
  442. * - rx-checksumming
  443. * - tx-checksumming
  444. */
  445. sp->data = sp->gso;
  446. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SGSO);
  447. sp->data = sp->tso;
  448. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STSO);
  449. sp->data = sp->rxcsum;
  450. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_SRXCSUM);
  451. sp->data = sp->txcsum;
  452. nm_do_ioctl(sp, SIOCETHTOOL, ETHTOOL_STXCSUM);
  453. }
  454. #endif /* linux */
  455. /* restore interface to normal mode */
  456. #if NETMAP_API < 10
  457. ioctl(sp->handle.fd, NIOCUNREGIF, NULL);
  458. #endif
  459. if (sp->mmap_addr)
  460. munmap(sp->mmap_addr, sp->mmap_size);
  461. close(sp->handle.fd);
  462. notice("done!");
  463. }
  464. bool netmap_tx_queues_empty(void *p)
  465. {
  466. sendpacket_t *sp = p;
  467. struct netmap_ring *txring;
  468. assert(sp);
  469. sp->cur_tx_ring = 0;
  470. txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring);
  471. while (NETMAP_TX_RING_EMPTY(txring)) {
  472. /* current ring is empty- go to next */
  473. ++sp->cur_tx_ring;
  474. if (sp->cur_tx_ring > sp->last_tx_ring) {
  475. /* last ring */
  476. sp->cur_tx_ring = 0;
  477. return true;
  478. }
  479. txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring);
  480. }
  481. /*
  482. * send TX interrupt signal
  483. */
  484. ioctl(sp->handle.fd, NIOCTXSYNC, NULL);
  485. return false;
  486. }
  487. int sendpacket_send_netmap(void *p, const u_char *data, size_t len)
  488. {
  489. sendpacket_t *sp = p;
  490. struct netmap_ring *txring;
  491. struct netmap_slot *slot;
  492. char *pkt;
  493. uint32_t cur, avail;
  494. if (sp->abort)
  495. return 0;
  496. txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring);
  497. while ((avail = nm_ring_space(txring)) == 0) {
  498. /* out of space on current TX queue - go to next */
  499. ++sp->cur_tx_ring;
  500. if (sp->cur_tx_ring > sp->last_tx_ring) {
  501. /*
  502. * out of space on all queues
  503. *
  504. * we have looped through all configured TX queues
  505. * so we have to reset to the first queue and
  506. * wait for available space
  507. */
  508. sp->cur_tx_ring = sp->first_tx_ring;
  509. /* send TX interrupt signal
  510. *
  511. * On Linux this makes one slot free on the
  512. * ring, which increases speed by about 10Mbps.
  513. *
  514. * But it will never free up all the slots. For
  515. * that we must poll and call again.
  516. */
  517. ioctl(sp->handle.fd, NIOCTXSYNC, NULL);
  518. /* loop again */
  519. return -2;
  520. }
  521. txring = NETMAP_TXRING(sp->nm_if, sp->cur_tx_ring);
  522. }
  523. /*
  524. * send
  525. */
  526. cur = txring->cur;
  527. slot = &txring->slot[cur];
  528. slot->flags = 0;
  529. pkt = NETMAP_BUF(txring, slot->buf_idx);
  530. memcpy(pkt, data, min(len, txring->nr_buf_size));
  531. slot->len = len;
  532. if (avail <= 1)
  533. slot->flags = NS_REPORT;
  534. dbgx(3, "netmap cur=%d slot index=%d flags=0x%x empty=%d avail=%u bufsize=%d\n",
  535. cur, slot->buf_idx, slot->flags, NETMAP_TX_RING_EMPTY(txring),
  536. nm_ring_space(txring), txring->nr_buf_size);
  537. /* let kernel know that packet is available */
  538. cur = NETMAP_RING_NEXT(txring, cur);
  539. #ifdef HAVE_NETMAP_RING_HEAD_TAIL
  540. txring->head = cur;
  541. #else
  542. txring->avail--;
  543. #endif
  544. txring->cur = cur;
  545. return len;
  546. }