Annotation of libaitio/src/bpf.c, revision 1.1.2.21
1.1.2.21! misho 1: /*************************************************************************
! 2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
! 3: * by Michael Pounov <misho@elwix.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: aio.c,v 1.8 2013/05/30 09:10:13 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
1.1.2.1 misho 46: #include "global.h"
47:
48:
1.1.2.2 misho 49: /*
50: * io_get1stiface() - Get first interface of host
51: *
52: * @szIface = interface string buffer
53: * @iflen = size of interface buffer
54: * return: -1 error or 0 ok
55: */
56: int
57: io_get1stiface(char *szIface, int iflen)
58: {
59: struct ifaddrs *ifa;
60:
61: if (!szIface || !iflen)
62: return -1;
63:
64: getifaddrs(&ifa);
65: strlcpy(szIface, ifa->ifa_name, iflen);
66: freeifaddrs(ifa);
67: return 0;
68: }
69:
70: /*
71: * io_etherClose() - Close BPF interface
72: *
73: * @eth = bpf handle
1.1.2.3 misho 74: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
1.1.2.2 misho 75: * return: none
76: */
77: void
1.1.2.3 misho 78: io_etherClose(int eth, void **zcbuf)
1.1.2.2 misho 79: {
1.1.2.3 misho 80: #ifdef __FreeBSD__
81: struct bpf_zbuf *zbuf = NULL;
82: #endif
83:
1.1.2.2 misho 84: if (eth > STDERR_FILENO)
85: close(eth);
1.1.2.3 misho 86:
87: if (zcbuf && *zcbuf) {
88: #ifdef __FreeBSD__
89: zbuf = *zcbuf;
90: munmap(zbuf->bz_bufb, zbuf->bz_buflen);
91: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
92: e_free(*zcbuf);
93: *zcbuf = NULL;
94: #endif
95: }
96: }
97:
98: #ifdef __FreeBSD__
99: static inline struct bpf_zbuf *
100: allocZCbuf(u_int len)
101: {
102: struct bpf_zbuf *zbuf = NULL;
103:
104: zbuf = e_malloc(sizeof(struct bpf_zbuf));
105: if (!zbuf) {
106: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
107: return NULL;
108: } else
109: memset(zbuf, 0, sizeof(struct bpf_zbuf));
110:
111: zbuf->bz_buflen = roundup(len, getpagesize());
112: zbuf->bz_bufa = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
113: if (zbuf->bz_bufa == MAP_FAILED) {
114: LOGERR;
115: e_free(zbuf);
116: return NULL;
117: } else
118: memset(zbuf->bz_bufa, 0, zbuf->bz_buflen);
119: zbuf->bz_bufb = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
120: if (zbuf->bz_bufb == MAP_FAILED) {
121: LOGERR;
122: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
123: e_free(zbuf);
124: return NULL;
125: } else
126: memset(zbuf->bz_bufb, 0, zbuf->bz_buflen);
127:
128: return zbuf;
1.1.2.2 misho 129: }
1.1.2.3 misho 130: #endif
1.1.2.2 misho 131:
132: /*
133: * io_etherOpen() - Open BPF interface to device
134: *
135: * @csIface = interface name
136: * @flags = open flags
1.1.2.3 misho 137: * @whdr = with complete headers
138: * @buflen = buffer length
139: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
1.1.2.2 misho 140: * return: -1 error or >-1 bpf handle
141: */
142: int
1.1.2.4 misho 143: io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
1.1.2.2 misho 144: {
1.1.2.11 misho 145: int eth = -1;
1.1.2.2 misho 146: register int i;
147: char szStr[STRSIZ];
148: struct ifreq ifr;
1.1.2.11 misho 149: u_int n = 1;
150:
151: #ifndef __FreeBSD__
152: if (zcbuf) {
153: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
154: return -1;
155: }
156: #endif
1.1.2.2 misho 157:
158: for (i = 0; i < BPF_DEV_MAX; i++) {
159: memset(szStr, 0, sizeof szStr);
160: snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
161: eth = open(szStr, flags);
162: if (eth > STDERR_FILENO)
163: break;
164: }
165: if (eth < 3) {
166: LOGERR;
167: return -1;
168: }
169:
1.1.2.11 misho 170: if (!zcbuf) {
171: if (ioctl(eth, BIOCGBLEN, &n) == -1) {
172: LOGERR;
173: close(eth);
174: return -1;
175: } else
1.1.2.12 misho 176: n = (buflen && *buflen) ? *buflen : n;
1.1.2.11 misho 177: if (ioctl(eth, BIOCSBLEN, &n) == -1) {
178: LOGERR;
179: close(eth);
180: return -1;
181: }
182: if (buflen && *buflen)
183: *buflen = n;
184: } else {
1.1.2.3 misho 185: #ifdef __FreeBSD__
1.1.2.11 misho 186: n = BPF_BUFMODE_ZBUF;
187: if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
188: LOGERR;
189: close(eth);
190: return -1;
191: }
192: if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
193: LOGERR;
194: close(eth);
195: return -1;
196: } else
1.1.2.12 misho 197: n = (buflen && *buflen) ? *buflen : n;
1.1.2.11 misho 198: if (!(*zcbuf = allocZCbuf(n))) {
199: close(eth);
200: return -1;
201: }
1.1.2.16 misho 202: if (ioctl(eth, BIOCSETZBUF, *zcbuf) == -1) {
1.1.2.11 misho 203: LOGERR;
204: io_etherClose(eth, zcbuf);
205: return -1;
1.1.2.3 misho 206: }
1.1.2.11 misho 207: if (buflen && *buflen)
208: *buflen = n;
209: #endif
1.1.2.3 misho 210: }
1.1.2.11 misho 211:
1.1.2.2 misho 212: if (csIface)
213: strlcpy(szStr, csIface, sizeof szStr);
214: else if (io_get1stiface(szStr, sizeof szStr) == -1) {
1.1.2.3 misho 215: io_etherClose(eth, zcbuf);
1.1.2.2 misho 216: return -1;
217: }
1.1.2.10 misho 218: memset(&ifr, 0, sizeof ifr);
1.1.2.2 misho 219: strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
220: if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
221: LOGERR;
1.1.2.3 misho 222: io_etherClose(eth, zcbuf);
1.1.2.2 misho 223: return -1;
224: }
225:
1.1.2.15 misho 226: n = 1;
1.1.2.14 misho 227: if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
228: LOGERR;
229: io_etherClose(eth, zcbuf);
230: return -1;
231: }
232: if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
233: LOGERR;
234: io_etherClose(eth, zcbuf);
235: return -1;
236: }
237:
1.1.2.2 misho 238: return eth;
239: }
1.1.2.6 misho 240:
241: /*
242: * io_etherSend() - Send packet to bpf
243: *
244: * @eth = bpf handle
245: * @buf = buffer
246: * @buflen = buffer length
247: * return: -1 error or !=-1 written bytes
248: */
249: ssize_t
250: io_etherSend(int eth, const void *buf, size_t buflen)
251: {
252: ssize_t wlen = 0;
253:
254: if (!buf || !buflen) {
255: io_SetErr(EINVAL, "invalid arguments");
256: return -1;
257: }
258:
259: wlen = write(eth, buf, buflen);
260: if (wlen == -1)
261: LOGERR;
262: return wlen;
263: }
264:
265: #ifdef __FreeBSD__
1.1.2.8 misho 266: static inline void
1.1.2.17 misho 267: ackZCbuf(struct bpf_zbuf_header *bzh)
1.1.2.8 misho 268: {
269: atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
270: }
271:
272: static inline int
1.1.2.17 misho 273: chkZCbuf(struct bpf_zbuf_header *bzh)
1.1.2.8 misho 274: {
275: /* return true if userspace owns buffer, and false otherwise. */
276: return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen));
277: }
278:
1.1.2.20 misho 279: static ssize_t
1.1.2.19 misho 280: nextZCbuf(int eth, struct bpf_zbuf * __restrict zbuf, void * __restrict buf, size_t buflen)
1.1.2.6 misho 281: {
1.1.2.17 misho 282: ssize_t rlen = 0;
1.1.2.19 misho 283: struct bpf_zbuf bz;
1.1.2.6 misho 284: struct bpf_zbuf_header *bzh;
1.1.2.19 misho 285: off_t pos = 0;
1.1.2.6 misho 286:
1.1.2.19 misho 287: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
288: if (chkZCbuf(bzh)) {
289: rlen = MIN(atomic_load_acq_int(&bzh->bzh_kernel_len), buflen);
290: memcpy(buf + pos, zbuf->bz_bufa + sizeof(struct bpf_zbuf_header), rlen);
291: ackZCbuf(bzh);
292: pos += rlen;
293: }
294: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
295: if (chkZCbuf(bzh)) {
296: rlen = MIN(atomic_load_acq_int(&bzh->bzh_kernel_len), buflen);
297: memcpy(buf + pos, zbuf->bz_bufb + sizeof(struct bpf_zbuf_header), rlen);
298: ackZCbuf(bzh);
299: pos += rlen;
1.1.2.6 misho 300: }
301:
1.1.2.20 misho 302: if (!pos) {
303: if ((rlen = ioctl(eth, BIOCROTZBUF, &bz)) == -1)
304: LOGERR;
305: } else
306: rlen = pos;
1.1.2.6 misho 307: return rlen;
308: }
309: #endif
310:
311: /*
312: * io_etherRecv() - Receive packet from bpf
313: *
314: * @eth = bpf handle
315: * @buf = buffer
316: * @buflen = buffer length
317: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
318: * return: -1 error or !=-1 readed bytes
319: */
320: ssize_t
321: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
322: {
323: ssize_t rlen = 0;
324:
325: if (!buf || !buflen) {
326: io_SetErr(EINVAL, "invalid arguments");
327: return -1;
328: }
329:
330: if (!zcbuf) {
331: rlen = read(eth, buf, buflen);
332: if (rlen == -1)
333: LOGERR;
334: } else {
335: #ifdef __FreeBSD__
1.1.2.20 misho 336: rlen = nextZCbuf(eth, (struct bpf_zbuf*) zcbuf, buf, buflen);
337: if (!rlen)
1.1.2.19 misho 338: rlen = nextZCbuf(eth, (struct bpf_zbuf*) zcbuf, buf, buflen);
1.1.2.6 misho 339: #else
1.1.2.16 misho 340: rlen = -1;
1.1.2.6 misho 341: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
342: #endif
343: }
344:
345: return rlen;
346: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>