Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Apr 2013 21:09:54 +0400
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        "freebsd-net@freebsd.org" <net@freebsd.org>, hackers@freebsd.org
Cc:        Jack Vogel <jfvogel@gmail.com>
Subject:   VLANHWFILTER "upgrade"
Message-ID:  <516C3462.30501@FreeBSD.org>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------000509050108030808090809
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit

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

--------------000509050108030808090809
Content-Type: text/plain; charset=UTF-8;
 name="ixgbe_vlans2.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="ixgbe_vlans2.diff"

Index: sys/dev/ixgbe/ixgbe.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- 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 =3D ENOMEM;
 			goto err_rx_desc;
 		}
+
+		if ((rxr->vlans =3D malloc(sizeof(struct ifvlans), M_DEVBUF,
+		    M_NOWAIT | M_ZERO)) =3D=3D NULL) {
+			device_printf(dev,
+			    "Critical Failure setting up vlan index\n");
+			error =3D ENOMEM;
+			goto err_rx_desc;
+		}
 	}
=20
 	/*
@@ -4271,6 +4279,11 @@ ixgbe_free_receive_buffers(struct rx_ring *rxr)
 		rxr->ptag =3D NULL;
 	}
=20
+	if (rxr->vlans !=3D NULL) {
+		free(rxr->vlans, M_DEVBUF);
+		rxr->vlans =3D NULL;
+	}
+
 	return;
 }
=20
@@ -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);
 }
=20
@@ -4360,6 +4373,7 @@ ixgbe_rxeof(struct ix_queue *que)
 	u16			count =3D rxr->process_limit;
 	union ixgbe_adv_rx_desc	*cur;
 	struct ixgbe_rx_buf	*rbuf, *nbuf;
+	struct ifnet		*ifp_dst;
=20
 	IXGBE_RX_LOCK(rxr);
=20
@@ -4522,9 +4536,19 @@ ixgbe_rxeof(struct ix_queue *que)
 			    (staterr & IXGBE_RXD_STAT_VP))
 				vtag =3D le16toh(cur->wb.upper.vlan);
 			if (vtag) {
-				sendmp->m_pkthdr.ether_vtag =3D vtag;
-				sendmp->m_flags |=3D M_VLANTAG;
-			}
+				ifp_dst =3D rxr->vlans->idx[EVL_VLANOFTAG(vtag)];
+
+				if (ifp_dst !=3D NULL) {
+					ifp_dst->if_ipackets++;
+					sendmp->m_pkthdr.rcvif =3D ifp_dst;
+				} else {
+					sendmp->m_pkthdr.ether_vtag =3D vtag;
+					sendmp->m_flags |=3D M_VLANTAG;
+					sendmp->m_pkthdr.rcvif =3D ifp;
+				}
+			} else
+				sendmp->m_pkthdr.rcvif =3D ifp;
+
 			if ((ifp->if_capenable & IFCAP_RXCSUM) !=3D 0)
 				ixgbe_rx_checksum(staterr, sendmp, ptype);
 #if __FreeBSD_version >=3D 800000
@@ -4625,7 +4649,32 @@ ixgbe_rx_checksum(u32 staterr, struct mbuf * mp, u=

 	return;
 }
=20
+/*
+ * 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)
+{
=20
+	/* XXX: IFF_MONITOR */
+#if 0
+	struct lagg_port *lp =3D ifp->if_lagg;
+	struct lagg_softc *sc =3D lp->lp_softc;
+
+	/* Skip lagg nesting */
+	while (ifp->if_type =3D=3D IFT_IEEE8023ADLAG) {
+		lp =3D ifp->if_lagg;
+		sc =3D lp->lp_softc;
+		ifp =3D sc->sc_ifp;
+	}
+#endif
+	/* Get vlan interface based on tag */
+	ifp =3D 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 =3D ifp->if_softc;
-	u16		index, bit;
+	u16		index, bit, j;
+	struct rx_ring	*rxr;
+	struct ifnet	*ifv;
=20
 	if (ifp->if_softc !=3D  arg)   /* Not our event */
 		return;
@@ -4645,7 +4696,20 @@ ixgbe_register_vlan(void *arg, struct ifnet *ifp,
 	if ((vtag =3D=3D 0) || (vtag > 4095))	/* Invalid */
 		return;
=20
+	ifv =3D ixgbe_get_vlan(ifp, vtag);
+
 	IXGBE_CORE_LOCK(adapter);
+
+	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
+		rxr =3D adapter->rx_rings;
+
+		for (j =3D 0; j < adapter->num_queues; j++, rxr++) {
+			IXGBE_RX_LOCK(rxr);
+			rxr->vlans->idx[vtag] =3D ifv;
+			IXGBE_RX_UNLOCK(rxr);
+		}
+	}
+
 	index =3D (vtag >> 5) & 0x7F;
 	bit =3D vtag & 0x1F;
 	adapter->shadow_vfta[index] |=3D (1 << bit);
@@ -4663,7 +4727,8 @@ static void
 ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
 {
 	struct adapter	*adapter =3D ifp->if_softc;
-	u16		index, bit;
+	u16		index, bit, j;
+	struct rx_ring	*rxr;
=20
 	if (ifp->if_softc !=3D  arg)
 		return;
@@ -4672,6 +4737,15 @@ ixgbe_unregister_vlan(void *arg, struct ifnet *ifp=

 		return;
=20
 	IXGBE_CORE_LOCK(adapter);
+
+	rxr =3D adapter->rx_rings;
+
+	for (j =3D 0; j < adapter->num_queues; j++, rxr++) {
+		IXGBE_RX_LOCK(rxr);
+		rxr->vlans->idx[vtag] =3D NULL;
+		IXGBE_RX_UNLOCK(rxr);
+	}
+
 	index =3D (vtag >> 5) & 0x7F;
 	bit =3D vtag & 0x1F;
 	adapter->shadow_vfta[index] &=3D ~(1 << bit);
@@ -4686,8 +4760,8 @@ ixgbe_setup_vlan_hw_support(struct adapter *adapte
 {
 	struct ifnet 	*ifp =3D adapter->ifp;
 	struct ixgbe_hw *hw =3D &adapter->hw;
+	u32		ctrl, j;
 	struct rx_ring	*rxr;
-	u32		ctrl;
=20
=20
 	/*
@@ -4713,6 +4787,15 @@ ixgbe_setup_vlan_hw_support(struct adapter *adapte=

 	if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) {
 		ctrl &=3D ~IXGBE_VLNCTRL_CFIEN;
 		ctrl |=3D IXGBE_VLNCTRL_VFE;
+	} else {
+		/* Zero vlan table */
+		rxr =3D adapter->rx_rings;
+
+		for (j =3D 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 =3D=3D ixgbe_mac_82598EB)
 		ctrl |=3D IXGBE_VLNCTRL_VME;
Index: sys/dev/ixgbe/ixgbe.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- sys/dev/ixgbe/ixgbe.h	(revision 248704)
+++ sys/dev/ixgbe/ixgbe.h	(working copy)
@@ -284,6 +284,11 @@ struct ix_queue {
 	u64			irqs;
 };
=20
+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];
 };
=20
=20
@@ -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;
=20
 	u32			bytes; /* Used for AIM calc */
@@ -363,6 +368,7 @@ struct rx_ring {
 #ifdef IXGBE_FDIR
 	u64			flm;
 #endif
+	char			mtx_name[16];
 };
=20
 /* Our adapter structure */

--------------000509050108030808090809--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?516C3462.30501>