summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_bridge.c45
-rw-r--r--sys/net/if_lagg.c38
2 files changed, 83 insertions, 0 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 6e060f0..fdd43b1 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -243,6 +243,7 @@ static void bridge_ifdetach(void *arg __unused, struct ifnet *);
static void bridge_init(void *);
static void bridge_dummynet(struct mbuf *, struct ifnet *);
static void bridge_stop(struct ifnet *, int);
+static void bridge_start(struct ifnet *);
static int bridge_transmit(struct ifnet *, struct mbuf *);
static void bridge_qflush(struct ifnet *);
static struct mbuf *bridge_input(struct ifnet *, struct mbuf *);
@@ -607,10 +608,13 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
if_initname(ifp, bridge_name, unit);
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = bridge_ioctl;
+ ifp->if_start = bridge_start;
ifp->if_transmit = bridge_transmit;
ifp->if_qflush = bridge_qflush;
ifp->if_init = bridge_init;
ifp->if_type = IFT_BRIDGE;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ IFQ_SET_READY(&ifp->if_snd);
/*
* Generate an ethernet address with a locally administered address.
@@ -2074,6 +2078,47 @@ bridge_qflush(struct ifnet *ifp __unused)
}
/*
+ * bridge_start:
+ *
+ * Start output on a bridge.
+ *
+ */
+static void
+bridge_start(struct ifnet *ifp)
+{
+ struct bridge_softc *sc;
+ struct mbuf *m;
+ struct ether_header *eh;
+ struct ifnet *dst_if;
+
+ sc = ifp->if_softc;
+
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ for (;;) {
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ break;
+ ETHER_BPF_MTAP(ifp, m);
+
+ eh = mtod(m, struct ether_header *);
+ dst_if = NULL;
+
+ BRIDGE_LOCK(sc);
+ if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
+ dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1);
+ }
+
+ if (dst_if == NULL)
+ bridge_broadcast(sc, ifp, m, 0);
+ else {
+ BRIDGE_UNLOCK(sc);
+ bridge_enqueue(sc, dst_if, m);
+ }
+ }
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+}
+
+/*
* bridge_forward:
*
* The forwarding function of the bridge.
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 4d41e63..2348f1e 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -116,6 +116,7 @@ static int lagg_setflag(struct lagg_port *, int, int,
int (*func)(struct ifnet *, int));
static int lagg_setflags(struct lagg_port *, int status);
static int lagg_transmit(struct ifnet *, struct mbuf *);
+static void lagg_start(struct ifnet *);
static void lagg_qflush(struct ifnet *);
static int lagg_media_change(struct ifnet *);
static void lagg_media_status(struct ifnet *, struct ifmediareq *);
@@ -353,11 +354,14 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
if_initname(ifp, laggname, unit);
ifp->if_softc = sc;
ifp->if_transmit = lagg_transmit;
+ ifp->if_start = lagg_start;
ifp->if_qflush = lagg_qflush;
ifp->if_init = lagg_init;
ifp->if_ioctl = lagg_ioctl;
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
ifp->if_capenable = ifp->if_capabilities = IFCAP_HWSTATS;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ IFQ_SET_READY(&ifp->if_snd);
/*
* Attach as an ordinary ethernet device, children will be attached
@@ -1345,6 +1349,40 @@ lagg_transmit(struct ifnet *ifp, struct mbuf *m)
return (error);
}
+static void
+lagg_start(struct ifnet *ifp)
+{
+ struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
+ struct rm_priotracker tracker;
+ struct mbuf *m;
+ int error = 0, len;
+
+ LAGG_RLOCK(sc, &tracker);
+ /* We need a Tx algorithm and at least one port */
+ if (sc->sc_proto == LAGG_PROTO_NONE || sc->sc_count == 0) {
+ IF_DRAIN(&ifp->if_snd);
+ LAGG_RUNLOCK(sc, &tracker);
+ return;
+ }
+
+ for (;; error = 0) {
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+
+ ETHER_BPF_MTAP(ifp, m);
+
+ len = m->m_pkthdr.len;
+ error = (*sc->sc_start)(sc, m);
+ if (error == 0) {
+ counter_u64_add(sc->sc_opackets, 1);
+ counter_u64_add(sc->sc_obytes, len);
+ } else
+ ifp->if_oerrors++;
+ }
+ LAGG_RUNLOCK(sc, &tracker);
+}
+
/*
* The ifp->if_qflush entry point for lagg(4) is no-op.
*/
OpenPOWER on IntegriCloud