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>