Thu Nov 16 14:45:40 2023 UTC ()
- 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.


(thorpej)
diff -r1.529.2.1.2.4 -r1.529.2.1.2.5 src/sys/net/if.c

cvs diff -r1.529.2.1.2.4 -r1.529.2.1.2.5 src/sys/net/if.c (expand / switch to unified diff)

--- src/sys/net/if.c 2023/11/16 05:13:13 1.529.2.1.2.4
+++ src/sys/net/if.c 2023/11/16 14:45:40 1.529.2.1.2.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $ */ 1/* $NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1999, 2000, 2001, 2008, 2023 The NetBSD Foundation, Inc. 4 * Copyright (c) 1999, 2000, 2001, 2008, 2023 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by William Studenmund and Jason R. Thorpe. 8 * by William Studenmund and Jason R. Thorpe.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -80,27 +80,27 @@ @@ -80,27 +80,27 @@
80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87 * SUCH DAMAGE. 87 * SUCH DAMAGE.
88 * 88 *
89 * @(#)if.c 8.5 (Berkeley) 1/9/95 89 * @(#)if.c 8.5 (Berkeley) 1/9/95
90 */ 90 */
91 91
92#include <sys/cdefs.h> 92#include <sys/cdefs.h>
93__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.4 2023/11/16 05:13:13 thorpej Exp $"); 93__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.529.2.1.2.5 2023/11/16 14:45:40 thorpej Exp $");
94 94
95#if defined(_KERNEL_OPT) 95#if defined(_KERNEL_OPT)
96#include "opt_inet.h" 96#include "opt_inet.h"
97#include "opt_ipsec.h" 97#include "opt_ipsec.h"
98#include "opt_atalk.h" 98#include "opt_atalk.h"
99#include "opt_wlan.h" 99#include "opt_wlan.h"
100#include "opt_net_mpsafe.h" 100#include "opt_net_mpsafe.h"
101#include "opt_mrouting.h" 101#include "opt_mrouting.h"
102#endif 102#endif
103 103
104#define __IFQ_PRIVATE 104#define __IFQ_PRIVATE
105 105
106#include <sys/param.h> 106#include <sys/param.h>
@@ -221,27 +221,27 @@ static int if_cloners_count; @@ -221,27 +221,27 @@ static int if_cloners_count;
221pfil_head_t * if_pfil __read_mostly; 221pfil_head_t * if_pfil __read_mostly;
222 222
223static kauth_listener_t if_listener; 223static kauth_listener_t if_listener;
224 224
225static int doifioctl(struct socket *, u_long, void *, struct lwp *); 225static int doifioctl(struct socket *, u_long, void *, struct lwp *);
226static void sysctl_sndq_setup(struct sysctllog **, const char *, 226static void sysctl_sndq_setup(struct sysctllog **, const char *,
227 struct ifqueue *); 227 struct ifqueue *);
228static void if_slowtimo_intr(void *); 228static void if_slowtimo_intr(void *);
229static void if_slowtimo_work(struct work *, void *); 229static void if_slowtimo_work(struct work *, void *);
230static int sysctl_if_watchdog(SYSCTLFN_PROTO); 230static int sysctl_if_watchdog(SYSCTLFN_PROTO);
231static void sysctl_watchdog_setup(struct ifnet *); 231static void sysctl_watchdog_setup(struct ifnet *);
232static void if_attachdomain1(struct ifnet *); 232static void if_attachdomain1(struct ifnet *);
233static int ifconf(u_long, void *); 233static int ifconf(u_long, void *);
234static int if_transmit(struct ifnet *, struct mbuf *); 234static int if_transmit_default(struct ifnet *, struct mbuf *);
235static int if_clone_create(const char *); 235static int if_clone_create(const char *);
236static int if_clone_destroy(const char *); 236static int if_clone_destroy(const char *);
237static void if_link_state_change_work(struct work *, void *); 237static void if_link_state_change_work(struct work *, void *);
238static void if_up_locked(struct ifnet *); 238static void if_up_locked(struct ifnet *);
239static void _if_down(struct ifnet *); 239static void _if_down(struct ifnet *);
240static void if_down_deactivated(struct ifnet *); 240static void if_down_deactivated(struct ifnet *);
241 241
242struct if_percpuq { 242struct if_percpuq {
243 struct ifnet *ipq_ifp; 243 struct ifnet *ipq_ifp;
244 void *ipq_si; 244 void *ipq_si;
245 struct percpu *ipq_ifqs; /* struct ifqueue */ 245 struct percpu *ipq_ifqs; /* struct ifqueue */
246}; 246};
247 247
@@ -799,27 +799,27 @@ if_register(ifnet_t *ifp) @@ -799,27 +799,27 @@ if_register(ifnet_t *ifp)
799 mutex_init(&isd->isd_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK); 799 mutex_init(&isd->isd_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
800 callout_init(&isd->isd_ch, CALLOUT_MPSAFE); 800 callout_init(&isd->isd_ch, CALLOUT_MPSAFE);
801 callout_setfunc(&isd->isd_ch, if_slowtimo_intr, ifp); 801 callout_setfunc(&isd->isd_ch, if_slowtimo_intr, ifp);
802 isd->isd_ifp = ifp; 802 isd->isd_ifp = ifp;
803 803
804 ifp->if_slowtimo_data = isd; 804 ifp->if_slowtimo_data = isd;
805 805
806 if_slowtimo_intr(ifp); 806 if_slowtimo_intr(ifp);
807 807
808 sysctl_watchdog_setup(ifp); 808 sysctl_watchdog_setup(ifp);
809 } 809 }
810 810
811 if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) 811 if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit)
812 ifp->if_transmit = if_transmit; 812 ifp->if_transmit = if_transmit_default;
813 813
814 IFNET_GLOBAL_LOCK(); 814 IFNET_GLOBAL_LOCK();
815 TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); 815 TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list);
816 IFNET_WRITER_INSERT_TAIL(ifp); 816 IFNET_WRITER_INSERT_TAIL(ifp);
817 IFNET_GLOBAL_UNLOCK(); 817 IFNET_GLOBAL_UNLOCK();
818} 818}
819 819
820/* 820/*
821 * The if_percpuq framework 821 * The if_percpuq framework
822 * 822 *
823 * It allows network device drivers to execute the network stack 823 * It allows network device drivers to execute the network stack
824 * in softint (so called softint-based if_input). It utilizes 824 * in softint (so called softint-based if_input). It utilizes
825 * softint and percpu ifqueue. It doesn't distribute any packets 825 * softint and percpu ifqueue. It doesn't distribute any packets
@@ -1057,27 +1057,27 @@ if_deferred_start_softint(void *arg) @@ -1057,27 +1057,27 @@ if_deferred_start_softint(void *arg)
1057static void 1057static void
1058if_deferred_start_common(struct ifnet *ifp) 1058if_deferred_start_common(struct ifnet *ifp)
1059{ 1059{
1060 const int s = splnet(); 1060 const int s = splnet();
1061 if_start_lock(ifp); 1061 if_start_lock(ifp);
1062 splx(s); 1062 splx(s);
1063} 1063}
1064 1064
1065static inline bool 1065static inline bool
1066if_snd_is_used(struct ifnet *ifp) 1066if_snd_is_used(struct ifnet *ifp)
1067{ 1067{
1068 1068
1069 return ALTQ_IS_ENABLED(&ifp->if_snd) || 1069 return ALTQ_IS_ENABLED(&ifp->if_snd) ||
1070 ifp->if_transmit == if_transmit || 1070 ifp->if_transmit == if_transmit_default ||
1071 ifp->if_transmit == NULL || 1071 ifp->if_transmit == NULL ||
1072 ifp->if_transmit == if_nulltransmit; 1072 ifp->if_transmit == if_nulltransmit;
1073} 1073}
1074 1074
1075/* 1075/*
1076 * Schedule deferred if_start. 1076 * Schedule deferred if_start.
1077 */ 1077 */
1078void 1078void
1079if_schedule_deferred_start(struct ifnet *ifp) 1079if_schedule_deferred_start(struct ifnet *ifp)
1080{ 1080{
1081 1081
1082 KASSERT(ifp->if_deferred_start != NULL); 1082 KASSERT(ifp->if_deferred_start != NULL);
1083 1083
@@ -3755,58 +3755,26 @@ ifreq_setaddr(u_long cmd, struct ifreq * @@ -3755,58 +3755,26 @@ ifreq_setaddr(u_long cmd, struct ifreq *
3755 3755
3756 if (len < sa->sa_len) 3756 if (len < sa->sa_len)
3757 return EFBIG; 3757 return EFBIG;
3758 3758
3759 memset(&ifr->ifr_addr, 0, len); 3759 memset(&ifr->ifr_addr, 0, len);
3760 sockaddr_copy(&ifr->ifr_addr, len, sa); 3760 sockaddr_copy(&ifr->ifr_addr, len, sa);
3761 3761
3762 if (cmd != ocmd) 3762 if (cmd != ocmd)
3763 IFREQN2O_43(oifr, ifr); 3763 IFREQN2O_43(oifr, ifr);
3764 return 0; 3764 return 0;
3765} 3765}
3766 3766
3767/* 3767/*
3768 * wrapper function for the drivers which doesn't have if_transmit(). 
3769 */ 
3770static int 
3771if_transmit(struct ifnet *ifp, struct mbuf *m) 
3772{ 
3773 int error; 
3774 size_t pktlen = m->m_pkthdr.len; 
3775 bool mcast = (m->m_flags & M_MCAST) != 0; 
3776 
3777 const int s = splnet(); 
3778 
3779 IFQ_ENQUEUE(&ifp->if_snd, m, error); 
3780 if (error != 0) { 
3781 /* mbuf is already freed */ 
3782 goto out; 
3783 } 
3784 
3785 net_stat_ref_t nsr = IF_STAT_GETREF(ifp); 
3786 if_statadd_ref(nsr, if_obytes, pktlen); 
3787 if (mcast) 
3788 if_statinc_ref(nsr, if_omcasts); 
3789 IF_STAT_PUTREF(ifp); 
3790 
3791 if ((ifp->if_flags & IFF_OACTIVE) == 0) 
3792 if_start_lock(ifp); 
3793out: 
3794 splx(s); 
3795 
3796 return error; 
3797} 
3798 
3799/* 
3800 * ifq_init -- 3768 * ifq_init --
3801 * 3769 *
3802 * Initialize an interface queue. 3770 * Initialize an interface queue.
3803 */ 3771 */
3804void 3772void
3805ifq_init(struct ifqueue * const ifq, unsigned int maxqlen) 3773ifq_init(struct ifqueue * const ifq, unsigned int maxqlen)
3806{ 3774{
3807#ifdef ALTQ 3775#ifdef ALTQ
3808 /* 3776 /*
3809 * ALTQ data can be allocated via IFQ_SET_READY() which 3777 * ALTQ data can be allocated via IFQ_SET_READY() which
3810 * can be called before if_initialize(), which in turn 3778 * can be called before if_initialize(), which in turn
3811 * calls ifq_init(). Preserve it. 3779 * calls ifq_init(). Preserve it.
3812 */ 3780 */
@@ -4391,69 +4359,131 @@ ifq_classify_packet(struct ifqueue * con @@ -4391,69 +4359,131 @@ ifq_classify_packet(struct ifqueue * con
4391 (m)->m_pkthdr.pattr_class = 4359 (m)->m_pkthdr.pattr_class =
4392 (*altq->altq_classify) 4360 (*altq->altq_classify)
4393 (altq->altq_clfier, m, af); 4361 (altq->altq_clfier, m, af);
4394 } 4362 }
4395 m->m_pkthdr.pattr_af = af; 4363 m->m_pkthdr.pattr_af = af;
4396 m->m_pkthdr.pattr_hdr = mtod(m, void *); 4364 m->m_pkthdr.pattr_hdr = mtod(m, void *);
4397 } 4365 }
4398 KERNEL_UNLOCK_ONE(NULL); 4366 KERNEL_UNLOCK_ONE(NULL);
4399 } 4367 }
4400 mutex_exit((ifq)->ifq_lock); 4368 mutex_exit((ifq)->ifq_lock);
4401#endif /* ALTQ */ 4369#endif /* ALTQ */
4402} 4370}
4403 4371
4404#ifdef ALTQ 
4405static void 4372static void
4406ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1) 4373if_transmit_tail(struct ifnet *ifp, size_t pktlen, bool mcast)
4407{ 4374{
4408 KASSERT(ifq0 != ifq1); 4375 const int s = splnet(); /* XXX */
4409 if (ifq0 < ifq1) { 4376
4410 mutex_enter(ifq0->ifq_lock); 4377 net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
4411 mutex_enter(ifq1->ifq_lock); 4378 if_statadd_ref(nsr, if_obytes, pktlen);
4412 } else { 4379 if (mcast)
4413 mutex_enter(ifq1->ifq_lock); 4380 if_statinc_ref(nsr, if_omcasts);
4414 mutex_enter(ifq0->ifq_lock); 4381 IF_STAT_PUTREF(ifp);
 4382
 4383 if ((ifp->if_flags & IFF_OACTIVE) == 0)
 4384 if_start_lock(ifp);
 4385
 4386 splx(s);
 4387}
 4388
 4389/*
 4390 * wrapper function for the drivers which doesn't have if_transmit().
 4391 */
 4392static int
 4393if_transmit_default(struct ifnet *ifp, struct mbuf *m)
 4394{
 4395 int error;
 4396 size_t pktlen = m->m_pkthdr.len;
 4397 bool mcast = (m->m_flags & M_MCAST) != 0;
 4398
 4399 error = ifq_put(&ifp->if_snd, m);
 4400 if (error == 0) {
 4401 if_transmit_tail(ifp, pktlen, mcast);
4415 } 4402 }
 4403
 4404 return error;
4416} 4405}
4417#endif /* ALTQ */ 
4418 4406
4419/* 4407/*
4420 * Queue message on interface, and start output if interface 4408 * Queue message on interface, and start output if interface
4421 * not yet active. 4409 * not yet active.
4422 */ 4410 */
4423int 4411int
4424if_enqueue(struct ifnet *ifp, struct mbuf *m) 4412if_enqueue(struct ifnet *ifp, struct mbuf *m)
4425{ 4413{
4426 int error; 
4427 
4428 kmsan_check_mbuf(m); 4414 kmsan_check_mbuf(m);
4429 4415
4430#ifdef ALTQ 4416#ifdef ALTQ
4431 KERNEL_LOCK(1, NULL); 4417 mutex_enter(ifp->if_snd.ifq_lock);
4432 if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 4418 if (__predict_false(ALTQ_IS_ENABLED(&ifp->if_snd))) {
4433 error = if_transmit(ifp, m); 4419 size_t pktlen = m->m_pkthdr.len;
4434 KERNEL_UNLOCK_ONE(NULL); 4420 bool mcast = (m->m_flags & M_MCAST) != 0;
4435 } else { 4421 int error;
 4422
 4423 /*
 4424 * All of this amounts to an elaborate ifq_put_slow()
 4425 * that kicks the output queue.
 4426 */
 4427
 4428 mutex_exit(ifp->if_snd.ifq_lock);
 4429 KERNEL_LOCK(1, NULL);
 4430 mutex_enter(ifp->if_snd.ifq_lock);
 4431 if (__predict_true(ALTQ_IS_ENABLED(&ifp->if_snd))) {
 4432 ALTQ_ENQUEUE(&ifp->if_snd, m, error);
 4433 KERNEL_UNLOCK_ONE(NULL);
 4434 goto finish;
 4435 }
4436 KERNEL_UNLOCK_ONE(NULL); 4436 KERNEL_UNLOCK_ONE(NULL);
4437 error = (*ifp->if_transmit)(ifp, m); 4437
4438 /* mbuf is already freed */ 4438 if (__predict_true(ifp->if_transmit == if_transmit_default)) {
 4439 if (__predict_false(IF_QFULL(&ifp->if_snd))) {
 4440 error = ENOBUFS;
 4441 } else {
 4442 IF_ENQUEUE(&ifp->if_snd, m);
 4443 error = 0;
 4444 }
 4445 finish:
 4446 if (__predict_false(error != 0)) {
 4447 ifp->if_snd.ifq_drops++;
 4448 mutex_exit(ifp->if_snd.ifq_lock);
 4449 m_freem(m);
 4450 return error;
 4451 }
 4452 mutex_exit(ifp->if_snd.ifq_lock);
 4453 if_transmit_tail(ifp, pktlen, mcast);
 4454 return 0;
 4455 }
4439 } 4456 }
4440#else /* !ALTQ */ 4457 mutex_exit(ifp->if_snd.ifq_lock);
4441 error = (*ifp->if_transmit)(ifp, m); 4458#endif /* ALTQ */
4442 /* mbuf is already freed */ 
4443#endif /* !ALTQ */ 
4444 4459
4445 return error; 4460 return (*ifp->if_transmit)(ifp, m);
 4461}
 4462
 4463#ifdef ALTQ
 4464static void
 4465ifq_lock2(struct ifqueue * const ifq0, struct ifqueue * const ifq1)
 4466{
 4467 KASSERT(ifq0 != ifq1);
 4468 if (ifq0 < ifq1) {
 4469 mutex_enter(ifq0->ifq_lock);
 4470 mutex_enter(ifq1->ifq_lock);
 4471 } else {
 4472 mutex_enter(ifq1->ifq_lock);
 4473 mutex_enter(ifq0->ifq_lock);
 4474 }
4446} 4475}
 4476#endif /* ALTQ */
4447 4477
4448/* 4478/*
4449 * Queue message on interface, possibly using a second fast queue 4479 * Queue message on interface, possibly using a second fast queue
4450 * 4480 *
4451 * N.B. Unlike ifq_enqueue(), this does *not* start transmission on 4481 * N.B. Unlike ifq_enqueue(), this does *not* start transmission on
4452 * the interface. 4482 * the interface.
4453 */ 4483 */
4454int 4484int
4455if_enqueue2(struct ifnet *ifp, struct ifqueue *ifq, struct mbuf *m) 4485if_enqueue2(struct ifnet *ifp, struct ifqueue *ifq, struct mbuf *m)
4456{ 4486{
4457 struct ifqueue * const ifq0 = &ifp->if_snd; 4487 struct ifqueue * const ifq0 = &ifp->if_snd;
4458 int error = 0; 4488 int error = 0;
4459 4489