2 * Copyright (C) 2014 Luigi Rizzo. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #define NETMAP_WITH_LIBS
43 #include <net/netmap_user.h>
47 #define NM_PRIV(p) ((struct pcap_netmap *)(p->priv))
50 /* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh.
51 * remap to IFF_PROMISC on linux
53 #define IFF_PPROMISC IFF_PROMISC
57 struct nm_desc *d; /* pointer returned by nm_open() */
58 pcap_handler cb; /* callback and argument */
60 int must_clear_promisc; /* flag */
61 uint64_t rx_pkts; /* # of pkts received before the filter */
66 pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps)
68 struct pcap_netmap *pn = NM_PRIV(p);
70 ps->ps_recv = pn->rx_pkts;
78 pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
80 pcap_t *p = (pcap_t *)arg;
81 struct pcap_netmap *pn = NM_PRIV(p);
82 const struct bpf_insn *pc = p->fcode.bf_insns;
85 if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen))
86 pn->cb(pn->cb_arg, h, buf);
91 pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user)
94 struct pcap_netmap *pn = NM_PRIV(p);
95 struct nm_desc *d = pn->d;
96 struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 };
104 return PCAP_ERROR_BREAK;
106 /* nm_dispatch won't run forever */
108 ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p);
112 ret = poll(&pfd, 1, p->opt.timeout);
118 /* XXX need to check the NIOCTXSYNC/poll */
120 pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
122 struct nm_desc *d = NM_PRIV(p)->d;
124 return nm_inject(d, buf, size);
129 pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags)
131 struct pcap_netmap *pn = NM_PRIV(p);
132 struct nm_desc *d = pn->d;
134 int error, fd = d->fd;
137 fd = socket(AF_INET, SOCK_DGRAM, 0);
139 fprintf(stderr, "Error: cannot get device control socket.\n");
143 bzero(&ifr, sizeof(ifr));
144 strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name));
147 ifr.ifr_flags = *if_flags;
149 ifr.ifr_flagshigh = *if_flags >> 16;
150 #endif /* __FreeBSD__ */
153 error = ioctl(fd, what, &ifr);
157 *if_flags = ifr.ifr_flags;
159 *if_flags |= (ifr.ifr_flagshigh << 16);
160 #endif /* __FreeBSD__ */
166 return error ? -1 : 0;
171 pcap_netmap_close(pcap_t *p)
173 struct pcap_netmap *pn = NM_PRIV(p);
174 struct nm_desc *d = pn->d;
175 uint32_t if_flags = 0;
177 if (pn->must_clear_promisc) {
178 pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
179 if (if_flags & IFF_PPROMISC) {
180 if_flags &= ~IFF_PPROMISC;
181 pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
185 pcap_cleanup_live_common(p);
190 pcap_netmap_activate(pcap_t *p)
192 struct pcap_netmap *pn = NM_PRIV(p);
193 struct nm_desc *d = nm_open(p->opt.device, NULL, 0, NULL);
194 uint32_t if_flags = 0;
197 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
198 "netmap open: cannot access %s: %s\n",
199 p->opt.device, pcap_strerror(errno));
200 pcap_cleanup_live_common(p);
204 fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n",
205 __FUNCTION__, p->opt.device, d, d->fd,
206 d->first_rx_ring, d->last_rx_ring);
209 if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) {
210 pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
211 if (!(if_flags & IFF_PPROMISC)) {
212 pn->must_clear_promisc = 1;
213 if_flags |= IFF_PPROMISC;
214 pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
217 p->linktype = DLT_EN10MB;
218 p->selectable_fd = p->fd;
219 p->read_op = pcap_netmap_dispatch;
220 p->inject_op = pcap_netmap_inject;
221 p->setfilter_op = install_bpf_program;
222 p->setdirection_op = NULL;
223 p->set_datalink_op = NULL;
224 p->getnonblock_op = pcap_getnonblock_fd;
225 p->setnonblock_op = pcap_setnonblock_fd;
226 p->stats_op = pcap_netmap_stats;
227 p->cleanup_op = pcap_netmap_close;
234 pcap_netmap_create(const char *device, char *ebuf, int *is_ours)
238 *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
241 p = pcap_create_common(ebuf, sizeof (struct pcap_netmap));
244 p->activate_op = pcap_netmap_activate;