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