VLANHWFILTER "upgrade"

Alexander V. Chernikov melifaro at FreeBSD.org
Mon Apr 15 17:10:30 UTC 2013


Hello list.

We currently have VLAHWFILTER functionality allowing underlying
physical/virtual interfaces to be aware of vlans stacked on them.

However, this knowledge is only used to program NIC hw filter (or to
broadcast to member ifaces in lagg case).

Proposed idea is to save vlan ifp pointer inside the driver and push
packet to given vlan directly.

This changes removes 1 read lock on RX fast path.

Additionally, we can do the same in more popular case of

ix -> lagg [ -> lagg -> lagg ] -> vlan

if we solve
1) lagg interface counters issue (trivial)
2) IFF_MONITOR on lagg interface issue (not so trivial, unfortunately).

Patch to ixgbe driver attached (maybe it is better to put
ixgbe_vlan_get() and struct ifvlans directly to if_vlan.[ch]).


-- 
WBR, Alexander
-------------- next part --------------
Index: sys/dev/ixgbe/ixgbe.c
===================================================================
--- sys/dev/ixgbe/ixgbe.c	(revision 248704)
+++ sys/dev/ixgbe/ixgbe.c	(working copy)
@@ -2880,6 +2880,14 @@ ixgbe_allocate_queues(struct adapter *adapter)
 			error = ENOMEM;
 			goto err_rx_desc;
 		}
+
+		if ((rxr->vlans = malloc(sizeof(struct ifvlans), M_DEVBUF,
+		    M_NOWAIT | M_ZERO)) == NULL) {
+			device_printf(dev,
+			    "Critical Failure setting up vlan index\n");
+			error = ENOMEM;
+			goto err_rx_desc;
+		}
 	}
 
 	/*
@@ -4271,6 +4279,11 @@ ixgbe_free_receive_buffers(struct rx_ring *rxr)
 		rxr->ptag = NULL;
 	}
 
+	if (rxr->vlans != NULL) {
+		free(rxr->vlans, M_DEVBUF);
+		rxr->vlans = NULL;
+	}
+
 	return;
 }
 
@@ -4303,7 +4316,7 @@ ixgbe_rx_input(struct rx_ring *rxr, struct ifnet *
                                 return;
         }
 	IXGBE_RX_UNLOCK(rxr);
-        (*ifp->if_input)(ifp, m);
+        (*ifp->if_input)(m->m_pkthdr.rcvif, m);
 	IXGBE_RX_LOCK(rxr);
 }
 
@@ -4360,6 +4373,7 @@ ixgbe_rxeof(struct ix_queue *que)
 	u16			count = rxr->process_limit;
 	union ixgbe_adv_rx_desc	*cur;
 	struct ixgbe_rx_buf	*rbuf, *nbuf;
+	struct ifnet		*ifp_dst;
 
 	IXGBE_RX_LOCK(rxr);
 
@@ -4522,9 +4536,19 @@ ixgbe_rxeof(struct ix_queue *que)
 			    (staterr & IXGBE_RXD_STAT_VP))
 				vtag = le16toh(cur->wb.upper.vlan);
 			if (vtag) {
-				sendmp->m_pkthdr.ether_vtag = vtag;
-				sendmp->m_flags |= M_VLANTAG;
-			}
+				ifp_dst = rxr->vlans->idx[EVL_VLANOFTAG(vtag)];
+
+				if (ifp_dst != NULL) {
+					ifp_dst->if_ipackets++;
+					sendmp->m_pkthdr.rcvif = ifp_dst;
+				} else {
+					sendmp->m_pkthdr.ether_vtag = vtag;
+					sendmp->m_flags |= M_VLANTAG;
+					sendmp->m_pkthdr.rcvif = ifp;
+				}
+			} else
+				sendmp->m_pkthdr.rcvif = ifp;
+
 			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
 				ixgbe_rx_checksum(staterr, sendmp, ptype);
 #if __FreeBSD_version >= 800000
@@ -4625,7 +4649,32 @@ ixgbe_rx_checksum(u32 staterr, struct mbuf * mp, u
 	return;
 }
 
+/*
+ * This routine gets real vlan ifp based on
+ * underlying ifp and vlan tag.
+ */
+static struct ifnet *
+ixgbe_get_vlan(struct ifnet *ifp, uint16_t vtag)
+{
 
+	/* XXX: IFF_MONITOR */
+#if 0
+	struct lagg_port *lp = ifp->if_lagg;
+	struct lagg_softc *sc = lp->lp_softc;
+
+	/* Skip lagg nesting */
+	while (ifp->if_type == IFT_IEEE8023ADLAG) {
+		lp = ifp->if_lagg;
+		sc = lp->lp_softc;
+		ifp = sc->sc_ifp;
+	}
+#endif
+	/* Get vlan interface based on tag */
+	ifp = VLAN_DEVAT(ifp, vtag);
+
+	return (ifp);
+}
+
 /*
 ** This routine is run via an vlan config EVENT,
 ** it enables us to use the HW Filter table since
@@ -4637,7 +4686,9 @@ static void
 ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
 {
 	struct adapter	*adapter = ifp->if_softc;
-	u16		index, bit;
+	u16		index, bit, j;
+	struct rx_ring	*rxr;
+	struct ifnet	*ifv;
 
 	if (ifp->if_softc !=  arg)   /* Not our event */
 		return;
@@ -4645,7 +4696,20 @@ ixgbe_register_vlan(void *arg, struct ifnet *ifp,
 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
 		return;
 
+	ifv = ixgbe_get_vlan(ifp, vtag);
+
 	IXGBE_CORE_LOCK(adapter);
+
+	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
+		rxr = adapter->rx_rings;
+
+		for (j = 0; j < adapter->num_queues; j++, rxr++) {
+			IXGBE_RX_LOCK(rxr);
+			rxr->vlans->idx[vtag] = ifv;
+			IXGBE_RX_UNLOCK(rxr);
+		}
+	}
+
 	index = (vtag >> 5) & 0x7F;
 	bit = vtag & 0x1F;
 	adapter->shadow_vfta[index] |= (1 << bit);
@@ -4663,7 +4727,8 @@ static void
 ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
 {
 	struct adapter	*adapter = ifp->if_softc;
-	u16		index, bit;
+	u16		index, bit, j;
+	struct rx_ring	*rxr;
 
 	if (ifp->if_softc !=  arg)
 		return;
@@ -4672,6 +4737,15 @@ ixgbe_unregister_vlan(void *arg, struct ifnet *ifp
 		return;
 
 	IXGBE_CORE_LOCK(adapter);
+
+	rxr = adapter->rx_rings;
+
+	for (j = 0; j < adapter->num_queues; j++, rxr++) {
+		IXGBE_RX_LOCK(rxr);
+		rxr->vlans->idx[vtag] = NULL;
+		IXGBE_RX_UNLOCK(rxr);
+	}
+
 	index = (vtag >> 5) & 0x7F;
 	bit = vtag & 0x1F;
 	adapter->shadow_vfta[index] &= ~(1 << bit);
@@ -4686,8 +4760,8 @@ ixgbe_setup_vlan_hw_support(struct adapter *adapte
 {
 	struct ifnet 	*ifp = adapter->ifp;
 	struct ixgbe_hw *hw = &adapter->hw;
+	u32		ctrl, j;
 	struct rx_ring	*rxr;
-	u32		ctrl;
 
 
 	/*
@@ -4713,6 +4787,15 @@ ixgbe_setup_vlan_hw_support(struct adapter *adapte
 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
 		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
 		ctrl |= IXGBE_VLNCTRL_VFE;
+	} else {
+		/* Zero vlan table */
+		rxr = adapter->rx_rings;
+
+		for (j = 0; j < adapter->num_queues; j++, rxr++) {
+			IXGBE_RX_LOCK(rxr);
+			memset(rxr->vlans->idx, 0, sizeof(struct ifvlans));
+			IXGBE_RX_UNLOCK(rxr);
+		}
 	}
 	if (hw->mac.type == ixgbe_mac_82598EB)
 		ctrl |= IXGBE_VLNCTRL_VME;
Index: sys/dev/ixgbe/ixgbe.h
===================================================================
--- sys/dev/ixgbe/ixgbe.h	(revision 248704)
+++ sys/dev/ixgbe/ixgbe.h	(working copy)
@@ -284,6 +284,11 @@ struct ix_queue {
 	u64			irqs;
 };
 
+struct ifvlans {
+	struct ifnet 		*idx[4096];
+};
+
+
 /*
  * The transmit ring, one per queue
  */
@@ -307,7 +312,6 @@ struct tx_ring {
 	}			queue_status;
 	u32			txd_cmd;
 	bus_dma_tag_t		txtag;
-	char			mtx_name[16];
 #ifndef IXGBE_LEGACY_TX
 	struct buf_ring		*br;
 	struct task		txq_task;
@@ -324,6 +328,7 @@ struct tx_ring {
 	unsigned long   	no_tx_dma_setup;
 	u64			no_desc_avail;
 	u64			total_packets;
+	char			mtx_name[16];
 };
 
 
@@ -346,8 +351,8 @@ struct rx_ring {
 	u16			num_desc;
 	u16			mbuf_sz;
 	u16			process_limit;
-	char			mtx_name[16];
 	struct ixgbe_rx_buf	*rx_buffers;
+	struct ifvlans		*vlans;
 	bus_dma_tag_t		ptag;
 
 	u32			bytes; /* Used for AIM calc */
@@ -363,6 +368,7 @@ struct rx_ring {
 #ifdef IXGBE_FDIR
 	u64			flm;
 #endif
+	char			mtx_name[16];
 };
 
 /* Our adapter structure */


More information about the freebsd-net mailing list