pcap-snf.c revision 214455
1214455Srpaulo#ifdef HAVE_CONFIG_H 2214455Srpaulo#include "config.h" 3214455Srpaulo#endif 4214455Srpaulo 5214455Srpaulo#include <sys/param.h> 6214455Srpaulo 7214455Srpaulo#include <stdlib.h> 8214455Srpaulo#include <string.h> 9214455Srpaulo#include <errno.h> 10214455Srpaulo 11214455Srpaulo#include <ctype.h> 12214455Srpaulo#include <netinet/in.h> 13214455Srpaulo#include <sys/mman.h> 14214455Srpaulo#include <sys/socket.h> 15214455Srpaulo#include <sys/types.h> 16214455Srpaulo#include <unistd.h> 17214455Srpaulo 18214455Srpaulo#include "snf.h" 19214455Srpaulo#include "pcap-int.h" 20214455Srpaulo 21214455Srpaulo#ifdef SNF_ONLY 22214455Srpaulo#define snf_create pcap_create 23214455Srpaulo#define snf_platform_finddevs pcap_platform_finddevs 24214455Srpaulo#endif 25214455Srpaulo 26214455Srpaulostatic int 27214455Srpaulosnf_set_datalink(pcap_t *p, int dlt) 28214455Srpaulo{ 29214455Srpaulo p->linktype = dlt; 30214455Srpaulo return (0); 31214455Srpaulo} 32214455Srpaulo 33214455Srpaulostatic int 34214455Srpaulosnf_pcap_stats(pcap_t *p, struct pcap_stat *ps) 35214455Srpaulo{ 36214455Srpaulo struct snf_ring_stats stats; 37214455Srpaulo int rc; 38214455Srpaulo 39214455Srpaulo if ((rc = snf_ring_getstats(p->md.snf_ring, &stats))) { 40214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", 41214455Srpaulo pcap_strerror(rc)); 42214455Srpaulo return -1; 43214455Srpaulo } 44214455Srpaulo ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; 45214455Srpaulo ps->ps_drop = stats.ring_pkt_overflow; 46214455Srpaulo ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; 47214455Srpaulo return 0; 48214455Srpaulo} 49214455Srpaulo 50214455Srpaulostatic void 51214455Srpaulosnf_platform_cleanup(pcap_t *p) 52214455Srpaulo{ 53214455Srpaulo if (p == NULL) 54214455Srpaulo return; 55214455Srpaulo 56214455Srpaulo snf_ring_close(p->md.snf_ring); 57214455Srpaulo snf_close(p->md.snf_handle); 58214455Srpaulo pcap_cleanup_live_common(p); 59214455Srpaulo} 60214455Srpaulo 61214455Srpaulostatic int 62214455Srpaulosnf_getnonblock(pcap_t *p, char *errbuf) 63214455Srpaulo{ 64214455Srpaulo return (p->md.snf_timeout == 0); 65214455Srpaulo} 66214455Srpaulo 67214455Srpaulostatic int 68214455Srpaulosnf_setnonblock(pcap_t *p, int nonblock, char *errbuf) 69214455Srpaulo{ 70214455Srpaulo if (nonblock) 71214455Srpaulo p->md.snf_timeout = 0; 72214455Srpaulo else { 73214455Srpaulo if (p->md.timeout <= 0) 74214455Srpaulo p->md.snf_timeout = -1; /* forever */ 75214455Srpaulo else 76214455Srpaulo p->md.snf_timeout = p->md.timeout; 77214455Srpaulo } 78214455Srpaulo return (0); 79214455Srpaulo} 80214455Srpaulo 81214455Srpaulo#define _NSEC_PER_SEC 1000000000 82214455Srpaulo 83214455Srpaulostatic inline 84214455Srpaulostruct timeval 85214455Srpaulosnf_timestamp_to_timeval(const int64_t ts_nanosec) 86214455Srpaulo{ 87214455Srpaulo struct timeval tv; 88214455Srpaulo int32_t rem; 89214455Srpaulo if (ts_nanosec == 0) 90214455Srpaulo return (struct timeval) { 0, 0 }; 91214455Srpaulo tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; 92214455Srpaulo tv.tv_usec = (ts_nanosec % _NSEC_PER_SEC) / 1000; 93214455Srpaulo return tv; 94214455Srpaulo} 95214455Srpaulo 96214455Srpaulostatic int 97214455Srpaulosnf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 98214455Srpaulo{ 99214455Srpaulo struct pcap_pkthdr hdr; 100214455Srpaulo int i, flags, err, caplen, n; 101214455Srpaulo struct snf_recv_req req; 102214455Srpaulo 103214455Srpaulo if (!p || cnt == 0) 104214455Srpaulo return -1; 105214455Srpaulo 106214455Srpaulo n = 0; 107214455Srpaulo while (n < cnt || cnt < 0) { 108214455Srpaulo /* 109214455Srpaulo * Has "pcap_breakloop()" been called? 110214455Srpaulo */ 111214455Srpaulo if (p->break_loop) { 112214455Srpaulo if (n == 0) { 113214455Srpaulo p->break_loop = 0; 114214455Srpaulo return (-2); 115214455Srpaulo } else { 116214455Srpaulo return (n); 117214455Srpaulo } 118214455Srpaulo } 119214455Srpaulo 120214455Srpaulo err = snf_ring_recv(p->md.snf_ring, p->md.snf_timeout, &req); 121214455Srpaulo 122214455Srpaulo if (err) { 123214455Srpaulo if (err == EBUSY || err == EAGAIN) 124214455Srpaulo return (0); 125214455Srpaulo if (err == EINTR) 126214455Srpaulo continue; 127214455Srpaulo if (err != 0) { 128214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", 129214455Srpaulo pcap_strerror(err)); 130214455Srpaulo return -1; 131214455Srpaulo } 132214455Srpaulo } 133214455Srpaulo 134214455Srpaulo caplen = req.length; 135214455Srpaulo if (caplen > p->snapshot) 136214455Srpaulo caplen = p->snapshot; 137214455Srpaulo 138214455Srpaulo if ((p->fcode.bf_insns == NULL) || 139214455Srpaulo bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { 140214455Srpaulo hdr.ts = snf_timestamp_to_timeval(req.timestamp); 141214455Srpaulo hdr.caplen = caplen; 142214455Srpaulo hdr.len = req.length; 143214455Srpaulo callback(user, &hdr, req.pkt_addr); 144214455Srpaulo } 145214455Srpaulo n++; 146214455Srpaulo } 147214455Srpaulo return (n); 148214455Srpaulo} 149214455Srpaulo 150214455Srpaulostatic int 151214455Srpaulosnf_setfilter(pcap_t *p, struct bpf_program *fp) 152214455Srpaulo{ 153214455Srpaulo if (!p) 154214455Srpaulo return -1; 155214455Srpaulo if (!fp) { 156214455Srpaulo strncpy(p->errbuf, "setfilter: No filter specified", 157214455Srpaulo sizeof(p->errbuf)); 158214455Srpaulo return -1; 159214455Srpaulo } 160214455Srpaulo 161214455Srpaulo /* Make our private copy of the filter */ 162214455Srpaulo 163214455Srpaulo if (install_bpf_program(p, fp) < 0) 164214455Srpaulo return -1; 165214455Srpaulo 166214455Srpaulo p->md.use_bpf = 0; 167214455Srpaulo 168214455Srpaulo return (0); 169214455Srpaulo} 170214455Srpaulo 171214455Srpaulostatic int 172214455Srpaulosnf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 173214455Srpaulo{ 174214455Srpaulo strlcpy(p->errbuf, "Sending packets isn't supported with snf", 175214455Srpaulo PCAP_ERRBUF_SIZE); 176214455Srpaulo return (-1); 177214455Srpaulo} 178214455Srpaulo 179214455Srpaulostatic int 180214455Srpaulosnf_activate(pcap_t* p) 181214455Srpaulo{ 182214455Srpaulo char *device = p->opt.source; 183214455Srpaulo const char *nr = NULL; 184214455Srpaulo int err; 185214455Srpaulo int flags = 0; 186214455Srpaulo 187214455Srpaulo if (device == NULL) { 188214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 189214455Srpaulo "device is NULL: %s", pcap_strerror(errno)); 190214455Srpaulo return -1; 191214455Srpaulo } 192214455Srpaulo 193214455Srpaulo /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. 194214455Srpaulo * Since libpcap isn't thread-safe */ 195214455Srpaulo if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) 196214455Srpaulo flags |= SNF_F_PSHARED; 197214455Srpaulo else 198214455Srpaulo nr = NULL; 199214455Srpaulo 200214455Srpaulo err = snf_open(p->md.snf_boardnum, 201214455Srpaulo 0, /* let SNF API parse SNF_NUM_RINGS, if set */ 202214455Srpaulo NULL, /* default RSS, or use SNF_RSS_FLAGS env */ 203214455Srpaulo 0, /* default to SNF_DATARING_SIZE from env */ 204214455Srpaulo flags, /* may want pshared */ 205214455Srpaulo &p->md.snf_handle); 206214455Srpaulo if (err != 0) { 207214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 208214455Srpaulo "snf_open failed: %s", pcap_strerror(err)); 209214455Srpaulo return -1; 210214455Srpaulo } 211214455Srpaulo 212214455Srpaulo err = snf_ring_open(p->md.snf_handle, &p->md.snf_ring); 213214455Srpaulo if (err != 0) { 214214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 215214455Srpaulo "snf_ring_open failed: %s", pcap_strerror(err)); 216214455Srpaulo return -1; 217214455Srpaulo } 218214455Srpaulo 219214455Srpaulo if (p->md.timeout <= 0) 220214455Srpaulo p->md.snf_timeout = -1; 221214455Srpaulo else 222214455Srpaulo p->md.snf_timeout = p->md.timeout; 223214455Srpaulo 224214455Srpaulo err = snf_start(p->md.snf_handle); 225214455Srpaulo if (err != 0) { 226214455Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 227214455Srpaulo "snf_start failed: %s", pcap_strerror(err)); 228214455Srpaulo return -1; 229214455Srpaulo } 230214455Srpaulo 231214455Srpaulo /* 232214455Srpaulo * "select()" and "poll()" don't work on snf descriptors. 233214455Srpaulo */ 234214455Srpaulo p->selectable_fd = -1; 235214455Srpaulo p->linktype = DLT_EN10MB; 236214455Srpaulo p->read_op = snf_read; 237214455Srpaulo p->inject_op = snf_inject; 238214455Srpaulo p->setfilter_op = snf_setfilter; 239214455Srpaulo p->setdirection_op = NULL; /* Not implemented.*/ 240214455Srpaulo p->set_datalink_op = snf_set_datalink; 241214455Srpaulo p->getnonblock_op = snf_getnonblock; 242214455Srpaulo p->setnonblock_op = snf_setnonblock; 243214455Srpaulo p->stats_op = snf_pcap_stats; 244214455Srpaulo p->cleanup_op = snf_platform_cleanup; 245214455Srpaulo p->md.stat.ps_recv = 0; 246214455Srpaulo p->md.stat.ps_drop = 0; 247214455Srpaulo p->md.stat.ps_ifdrop = 0; 248214455Srpaulo return 0; 249214455Srpaulo} 250214455Srpaulo 251214455Srpauloint 252214455Srpaulosnf_platform_finddevs(pcap_if_t **devlistp, char *errbuf) 253214455Srpaulo{ 254214455Srpaulo /* 255214455Srpaulo * There are no platform-specific devices since each device 256214455Srpaulo * exists as a regular Ethernet device. 257214455Srpaulo */ 258214455Srpaulo return 0; 259214455Srpaulo} 260214455Srpaulo 261214455Srpaulopcap_t * 262214455Srpaulosnf_create(const char *device, char *ebuf) 263214455Srpaulo{ 264214455Srpaulo pcap_t *p; 265214455Srpaulo int boardnum = -1; 266214455Srpaulo struct snf_ifaddrs *ifaddrs, *ifa; 267214455Srpaulo size_t devlen; 268214455Srpaulo 269214455Srpaulo if (snf_init(SNF_VERSION_API)) 270214455Srpaulo return NULL; 271214455Srpaulo 272214455Srpaulo /* 273214455Srpaulo * Match a given interface name to our list of interface names, from 274214455Srpaulo * which we can obtain the intended board number 275214455Srpaulo */ 276214455Srpaulo if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) 277214455Srpaulo return NULL; 278214455Srpaulo devlen = strlen(device) + 1; 279214455Srpaulo ifa = ifaddrs; 280214455Srpaulo while (ifa) { 281214455Srpaulo if (!strncmp(device, ifa->snf_ifa_name, devlen)) { 282214455Srpaulo boardnum = ifa->snf_ifa_boardnum; 283214455Srpaulo break; 284214455Srpaulo } 285214455Srpaulo ifa = ifa->snf_ifa_next; 286214455Srpaulo } 287214455Srpaulo snf_freeifaddrs(ifaddrs); 288214455Srpaulo 289214455Srpaulo if (ifa == NULL) { 290214455Srpaulo /* 291214455Srpaulo * If we can't find the device by name, support the name "snfX" 292214455Srpaulo * and "snf10gX" where X is the board number. 293214455Srpaulo */ 294214455Srpaulo if (sscanf(device, "snf10g%d", &boardnum) != 1 && 295214455Srpaulo sscanf(device, "snf%d", &boardnum) != 1) 296214455Srpaulo return NULL; 297214455Srpaulo } 298214455Srpaulo 299214455Srpaulo p = pcap_create_common(device, ebuf); 300214455Srpaulo if (p == NULL) 301214455Srpaulo return NULL; 302214455Srpaulo 303214455Srpaulo p->activate_op = snf_activate; 304214455Srpaulo p->md.snf_boardnum = boardnum; 305214455Srpaulo return p; 306214455Srpaulo} 307