Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Jul 2013 00:56:10 +0900
From:      Takuya ASADA <syuu@dokukino.com>
To:        Luigi Rizzo <rizzo@iet.unipi.it>
Cc:        FreeBSD Net <freebsd-net@freebsd.org>
Subject:   Re: Multiqueue support for bpf
Message-ID:  <CALG4x-UYBFsMttpZx1-c_wtVf5MST8%2B_t1psY2HQskTiOZDFLA@mail.gmail.com>
In-Reply-To: <CA%2BhQ2%2BgwW6FOQS79xmWVLSWWHrZMFnhaUM98Kp6aDVaUePNfTA@mail.gmail.com>
References:  <CALG4x-V-OLoqMXQarSNy5Lv3kNVu01AiN4A49Nv7t-Ysfr1DBg@mail.gmail.com> <CA%2BhQ2%2BgwW6FOQS79xmWVLSWWHrZMFnhaUM98Kp6aDVaUePNfTA@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

Do you have an updated URL for the diffs ? The link below from your
> original message
> seems not working now (NXDOMAIN)
>
> http://www.dokukino.com/mq_bpf_20110813.diff
>

Changes with recent head is on my repository:
http://svnweb.freebsd.org/base/user/syuu/mq_bpf/
And I attached a diff file on this mail.

[-- Attachment #2 --]
Index: ifnet.9
===================================================================
--- ifnet.9	(.../head/share/man/man9/ifnet.9)	(revision 252509)
+++ ifnet.9	(.../user/syuu/mq_bpf/share/man/man9/ifnet.9)	(revision 252509)
@@ -119,6 +119,14 @@
 .Fo \*(lp*if_resolvemulti\*(rp
 .Fa "struct ifnet *ifp" "struct sockaddr **retsa" "struct sockaddr *addr"
 .Fc
+.Ft int
+.Fn \*(lp*if_get_rxqueue_len\*(rp "struct ifnet *ifp"
+.Ft int
+.Fn \*(lp*if_get_txqueue_len\*(rp "struct ifnet *ifp"
+.Ft int
+.Fn \*(lp*if_get_rxqueue_affinity\*(rp "struct ifnet *ifp" "int queid"
+.Ft int
+.Fn \*(lp*if_get_txqueue_affinity\*(rp "struct ifnet *ifp" "int queid"
 .Ss "struct ifaddr member function"
 .Ft void
 .Fo \*(lp*ifa_rtrequest\*(rp
@@ -537,6 +545,14 @@
 corresponds to that address which is returned in
 .Fa *retsa .
 Returns zero on success, or an error code on failure.
+.It Fn if_get_rxqueue_len
+Get RX queue length, only required for multiqueue supported interfaces.
+.It Fn if_get_txqueue_len
+Get TX queue length, only required for multiqueue supported interfaces.
+.It Fn if_get_rxqueue_affinity
+Get RX queue affinity, only required for multiqueue supported interfaces.
+.It Fn if_get_txqueue_affinity
+Get TX queue affinity, only required for multiqueue supported interfaces.
 .El
 .Ss "Interface Flags"
 Interface flags are used for a number of different purposes.
Index: bpf.4
===================================================================
--- bpf.4	(.../head/share/man/man4/bpf.4)	(revision 252509)
+++ bpf.4	(.../user/syuu/mq_bpf/share/man/man4/bpf.4)	(revision 252509)
@@ -631,6 +631,46 @@
 .Vt bzh_kernel_gen
 against
 .Vt bzh_user_gen .
+.It Dv BIOCENAQMASK
+Enables multiqueue filter on the descriptor.
+
+.It Dv BIOCDISQMASK
+Disables multiqueue filter on the descriptor.
+
+.It Dv BIOCSTRXQMASK
+.Pq Li uint32_t
+Set mask bit on specified RX queue.
+
+.It Dv BIOCCRRXQMASK
+.Pq Li uint32_t
+Clear mask bit on specified RX queue.
+
+.It Dv BIOCGTRXQMASK
+.Pq Li uint32_t
+Get mask bit on specified RX queue.
+
+.It Dv BIOCSTTXQMASK
+.Pq Li uint32_t
+Set mask bit on specified TX queue.
+
+.It Dv BIOCCRTXQMASK
+.Pq Li uint32_t
+Clear mask bit on specified TX queue.
+
+.It Dv BIOCGTTXQMASK
+.Pq Li uint32_t
+Get mask bit on specified TX queue.
+
+.It Dv BIOCSTOTHERMASK
+Set mask bit for the packets which not tied with any queues.
+
+.It Dv BIOCCROTHERMASK
+Clear mask bit for the packets which not tied with any queues.
+
+.It Dv BIOCGTOTHERMASK
+.Pq Li uint32_t
+Get mask bit for the packets which not tied with any queues.
+
 .El
 .Sh BPF HEADER
 One of the following structures is prepended to each packet returned by
@@ -1037,6 +1077,24 @@
 	BPF_STMT(BPF_RET+BPF_K, 0),
 };
 .Ed
+.Sh MULTIQUEUE SUPPORT
+Multiqueue network interface support function provides interfaces for 
+multithreaded packet processing using bpf.
+
+Normal bpf can receive packets from specified interface, multiqueue support 
+function can receive packets from specified hardware queue.
+
+This distributes bpf workload on multiple threads, also reduces lock 
+contention on bpf.
+
+To make your program multithreaded, you'll need to open bpf descriptor on each 
+thread, enable multiqueue support by BIOCENAQMASK ioctl, and set queue mask by 
+BIOCSTRXQMASK / BIOCSTTXQMASK / BIOCSTOTHERMASK ioctls.
+
+Queue length and queue affinity information may useful to optimize setting 
+queue mask on bpf descriptor, see
+.Xr netintro 4 .
+
 .Sh SEE ALSO
 .Xr tcpdump 1 ,
 .Xr ioctl 2 ,
Index: ifconfig.c
===================================================================
--- ifconfig.c	(.../head/sbin/ifconfig/ifconfig.c)	(revision 252509)
+++ ifconfig.c	(.../user/syuu/mq_bpf/sbin/ifconfig/ifconfig.c)	(revision 252509)
@@ -917,7 +917,7 @@
 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
 "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
-"\26RXCSUM_IPV6\27TXCSUM_IPV6"
+"\26RXCSUM_IPV6\27TXCSUM_IPV6\30MULTIQUEUE"
 
 /*
  * Print the status of the interface.  If an address family was
@@ -984,6 +984,38 @@
 		}
 	}
 
+	if ((ifr.ifr_reqcap & IFCAP_MULTIQUEUE)) {
+		int i, rxqlen = 0, txqlen = 0;
+
+		if (ioctl(s, SIOCGIFQLEN, &ifr) == 0) {
+			rxqlen = ifr.ifr_rxqueue_len;
+			txqlen = ifr.ifr_txqueue_len;
+		}else
+			perror("ioctl");
+
+		printf("\trxqueue len=%d affinity=[", rxqlen);
+		for (i = 0; i < rxqlen; i++) {
+			ifr.ifr_queue_affinity_index = i;
+			if (ioctl(s, SIOCGIFRXQAFFINITY, &ifr) == 0)
+				printf(" %d:%d", ifr.ifr_queue_affinity_index,
+					ifr.ifr_queue_affinity_cpu);
+			else
+				perror("ioctl");
+		}
+		printf(" ]\n");
+
+		printf("\ttxqueue len=%d affinity=[", txqlen);
+		for (i = 0; i < txqlen; i++) {
+			ifr.ifr_queue_affinity_index = i;
+			if (ioctl(s, SIOCGIFTXQAFFINITY, &ifr) == 0)
+				printf(" %d:%d", ifr.ifr_queue_affinity_index,
+					ifr.ifr_queue_affinity_cpu);
+			else
+				perror("ioctl");
+		}
+		printf(" ]\n");
+	}
+
 	tunnel_status(s);
 
 	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
Index: tcpdump.c
===================================================================
--- tcpdump.c	(.../head/contrib/tcpdump/tcpdump.c)	(revision 252509)
+++ tcpdump.c	(.../user/syuu/mq_bpf/contrib/tcpdump/tcpdump.c)	(revision 252509)
@@ -702,6 +702,7 @@
 #endif
 	int status;
 	FILE *VFile;
+	uint32_t rxq = (uint32_t)-1, txq = (uint32_t)-1, other = (uint32_t)-1;
 #ifdef WIN32
 	if(wsockinit() != 0) return 1;
 #endif /* WIN32 */
@@ -737,7 +738,7 @@
 #endif
 
 	while (
-	    (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "V:vw:W:xXy:Yz:Z:")) != -1)
+	    (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "V:vw:W:xXy:Yz:Z:Q:g:k")) != -1)
 		switch (op) {
 
 		case 'a':
@@ -815,6 +816,10 @@
 			infile = optarg;
 			break;
 
+		case 'g':
+			txq = atoi(optarg);
+			break;
+
 		case 'G':
 			Gflag = atoi(optarg);
 			if (Gflag < 0)
@@ -919,6 +924,12 @@
 #endif /* WIN32 */
 			break;
 
+		case 'k':
+			other = atoi(optarg);
+			if (other != 0 || other != 1)
+				usage();
+			break;
+
 		case 'K':
 			++Kflag;
 			break;
@@ -965,6 +976,10 @@
 			++suppress_default_print;
 			break;
 
+		case 'Q':
+			rxq = atoi(optarg);
+			break;
+
 		case 'r':
 			RFileName = optarg;
 			break;
@@ -1274,6 +1289,13 @@
 			    	    device, pcap_statustostr(status));
 		}
 #endif
+ 		if (rxq != (uint32_t)-1)
+ 			pcap_set_rxq_mask(pd, rxq);
+ 		if (txq != (uint32_t)-1)
+ 			pcap_set_txq_mask(pd, txq);
+ 		if (other != (uint32_t)-1)
+ 			pcap_set_other_mask(pd, other);
+
 		status = pcap_activate(pd);
 		if (status < 0) {
 			/*
@@ -2078,7 +2100,7 @@
 #endif /* WIN32 */
 #endif /* HAVE_PCAP_LIB_VERSION */
 	(void)fprintf(stderr,
-"Usage: %s [-aAbd" D_FLAG "efhH" I_FLAG J_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name);
+"Usage: %s [-aAbd" D_FLAG "efghH" I_FLAG J_FLAG "kKlLnNOpqQRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name);
 	(void)fprintf(stderr,
 "\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
 	(void)fprintf(stderr,
Index: pcap-int.h
===================================================================
--- pcap-int.h	(.../head/contrib/libpcap/pcap-int.h)	(revision 252509)
+++ pcap-int.h	(.../user/syuu/mq_bpf/contrib/libpcap/pcap-int.h)	(revision 252509)
@@ -337,6 +337,9 @@
 	u_int *tstamp_type_list;
 
 	struct pcap_pkthdr pcap_header;	/* This is needed for the pcap_next_ex() to work */
+
+	uint32_t rxq_num, txq_num;
+	uint32_t other_mask;
 };
 
 /*
Index: pcap.h
===================================================================
--- pcap.h	(.../head/contrib/libpcap/pcap/pcap.h)	(revision 252509)
+++ pcap.h	(.../user/syuu/mq_bpf/contrib/libpcap/pcap/pcap.h)	(revision 252509)
@@ -331,6 +331,10 @@
 #define PCAP_TSTAMP_ADAPTER		3	/* device-provided, synced with the system clock */
 #define PCAP_TSTAMP_ADAPTER_UNSYNCED	4	/* device-provided, not synced with the system clock */
 
+int	pcap_set_rxq_mask(pcap_t *, uint32_t);
+int	pcap_set_txq_mask(pcap_t *, uint32_t);
+int	pcap_set_other_mask(pcap_t *, uint32_t);
+
 pcap_t	*pcap_open_live(const char *, int, int, int, char *);
 pcap_t	*pcap_open_dead(int, int);
 pcap_t	*pcap_open_offline(const char *, char *);
Index: pcap.c
===================================================================
--- pcap.c	(.../head/contrib/libpcap/pcap.c)	(revision 252509)
+++ pcap.c	(.../user/syuu/mq_bpf/contrib/libpcap/pcap.c)	(revision 252509)
@@ -505,6 +505,9 @@
 	p->opt.promisc = 0;
 	p->opt.buffer_size = 0;
 	p->opt.tstamp_type = -1;	/* default to not setting time stamp type */
+ 	p->rxq_num = (uint32_t)-1;
+ 	p->txq_num = (uint32_t)-1;
+ 	p->other_mask = (uint32_t)-1;
 	return (p);
 }
 
@@ -637,6 +640,33 @@
 	return (status);
 }
 
+int
+pcap_set_rxq_mask(pcap_t *p, uint32_t num)
+{
+	if (pcap_check_activated(p))
+		return PCAP_ERROR_ACTIVATED;
+	p->rxq_num = num;
+	return 0;
+}
+
+int
+pcap_set_txq_mask(pcap_t *p, uint32_t num)
+{
+	if (pcap_check_activated(p))
+		return PCAP_ERROR_ACTIVATED;
+	p->txq_num = num;
+	return 0;
+}
+
+int
+pcap_set_other_mask(pcap_t *p, uint32_t mask)
+{
+	if (pcap_check_activated(p))
+		return PCAP_ERROR_ACTIVATED;
+	p->other_mask = mask;
+	return 0;
+}
+
 pcap_t *
 pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf)
 {
Index: pcap-bpf.c
===================================================================
--- pcap-bpf.c	(.../head/contrib/libpcap/pcap-bpf.c)	(revision 252509)
+++ pcap-bpf.c	(.../user/syuu/mq_bpf/contrib/libpcap/pcap-bpf.c)	(revision 252509)
@@ -34,6 +34,7 @@
 #include <sys/mman.h>
 #endif
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <time.h>
 /*
  * <net/bpf.h> defines ioctls, but doesn't include <sys/ioccom.h>.
@@ -2187,6 +2188,40 @@
 	}
 #endif
 
+	if (p->rxq_num != (uint32_t)-1 || p->txq_num != (uint32_t)-1 ||
+		p->other_mask != (uint32_t)-1) {
+		if (ioctl(fd, BIOCENAQMASK, NULL) < 0) {
+			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCENAQMASK: %s",
+			    pcap_strerror(errno));
+			status = PCAP_ERROR;
+			goto bad;
+		}
+		if (p->rxq_num != (uint32_t)-1) {
+			if (ioctl(fd, BIOCSTRXQMASK, &p->rxq_num) < 0) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTRXQMASK: %s",
+				    pcap_strerror(errno));
+				status = PCAP_ERROR;
+				goto bad;
+			}
+		}
+		if (p->txq_num != (uint32_t)-1) {
+			if (ioctl(fd, BIOCSTTXQMASK, &p->txq_num) < 0) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTTXQMASK: %s",
+				    pcap_strerror(errno));
+				status = PCAP_ERROR;
+				goto bad;
+			}
+		}
+		if (p->other_mask != (uint32_t)-1) {
+			if (ioctl(fd, BIOCSTOTHERMASK, &p->other_mask) < 0) {
+				snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTOTHERQMASK: %s",
+				    pcap_strerror(errno));
+				status = PCAP_ERROR;
+				goto bad;
+			}
+		}
+	}
+
 	/*
 	 * If there's no filter program installed, there's
 	 * no indication to the kernel of what the snapshot
Index: ifnet.9
===================================================================
--- ifnet.9	(.../head/share/man/man9/ifnet.9)	(revision 252509)
+++ ifnet.9	(.../user/syuu/mq_bpf/share/man/man9/ifnet.9)	(revision 252509)
@@ -119,6 +119,14 @@
 .Fo \*(lp*if_resolvemulti\*(rp
 .Fa "struct ifnet *ifp" "struct sockaddr **retsa" "struct sockaddr *addr"
 .Fc
+.Ft int
+.Fn \*(lp*if_get_rxqueue_len\*(rp "struct ifnet *ifp"
+.Ft int
+.Fn \*(lp*if_get_txqueue_len\*(rp "struct ifnet *ifp"
+.Ft int
+.Fn \*(lp*if_get_rxqueue_affinity\*(rp "struct ifnet *ifp" "int queid"
+.Ft int
+.Fn \*(lp*if_get_txqueue_affinity\*(rp "struct ifnet *ifp" "int queid"
 .Ss "struct ifaddr member function"
 .Ft void
 .Fo \*(lp*ifa_rtrequest\*(rp
@@ -537,6 +545,14 @@
 corresponds to that address which is returned in
 .Fa *retsa .
 Returns zero on success, or an error code on failure.
+.It Fn if_get_rxqueue_len
+Get RX queue length, only required for multiqueue supported interfaces.
+.It Fn if_get_txqueue_len
+Get TX queue length, only required for multiqueue supported interfaces.
+.It Fn if_get_rxqueue_affinity
+Get RX queue affinity, only required for multiqueue supported interfaces.
+.It Fn if_get_txqueue_affinity
+Get TX queue affinity, only required for multiqueue supported interfaces.
 .El
 .Ss "Interface Flags"
 Interface flags are used for a number of different purposes.
Index: netintro.4
===================================================================
--- netintro.4	(.../head/share/man/man4/netintro.4)	(revision 252509)
+++ netintro.4	(.../user/syuu/mq_bpf/share/man/man4/netintro.4)	(revision 252509)
@@ -213,6 +213,8 @@
         int       ifru_media;
         caddr_t   ifru_data;
         int       ifru_cap[2];
+        int       ifru_queue_len[2];
+        int       ifru_queue_affinity[2];
     } ifr_ifru;
 #define ifr_addr      ifr_ifru.ifru_addr      /* address */
 #define ifr_dstaddr   ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
@@ -228,6 +230,10 @@
 #define ifr_reqcap    ifr_ifru.ifru_cap[0]    /* requested capabilities */
 #define ifr_curcap    ifr_ifru.ifru_cap[1]    /* current capabilities */
 #define ifr_index     ifr_ifru.ifru_index     /* interface index */
+#define ifr_rxqueue_len	ifr_ifru.ifru_queue_len[0] /* rxqueue len */
+#define ifr_txqueue_len	ifr_ifru.ifru_queue_len[1] /* txqueue len */
+#define ifr_queue_affinity_index ifr_ifru.ifru_queue_affinity[0] /* queue id */
+#define ifr_queue_affinity_cpu ifr_ifru.ifru_queue_affinity[1] /* cpu id */
 };
 .Ed
 .Pp
@@ -319,6 +325,12 @@
 field will contain the new interface name.
 .It Dv SIOCIFDESTROY
 Attempt to destroy the specified interface.
+.It Dv SIOCGIFQLEN
+Get interface RX/TX queue length.
+.It Dv SIOCGIFRXQAFFINITY
+Get interface RX queue affinity.
+.It Dv SIOCGIFTXQAFFINITY
+Get interface TX queue affinity.
 .El
 .Pp
 There are two requests that make use of a new structure:
Index: bpf.4
===================================================================
--- bpf.4	(.../head/share/man/man4/bpf.4)	(revision 252509)
+++ bpf.4	(.../user/syuu/mq_bpf/share/man/man4/bpf.4)	(revision 252509)
@@ -631,6 +631,46 @@
 .Vt bzh_kernel_gen
 against
 .Vt bzh_user_gen .
+.It Dv BIOCENAQMASK
+Enables multiqueue filter on the descriptor.
+
+.It Dv BIOCDISQMASK
+Disables multiqueue filter on the descriptor.
+
+.It Dv BIOCSTRXQMASK
+.Pq Li uint32_t
+Set mask bit on specified RX queue.
+
+.It Dv BIOCCRRXQMASK
+.Pq Li uint32_t
+Clear mask bit on specified RX queue.
+
+.It Dv BIOCGTRXQMASK
+.Pq Li uint32_t
+Get mask bit on specified RX queue.
+
+.It Dv BIOCSTTXQMASK
+.Pq Li uint32_t
+Set mask bit on specified TX queue.
+
+.It Dv BIOCCRTXQMASK
+.Pq Li uint32_t
+Clear mask bit on specified TX queue.
+
+.It Dv BIOCGTTXQMASK
+.Pq Li uint32_t
+Get mask bit on specified TX queue.
+
+.It Dv BIOCSTOTHERMASK
+Set mask bit for the packets which not tied with any queues.
+
+.It Dv BIOCCROTHERMASK
+Clear mask bit for the packets which not tied with any queues.
+
+.It Dv BIOCGTOTHERMASK
+.Pq Li uint32_t
+Get mask bit for the packets which not tied with any queues.
+
 .El
 .Sh BPF HEADER
 One of the following structures is prepended to each packet returned by
@@ -1037,6 +1077,24 @@
 	BPF_STMT(BPF_RET+BPF_K, 0),
 };
 .Ed
+.Sh MULTIQUEUE SUPPORT
+Multiqueue network interface support function provides interfaces for 
+multithreaded packet processing using bpf.
+
+Normal bpf can receive packets from specified interface, multiqueue support 
+function can receive packets from specified hardware queue.
+
+This distributes bpf workload on multiple threads, also reduces lock 
+contention on bpf.
+
+To make your program multithreaded, you'll need to open bpf descriptor on each 
+thread, enable multiqueue support by BIOCENAQMASK ioctl, and set queue mask by 
+BIOCSTRXQMASK / BIOCSTTXQMASK / BIOCSTOTHERMASK ioctls.
+
+Queue length and queue affinity information may useful to optimize setting 
+queue mask on bpf descriptor, see
+.Xr netintro 4 .
+
 .Sh SEE ALSO
 .Xr tcpdump 1 ,
 .Xr ioctl 2 ,
Index: if_mxge.c
===================================================================
--- if_mxge.c	(.../head/sys/dev/mxge/if_mxge.c)	(revision 252509)
+++ if_mxge.c	(.../user/syuu/mq_bpf/sys/dev/mxge/if_mxge.c)	(revision 252509)
@@ -120,6 +120,11 @@
 static int mxge_shutdown(device_t dev);
 static void mxge_intr(void *arg);
 
+static int mxge_get_rxqueue_len(struct ifnet *);
+static int mxge_get_txqueue_len(struct ifnet *);
+static int mxge_get_rxqueue_affinity(struct ifnet *, int);
+static int mxge_get_txqueue_affinity(struct ifnet *, int);
+
 static device_method_t mxge_methods[] =
 {
   /* Device interface */
@@ -2272,6 +2277,9 @@
 		if (m == NULL) {
 			return;
 		}
+		m->m_pkthdr.rxqueue = (uint32_t)-1;
+		m->m_pkthdr.txqueue = (ss - sc->ss);
+
 		/* let BPF see it */
 		BPF_MTAP(ifp, m);
 
@@ -2306,6 +2314,9 @@
 
 	if (!drbr_needs_enqueue(ifp, tx->br) &&
 	    ((tx->mask - (tx->req - tx->done)) > tx->max_desc)) {
+		m->m_pkthdr.rxqueue = (uint32_t)-1;
+		m->m_pkthdr.txqueue = (ss - sc->ss);
+
 		/* let BPF see it */
 		BPF_MTAP(ifp, m);
 		/* give it to the nic */
@@ -2719,6 +2730,8 @@
 	if (sc->num_slices > 1) {
 		m->m_pkthdr.flowid = (ss - sc->ss);
 		m->m_flags |= M_FLOWID;
+		m->m_pkthdr.rxqueue = (ss - sc->ss);
+		m->m_pkthdr.txqueue = (uint32_t)-1;
 	}
 	/* pass the frame up the stack */
 	(*ifp->if_input)(ifp, m);
@@ -4896,6 +4909,7 @@
 #if defined(INET) || defined(INET6)
 	ifp->if_capabilities |= IFCAP_LRO;
 #endif
+	ifp->if_capabilities |= IFCAP_MULTIQUEUE;
 
 #ifdef MXGE_NEW_VLAN_API
 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
@@ -4929,6 +4943,11 @@
         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
         ifp->if_ioctl = mxge_ioctl;
         ifp->if_start = mxge_start;
+	ifp->if_get_rxqueue_len = mxge_get_rxqueue_len;
+	ifp->if_get_txqueue_len = mxge_get_txqueue_len;
+	ifp->if_get_rxqueue_affinity = mxge_get_rxqueue_affinity;
+	ifp->if_get_txqueue_affinity = mxge_get_txqueue_affinity;
+
 	/* Initialise the ifmedia structure */
 	ifmedia_init(&sc->media, 0, mxge_media_change, 
 		     mxge_media_status);
@@ -5025,6 +5044,33 @@
 	return 0;
 }
 
+
+static int
+mxge_get_rxqueue_len(struct ifnet *ifp)
+{
+	mxge_softc_t *sc = ifp->if_softc;
+	return (sc->num_slices);
+}
+
+static int
+mxge_get_txqueue_len(struct ifnet *ifp)
+{
+	mxge_softc_t *sc = ifp->if_softc;
+	return (sc->num_slices);
+}
+
+static int
+mxge_get_rxqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
+
+static int
+mxge_get_txqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
+
 /*
   This file uses Myri10GE driver indentation.
 
Index: ixgbe.c
===================================================================
--- ixgbe.c	(.../head/sys/dev/ixgbe/ixgbe.c)	(revision 252509)
+++ ixgbe.c	(.../user/syuu/mq_bpf/sys/dev/ixgbe/ixgbe.c)	(revision 252509)
@@ -210,6 +210,12 @@
 /* Missing shared code prototype */
 extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw);
 
+static int	ixgbe_get_rxqueue_len(struct ifnet *);
+static int	ixgbe_get_txqueue_len(struct ifnet *);
+static int	ixgbe_get_rxqueue_affinity(struct ifnet *, int);
+static int	ixgbe_get_txqueue_affinity(struct ifnet *, int);
+
+
 /*********************************************************************
  *  FreeBSD Device Interface Entry Points
  *********************************************************************/
@@ -753,6 +759,10 @@
 				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 			break;
 		}
+
+		m_head->m_pkthdr.rxqueue = (uint32_t)-1;
+		m_head->m_pkthdr.txqueue = txr->me;
+
 		/* Send a copy of the frame to the BPF listener */
 		ETHER_BPF_MTAP(ifp, m_head);
 
@@ -851,6 +861,10 @@
 		drbr_advance(ifp, txr->br);
 #endif
 		enqueued++;
+ 
+ 		next->m_pkthdr.rxqueue = (uint32_t)-1;
+ 		next->m_pkthdr.txqueue = txr->me;
+
 		/* Send a copy of the frame to the BPF listener */
 		ETHER_BPF_MTAP(ifp, next);
 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
@@ -2618,6 +2632,10 @@
 	ifp->if_softc = adapter;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = ixgbe_ioctl;
+ 	ifp->if_get_rxqueue_len = ixgbe_get_rxqueue_len;
+ 	ifp->if_get_txqueue_len = ixgbe_get_txqueue_len;
+ 	ifp->if_get_rxqueue_affinity = ixgbe_get_rxqueue_affinity;
+ 	ifp->if_get_txqueue_affinity = ixgbe_get_txqueue_affinity;
 #ifndef IXGBE_LEGACY_TX
 	ifp->if_transmit = ixgbe_mq_start;
 	ifp->if_qflush = ixgbe_qflush;
@@ -2644,6 +2662,7 @@
 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
 			     |  IFCAP_VLAN_HWTSO
 			     |  IFCAP_VLAN_MTU;
+	ifp->if_capabilities |= IFCAP_MULTIQUEUE;
 	ifp->if_capenable = ifp->if_capabilities;
 
 	/*
@@ -4547,6 +4566,8 @@
 			sendmp->m_pkthdr.flowid = que->msix;
 			sendmp->m_flags |= M_FLOWID;
 #endif
+			sendmp->m_pkthdr.rxqueue = que->msix;
+			sendmp->m_pkthdr.txqueue = (uint32_t)-1;
 		}
 next_desc:
 		bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map,
@@ -5743,6 +5764,32 @@
 	return (error);
 }
 
+static int
+ixgbe_get_rxqueue_len(struct ifnet *ifp)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	return (adapter->num_queues);
+}
+
+static int
+ixgbe_get_txqueue_len(struct ifnet *ifp)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	return (adapter->num_queues);
+}
+
+static int
+ixgbe_get_rxqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
+
+static int
+ixgbe_get_txqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
+
 /*
 ** Thermal Shutdown Trigger
 **   - cause a Thermal Overtemp IRQ
Index: if_igb.c
===================================================================
--- if_igb.c	(.../head/sys/dev/e1000/if_igb.c)	(revision 252509)
+++ if_igb.c	(.../user/syuu/mq_bpf/sys/dev/e1000/if_igb.c)	(revision 252509)
@@ -278,6 +278,11 @@
 static int	igb_sysctl_dmac(SYSCTL_HANDLER_ARGS);
 static int	igb_sysctl_eee(SYSCTL_HANDLER_ARGS);
 
+static int	igb_get_rxqueue_len(struct ifnet *);
+static int	igb_get_txqueue_len(struct ifnet *);
+static int	igb_get_rxqueue_affinity(struct ifnet *, int);
+static int	igb_get_txqueue_affinity(struct ifnet *, int);
+
 #ifdef DEVICE_POLLING
 static poll_handler_t igb_poll;
 #endif /* POLLING */
@@ -919,6 +924,9 @@
 			break;
 		}
 
+		m_head->m_pkthdr.rxqueue = (uint32_t)-1;
+		m_head->m_pkthdr.txqueue = txr->me;
+
 		/* Send a copy of the frame to the BPF listener */
 		ETHER_BPF_MTAP(ifp, m_head);
 
@@ -1012,6 +1020,8 @@
 		ifp->if_obytes += next->m_pkthdr.len;
 		if (next->m_flags & M_MCAST)
 			ifp->if_omcasts++;
+		next->m_pkthdr.rxqueue = (uint32_t)-1;
+		next->m_pkthdr.txqueue = txr->me;
 		ETHER_BPF_MTAP(ifp, next);
 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 			break;
@@ -3112,6 +3122,10 @@
 	ifp->if_softc = adapter;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = igb_ioctl;
+ 	ifp->if_get_rxqueue_len = igb_get_rxqueue_len;
+ 	ifp->if_get_txqueue_len = igb_get_txqueue_len;
+ 	ifp->if_get_rxqueue_affinity = igb_get_rxqueue_affinity;
+ 	ifp->if_get_txqueue_affinity = igb_get_txqueue_affinity;
 #ifndef IGB_LEGACY_TX
 	ifp->if_transmit = igb_mq_start;
 	ifp->if_qflush = igb_qflush;
@@ -3159,6 +3173,7 @@
 	** enable this and get full hardware tag filtering.
 	*/
 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
+	ifp->if_capabilities |= IFCAP_MULTIQUEUE;
 
 	/*
 	 * Specify the media types supported by this adapter and register
@@ -4883,6 +4898,9 @@
 			rxr->fmp->m_pkthdr.flowid = que->msix;
 			rxr->fmp->m_flags |= M_FLOWID;
 #endif
+			rxr->fmp->m_pkthdr.rxqueue = que->msix;
+			rxr->fmp->m_pkthdr.txqueue = (uint32_t)-1;
+
 			sendmp = rxr->fmp;
 			/* Make sure to set M_PKTHDR. */
 			sendmp->m_flags |= M_PKTHDR;
@@ -6047,3 +6065,29 @@
 	IGB_CORE_UNLOCK(adapter);
 	return (0);
 }
+
+static int
+igb_get_rxqueue_len(struct ifnet *ifp)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	return (adapter->num_queues);
+}
+
+static int
+igb_get_txqueue_len(struct ifnet *ifp)
+{
+	struct adapter	*adapter = ifp->if_softc;
+	return (adapter->num_queues);
+}
+
+static int
+igb_get_rxqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
+
+static int
+igb_get_txqueue_affinity(struct ifnet *ifp, int queid)
+{
+	return (queid);
+}
Index: bpfdesc.h
===================================================================
--- bpfdesc.h	(.../head/sys/net/bpfdesc.h)	(revision 252509)
+++ bpfdesc.h	(.../user/syuu/mq_bpf/sys/net/bpfdesc.h)	(revision 252509)
@@ -45,6 +45,20 @@
 #include <sys/conf.h>
 #include <net/if.h>
 
+struct bpf_qmask {
+	boolean_t	qm_enabled;
+	boolean_t *	qm_rxq_mask;
+	boolean_t *	qm_txq_mask;
+	boolean_t	qm_other_mask;
+	struct rwlock	qm_lock;
+};
+
+#define BPFQ_LOCK_DESTROY(qm)		rw_destroy(&(qm)->qm_lock)
+#define BPFQ_RLOCK(qm)			rw_rlock(&(qm)->qm_lock)
+#define BPFQ_RUNLOCK(qm)		rw_runlock(&(qm)->qm_lock)
+#define BPFQ_WLOCK(qm)			rw_wlock(&(qm)->qm_lock)
+#define BPFQ_WUNLOCK(qm)		rw_wunlock(&(qm)->qm_lock)
+
 /*
  * Descriptor associated with each open bpf file.
  */
@@ -101,6 +115,7 @@
 	u_int64_t	bd_wdcount;	/* number of packets dropped during a write */
 	u_int64_t	bd_zcopy;	/* number of zero copy operations */
 	u_char		bd_compat32;	/* 32-bit stream on LP64 system */
+	struct bpf_qmask bd_qmask;
 };
 
 /* Values for bd_state */
Index: if_var.h
===================================================================
--- if_var.h	(.../head/sys/net/if_var.h)	(revision 252509)
+++ if_var.h	(.../user/syuu/mq_bpf/sys/net/if_var.h)	(revision 252509)
@@ -176,6 +176,15 @@
 		(struct ifnet *, struct mbuf *);
 	void	(*if_reassign)		/* reassign to vnet routine */
 		(struct ifnet *, struct vnet *, char *);
+	int	(*if_get_rxqueue_len)
+		(struct ifnet *);
+	int	(*if_get_txqueue_len)
+		(struct ifnet *);
+	int	(*if_get_rxqueue_affinity)
+		(struct ifnet *, int);
+	int	(*if_get_txqueue_affinity)
+		(struct ifnet *, int);
+
 	struct	vnet *if_home_vnet;	/* where this ifnet originates from */
 	struct	ifaddr	*if_addr;	/* pointer to link-level address */
 	void	*if_llsoftc;		/* link layer softc */
Index: bpf.h
===================================================================
--- bpf.h	(.../head/sys/net/bpf.h)	(revision 252509)
+++ bpf.h	(.../user/syuu/mq_bpf/sys/net/bpf.h)	(revision 252509)
@@ -147,6 +147,17 @@
 #define	BIOCSETFNR	_IOW('B', 130, struct bpf_program)
 #define	BIOCGTSTAMP	_IOR('B', 131, u_int)
 #define	BIOCSTSTAMP	_IOW('B', 132, u_int)
+#define	BIOCENAQMASK	_IO('B', 133)
+#define	BIOCDISQMASK	_IO('B', 134)
+#define	BIOCSTRXQMASK	_IOWR('B', 135, uint32_t)
+#define	BIOCCRRXQMASK	_IOWR('B', 136, uint32_t)
+#define	BIOCGTRXQMASK	_IOR('B', 137, uint32_t)
+#define	BIOCSTTXQMASK	_IOWR('B', 138, uint32_t)
+#define	BIOCCRTXQMASK	_IOWR('B', 139, uint32_t)
+#define	BIOCGTTXQMASK	_IOR('B', 140, uint32_t)
+#define	BIOCSTOTHERMASK	_IO('B', 141)
+#define	BIOCCROTHERMASK	_IO('B', 142)
+#define	BIOCGTOTHERMASK	_IOR('B', 143, uint32_t)
 
 /* Obsolete */
 #define	BIOCGSEESENT	BIOCGDIRECTION
Index: if.c
===================================================================
--- if.c	(.../head/sys/net/if.c)	(revision 252509)
+++ if.c	(.../user/syuu/mq_bpf/sys/net/if.c)	(revision 252509)
@@ -2428,6 +2428,31 @@
 		break;
 	}
 
+	case SIOCGIFQLEN:
+		if (!(ifp->if_capabilities & IFCAP_MULTIQUEUE))
+			return (EOPNOTSUPP);
+		KASSERT(ifp->if_get_rxqueue_len, ("if_get_rxqueue_len not set"));
+		KASSERT(ifp->if_get_txqueue_len, ("if_get_txqueue_len not set"));
+		ifr->ifr_rxqueue_len = ifp->if_get_rxqueue_len(ifp);
+		ifr->ifr_txqueue_len = ifp->if_get_txqueue_len(ifp);
+		break;
+
+	case SIOCGIFRXQAFFINITY:
+		if (!(ifp->if_capabilities & IFCAP_MULTIQUEUE))
+			return (EOPNOTSUPP);
+		KASSERT(ifp->if_get_rxqueue_affinity, ("if_get_rxqueue_affinity not set"));
+		ifr->ifr_queue_affinity_cpu =
+			ifp->if_get_rxqueue_affinity(ifp, ifr->ifr_queue_affinity_index);
+		break;
+
+	case SIOCGIFTXQAFFINITY:
+		if (!(ifp->if_capabilities & IFCAP_MULTIQUEUE))
+			return (EOPNOTSUPP);
+		KASSERT(ifp->if_get_rxqueue_affinity, ("if_get_rxqueue_affinity not set"));
+		ifr->ifr_queue_affinity_cpu = 
+			ifp->if_get_rxqueue_affinity(ifp, ifr->ifr_queue_affinity_index);
+		break;
+
 	default:
 		error = ENOIOCTL;
 		break;
Index: if.h
===================================================================
--- if.h	(.../head/sys/net/if.h)	(revision 252509)
+++ if.h	(.../user/syuu/mq_bpf/sys/net/if.h)	(revision 252509)
@@ -231,6 +231,7 @@
 #define	IFCAP_NETMAP		0x100000 /* netmap mode supported/enabled */
 #define	IFCAP_RXCSUM_IPV6	0x200000  /* can offload checksum on IPv6 RX */
 #define	IFCAP_TXCSUM_IPV6	0x400000  /* can offload checksum on IPv6 TX */
+#define	IFCAP_MULTIQUEUE	0x800000
 
 #define IFCAP_HWCSUM_IPV6	(IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6)
 
@@ -385,6 +386,8 @@
 		caddr_t	ifru_data;
 		int	ifru_cap[2];
 		u_int	ifru_fib;
+		int	ifru_queue_len[2];
+		int	ifru_queue_affinity[2];
 	} ifr_ifru;
 #define	ifr_addr	ifr_ifru.ifru_addr	/* address */
 #define	ifr_dstaddr	ifr_ifru.ifru_dstaddr	/* other end of p-to-p link */
@@ -402,6 +405,11 @@
 #define	ifr_curcap	ifr_ifru.ifru_cap[1]	/* current capabilities */
 #define	ifr_index	ifr_ifru.ifru_index	/* interface index */
 #define	ifr_fib		ifr_ifru.ifru_fib	/* interface fib */
+#define ifr_rxqueue_len	ifr_ifru.ifru_queue_len[0] /* rxqueue len */
+#define ifr_txqueue_len	ifr_ifru.ifru_queue_len[1] /* txqueue len */
+#define ifr_queue_affinity_index ifr_ifru.ifru_queue_affinity[0] /* queue id */
+#define ifr_queue_affinity_cpu ifr_ifru.ifru_queue_affinity[1] /* cpu id */
+
 };
 
 #define	_SIZEOF_ADDR_IFREQ(ifr) \
Index: bpf.c
===================================================================
--- bpf.c	(.../head/sys/net/bpf.c)	(revision 252509)
+++ bpf.c	(.../user/syuu/mq_bpf/sys/net/bpf.c)	(revision 252509)
@@ -819,6 +819,12 @@
 	size = d->bd_bufsize;
 	bpf_buffer_ioctl_sblen(d, &size);
 
+ 	d->bd_qmask.qm_enabled = FALSE;
+ 	d->bd_qmask.qm_rxq_mask = NULL;
+ 	d->bd_qmask.qm_txq_mask = NULL;
+ 	d->bd_qmask.qm_other_mask = FALSE;
+ 	rw_init(&d->bd_qmask.qm_lock, "qmask lock");
+
 	return (0);
 }
 
@@ -1697,6 +1703,266 @@
 	case BIOCROTZBUF:
 		error = bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr);
 		break;
+
+	case BIOCENAQMASK:
+		{
+			struct ifnet *ifp;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			ifp = d->bd_bif->bif_ifp;
+			if (!(ifp->if_capabilities & IFCAP_MULTIQUEUE)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			KASSERT(ifp->if_get_rxqueue_len, ("ifp->if_get_rxqueue_len not set\n"));
+			KASSERT(ifp->if_get_txqueue_len, ("ifp->if_get_rxqueue_len not set\n"));
+			d->bd_qmask.qm_enabled = TRUE;
+			d->bd_qmask.qm_rxq_mask =
+				malloc(ifp->if_get_rxqueue_len(ifp) * sizeof(boolean_t), M_BPF, 
+					M_WAITOK | M_ZERO);
+			d->bd_qmask.qm_txq_mask =
+				malloc(ifp->if_get_txqueue_len(ifp) * sizeof(boolean_t), M_BPF, 
+					M_WAITOK | M_ZERO);
+			d->bd_qmask.qm_other_mask = FALSE;
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCDISQMASK:
+		{
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			d->bd_qmask.qm_enabled = FALSE;
+			
+			free(d->bd_qmask.qm_rxq_mask, M_BPF);
+			free(d->bd_qmask.qm_txq_mask, M_BPF);
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCSTRXQMASK:
+		{
+			struct ifnet *ifp;
+			int index;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;	
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_rxqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			d->bd_qmask.qm_rxq_mask[index] = TRUE;
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCCRRXQMASK:
+		{
+			int index;
+			struct ifnet *ifp;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_rxqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			d->bd_qmask.qm_rxq_mask[index] = FALSE;
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCGTRXQMASK:
+		{
+			int index;
+			struct ifnet *ifp;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_rxqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			*(uint32_t *)addr = d->bd_qmask.qm_rxq_mask[index];
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCSTTXQMASK:
+		{
+			struct ifnet *ifp;
+			int index;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_txqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			d->bd_qmask.qm_txq_mask[index] = TRUE;
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCCRTXQMASK:
+		{
+			struct ifnet *ifp;
+			int index;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_txqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			d->bd_qmask.qm_txq_mask[index] = FALSE;
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCGTTXQMASK:
+		{
+			int index;
+			struct ifnet *ifp;
+
+			if (d->bd_bif == NULL) {
+				/*
+				 * No interface attached yet.
+				 */
+				error = EINVAL;
+				break;
+			}
+			BPFQ_WLOCK(&d->bd_qmask);
+			if (!d->bd_qmask.qm_enabled) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			ifp = d->bd_bif->bif_ifp;
+			index = *(uint32_t *)addr;
+			if (index > ifp->if_get_txqueue_len(ifp)) {
+				BPFQ_WUNLOCK(&d->bd_qmask);
+				error = EINVAL;
+				break;
+			}
+			*(uint32_t *)addr = d->bd_qmask.qm_txq_mask[index];
+			BPFQ_WUNLOCK(&d->bd_qmask);
+			break;
+		}
+
+	case BIOCSTOTHERMASK:
+		BPFQ_WLOCK(&d->bd_qmask);
+		d->bd_qmask.qm_other_mask = TRUE;
+		BPFQ_WUNLOCK(&d->bd_qmask);
+		break;
+
+	case BIOCCROTHERMASK:
+		BPFQ_WLOCK(&d->bd_qmask);
+		d->bd_qmask.qm_other_mask = FALSE;
+		BPFQ_WUNLOCK(&d->bd_qmask);
+		break;
+
+	case BIOCGTOTHERMASK:
+		BPFQ_WLOCK(&d->bd_qmask);
+		*(uint32_t *)addr = (uint32_t)d->bd_qmask.qm_other_mask;
+		BPFQ_WUNLOCK(&d->bd_qmask);
+		break;
 	}
 	CURVNET_RESTORE();
 	return (error);
@@ -2050,6 +2316,14 @@
 		 * 2) destroying/detaching d is protected by interface
 		 * write lock, too
 		 */
+ 		BPFQ_RLOCK(&d->bd_qmask);
+ 		if (d->bd_qmask.qm_enabled) {
+ 			if (!d->bd_qmask.qm_other_mask) {
+				BPFQ_RUNLOCK(&d->bd_qmask);
+ 				continue;
+ 			}
+ 		}
+		BPFQ_RUNLOCK(&d->bd_qmask);
 
 		/* XXX: Do not protect counter for the sake of performance. */
 		++d->bd_rcount;
@@ -2117,6 +2391,42 @@
 	BPFIF_RLOCK(bp);
 
 	LIST_FOREACH(d, &bp->bif_dlist, bd_next) {
+ 		BPFQ_RLOCK(&d->bd_qmask);
+ 		if (d->bd_qmask.qm_enabled) {
+ 			M_ASSERTPKTHDR(m);
+ 			if (!(m->m_flags & M_FLOWID)) {
+ 				if (!d->bd_qmask.qm_other_mask) {
+ 					BPFQ_RUNLOCK(&d->bd_qmask);
+ 					continue;
+ 				}
+ 			} else {
+ 				struct ifnet *ifp = bp->bif_ifp;
+ 				if (m->m_pkthdr.rxqueue != (uint32_t)-1) {
+ 					if (m->m_pkthdr.rxqueue >= ifp->if_get_rxqueue_len(ifp)) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						BPFIF_RUNLOCK(bp);
+ 						return;
+					}
+ 					if (!d->bd_qmask.qm_rxq_mask[m->m_pkthdr.rxqueue]) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						continue;
+ 					}
+ 				}
+ 				if (m->m_pkthdr.txqueue != (uint32_t)-1) {
+ 					if (m->m_pkthdr.txqueue >= ifp->if_get_txqueue_len(ifp)) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						BPFIF_RUNLOCK(bp);
+ 						return;
+ 					}
+ 					if (!d->bd_qmask.qm_txq_mask[m->m_pkthdr.txqueue]) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						continue;
+ 					}
+ 				}
+ 			}
+ 		}
+ 		BPFQ_RUNLOCK(&d->bd_qmask);
+ 
 		if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp))
 			continue;
 		++d->bd_rcount;
@@ -2180,6 +2490,42 @@
 	BPFIF_RLOCK(bp);
 
 	LIST_FOREACH(d, &bp->bif_dlist, bd_next) {
+ 		BPFQ_RLOCK(&d->bd_qmask);
+ 		if (d->bd_qmask.qm_enabled) {
+ 			M_ASSERTPKTHDR(m);
+ 			if (!(m->m_flags & M_FLOWID)) {
+ 				if (!d->bd_qmask.qm_other_mask) {
+ 					BPFQ_RUNLOCK(&d->bd_qmask);
+ 					continue;
+ 				}
+ 			} else {
+ 				struct ifnet *ifp = bp->bif_ifp;
+ 				if (m->m_pkthdr.rxqueue != (uint32_t)-1) {
+ 					if (m->m_pkthdr.rxqueue >= ifp->if_get_rxqueue_len(ifp)) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						BPFIF_RUNLOCK(bp);
+ 						return;
+ 					}
+ 					if (!d->bd_qmask.qm_rxq_mask[m->m_pkthdr.rxqueue]) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						continue;
+ 					}
+ 				}
+ 				if (m->m_pkthdr.txqueue != (uint32_t)-1) {
+ 					if (m->m_pkthdr.txqueue >= ifp->if_get_txqueue_len(ifp)) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						BPFIF_RUNLOCK(bp);
+ 						return;
+ 					}
+ 					if (!d->bd_qmask.qm_txq_mask[m->m_pkthdr.txqueue]) {
+ 						BPFQ_RUNLOCK(&d->bd_qmask);
+ 						continue;
+ 					}
+ 				}
+ 			}
+ 		}
+ 		BPFQ_RUNLOCK(&d->bd_qmask);
+ 
 		if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp))
 			continue;
 		++d->bd_rcount;
@@ -2443,6 +2789,12 @@
 	}
 	if (d->bd_wfilter != NULL)
 		free((caddr_t)d->bd_wfilter, M_BPF);
+ 
+ 	if (d->bd_qmask.qm_enabled) {
+ 		free(d->bd_qmask.qm_rxq_mask, M_BPF);
+ 		free(d->bd_qmask.qm_txq_mask, M_BPF);
+ 	}
+ 
 	mtx_destroy(&d->bd_lock);
 }
 
Index: sockio.h
===================================================================
--- sockio.h	(.../head/sys/sys/sockio.h)	(revision 252509)
+++ sockio.h	(.../user/syuu/mq_bpf/sys/sys/sockio.h)	(revision 252509)
@@ -82,6 +82,10 @@
 #define	SIOCGIFDESCR	_IOWR('i', 42, struct ifreq)	/* get ifnet descr */ 
 #define	SIOCAIFADDR	 _IOW('i', 43, struct ifaliasreq)/* add/chg IF alias */
 
+#define	SIOCGIFQLEN 	_IOWR('i', 45, struct ifreq)	/* get IF queue len */
+#define	SIOCGIFRXQAFFINITY _IOWR('i', 46, struct ifreq)	/* get IF rx queue affinity */
+#define	SIOCGIFTXQAFFINITY _IOWR('i', 47, struct ifreq)	/* get IF tx queue affinity */
+
 #define	SIOCADDMULTI	 _IOW('i', 49, struct ifreq)	/* add m'cast addr */
 #define	SIOCDELMULTI	 _IOW('i', 50, struct ifreq)	/* del m'cast addr */
 #define	SIOCGIFMTU	_IOWR('i', 51, struct ifreq)	/* get IF mtu */
Index: mbuf.h
===================================================================
--- mbuf.h	(.../head/sys/sys/mbuf.h)	(revision 252509)
+++ mbuf.h	(.../user/syuu/mq_bpf/sys/sys/mbuf.h)	(revision 252509)
@@ -121,6 +121,8 @@
 	uint32_t	 flowid;	/* packet's 4-tuple system
 					 * flow identifier
 					 */
+	uint32_t	rxqueue;
+	uint32_t	txqueue;
 	/* variables for hardware checksum */
 	int		 csum_flags;	/* flags regarding checksum */
 	int		 csum_data;	/* data field used by csum routines */

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALG4x-UYBFsMttpZx1-c_wtVf5MST8%2B_t1psY2HQskTiOZDFLA>