pcap-snf.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. #ifdef HAVE_CONFIG_H
  2. #include <config.h>
  3. #endif
  4. #ifndef _WIN32
  5. #include <sys/param.h>
  6. #endif /* !_WIN32 */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <ctype.h>
  11. #ifndef _WIN32
  12. #include <netinet/in.h>
  13. #include <sys/mman.h>
  14. #include <sys/socket.h>
  15. #include <sys/types.h>
  16. #include <unistd.h>
  17. #endif /* !_WIN32 */
  18. #include <snf.h>
  19. #if SNF_VERSION_API >= 0x0003
  20. #define SNF_HAVE_INJECT_API
  21. #endif
  22. #include "pcap-int.h"
  23. #include "pcap-snf.h"
  24. /*
  25. * Private data for capturing on SNF devices.
  26. */
  27. struct pcap_snf {
  28. snf_handle_t snf_handle; /* opaque device handle */
  29. snf_ring_t snf_ring; /* opaque device ring handle */
  30. #ifdef SNF_HAVE_INJECT_API
  31. snf_inject_t snf_inj; /* inject handle, if inject is used */
  32. #endif
  33. int snf_timeout;
  34. int snf_boardnum;
  35. };
  36. static int
  37. snf_set_datalink(pcap_t *p, int dlt)
  38. {
  39. p->linktype = dlt;
  40. return (0);
  41. }
  42. static int
  43. snf_pcap_stats(pcap_t *p, struct pcap_stat *ps)
  44. {
  45. struct snf_ring_stats stats;
  46. struct pcap_snf *snfps = p->priv;
  47. int rc;
  48. if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) {
  49. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  50. rc, "snf_get_stats");
  51. return -1;
  52. }
  53. ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow;
  54. ps->ps_drop = stats.ring_pkt_overflow;
  55. ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad;
  56. return 0;
  57. }
  58. static void
  59. snf_platform_cleanup(pcap_t *p)
  60. {
  61. struct pcap_snf *ps = p->priv;
  62. #ifdef SNF_HAVE_INJECT_API
  63. if (ps->snf_inj)
  64. snf_inject_close(ps->snf_inj);
  65. #endif
  66. snf_ring_close(ps->snf_ring);
  67. snf_close(ps->snf_handle);
  68. pcap_cleanup_live_common(p);
  69. }
  70. static int
  71. snf_getnonblock(pcap_t *p)
  72. {
  73. struct pcap_snf *ps = p->priv;
  74. return (ps->snf_timeout == 0);
  75. }
  76. static int
  77. snf_setnonblock(pcap_t *p, int nonblock)
  78. {
  79. struct pcap_snf *ps = p->priv;
  80. if (nonblock)
  81. ps->snf_timeout = 0;
  82. else {
  83. if (p->opt.timeout <= 0)
  84. ps->snf_timeout = -1; /* forever */
  85. else
  86. ps->snf_timeout = p->opt.timeout;
  87. }
  88. return (0);
  89. }
  90. #define _NSEC_PER_SEC 1000000000
  91. static inline
  92. struct timeval
  93. snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision)
  94. {
  95. struct timeval tv;
  96. long tv_nsec;
  97. const static struct timeval zero_timeval;
  98. if (ts_nanosec == 0)
  99. return zero_timeval;
  100. tv.tv_sec = ts_nanosec / _NSEC_PER_SEC;
  101. tv_nsec = (ts_nanosec % _NSEC_PER_SEC);
  102. /* libpcap expects tv_usec to be nanos if using nanosecond precision. */
  103. if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO)
  104. tv.tv_usec = tv_nsec;
  105. else
  106. tv.tv_usec = tv_nsec / 1000;
  107. return tv;
  108. }
  109. static int
  110. snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
  111. {
  112. struct pcap_snf *ps = p->priv;
  113. struct pcap_pkthdr hdr;
  114. int i, flags, err, caplen, n;
  115. struct snf_recv_req req;
  116. int nonblock, timeout;
  117. if (!p)
  118. return -1;
  119. n = 0;
  120. timeout = ps->snf_timeout;
  121. while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) {
  122. /*
  123. * Has "pcap_breakloop()" been called?
  124. */
  125. if (p->break_loop) {
  126. if (n == 0) {
  127. p->break_loop = 0;
  128. return (-2);
  129. } else {
  130. return (n);
  131. }
  132. }
  133. err = snf_ring_recv(ps->snf_ring, timeout, &req);
  134. if (err) {
  135. if (err == EBUSY || err == EAGAIN) {
  136. return (n);
  137. }
  138. else if (err == EINTR) {
  139. timeout = 0;
  140. continue;
  141. }
  142. else {
  143. pcap_fmt_errmsg_for_errno(p->errbuf,
  144. PCAP_ERRBUF_SIZE, err, "snf_read");
  145. return -1;
  146. }
  147. }
  148. caplen = req.length;
  149. if (caplen > p->snapshot)
  150. caplen = p->snapshot;
  151. if ((p->fcode.bf_insns == NULL) ||
  152. bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
  153. hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
  154. hdr.caplen = caplen;
  155. hdr.len = req.length;
  156. callback(user, &hdr, req.pkt_addr);
  157. }
  158. n++;
  159. /* After one successful packet is received, we won't block
  160. * again for that timeout. */
  161. if (timeout != 0)
  162. timeout = 0;
  163. }
  164. return (n);
  165. }
  166. static int
  167. snf_setfilter(pcap_t *p, struct bpf_program *fp)
  168. {
  169. if (!p)
  170. return -1;
  171. if (!fp) {
  172. strncpy(p->errbuf, "setfilter: No filter specified",
  173. sizeof(p->errbuf));
  174. return -1;
  175. }
  176. /* Make our private copy of the filter */
  177. if (install_bpf_program(p, fp) < 0)
  178. return -1;
  179. return (0);
  180. }
  181. static int
  182. snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
  183. {
  184. #ifdef SNF_HAVE_INJECT_API
  185. struct pcap_snf *ps = p->priv;
  186. int rc;
  187. if (ps->snf_inj == NULL) {
  188. rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj);
  189. if (rc) {
  190. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  191. rc, "snf_inject_open");
  192. return (-1);
  193. }
  194. }
  195. rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size);
  196. if (!rc) {
  197. return (size);
  198. }
  199. else {
  200. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  201. rc, "snf_inject_send");
  202. return (-1);
  203. }
  204. #else
  205. strlcpy(p->errbuf, "Sending packets isn't supported with this snf version",
  206. PCAP_ERRBUF_SIZE);
  207. return (-1);
  208. #endif
  209. }
  210. static int
  211. snf_activate(pcap_t* p)
  212. {
  213. struct pcap_snf *ps = p->priv;
  214. char *device = p->opt.device;
  215. const char *nr = NULL;
  216. int err;
  217. int flags = -1, ring_id = -1;
  218. if (device == NULL) {
  219. pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
  220. return -1;
  221. }
  222. /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1.
  223. * Since libpcap isn't thread-safe */
  224. if ((nr = getenv("SNF_FLAGS")) && *nr)
  225. flags = strtol(nr, NULL, 0);
  226. else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1)
  227. flags = SNF_F_PSHARED;
  228. else
  229. nr = NULL;
  230. /* Allow pcap_set_buffer_size() to set dataring_size.
  231. * Default is zero which allows setting from env SNF_DATARING_SIZE.
  232. * pcap_set_buffer_size() is in bytes while snf_open() accepts values
  233. * between 0 and 1048576 in Megabytes. Values in this range are
  234. * mapped to 1MB.
  235. */
  236. err = snf_open(ps->snf_boardnum,
  237. 0, /* let SNF API parse SNF_NUM_RINGS, if set */
  238. NULL, /* default RSS, or use SNF_RSS_FLAGS env */
  239. (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */
  240. flags, /* may want pshared */
  241. &ps->snf_handle);
  242. if (err != 0) {
  243. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  244. err, "snf_open failed");
  245. return -1;
  246. }
  247. if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) {
  248. ring_id = (int) strtol(nr, NULL, 0);
  249. }
  250. err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring);
  251. if (err != 0) {
  252. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  253. err, "snf_ring_open_id(ring=%d) failed", ring_id);
  254. return -1;
  255. }
  256. /*
  257. * Turn a negative snapshot value (invalid), a snapshot value of
  258. * 0 (unspecified), or a value bigger than the normal maximum
  259. * value, into the maximum allowed value.
  260. *
  261. * If some application really *needs* a bigger snapshot
  262. * length, we should just increase MAXIMUM_SNAPLEN.
  263. */
  264. if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
  265. p->snapshot = MAXIMUM_SNAPLEN;
  266. if (p->opt.timeout <= 0)
  267. ps->snf_timeout = -1;
  268. else
  269. ps->snf_timeout = p->opt.timeout;
  270. err = snf_start(ps->snf_handle);
  271. if (err != 0) {
  272. pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
  273. err, "snf_start failed");
  274. return -1;
  275. }
  276. /*
  277. * "select()" and "poll()" don't work on snf descriptors.
  278. */
  279. #ifndef _WIN32
  280. p->selectable_fd = -1;
  281. #endif /* !_WIN32 */
  282. p->linktype = DLT_EN10MB;
  283. p->read_op = snf_read;
  284. p->inject_op = snf_inject;
  285. p->setfilter_op = snf_setfilter;
  286. p->setdirection_op = NULL; /* Not implemented.*/
  287. p->set_datalink_op = snf_set_datalink;
  288. p->getnonblock_op = snf_getnonblock;
  289. p->setnonblock_op = snf_setnonblock;
  290. p->stats_op = snf_pcap_stats;
  291. p->cleanup_op = snf_platform_cleanup;
  292. #ifdef SNF_HAVE_INJECT_API
  293. ps->snf_inj = NULL;
  294. #endif
  295. return 0;
  296. }
  297. #define MAX_DESC_LENGTH 128
  298. int
  299. snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
  300. {
  301. pcap_if_t *dev;
  302. #ifdef _WIN32
  303. struct sockaddr_in addr;
  304. #endif
  305. struct snf_ifaddrs *ifaddrs, *ifa;
  306. char name[MAX_DESC_LENGTH];
  307. char desc[MAX_DESC_LENGTH];
  308. int ret, allports = 0, merge = 0;
  309. const char *nr = NULL;
  310. if (snf_init(SNF_VERSION_API)) {
  311. (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
  312. "snf_getifaddrs: snf_init failed");
  313. return (-1);
  314. }
  315. if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL)
  316. {
  317. pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
  318. errno, "snf_getifaddrs");
  319. return (-1);
  320. }
  321. if ((nr = getenv("SNF_FLAGS")) && *nr) {
  322. errno = 0;
  323. merge = strtol(nr, NULL, 0);
  324. if (errno) {
  325. (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
  326. "snf_getifaddrs: SNF_FLAGS is not a valid number");
  327. return (-1);
  328. }
  329. merge = merge & SNF_F_AGGREGATE_PORTMASK;
  330. }
  331. for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) {
  332. /*
  333. * Myricom SNF adapter ports may appear as regular
  334. * network interfaces, which would already have been
  335. * added to the list of adapters by pcap_platform_finddevs()
  336. * if this isn't an SNF-only version of libpcap.
  337. *
  338. * Our create routine intercepts pcap_create() calls for
  339. * those interfaces and arranges that they will be
  340. * opened using the SNF API instead.
  341. *
  342. * So if we already have an entry for the device, we
  343. * don't add an additional entry for it, we just
  344. * update the description for it, if any, to indicate
  345. * which snfN device it is. Otherwise, we add an entry
  346. * for it.
  347. *
  348. * In either case, if SNF_F_AGGREGATE_PORTMASK is set
  349. * in SNF_FLAGS, we add this port to the bitmask
  350. * of ports, which we use to generate a device
  351. * we can use to capture on all ports.
  352. *
  353. * Generate the description string. If port aggregation
  354. * is set, use 2^{port number} as the unit number,
  355. * rather than {port number}.
  356. *
  357. * XXX - do entries in this list have IP addresses for
  358. * the port? If so, should we add them to the
  359. * entry for the device, if they're not already in the
  360. * list of IP addresses for the device?
  361. */
  362. (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d",
  363. merge ? "Merge Bitmask Port " : "",
  364. merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum);
  365. /*
  366. * Add the port to the bitmask.
  367. */
  368. if (merge)
  369. allports |= 1 << ifa->snf_ifa_portnum;
  370. /*
  371. * See if there's already an entry for the device
  372. * with the name ifa->snf_ifa_name.
  373. */
  374. dev = find_dev(devlistp, ifa->snf_ifa_name);
  375. if (dev != NULL) {
  376. /*
  377. * Yes. Update its description.
  378. */
  379. char *desc_str;
  380. desc_str = strdup(desc);
  381. if (desc_str == NULL) {
  382. pcap_fmt_errmsg_for_errno(errbuf,
  383. PCAP_ERRBUF_SIZE, errno,
  384. "snf_findalldevs strdup");
  385. return -1;
  386. }
  387. free(dev->description);
  388. dev->description = desc_str;
  389. } else {
  390. /*
  391. * No. Add an entry for it.
  392. *
  393. * XXX - is there a notion of "up" or "running",
  394. * and can we determine whether something's
  395. * plugged into the adapter and set
  396. * PCAP_IF_CONNECTION_STATUS_CONNECTED or
  397. * PCAP_IF_CONNECTION_STATUS_DISCONNECTED?
  398. */
  399. dev = add_dev(devlistp, ifa->snf_ifa_name, 0, desc,
  400. errbuf);
  401. if (dev == NULL)
  402. return -1;
  403. #ifdef _WIN32
  404. /*
  405. * On Windows, fill in IP# from device name
  406. */
  407. ret = inet_pton(AF_INET, dev->name, &addr.sin_addr);
  408. if (ret == 1) {
  409. /*
  410. * Successful conversion of device name
  411. * to IPv4 address.
  412. */
  413. addr.sin_family = AF_INET;
  414. if (add_addr_to_dev(dev, &addr, sizeof(addr),
  415. NULL, 0, NULL, 0, NULL, 0, errbuf) == -1)
  416. return -1;
  417. } else if (ret == -1) {
  418. /*
  419. * Error.
  420. */
  421. pcap_fmt_errmsg_for_errno(errbuf,
  422. PCAP_ERRBUF_SIZE, errno,
  423. "sinf_findalldevs inet_pton");
  424. return -1;
  425. }
  426. #endif _WIN32
  427. }
  428. }
  429. snf_freeifaddrs(ifaddrs);
  430. /*
  431. * Create a snfX entry if port aggregation is enabled
  432. */
  433. if (merge) {
  434. /*
  435. * Add a new entry with all ports bitmask
  436. */
  437. (void)pcap_snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
  438. (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
  439. allports);
  440. /*
  441. * XXX - is there any notion of "up" and "running" that
  442. * would apply to this device, given that it handles
  443. * multiple ports?
  444. *
  445. * Presumably, there's no notion of "connected" vs.
  446. * "disconnected", as "is this plugged into a network?"
  447. * would be a per-port property.
  448. */
  449. if (add_dev(devlistp, name,
  450. PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc,
  451. errbuf) == NULL)
  452. return (-1);
  453. /*
  454. * XXX - should we give it a list of addresses with all
  455. * the addresses for all the ports?
  456. */
  457. }
  458. return 0;
  459. }
  460. pcap_t *
  461. snf_create(const char *device, char *ebuf, int *is_ours)
  462. {
  463. pcap_t *p;
  464. int boardnum = -1;
  465. struct snf_ifaddrs *ifaddrs, *ifa;
  466. size_t devlen;
  467. struct pcap_snf *ps;
  468. if (snf_init(SNF_VERSION_API)) {
  469. /* Can't initialize the API, so no SNF devices */
  470. *is_ours = 0;
  471. return NULL;
  472. }
  473. /*
  474. * Match a given interface name to our list of interface names, from
  475. * which we can obtain the intended board number
  476. */
  477. if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) {
  478. /* Can't get SNF addresses */
  479. *is_ours = 0;
  480. return NULL;
  481. }
  482. devlen = strlen(device) + 1;
  483. ifa = ifaddrs;
  484. while (ifa) {
  485. if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) {
  486. boardnum = ifa->snf_ifa_boardnum;
  487. break;
  488. }
  489. ifa = ifa->snf_ifa_next;
  490. }
  491. snf_freeifaddrs(ifaddrs);
  492. if (ifa == NULL) {
  493. /*
  494. * If we can't find the device by name, support the name "snfX"
  495. * and "snf10gX" where X is the board number.
  496. */
  497. if (sscanf(device, "snf10g%d", &boardnum) != 1 &&
  498. sscanf(device, "snf%d", &boardnum) != 1) {
  499. /* Nope, not a supported name */
  500. *is_ours = 0;
  501. return NULL;
  502. }
  503. }
  504. /* OK, it's probably ours. */
  505. *is_ours = 1;
  506. p = pcap_create_common(ebuf, sizeof (struct pcap_snf));
  507. if (p == NULL)
  508. return NULL;
  509. ps = p->priv;
  510. /*
  511. * We support microsecond and nanosecond time stamps.
  512. */
  513. p->tstamp_precision_count = 2;
  514. p->tstamp_precision_list = malloc(2 * sizeof(u_int));
  515. if (p->tstamp_precision_list == NULL) {
  516. pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
  517. "malloc");
  518. pcap_close(p);
  519. return NULL;
  520. }
  521. p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
  522. p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
  523. p->activate_op = snf_activate;
  524. ps->snf_boardnum = boardnum;
  525. return p;
  526. }
  527. #ifdef SNF_ONLY
  528. /*
  529. * This libpcap build supports only SNF cards, not regular network
  530. * interfaces..
  531. */
  532. /*
  533. * There are no regular interfaces, just SNF interfaces.
  534. */
  535. int
  536. pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
  537. {
  538. return (0);
  539. }
  540. /*
  541. * Attempts to open a regular interface fail.
  542. */
  543. pcap_t *
  544. pcap_create_interface(const char *device, char *errbuf)
  545. {
  546. pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
  547. "This version of libpcap only supports SNF cards");
  548. return NULL;
  549. }
  550. /*
  551. * Libpcap version string.
  552. */
  553. const char *
  554. pcap_lib_version(void)
  555. {
  556. return (PCAP_VERSION_STRING " (SNF-only)");
  557. }
  558. #endif