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
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 */
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to