Annotation of libaitio/src/bpf.c, revision 1.1.2.10
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: {
100: int n = 1, eth = -1;
101: register int i;
102: char szStr[STRSIZ];
103: struct ifreq ifr;
104:
105: for (i = 0; i < BPF_DEV_MAX; i++) {
106: memset(szStr, 0, sizeof szStr);
107: snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
108: eth = open(szStr, flags);
109: if (eth > STDERR_FILENO)
110: break;
111: }
112: if (eth < 3) {
113: LOGERR;
114: return -1;
115: }
116:
117: if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
118: LOGERR;
119: close(eth);
120: return -1;
121: }
1.1.2.3 misho 122: if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
1.1.2.2 misho 123: LOGERR;
124: close(eth);
125: return -1;
126: }
1.1.2.4 misho 127: if (buflen && *buflen) {
1.1.2.3 misho 128: if (!zcbuf) {
1.1.2.4 misho 129: if (ioctl(eth, BIOCSBLEN, buflen) == -1) {
1.1.2.3 misho 130: LOGERR;
131: close(eth);
132: return -1;
133: }
134: } else {
135: #ifdef __FreeBSD__
136: n = BPF_BUFMODE_ZBUF;
137: if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
138: LOGERR;
139: close(eth);
140: return -1;
141: }
142: if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
143: LOGERR;
144: close(eth);
145: return -1;
1.1.2.5 misho 146: } else
147: *buflen = MIN(n, *buflen);
148: if (!(*zcbuf = allocZCbuf(*buflen))) {
1.1.2.3 misho 149: close(eth);
150: return -1;
151: }
152: if (ioctl(eth, BIOCSETZBUF, (struct bpf_zbuf*) *zcbuf) == -1) {
153: LOGERR;
154: io_etherClose(eth, zcbuf);
155: return -1;
156: }
157: #endif
158: }
159: }
1.1.2.2 misho 160: if (csIface)
161: strlcpy(szStr, csIface, sizeof szStr);
162: else if (io_get1stiface(szStr, sizeof szStr) == -1) {
1.1.2.3 misho 163: io_etherClose(eth, zcbuf);
1.1.2.2 misho 164: return -1;
165: }
1.1.2.10! misho 166: memset(&ifr, 0, sizeof ifr);
1.1.2.2 misho 167: strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
168: if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
169: LOGERR;
1.1.2.3 misho 170: io_etherClose(eth, zcbuf);
1.1.2.2 misho 171: return -1;
172: }
173:
174: return eth;
175: }
1.1.2.6 misho 176:
177: /*
178: * io_etherSend() - Send packet to bpf
179: *
180: * @eth = bpf handle
181: * @buf = buffer
182: * @buflen = buffer length
183: * return: -1 error or !=-1 written bytes
184: */
185: ssize_t
186: io_etherSend(int eth, const void *buf, size_t buflen)
187: {
188: ssize_t wlen = 0;
189:
190: if (!buf || !buflen) {
191: io_SetErr(EINVAL, "invalid arguments");
192: return -1;
193: }
194:
195: wlen = write(eth, buf, buflen);
196: if (wlen == -1)
197: LOGERR;
198: return wlen;
199: }
200:
201: #ifdef __FreeBSD__
1.1.2.8 misho 202: static inline void
203: ackZCbuf(struct bpf_zbuf_header * __restrict bzh)
204: {
205: atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
206: }
207:
208: static inline int
209: chkZCbuf(struct bpf_zbuf_header * __restrict bzh)
210: {
211: /* return true if userspace owns buffer, and false otherwise. */
212: return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen));
213: }
214:
1.1.2.6 misho 215: static inline ssize_t
1.1.2.7 misho 216: nextZCbuf(void ** __restrict zcache, struct bpf_zbuf * __restrict zbuf,
217: const void * __restrict buf)
1.1.2.6 misho 218: {
219: ssize_t rlen = -1;
220: struct bpf_zbuf_header *bzh;
221:
222: if (!*zcache || *zcache == zbuf->bz_bufb) {
223: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
1.1.2.8 misho 224: if (chkZCbuf(bzh)) {
1.1.2.6 misho 225: rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
226: *zcache = zbuf->bz_bufa;
1.1.2.7 misho 227: if (buf)
228: buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
1.1.2.8 misho 229: ackZCbuf(bzh);
1.1.2.9 misho 230: } else
231: io_SetErr(EAGAIN, "kernel owns the buffer");
1.1.2.6 misho 232: } else if (*zcache == zbuf->bz_bufa) {
233: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
1.1.2.8 misho 234: if (chkZCbuf(bzh)) {
1.1.2.6 misho 235: rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
236: *zcache = zbuf->bz_bufb;
1.1.2.7 misho 237: if (buf)
238: buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
1.1.2.8 misho 239: ackZCbuf(bzh);
1.1.2.9 misho 240: } else
241: io_SetErr(EAGAIN, "kernel owns the buffer");
1.1.2.6 misho 242: }
243:
244: return rlen;
245: }
246: #endif
247:
248: /*
249: * io_etherRecv() - Receive packet from bpf
250: *
251: * @eth = bpf handle
252: * @buf = buffer
253: * @buflen = buffer length
254: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
255: * return: -1 error or !=-1 readed bytes
256: */
257: ssize_t
258: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
259: {
260: ssize_t rlen = 0;
261: void **zcache = NULL;
262:
263: if (!buf || !buflen) {
264: io_SetErr(EINVAL, "invalid arguments");
265: return -1;
266: }
267:
268: if (!zcbuf) {
269: rlen = read(eth, buf, buflen);
270: if (rlen == -1)
271: LOGERR;
272: } else {
273: #ifdef __FreeBSD__
1.1.2.7 misho 274: rlen = nextZCbuf(zcache, (struct bpf_zbuf*) zcbuf, buf);
1.1.2.6 misho 275: #else
276: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
277: #endif
278: }
279:
280: return rlen;
281: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>