]> The Tcpdump Group git mirrors - libpcap/blob - pcap-snf.c
Fixup indentation in init_linktype().
[libpcap] / pcap-snf.c
1 #include <config.h>
2
3 #ifndef _WIN32
4 #include <sys/param.h>
5 #endif /* !_WIN32 */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <limits.h> /* for INT_MAX */
11
12 #ifndef _WIN32
13 #include <netinet/in.h>
14 #include <sys/mman.h>
15 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #endif /* !_WIN32 */
19
20 #include <snf.h>
21
22 #include "pcap-int.h"
23 #include "pcap-snf.h"
24
25 /*
26 * Private data for capturing on SNF devices.
27 */
28 struct pcap_snf {
29 snf_handle_t snf_handle; /* opaque device handle */
30 snf_ring_t snf_ring; /* opaque device ring handle */
31 snf_inject_t snf_inj; /* inject handle, if inject is used */
32 int snf_timeout;
33 int snf_boardnum;
34 };
35
36 static int
37 snf_set_datalink(pcap_t *p, int dlt)
38 {
39 p->linktype = dlt;
40 return (0);
41 }
42
43 static int
44 snf_pcap_stats(pcap_t *p, struct pcap_stat *ps)
45 {
46 struct snf_ring_stats stats;
47 struct pcap_snf *snfps = p->priv;
48 int rc;
49
50 if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) {
51 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
52 rc, "snf_get_stats");
53 return PCAP_ERROR;
54 }
55 ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow;
56 ps->ps_drop = stats.ring_pkt_overflow;
57 ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad;
58 return 0;
59 }
60
61 static void
62 snf_platform_cleanup(pcap_t *p)
63 {
64 struct pcap_snf *ps = p->priv;
65
66 if (ps->snf_inj)
67 snf_inject_close(ps->snf_inj);
68 snf_ring_close(ps->snf_ring);
69 snf_close(ps->snf_handle);
70 pcapint_cleanup_live_common(p);
71 }
72
73 static int
74 snf_getnonblock(pcap_t *p)
75 {
76 struct pcap_snf *ps = p->priv;
77
78 return (ps->snf_timeout == 0);
79 }
80
81 static int
82 snf_setnonblock(pcap_t *p, int nonblock)
83 {
84 struct pcap_snf *ps = p->priv;
85
86 if (nonblock)
87 ps->snf_timeout = 0;
88 else {
89 if (p->opt.timeout <= 0)
90 ps->snf_timeout = -1; /* forever */
91 else
92 ps->snf_timeout = p->opt.timeout;
93 }
94 return (0);
95 }
96
97 #define _NSEC_PER_SEC 1000000000
98
99 static inline
100 struct timeval
101 snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision)
102 {
103 struct timeval tv;
104 long tv_nsec;
105 static const struct timeval zero_timeval;
106
107 if (ts_nanosec == 0)
108 return zero_timeval;
109
110 tv.tv_sec = ts_nanosec / _NSEC_PER_SEC;
111 tv_nsec = (ts_nanosec % _NSEC_PER_SEC);
112
113 /* libpcap expects tv_usec to be nanos if using nanosecond precision. */
114 if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO)
115 tv.tv_usec = tv_nsec;
116 else
117 tv.tv_usec = tv_nsec / 1000;
118
119 return tv;
120 }
121
122 static int
123 snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
124 {
125 struct pcap_snf *ps = p->priv;
126 struct pcap_pkthdr hdr;
127 int err, caplen, n;
128 struct snf_recv_req req;
129 int timeout;
130
131 /*
132 * This can conceivably process more than INT_MAX packets,
133 * which would overflow the packet count, causing it either
134 * to look like a negative number, and thus cause us to
135 * return a value that looks like an error, or overflow
136 * back into positive territory, and thus cause us to
137 * return a too-low count.
138 *
139 * Therefore, if the packet count is unlimited, we clip
140 * it at INT_MAX; this routine is not expected to
141 * process packets indefinitely, so that's not an issue.
142 */
143 if (PACKET_COUNT_IS_UNLIMITED(cnt))
144 cnt = INT_MAX;
145
146 n = 0;
147 timeout = ps->snf_timeout;
148 while (n < cnt) {
149 /*
150 * Has "pcap_breakloop()" been called?
151 */
152 if (p->break_loop) {
153 if (n == 0) {
154 p->break_loop = 0;
155 return PCAP_ERROR_BREAK;
156 } else {
157 return (n);
158 }
159 }
160
161 err = snf_ring_recv(ps->snf_ring, timeout, &req);
162
163 if (err) {
164 if (err == EBUSY || err == EAGAIN) {
165 return (n);
166 }
167 else if (err == EINTR) {
168 timeout = 0;
169 continue;
170 }
171 else {
172 pcapint_fmt_errmsg_for_errno(p->errbuf,
173 PCAP_ERRBUF_SIZE, err, "%s", __func__);
174 return PCAP_ERROR;
175 }
176 }
177
178 /*
179 * In this libpcap module the two length arguments of
180 * pcapint_filter() (the wire length and the captured length)
181 * are always equal because SNF captures full packets.
182 *
183 * The wire and the capture length of this packet is
184 * req.length, the snapshot length configured for this pcap
185 * handle is p->snapshot.
186 */
187 caplen = req.length;
188 if (caplen > p->snapshot)
189 caplen = p->snapshot;
190
191 if ((p->fcode.bf_insns == NULL) ||
192 pcapint_filter(p->fcode.bf_insns, req.pkt_addr, req.length, req.length)) {
193 hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
194 hdr.caplen = caplen;
195 hdr.len = req.length;
196 callback(user, &hdr, req.pkt_addr);
197 n++;
198 }
199
200 /* After one successful packet is received, we won't block
201 * again for that timeout. */
202 if (timeout != 0)
203 timeout = 0;
204 }
205 return (n);
206 }
207
208 static int
209 snf_inject(pcap_t *p, const void *buf, int size)
210 {
211 struct pcap_snf *ps = p->priv;
212 int rc;
213 if (ps->snf_inj == NULL) {
214 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj);
215 if (rc) {
216 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
217 rc, "snf_inject_open");
218 return PCAP_ERROR;
219 }
220 }
221
222 rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size);
223 if (!rc) {
224 return (size);
225 }
226 else {
227 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
228 rc, "snf_inject_send");
229 return PCAP_ERROR;
230 }
231 }
232
233 static int
234 snf_activate(pcap_t* p)
235 {
236 struct pcap_snf *ps = p->priv;
237 const char *nr = NULL;
238 int err;
239 int flags = -1, ring_id = -1;
240
241 /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1.
242 * Since libpcap isn't thread-safe */
243 if ((nr = getenv("SNF_FLAGS")) && *nr)
244 flags = strtol(nr, NULL, 0);
245 else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1)
246 flags = SNF_F_PSHARED;
247 else
248 nr = NULL;
249
250
251 /* Allow pcap_set_buffer_size() to set dataring_size.
252 * Default is zero which allows setting from env SNF_DATARING_SIZE.
253 * pcap_set_buffer_size() is in bytes while snf_open() accepts values
254 * between 0 and 1048576 in Megabytes. Values in this range are
255 * mapped to 1MB.
256 */
257 err = snf_open(ps->snf_boardnum,
258 0, /* let SNF API parse SNF_NUM_RINGS, if set */
259 NULL, /* default RSS, or use SNF_RSS_FLAGS env */
260 (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */
261 flags, /* may want pshared */
262 &ps->snf_handle);
263 if (err != 0) {
264 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
265 err, "snf_open failed");
266 return PCAP_ERROR;
267 }
268
269 if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) {
270 ring_id = (int) strtol(nr, NULL, 0);
271 }
272 err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring);
273 if (err != 0) {
274 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
275 err, "snf_ring_open_id(ring=%d) failed", ring_id);
276 return PCAP_ERROR;
277 }
278
279 /*
280 * Turn a negative snapshot value (invalid), a snapshot value of
281 * 0 (unspecified), or a value bigger than the normal maximum
282 * value, into the maximum allowed value.
283 *
284 * If some application really *needs* a bigger snapshot
285 * length, we should just increase MAXIMUM_SNAPLEN.
286 */
287 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
288 p->snapshot = MAXIMUM_SNAPLEN;
289
290 if (p->opt.timeout <= 0)
291 ps->snf_timeout = -1;
292 else
293 ps->snf_timeout = p->opt.timeout;
294
295 err = snf_start(ps->snf_handle);
296 if (err != 0) {
297 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
298 err, "snf_start failed");
299 return PCAP_ERROR;
300 }
301
302 /*
303 * "select()" and "poll()" don't work on snf descriptors.
304 */
305 #ifndef _WIN32
306 p->selectable_fd = -1;
307 #endif /* !_WIN32 */
308 p->linktype = DLT_EN10MB;
309 p->read_op = snf_read;
310 p->inject_op = snf_inject;
311 p->setfilter_op = pcapint_install_bpf_program;
312 p->setdirection_op = NULL; /* Not implemented.*/
313 p->set_datalink_op = snf_set_datalink;
314 p->getnonblock_op = snf_getnonblock;
315 p->setnonblock_op = snf_setnonblock;
316 p->stats_op = snf_pcap_stats;
317 p->cleanup_op = snf_platform_cleanup;
318 ps->snf_inj = NULL;
319 return 0;
320 }
321
322 #define MAX_DESC_LENGTH 128
323 int
324 snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
325 {
326 pcap_if_t *dev;
327 #ifdef _WIN32
328 struct sockaddr_in addr;
329 #endif
330 struct snf_ifaddrs *ifaddrs, *ifa;
331 char name[MAX_DESC_LENGTH];
332 char desc[MAX_DESC_LENGTH];
333 int allports = 0, merge = 0;
334 const char *nr = NULL;
335
336 if (snf_init(SNF_VERSION_API)) {
337 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
338 errno, "snf_init");
339 return PCAP_ERROR;
340 }
341
342 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL)
343 {
344 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
345 errno, "snf_getifaddrs");
346 return PCAP_ERROR;
347 }
348 if ((nr = getenv("SNF_FLAGS")) && *nr) {
349 errno = 0;
350 merge = strtol(nr, NULL, 0);
351 if (errno) {
352 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
353 "%s: SNF_FLAGS is not a valid number", __func__);
354 return PCAP_ERROR;
355 }
356 merge = merge & SNF_F_AGGREGATE_PORTMASK;
357 }
358
359 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) {
360 /*
361 * Myricom SNF adapter ports may appear as regular
362 * network interfaces, which would already have been
363 * added to the list of adapters by pcapint_platform_finddevs()
364 * regardless of whether this build is SNF-only or not.
365 *
366 * Our create routine intercepts pcap_create() calls for
367 * those interfaces and arranges that they will be
368 * opened using the SNF API instead.
369 *
370 * So if we already have an entry for the device, we
371 * don't add an additional entry for it, we just
372 * update the description for it, if any, to indicate
373 * which snfN device it is. Otherwise, we add an entry
374 * for it.
375 *
376 * In either case, if SNF_F_AGGREGATE_PORTMASK is set
377 * in SNF_FLAGS, we add this port to the bitmask
378 * of ports, which we use to generate a device
379 * we can use to capture on all ports.
380 *
381 * Generate the description string. If port aggregation
382 * is set, use 2^{port number} as the unit number,
383 * rather than {port number}.
384 */
385 (void)snprintf(desc, MAX_DESC_LENGTH,
386 "Myricom %ssnf%u, Rx rings: %u, Tx handles: %u",
387 merge ? "Merge Bitmask Port " : "",
388 merge ? 1U << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum,
389 ifa->snf_ifa_maxrings,
390 ifa->snf_ifa_maxinject);
391 /*
392 * Add the port to the bitmask.
393 */
394 if (merge)
395 allports |= 1 << ifa->snf_ifa_portnum;
396 /*
397 * See if there's already an entry for the device
398 * with the name ifa->snf_ifa_name.
399 */
400 dev = pcapint_find_dev(devlistp, ifa->snf_ifa_name);
401 if (dev != NULL) {
402 /*
403 * Yes. Update its description.
404 *
405 * This is the expected and the most likely result.
406 * In this case the device's .flags already has the
407 * PCAP_IF_UP and PCAP_IF_RUNNING bits mapped from the
408 * regular network interface flags, as well as the
409 * PCAP_IF_CONNECTION_STATUS bits mapped from the
410 * current struct snf_ifaddrs; .addresses has already
411 * been populated.
412 */
413 char *desc_str;
414
415 desc_str = strdup(desc);
416 if (desc_str == NULL) {
417 pcapint_fmt_errmsg_for_errno(errbuf,
418 PCAP_ERRBUF_SIZE, errno,
419 "%s strdup", __func__);
420 return PCAP_ERROR;
421 }
422 free(dev->description);
423 dev->description = desc_str;
424 } else {
425 /*
426 * No. Add an entry for it.
427 *
428 * Possibly a race condition. In this case the device
429 * will still work, but will not have addresses, also
430 * snf_ifaddrs includes the operational (i.e. link
431 * detect), but not the administrative state of the
432 * port.
433 */
434 const bpf_u_int32 flags =
435 ifa->snf_ifa_link_state == SNF_LINK_UP ?
436 PCAP_IF_CONNECTION_STATUS_CONNECTED :
437 PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
438 dev = pcapint_add_dev(devlistp, ifa->snf_ifa_name, flags, desc,
439 errbuf);
440 if (dev == NULL)
441 return PCAP_ERROR;
442 #ifdef _WIN32
443 /*
444 * On Windows, fill in IP# from device name
445 */
446 int ret = inet_pton(AF_INET, dev->name, &addr.sin_addr);
447 if (ret == 1) {
448 /*
449 * Successful conversion of device name
450 * to IPv4 address.
451 */
452 addr.sin_family = AF_INET;
453 if (pcapint_add_addr_to_dev(dev, &addr, sizeof(addr),
454 NULL, 0, NULL, 0, NULL, 0, errbuf) == -1)
455 return PCAP_ERROR;
456 } else if (ret == -1) {
457 /*
458 * Error.
459 */
460 pcapint_fmt_errmsg_for_errno(errbuf,
461 PCAP_ERRBUF_SIZE, errno,
462 "%s inet_pton", __func__);
463 return PCAP_ERROR;
464 }
465 #endif // _WIN32
466 }
467 }
468 snf_freeifaddrs(ifaddrs);
469 /*
470 * Create a snfX entry if port aggregation is enabled
471 */
472 if (merge) {
473 /*
474 * Add a new entry with all ports bitmask
475 */
476 (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports);
477 (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d",
478 allports);
479 /*
480 * XXX - is there any notion of "up" and "running" that
481 * would apply to this device, given that it handles
482 * multiple ports?
483 *
484 * Presumably, there's no notion of "connected" vs.
485 * "disconnected", as "is this plugged into a network?"
486 * would be a per-port property.
487 */
488 if (pcapint_add_dev(devlistp, name,
489 PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc,
490 errbuf) == NULL)
491 return PCAP_ERROR;
492 /*
493 * XXX - should we give it a list of addresses with all
494 * the addresses for all the ports?
495 */
496 }
497
498 return 0;
499 }
500
501 /*
502 * If an SNF device exists for the given regular network interface name, copy
503 * its struct snf_ifaddrs to the provided pointer if the pointer is not NULL.
504 *
505 * Return:
506 * 0 if such SNF device does not exist
507 * 1 if such SNF device exists
508 * PCAP_ERROR on an SNF API error
509 */
510 static int
511 snf_device_exists(const char *device, struct snf_ifaddrs *out, char *errbuf)
512 {
513 if (snf_init(SNF_VERSION_API)) {
514 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
515 errno, "snf_init");
516 return PCAP_ERROR;
517 }
518 struct snf_ifaddrs *ifaddrs;
519 if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) {
520 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
521 errno, "snf_getifaddrs");
522 return PCAP_ERROR;
523 }
524 int ret = 0;
525 for (struct snf_ifaddrs *ifa = ifaddrs; ifa; ifa = ifa->snf_ifa_next)
526 if (! strcmp(device, ifa->snf_ifa_name)) {
527 ret = 1;
528 if (out)
529 *out = *ifa;
530 break;
531 }
532 snf_freeifaddrs(ifaddrs);
533 return ret;
534 }
535
536 /*
537 * If an SNF device exists for the given regular network interface name,
538 * replace the PCAP_IF_CONNECTION_STATUS part of the provided flags with the
539 * link state from the SNF API.
540 *
541 * The matter is, for a regular network interface that is administratively
542 * down the operational (link) state appears -- at least on Linux -- down and
543 * an attempt to capture on the interface would fail with ENETDOWN. The SNF
544 * API works differently: regardless of the administrative state it allows to
545 * use an SNF device and reports the same link state as the device's "link up"
546 * LED.
547 *
548 * Return:
549 * 0 if such SNF device does not exist
550 * 1 if such SNF device exists
551 * PCAP_ERROR on an SNF API error
552 */
553 int
554 snf_get_if_flags(const char *device, bpf_u_int32 *flags, char *errbuf)
555 {
556 struct snf_ifaddrs ifa;
557 int exists = snf_device_exists(device, &ifa, errbuf);
558 if (exists <= 0)
559 return exists;
560
561 *flags &= ~PCAP_IF_CONNECTION_STATUS;
562 switch (ifa.snf_ifa_link_state) {
563 case SNF_LINK_UP:
564 *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED;
565 break;
566 case SNF_LINK_DOWN:
567 *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
568 break;
569 default:
570 snprintf(errbuf, PCAP_ERRBUF_SIZE,
571 "invalid snf_ifa_link_state value %u",
572 ifa.snf_ifa_link_state);
573 return PCAP_ERROR;
574 }
575 return 1;
576 }
577
578 pcap_t *
579 snf_create(const char *device, char *ebuf, int *is_ours)
580 {
581 pcap_t *p;
582 int boardnum = -1;
583 struct snf_ifaddrs ifa;
584 struct pcap_snf *ps;
585
586 /*
587 * Match a given interface name to our list of interface names, from
588 * which we can obtain the intended board number
589 */
590 int exists = snf_device_exists(device, &ifa, ebuf);
591 if (exists < 0) {
592 /* Can't use the API, so no SNF devices */
593 *is_ours = 0;
594 return NULL;
595 }
596
597 if (! exists) {
598 /*
599 * If we can't find the device by name, support the name "snfX"
600 * and "snf10gX" where X is the board number.
601 */
602 if (sscanf(device, "snf10g%d", &boardnum) != 1 &&
603 sscanf(device, "snf%d", &boardnum) != 1) {
604 /* Nope, not a supported name */
605 *is_ours = 0;
606 return NULL;
607 }
608 }
609
610 /* OK, it's probably ours. */
611 *is_ours = 1;
612
613 p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf);
614 if (p == NULL)
615 return NULL;
616 ps = p->priv;
617
618 /*
619 * We support microsecond and nanosecond time stamps.
620 */
621 p->tstamp_precision_list = malloc(2 * sizeof(u_int));
622 if (p->tstamp_precision_list == NULL) {
623 pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno,
624 "malloc");
625 pcap_close(p);
626 return NULL;
627 }
628 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
629 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
630 p->tstamp_precision_count = 2;
631
632 p->activate_op = snf_activate;
633 ps->snf_boardnum = boardnum;
634 return p;
635 }
636
637 #ifdef SNF_ONLY
638 /*
639 * This libpcap build supports only SNF cards, not regular network
640 * interfaces..
641 */
642
643 /*
644 * There are no regular interfaces, just SNF interfaces.
645 */
646 static int
647 can_be_bound(const char *name)
648 {
649 char dummy[PCAP_ERRBUF_SIZE];
650 return snf_device_exists(name, NULL, dummy) == 1;
651 }
652
653 /*
654 * Even though this is an SNF-only build, use the regular "findalldevs" code
655 * for device enumeration, but pick only network interfaces that correspond to
656 * SNF devices. Use SNF-specific interpretation of device flags.
657 */
658 int
659 pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
660 {
661 return pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound,
662 snf_get_if_flags);
663 }
664
665 /*
666 * Attempts to open a regular interface fail.
667 */
668 pcap_t *
669 pcapint_create_interface(const char *device _U_, char *errbuf)
670 {
671 snprintf(errbuf, PCAP_ERRBUF_SIZE, PCAP_ENODEV_MESSAGE, "SNF");
672 return NULL;
673 }
674
675 /*
676 * Libpcap version string.
677 */
678 const char *
679 pcap_lib_version(void)
680 {
681 return (PCAP_VERSION_STRING " (SNF-only)");
682 }
683 #endif