diff --git a/sys/dev/virtual/vkernel/net/if_vke.c b/sys/dev/virtual/vkernel/net/if_vke.c
index c09b36d..f74d5fe 100644
--- a/sys/dev/virtual/vkernel/net/if_vke.c
+++ b/sys/dev/virtual/vkernel/net/if_vke.c
@@ -66,16 +66,14 @@
 
 #define VKE_CHUNK	8 /* number of mbufs to queue before interrupting */
 
-#define NETFIFOSIZE	256
-#define NETFIFOMASK	(NETFIFOSIZE -1)
-#define NETFIFOINDEX(u) ((u) & NETFIFOMASK)
+#define NETFIFOINDEX(u, sc) ((u) & ((sc)->sc_ringsize - 1))
 
 #define VKE_COTD_RUN	0
 #define VKE_COTD_EXIT	1
 #define VKE_COTD_DEAD	2
 
 struct vke_fifo {
-	struct mbuf	*array[NETFIFOSIZE];
+	struct mbuf	**array;
 	int		rindex;
 	int		windex;
 };
@@ -99,6 +97,8 @@ struct vke_softc {
 	fifo_t			sc_txfifo_done;
 	fifo_t			sc_rxfifo;
 
+	int			sc_ringsize;
+
 	long			cotd_ipackets;
 	long			cotd_oerrors;
 	long			cotd_opackets;
@@ -157,11 +157,11 @@ vke_txfifo_done_enqueue(struct vke_softc *sc, struct mbuf *m)
 {
 	fifo_t fifo = sc->sc_txfifo_done;
 
-	while (NETFIFOINDEX(fifo->windex + 1) == NETFIFOINDEX(fifo->rindex)) {
+	while (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc)) {
 		usleep(20000);
 	}
 
-	fifo->array[NETFIFOINDEX(fifo->windex)] = m;
+	fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
 	cpu_sfence();
 	++fifo->windex;
 	return (0);
@@ -176,11 +176,11 @@ vke_txfifo_done_dequeue(struct vke_softc *sc, struct mbuf *nm)
 	fifo_t fifo = sc->sc_txfifo_done;
 	struct mbuf *m;
 
-	if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
+	if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
 		return (NULL);
 
-	m = fifo->array[NETFIFOINDEX(fifo->rindex)];
-	fifo->array[NETFIFOINDEX(fifo->rindex)] = nm;
+	m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
+	fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = nm;
 	cpu_lfence();
 	++fifo->rindex;
 	return (m);
@@ -194,10 +194,10 @@ vke_txfifo_enqueue(struct vke_softc *sc, struct mbuf *m)
 {
 	fifo_t fifo = sc->sc_txfifo;
 
-	if (NETFIFOINDEX(fifo->windex + 1) == NETFIFOINDEX(fifo->rindex))
+	if (NETFIFOINDEX(fifo->windex + 1, sc) == NETFIFOINDEX(fifo->rindex, sc))
 		return (-1);
 
-	fifo->array[NETFIFOINDEX(fifo->windex)] = m;
+	fifo->array[NETFIFOINDEX(fifo->windex, sc)] = m;
 	cpu_sfence();
 	++fifo->windex;
 
@@ -214,11 +214,11 @@ vke_txfifo_dequeue(struct vke_softc *sc)
 	fifo_t fifo = sc->sc_txfifo;
 	struct mbuf *m;
 
-	if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
+	if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
 		return (NULL);
 
-	m = fifo->array[NETFIFOINDEX(fifo->rindex)];
-	fifo->array[NETFIFOINDEX(fifo->rindex)] = NULL;
+	m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
+	fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = NULL;
 
 	cpu_lfence();
 	++fifo->rindex;
@@ -230,7 +230,7 @@ vke_txfifo_empty(struct vke_softc *sc)
 {
 	fifo_t fifo = sc->sc_txfifo;
 
-	if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
+	if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
 		return (1);
 	return(0);
 }
@@ -246,11 +246,11 @@ vke_rxfifo_dequeue(struct vke_softc *sc, struct mbuf *newm)
 	fifo_t fifo = sc->sc_rxfifo;
 	struct mbuf *m;
 
-	if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
+	if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
 		return (NULL);
 
-	m = fifo->array[NETFIFOINDEX(fifo->rindex)];
-	fifo->array[NETFIFOINDEX(fifo->rindex)] = newm;
+	m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
+	fifo->array[NETFIFOINDEX(fifo->rindex, sc)] = newm;
 	cpu_lfence();
 	++fifo->rindex;
 	return (m);
@@ -265,10 +265,10 @@ vke_rxfifo_sniff(struct vke_softc *sc)
 	fifo_t fifo = sc->sc_rxfifo;
 	struct mbuf *m;
 
-	if (NETFIFOINDEX(fifo->rindex) == NETFIFOINDEX(fifo->windex))
+	if (NETFIFOINDEX(fifo->rindex, sc) == NETFIFOINDEX(fifo->windex, sc))
 		return (NULL);
 
-	m = fifo->array[NETFIFOINDEX(fifo->rindex)];
+	m = fifo->array[NETFIFOINDEX(fifo->rindex, sc)];
 	cpu_lfence();
 	return (m);
 }
@@ -278,6 +278,7 @@ vke_init(void *xsc)
 {
 	struct vke_softc *sc = xsc;
 	struct ifnet *ifp = &sc->arpcom.ac_if;
+	size_t ringsize = sc->sc_ringsize * sizeof(struct mbuf *);
 	int i;
 
 	ASSERT_SERIALIZED(ifp->if_serializer);
@@ -287,11 +288,17 @@ vke_init(void *xsc)
 	ifp->if_flags |= IFF_RUNNING;
 	ifsq_clr_oactive(ifq_get_subq_default(&ifp->if_snd));
 
+	/*
+	 * Allocate memory for FIFO structures and mbufs.
+	 */
 	sc->sc_txfifo = kmalloc(sizeof(*sc->sc_txfifo), M_DEVBUF, M_WAITOK);
 	sc->sc_txfifo_done = kmalloc(sizeof(*sc->sc_txfifo_done), M_DEVBUF, M_WAITOK);
-
 	sc->sc_rxfifo = kmalloc(sizeof(*sc->sc_rxfifo), M_DEVBUF, M_WAITOK);
-	for (i = 0; i < NETFIFOSIZE; i++) {
+	sc->sc_txfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->sc_txfifo_done->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->sc_rxfifo->array = kmalloc(ringsize, M_DEVBUF, M_WAITOK | M_ZERO);
+
+	for (i = 0; i < sc->sc_ringsize; i++) {
 		sc->sc_rxfifo->array[i] = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR);
 		sc->sc_txfifo->array[i] = NULL;
 		sc->sc_txfifo_done->array[i] = NULL;
@@ -443,7 +450,7 @@ vke_stop(struct vke_softc *sc)
 			cothread_delete(&sc->cotd_rx);
 		}
 
-		for (i = 0; i < NETFIFOSIZE; i++) {
+		for (i = 0; i < sc->sc_ringsize; i++) {
 			if (sc->sc_rxfifo && sc->sc_rxfifo->array[i]) {
 				m_freem(sc->sc_rxfifo->array[i]);
 				sc->sc_rxfifo->array[i] = NULL;
@@ -459,16 +466,22 @@ vke_stop(struct vke_softc *sc)
 		}
 
 		if (sc->sc_txfifo) {
+			if (sc->sc_txfifo->array)
+				kfree(sc->sc_txfifo->array, M_DEVBUF);
 			kfree(sc->sc_txfifo, M_DEVBUF);
 			sc->sc_txfifo = NULL;
 		}
 
 		if (sc->sc_txfifo_done) {
+			if (sc->sc_txfifo_done->array)
+				kfree(sc->sc_txfifo_done->array, M_DEVBUF);
 			kfree(sc->sc_txfifo_done, M_DEVBUF);
 			sc->sc_txfifo_done = NULL;
 		}
 
 		if (sc->sc_rxfifo) {
+			if (sc->sc_rxfifo->array)
+				kfree(sc->sc_rxfifo->array, M_DEVBUF);
 			kfree(sc->sc_rxfifo, M_DEVBUF);
 			sc->sc_rxfifo = NULL;
 		}
@@ -601,8 +614,8 @@ vke_rx_thread(cothread_t cotd)
 		 * Wait for the RX FIFO to be loaded with
 		 * empty mbufs.
 		 */
-		if (NETFIFOINDEX(fifo->windex + 1) ==
-		    NETFIFOINDEX(fifo->rindex)) {
+		if (NETFIFOINDEX(fifo->windex + 1, sc) ==
+		    NETFIFOINDEX(fifo->rindex, sc)) {
 			usleep(20000);
 			continue;
 		}
@@ -610,7 +623,7 @@ vke_rx_thread(cothread_t cotd)
 		/*
 		 * Load data into the rx fifo
 		 */
-		m = fifo->array[NETFIFOINDEX(fifo->windex)];
+		m = fifo->array[NETFIFOINDEX(fifo->windex, sc)];
 		if (m == NULL)
 			continue;
 		n = read(sc->sc_fd, mtod(m, void *), MCLBYTES);
@@ -706,6 +719,7 @@ vke_attach(const struct vknetif_info *info, int unit)
 	struct ifnet *ifp;
 	struct tapinfo tapinfo;
 	uint8_t enaddr[ETHER_ADDR_LEN];
+	int nmbufs;
 	int fd;
 
 	KKASSERT(info->tap_fd >= 0);
@@ -754,6 +768,19 @@ havemac:
 	sc->sc_addr = info->netif_addr;
 	sc->sc_mask = info->netif_mask;
 
+	/*
+	 * Calculate the number of mbuf clusters we are going to use
+	 * up to 50% of the total mbuf clusters available in the
+	 * system.
+	 * In the case our vkernel has so little mem that it can't
+	 * allocate even VKE_CHUNK for every vke(4) device, just panic.
+	 */
+	nmbufs = nmbclusters / (NetifNum * 2);
+	sc->sc_ringsize = (1 << (fls(nmbufs) - 1));
+
+	KASSERT(sc->sc_ringsize >= VKE_CHUNK,
+	    ("Not enough mbuf clusters for %d vke devices", NetifNum));
+
 	ifp = &sc->arpcom.ac_if;
 	if_initname(ifp, VKE_DEVNAME, sc->sc_unit);
 
@@ -789,8 +816,8 @@ havemac:
 
 	if (bootverbose && sc->sc_addr != 0) {
 		if_printf(ifp, "pre-configured "
-			  "address 0x%08x, netmask 0x%08x\n",
-			  ntohl(sc->sc_addr), ntohl(sc->sc_mask));
+		    "address 0x%08x, netmask 0x%08x, %d mbuf clusters\n",
+		    ntohl(sc->sc_addr), ntohl(sc->sc_mask), sc->sc_ringsize);
 	}
 
 	return 0;
