File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / src / bpf.c
Revision 1.1.2.15: download - view: text, annotated - select for diffs - revision graph
Wed Jun 26 12:30:17 2013 UTC (11 years ago) by misho
Branches: io5_4
most important!!! n=1 for immediate

    1: #include "global.h"
    2: 
    3: 
    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
   29:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
   30:  * return: none
   31:  */
   32: void
   33: io_etherClose(int eth, void **zcbuf)
   34: {
   35: #ifdef __FreeBSD__
   36: 	struct bpf_zbuf *zbuf = NULL;
   37: #endif
   38: 
   39: 	if (eth > STDERR_FILENO)
   40: 		close(eth);
   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;
   84: }
   85: #endif
   86: 
   87: /*
   88:  * io_etherOpen() - Open BPF interface to device
   89:  *
   90:  * @csIface = interface name
   91:  * @flags = open flags
   92:  * @whdr = with complete headers
   93:  * @buflen = buffer length
   94:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
   95:  * return: -1 error or >-1 bpf handle
   96:  */
   97: int
   98: io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
   99: {
  100: 	int eth = -1;
  101: 	register int i;
  102: 	char szStr[STRSIZ];
  103: 	struct ifreq ifr;
  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
  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: 
  125: 	if (!zcbuf) {
  126: 		if (ioctl(eth, BIOCGBLEN, &n) == -1) {
  127: 			LOGERR;
  128: 			close(eth);
  129: 			return -1;
  130: 		} else
  131: 			n = (buflen && *buflen) ? *buflen : n;
  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 {
  140: #ifdef __FreeBSD__
  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
  152: 			n = (buflen && *buflen) ? *buflen : n;
  153: 		if (!(*zcbuf = allocZCbuf(n))) {
  154: 			close(eth);
  155: 			return -1;
  156: 		}
  157: 		if (ioctl(eth, BIOCSETZBUF, (struct bpf_zbuf*) *zcbuf) == -1) {
  158: 			LOGERR;
  159: 			io_etherClose(eth, zcbuf);
  160: 			return -1;
  161: 		}
  162: 		if (buflen && *buflen)
  163: 			*buflen = n;
  164: #endif
  165: 	}
  166: 
  167: 	if (csIface)
  168: 		strlcpy(szStr, csIface, sizeof szStr);
  169: 	else if (io_get1stiface(szStr, sizeof szStr) == -1) {
  170: 		io_etherClose(eth, zcbuf);
  171: 		return -1;
  172: 	}
  173: 	memset(&ifr, 0, sizeof ifr);
  174: 	strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
  175: 	if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
  176: 		LOGERR;
  177: 		io_etherClose(eth, zcbuf);
  178: 		return -1;
  179: 	}
  180: 
  181: 	n = 1;
  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: 
  193: 	return eth;
  194: }
  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__
  221: static inline void
  222: ackZCbuf(struct bpf_zbuf_header * __restrict bzh)
  223: {
  224: 	atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
  225: }
  226: 
  227: static inline int
  228: chkZCbuf(struct bpf_zbuf_header * __restrict bzh)
  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: 
  234: static inline ssize_t
  235: nextZCbuf(void ** __restrict zcache, struct bpf_zbuf * __restrict zbuf, 
  236: 		const void * __restrict buf)
  237: {
  238: 	ssize_t rlen = -1;
  239: 	struct bpf_zbuf_header *bzh;
  240: 
  241: 	if (!*zcache || *zcache == zbuf->bz_bufb) {
  242: 		bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
  243: 		if (chkZCbuf(bzh)) {
  244: 			rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
  245: 			*zcache = zbuf->bz_bufa;
  246: 			if (buf)
  247: 				buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
  248: 			ackZCbuf(bzh);
  249: 		} else
  250: 			io_SetErr(EAGAIN, "kernel owns the buffer A");
  251: 	} else if (*zcache == zbuf->bz_bufa) {
  252: 		bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
  253: 		if (chkZCbuf(bzh)) {
  254: 			rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
  255: 			*zcache = zbuf->bz_bufb;
  256: 			if (buf)
  257: 				buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
  258: 			ackZCbuf(bzh);
  259: 		} else
  260: 			io_SetErr(EAGAIN, "kernel owns the buffer B");
  261: 	}
  262: 
  263: 	return rlen;
  264: }
  265: #endif
  266: 
  267: /*
  268:  * io_etherRecv() - Receive packet from bpf
  269:  *
  270:  * @eth = bpf handle
  271:  * @buf = buffer
  272:  * @buflen = buffer length
  273:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
  274:  * return: -1 error or !=-1 readed bytes
  275:  */
  276: ssize_t
  277: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
  278: {
  279: 	ssize_t rlen = 0;
  280: 	void *zcache = NULL;
  281: 
  282: 	if (!buf || !buflen) {
  283: 		io_SetErr(EINVAL, "invalid arguments");
  284: 		return -1;
  285: 	}
  286: 
  287: 	if (!zcbuf) {
  288: 		rlen = read(eth, buf, buflen);
  289: 		if (rlen == -1)
  290: 			LOGERR;
  291: 	} else {
  292: #ifdef __FreeBSD__
  293: 		rlen = nextZCbuf(&zcache, (struct bpf_zbuf*) zcbuf, buf);
  294: #else
  295: 		io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
  296: #endif
  297: 	}
  298: 
  299: 	return rlen;
  300: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>