Module Name:    src
Committed By:   thorpej
Date:           Thu Nov 16 14:45:40 UTC 2023

Modified Files:
        src/sys/net [thorpej-ifq]: if.c

Log Message:
- Rename if_transmit() -> if_transmit_default()
- In if_enqueue(), handle the ALTQ-is-enabled case by creating a sort of
  chimera from ifq_put_slow() and if_transmit_default(), mainly to avoid
  having to repeatedly take and release the ifq lock.


To generate a diff of this commit:
cvs rdiff -u -r1.529.2.1.2.4 -r1.529.2.1.2.5 src/sys/net/if.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.529.2.1.2.4 src/sys/net/if.c:1.529.2.1.2.5
--- src/sys/net/if.c:1.529.2.1.2.4	Thu Nov 16 05:13:13 2023
+++ src/sys/net/if.c	Thu Nov 16 14:45:40 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $	*/
+/*	$NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008, 2023 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -231,7 +231,7 @@ static int sysctl_if_watchdog(SYSCTLFN_P
 static void sysctl_watchdog_setup(struct ifnet *);
 static void if_attachdomain1(struct ifnet *);
 static int ifconf(u_long, void *);
-static int if_transmit(struct ifnet *, struct mbuf *);
+static int if_transmit_default(struct ifnet *, struct mbuf *);
 static int if_clone_create(const char *);
 static int if_clone_destroy(const char *);
 static void if_link_state_change_work(struct work *, void *);
@@ -809,7 +809,7 @@ if_register(ifnet_t *ifp)
 	}
 
 	if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit)
-		ifp->if_transmit = if_transmit;
+		ifp->if_transmit = if_transmit_default;
 
 	IFNET_GLOBAL_LOCK();
 	TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list);
@@ -1067,7 +1067,7 @@ if_snd_is_used(struct ifnet *ifp)
 {
 
 	return ALTQ_IS_ENABLED(&ifp->if_snd) ||
-	    ifp->if_transmit == if_transmit ||
+	    ifp->if_transmit == if_transmit_default ||
 	    ifp->if_transmit == NULL ||
 	    ifp->if_transmit == if_nulltransmit;
 }
@@ -3765,38 +3765,6 @@ ifreq_setaddr(u_long cmd, struct ifreq *
 }
 
 /*
- * wrapper function for the drivers which doesn't have if_transmit().
- */
-static int
-if_transmit(struct ifnet *ifp, struct mbuf *m)
-{
-	int error;
-	size_t pktlen = m->m_pkthdr.len;
-	bool mcast = (m->m_flags & M_MCAST) != 0;
-
-	const int s = splnet();
-
-	IFQ_ENQUEUE(&ifp->if_snd, m, error);
-	if (error != 0) {
-		/* mbuf is already freed */
-		goto out;
-	}
-
-	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
-	if_statadd_ref(nsr, if_obytes, pktlen);
-	if (mcast)
-		if_statinc_ref(nsr, if_omcasts);
-	IF_STAT_PUTREF(ifp);
-
-	if ((ifp->if_flags & IFF_OACTIVE) == 0)
-		if_start_lock(ifp);
-out:
-	splx(s);
-
-	return error;
-}
-
-/*
  * ifq_init --
  *
  *	Initialize an interface queue.
@@ -4401,20 +4369,40 @@ ifq_classify_packet(struct ifqueue * con
 #endif /* ALTQ */
 }
 
-#ifdef ALTQ
 static void
-ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1)
+if_transmit_tail(struct ifnet *ifp, size_t pktlen, bool mcast)
 {
-	KASSERT(ifq0 != ifq1);
-	if (ifq0 < ifq1) {
-		mutex_enter(ifq0->ifq_lock);
-		mutex_enter(ifq1->ifq_lock);
-	} else {
-		mutex_enter(ifq1->ifq_lock);
-		mutex_enter(ifq0->ifq_lock);
+	const int s = splnet();			/* XXX */
+
+	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
+	if_statadd_ref(nsr, if_obytes, pktlen);
+	if (mcast)
+		if_statinc_ref(nsr, if_omcasts);
+	IF_STAT_PUTREF(ifp);
+
+	if ((ifp->if_flags & IFF_OACTIVE) == 0)
+		if_start_lock(ifp);
+
+	splx(s);
+}
+
+/*
+ * wrapper function for the drivers which doesn't have if_transmit().
+ */
+static int
+if_transmit_default(struct ifnet *ifp, struct mbuf *m)
+{
+	int error;
+	size_t pktlen = m->m_pkthdr.len;
+	bool mcast = (m->m_flags & M_MCAST) != 0;
+
+	error = ifq_put(&ifp->if_snd, m);
+	if (error == 0) {
+		if_transmit_tail(ifp, pktlen, mcast);
 	}
+
+	return error;
 }
-#endif /* ALTQ */
 
 /*
  * Queue message on interface, and start output if interface
@@ -4423,27 +4411,69 @@ ifq_lock2(struct ifqueue * const ifq0, s
 int
 if_enqueue(struct ifnet *ifp, struct mbuf *m)
 {
-	int error;
-
 	kmsan_check_mbuf(m);
 
 #ifdef ALTQ
-	KERNEL_LOCK(1, NULL);
-	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
-		error = if_transmit(ifp, m);
-		KERNEL_UNLOCK_ONE(NULL);
-	} else {
+	mutex_enter(ifp->if_snd.ifq_lock);
+	if (__predict_false(ALTQ_IS_ENABLED(&ifp->if_snd))) {
+		size_t pktlen = m->m_pkthdr.len;
+		bool mcast = (m->m_flags & M_MCAST) != 0;
+		int error;
+
+		/*
+		 * All of this amounts to an elaborate ifq_put_slow()
+		 * that kicks the output queue.
+		 */
+
+		mutex_exit(ifp->if_snd.ifq_lock);
+		KERNEL_LOCK(1, NULL);
+		mutex_enter(ifp->if_snd.ifq_lock);
+		if (__predict_true(ALTQ_IS_ENABLED(&ifp->if_snd))) {
+			ALTQ_ENQUEUE(&ifp->if_snd, m, error);
+			KERNEL_UNLOCK_ONE(NULL);
+			goto finish;
+		}
 		KERNEL_UNLOCK_ONE(NULL);
-		error = (*ifp->if_transmit)(ifp, m);
-		/* mbuf is already freed */
+		
+		if (__predict_true(ifp->if_transmit == if_transmit_default)) {
+			if (__predict_false(IF_QFULL(&ifp->if_snd))) {
+				error = ENOBUFS;
+			} else {
+				IF_ENQUEUE(&ifp->if_snd, m);
+				error = 0;
+			}
+ finish:
+ 			if (__predict_false(error != 0)) {
+				ifp->if_snd.ifq_drops++;
+				mutex_exit(ifp->if_snd.ifq_lock);
+				m_freem(m);
+				return error;
+			}
+			mutex_exit(ifp->if_snd.ifq_lock);
+			if_transmit_tail(ifp, pktlen, mcast);
+			return 0;
+		}
 	}
-#else /* !ALTQ */
-	error = (*ifp->if_transmit)(ifp, m);
-	/* mbuf is already freed */
-#endif /* !ALTQ */
+	mutex_exit(ifp->if_snd.ifq_lock);
+#endif /* ALTQ */
 
-	return error;
+	return (*ifp->if_transmit)(ifp, m);
+}
+
+#ifdef ALTQ
+static void
+ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1)
+{
+	KASSERT(ifq0 != ifq1);
+	if (ifq0 < ifq1) {
+		mutex_enter(ifq0->ifq_lock);
+		mutex_enter(ifq1->ifq_lock);
+	} else {
+		mutex_enter(ifq1->ifq_lock);
+		mutex_enter(ifq0->ifq_lock);
+	}
 }
+#endif /* ALTQ */
 
 /*
  * Queue message on interface, possibly using a second fast queue

Reply via email to