Annotation of libaitio/src/bpf.c, revision 1.1.2.17
1.1.2.1 misho 1: #include "global.h"
2:
3:
1.1.2.2 misho 4: /*
5: * io_get1stiface() - Get first interface of host
6: *
7: * @szIface = interface string buffer
8: * @iflen = size of interface buffer
9: * return: -1 error or 0 ok
10: */
11: int
12: io_get1stiface(char *szIface, int iflen)
13: {
14: struct ifaddrs *ifa;
15:
16: if (!szIface || !iflen)
17: return -1;
18:
19: getifaddrs(&ifa);
20: strlcpy(szIface, ifa->ifa_name, iflen);
21: freeifaddrs(ifa);
22: return 0;
23: }
24:
25: /*
26: * io_etherClose() - Close BPF interface
27: *
28: * @eth = bpf handle
1.1.2.3 misho 29: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
1.1.2.2 misho 30: * return: none
31: */
32: void
1.1.2.3 misho 33: io_etherClose(int eth, void **zcbuf)
1.1.2.2 misho 34: {
1.1.2.3 misho 35: #ifdef __FreeBSD__
36: struct bpf_zbuf *zbuf = NULL;
37: #endif
38:
1.1.2.2 misho 39: if (eth > STDERR_FILENO)
40: close(eth);
1.1.2.3 misho 41:
42: if (zcbuf && *zcbuf) {
43: #ifdef __FreeBSD__
44: zbuf = *zcbuf;
45: munmap(zbuf->bz_bufb, zbuf->bz_buflen);
46: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
47: e_free(*zcbuf);
48: *zcbuf = NULL;
49: #endif
50: }
51: }
52:
53: #ifdef __FreeBSD__
54: static inline struct bpf_zbuf *
55: allocZCbuf(u_int len)
56: {
57: struct bpf_zbuf *zbuf = NULL;
58:
59: zbuf = e_malloc(sizeof(struct bpf_zbuf));
60: if (!zbuf) {
61: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
62: return NULL;
63: } else
64: memset(zbuf, 0, sizeof(struct bpf_zbuf));
65:
66: zbuf->bz_buflen = roundup(len, getpagesize());
67: zbuf->bz_bufa = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
68: if (zbuf->bz_bufa == MAP_FAILED) {
69: LOGERR;
70: e_free(zbuf);
71: return NULL;
72: } else
73: memset(zbuf->bz_bufa, 0, zbuf->bz_buflen);
74: zbuf->bz_bufb = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
75: if (zbuf->bz_bufb == MAP_FAILED) {
76: LOGERR;
77: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
78: e_free(zbuf);
79: return NULL;
80: } else
81: memset(zbuf->bz_bufb, 0, zbuf->bz_buflen);
82:
83: return zbuf;
1.1.2.2 misho 84: }
1.1.2.3 misho 85: #endif
1.1.2.2 misho 86:
87: /*
88: * io_etherOpen() - Open BPF interface to device
89: *
90: * @csIface = interface name
91: * @flags = open flags
1.1.2.3 misho 92: * @whdr = with complete headers
93: * @buflen = buffer length
94: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
1.1.2.2 misho 95: * return: -1 error or >-1 bpf handle
96: */
97: int
1.1.2.4 misho 98: io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
1.1.2.2 misho 99: {
1.1.2.11 misho 100: int eth = -1;
1.1.2.2 misho 101: register int i;
102: char szStr[STRSIZ];
103: struct ifreq ifr;
1.1.2.11 misho 104: u_int n = 1;
105:
106: #ifndef __FreeBSD__
107: if (zcbuf) {
108: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
109: return -1;
110: }
111: #endif
1.1.2.2 misho 112:
113: for (i = 0; i < BPF_DEV_MAX; i++) {
114: memset(szStr, 0, sizeof szStr);
115: snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
116: eth = open(szStr, flags);
117: if (eth > STDERR_FILENO)
118: break;
119: }
120: if (eth < 3) {
121: LOGERR;
122: return -1;
123: }
124:
1.1.2.11 misho 125: if (!zcbuf) {
126: if (ioctl(eth, BIOCGBLEN, &n) == -1) {
127: LOGERR;
128: close(eth);
129: return -1;
130: } else
1.1.2.12 misho 131: n = (buflen && *buflen) ? *buflen : n;
1.1.2.11 misho 132: if (ioctl(eth, BIOCSBLEN, &n) == -1) {
133: LOGERR;
134: close(eth);
135: return -1;
136: }
137: if (buflen && *buflen)
138: *buflen = n;
139: } else {
1.1.2.3 misho 140: #ifdef __FreeBSD__
1.1.2.11 misho 141: n = BPF_BUFMODE_ZBUF;
142: if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
143: LOGERR;
144: close(eth);
145: return -1;
146: }
147: if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
148: LOGERR;
149: close(eth);
150: return -1;
151: } else
1.1.2.12 misho 152: n = (buflen && *buflen) ? *buflen : n;
1.1.2.11 misho 153: if (!(*zcbuf = allocZCbuf(n))) {
154: close(eth);
155: return -1;
156: }
1.1.2.16 misho 157: if (ioctl(eth, BIOCSETZBUF, *zcbuf) == -1) {
1.1.2.11 misho 158: LOGERR;
159: io_etherClose(eth, zcbuf);
160: return -1;
1.1.2.3 misho 161: }
1.1.2.11 misho 162: if (buflen && *buflen)
163: *buflen = n;
164: #endif
1.1.2.3 misho 165: }
1.1.2.11 misho 166:
1.1.2.2 misho 167: if (csIface)
168: strlcpy(szStr, csIface, sizeof szStr);
169: else if (io_get1stiface(szStr, sizeof szStr) == -1) {
1.1.2.3 misho 170: io_etherClose(eth, zcbuf);
1.1.2.2 misho 171: return -1;
172: }
1.1.2.10 misho 173: memset(&ifr, 0, sizeof ifr);
1.1.2.2 misho 174: strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
175: if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
176: LOGERR;
1.1.2.3 misho 177: io_etherClose(eth, zcbuf);
1.1.2.2 misho 178: return -1;
179: }
180:
1.1.2.15 misho 181: n = 1;
1.1.2.14 misho 182: if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
183: LOGERR;
184: io_etherClose(eth, zcbuf);
185: return -1;
186: }
187: if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
188: LOGERR;
189: io_etherClose(eth, zcbuf);
190: return -1;
191: }
192:
1.1.2.2 misho 193: return eth;
194: }
1.1.2.6 misho 195:
196: /*
197: * io_etherSend() - Send packet to bpf
198: *
199: * @eth = bpf handle
200: * @buf = buffer
201: * @buflen = buffer length
202: * return: -1 error or !=-1 written bytes
203: */
204: ssize_t
205: io_etherSend(int eth, const void *buf, size_t buflen)
206: {
207: ssize_t wlen = 0;
208:
209: if (!buf || !buflen) {
210: io_SetErr(EINVAL, "invalid arguments");
211: return -1;
212: }
213:
214: wlen = write(eth, buf, buflen);
215: if (wlen == -1)
216: LOGERR;
217: return wlen;
218: }
219:
220: #ifdef __FreeBSD__
1.1.2.8 misho 221: static inline void
1.1.2.17! misho 222: ackZCbuf(struct bpf_zbuf_header *bzh)
1.1.2.8 misho 223: {
224: atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
225: }
226:
227: static inline int
1.1.2.17! misho 228: chkZCbuf(struct bpf_zbuf_header *bzh)
1.1.2.8 misho 229: {
230: /* return true if userspace owns buffer, and false otherwise. */
231: return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen));
232: }
233:
1.1.2.17! misho 234: static inline ssize_t
! 235: nextZCbuf(int eth, void ** __restrict zcache, struct bpf_zbuf * __restrict zbuf)
1.1.2.6 misho 236: {
1.1.2.17! misho 237: ssize_t rlen = 0;
1.1.2.6 misho 238: struct bpf_zbuf_header *bzh;
239:
240: if (!*zcache || *zcache == zbuf->bz_bufb) {
241: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
1.1.2.8 misho 242: if (chkZCbuf(bzh)) {
1.1.2.6 misho 243: *zcache = zbuf->bz_bufa;
1.1.2.17! misho 244: rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
1.1.2.16 misho 245: }
1.1.2.6 misho 246: } else if (*zcache == zbuf->bz_bufa) {
247: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
1.1.2.8 misho 248: if (chkZCbuf(bzh)) {
1.1.2.6 misho 249: *zcache = zbuf->bz_bufb;
1.1.2.17! misho 250: rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
1.1.2.16 misho 251: }
1.1.2.6 misho 252: }
253:
254: return rlen;
255: }
256: #endif
257:
258: /*
259: * io_etherRecv() - Receive packet from bpf
260: *
261: * @eth = bpf handle
262: * @buf = buffer
263: * @buflen = buffer length
264: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
265: * return: -1 error or !=-1 readed bytes
266: */
267: ssize_t
268: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
269: {
270: ssize_t rlen = 0;
1.1.2.14 misho 271: void *zcache = NULL;
1.1.2.16 misho 272: #ifdef __FreeBSD__
1.1.2.17! misho 273: struct bpf_zbuf bz;
1.1.2.16 misho 274: struct bpf_zbuf_header *bzh;
275: #endif
1.1.2.6 misho 276:
277: if (!buf || !buflen) {
278: io_SetErr(EINVAL, "invalid arguments");
279: return -1;
280: }
281:
282: if (!zcbuf) {
283: rlen = read(eth, buf, buflen);
284: if (rlen == -1)
285: LOGERR;
286: } else {
287: #ifdef __FreeBSD__
1.1.2.17! misho 288: do {
! 289: rlen = nextZCbuf(eth, &zcache, (struct bpf_zbuf*) zcbuf);
! 290: if (rlen > 0) {
! 291: bzh = (struct bpf_zbuf_header*) zcache;
! 292: memcpy(buf, zcache + sizeof(struct bpf_zbuf_header),
! 293: MIN(buflen, rlen));
! 294: ackZCbuf(bzh);
! 295: }
! 296: if (!rlen && !ioctl(eth, BIOCROTZBUF, &bz)) {
! 297: bzh = (struct bpf_zbuf_header*) bz.bz_bufa;
! 298: if (bzh && chkZCbuf(bzh)) {
! 299: rlen = bz.bz_buflen;
! 300: memcpy(buf, bz.bz_bufa + sizeof(struct bpf_zbuf_header),
! 301: MIN(buflen, rlen));
! 302: }
! 303: }
! 304: } while (0);
1.1.2.6 misho 305: #else
1.1.2.16 misho 306: rlen = -1;
1.1.2.6 misho 307: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
308: #endif
309: }
310:
311: return rlen;
312: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>