diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-09 13:04:41 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-21 10:29:37 +0200 |
commit | e4a8065910cd6b2e7e0448cc6431ca2906322389 (patch) | |
tree | 73492991cfa40f994c20d761d476e6bc16304536 /freebsd/sys/net | |
parent | Update to FreeBSD head 2017-08-01 (diff) | |
download | rtems-libbsd-e4a8065910cd6b2e7e0448cc6431ca2906322389.tar.bz2 |
Update to FreeBSD head 2017-10-01
Git mirror commit b2f0376b45428f13151d229c5ae9d4d8f74acbd1.
Update #3472.
Diffstat (limited to 'freebsd/sys/net')
-rw-r--r-- | freebsd/sys/net/bpf.c | 10 | ||||
-rw-r--r-- | freebsd/sys/net/ieee8023ad_lacp.c | 6 | ||||
-rw-r--r-- | freebsd/sys/net/if.c | 2 | ||||
-rw-r--r-- | freebsd/sys/net/if_bridge.c | 1 | ||||
-rw-r--r-- | freebsd/sys/net/if_enc.c | 49 | ||||
-rw-r--r-- | freebsd/sys/net/if_var.h | 10 | ||||
-rw-r--r-- | freebsd/sys/net/if_vlan.c | 526 | ||||
-rw-r--r-- | freebsd/sys/net/iflib.h | 9 | ||||
-rw-r--r-- | freebsd/sys/net/route.h | 12 |
9 files changed, 413 insertions, 212 deletions
diff --git a/freebsd/sys/net/bpf.c b/freebsd/sys/net/bpf.c index b0ecb039..cd8d34d7 100644 --- a/freebsd/sys/net/bpf.c +++ b/freebsd/sys/net/bpf.c @@ -113,6 +113,7 @@ struct bpf_if { struct rwlock bif_lock; /* interface lock */ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */ int bif_flags; /* Interface flags */ + struct bpf_if **bif_bpf; /* Pointer to pointer to us */ }; CTASSERT(offsetof(struct bpf_if, bif_ext) == 0); @@ -2658,6 +2659,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) bp->bif_dlt = dlt; rw_init(&bp->bif_lock, "bpf interface lock"); KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); + bp->bif_bpf = driverp; *driverp = bp; BPF_LOCK(); @@ -2728,6 +2730,7 @@ bpfdetach(struct ifnet *ifp) */ BPFIF_WLOCK(bp); bp->bif_flags |= BPFIF_FLAG_DYING; + *bp->bif_bpf = NULL; BPFIF_WUNLOCK(bp); CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p", @@ -2797,13 +2800,6 @@ bpf_ifdetach(void *arg __unused, struct ifnet *ifp) nmatched++; } BPF_UNLOCK(); - - /* - * Note that we cannot zero other pointers to - * custom DLTs possibly used by given interface. - */ - if (nmatched != 0) - ifp->if_bpf = NULL; } /* diff --git a/freebsd/sys/net/ieee8023ad_lacp.c b/freebsd/sys/net/ieee8023ad_lacp.c index fefe2a1f..d3fb457e 100644 --- a/freebsd/sys/net/ieee8023ad_lacp.c +++ b/freebsd/sys/net/ieee8023ad_lacp.c @@ -465,7 +465,11 @@ lacp_linkstate(struct lagg_port *lgp) uint16_t old_key; bzero((char *)&ifmr, sizeof(ifmr)); - error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); + error = (*ifp->if_ioctl)(ifp, SIOCGIFXMEDIA, (caddr_t)&ifmr); + if (error != 0) { + bzero((char *)&ifmr, sizeof(ifmr)); + error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); + } if (error != 0) return; diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c index ecf9955a..00505706 100644 --- a/freebsd/sys/net/if.c +++ b/freebsd/sys/net/if.c @@ -2663,6 +2663,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) case SIOCGIFMEDIA: case SIOCGIFXMEDIA: case SIOCGIFGENERIC: + case SIOCGIFRSSKEY: + case SIOCGIFRSSHASH: if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); error = (*ifp->if_ioctl)(ifp, cmd, data); diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c index 5d258493..3499f3db 100644 --- a/freebsd/sys/net/if_bridge.c +++ b/freebsd/sys/net/if_bridge.c @@ -586,6 +586,7 @@ static moduledata_t bridge_mod = { }; DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(if_bridge, 1); MODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); /* diff --git a/freebsd/sys/net/if_enc.c b/freebsd/sys/net/if_enc.c index 2a0b17d3..5fc53b5e 100644 --- a/freebsd/sys/net/if_enc.c +++ b/freebsd/sys/net/if_enc.c @@ -101,9 +101,15 @@ static void enc_remove_hhooks(struct enc_softc *); static const char encname[] = "enc"; +#define IPSEC_ENC_AFTER_PFIL 0x04 /* * Before and after are relative to when we are stripping the * outer IP header. + * + * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing + * after PFIL hook execution. It might be useful when PFIL hook does + * some changes to the packet, e.g. address translation. If PFIL hook + * consumes mbuf, nothing will be captured. */ static VNET_DEFINE(int, filter_mask_in) = IPSEC_ENC_BEFORE; static VNET_DEFINE(int, bpf_mask_in) = IPSEC_ENC_BEFORE; @@ -196,6 +202,30 @@ enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return (0); } +static void +enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, + int32_t hhook_type, uint8_t enc, uint8_t af) +{ + struct enchdr hdr; + + if (hhook_type == HHOOK_TYPE_IPSEC_IN && + (enc & V_bpf_mask_in) == 0) + return; + else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && + (enc & V_bpf_mask_out) == 0) + return; + if (bpf_peers_present(ifp->if_bpf) == 0) + return; + hdr.af = af; + hdr.spi = sav->spi; + hdr.flags = 0; + if (sav->alg_enc != SADB_EALG_NONE) + hdr.flags |= M_CONF; + if (sav->alg_auth != SADB_AALG_NONE) + hdr.flags |= M_AUTH; + bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); +} + /* * One helper hook function is used by any hook points. * + from hhook_type we can determine the packet direction: @@ -208,7 +238,6 @@ static int enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, void *hdata, struct osd *hosd) { - struct enchdr hdr; struct ipsec_ctx_data *ctx; struct enc_softc *sc; struct ifnet *ifp, *rcvif; @@ -225,21 +254,7 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, if (ctx->af != hhook_id) return (EPFNOSUPPORT); - if (((hhook_type == HHOOK_TYPE_IPSEC_IN && - (ctx->enc & V_bpf_mask_in) != 0) || - (hhook_type == HHOOK_TYPE_IPSEC_OUT && - (ctx->enc & V_bpf_mask_out) != 0)) && - bpf_peers_present(ifp->if_bpf) != 0) { - hdr.af = ctx->af; - hdr.spi = ctx->sav->spi; - hdr.flags = 0; - if (ctx->sav->alg_enc != SADB_EALG_NONE) - hdr.flags |= M_CONF; - if (ctx->sav->alg_auth != SADB_AALG_NONE) - hdr.flags |= M_AUTH; - bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), *ctx->mp); - } - + enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); switch (hhook_type) { case HHOOK_TYPE_IPSEC_IN: if (ctx->enc == IPSEC_ENC_BEFORE) { @@ -292,6 +307,8 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, return (EACCES); } (*ctx->mp)->m_pkthdr.rcvif = rcvif; + enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, + IPSEC_ENC_AFTER_PFIL, ctx->af); return (0); } diff --git a/freebsd/sys/net/if_var.h b/freebsd/sys/net/if_var.h index b8e5e5b8..c2de24a7 100644 --- a/freebsd/sys/net/if_var.h +++ b/freebsd/sys/net/if_var.h @@ -183,7 +183,8 @@ struct if_encap_req { struct m_snd_tag; #define IF_SND_TAG_TYPE_RATE_LIMIT 0 -#define IF_SND_TAG_TYPE_MAX 1 +#define IF_SND_TAG_TYPE_UNLIMITED 1 +#define IF_SND_TAG_TYPE_MAX 2 struct if_snd_tag_alloc_header { uint32_t type; /* send tag type, see IF_SND_TAG_XXX */ @@ -198,19 +199,26 @@ struct if_snd_tag_alloc_rate_limit { struct if_snd_tag_rate_limit_params { uint64_t max_rate; /* in bytes/s */ + uint32_t queue_level; /* 0 (empty) .. 65535 (full) */ +#define IF_SND_QUEUE_LEVEL_MIN 0 +#define IF_SND_QUEUE_LEVEL_MAX 65535 + uint32_t reserved; /* padding */ }; union if_snd_tag_alloc_params { struct if_snd_tag_alloc_header hdr; struct if_snd_tag_alloc_rate_limit rate_limit; + struct if_snd_tag_alloc_rate_limit unlimited; }; union if_snd_tag_modify_params { struct if_snd_tag_rate_limit_params rate_limit; + struct if_snd_tag_rate_limit_params unlimited; }; union if_snd_tag_query_params { struct if_snd_tag_rate_limit_params rate_limit; + struct if_snd_tag_rate_limit_params unlimited; }; typedef int (if_snd_tag_alloc_t)(struct ifnet *, union if_snd_tag_alloc_params *, diff --git a/freebsd/sys/net/if_vlan.c b/freebsd/sys/net/if_vlan.c index daba2606..872b07ad 100644 --- a/freebsd/sys/net/if_vlan.c +++ b/freebsd/sys/net/if_vlan.c @@ -3,6 +3,7 @@ /*- * Copyright 1998 Massachusetts Institute of Technology * Copyright 2012 ADARA Networks, Inc. + * Copyright 2017 Dell EMC Isilon * * Portions of this software were developed by Robert N. M. Watson under * contract to ADARA Networks, Inc. @@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/sx.h> +#include <sys/taskqueue.h> #include <net/bpf.h> #include <net/ethernet.h> @@ -103,6 +105,53 @@ struct ifvlantrunk { int refcnt; }; +/* + * This macro provides a facility to iterate over every vlan on a trunk with + * the assumption that none will be added/removed during iteration. + */ +#ifdef VLAN_ARRAY +#define VLAN_FOREACH(_ifv, _trunk) \ + size_t _i; \ + for (_i = 0; _i < VLAN_ARRAY_SIZE; _i++) \ + if (((_ifv) = (_trunk)->vlans[_i]) != NULL) +#else /* VLAN_ARRAY */ +#define VLAN_FOREACH(_ifv, _trunk) \ + struct ifvlan *_next; \ + size_t _i; \ + for (_i = 0; _i < (1 << (_trunk)->hwidth); _i++) \ + LIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i], ifv_list, _next) +#endif /* VLAN_ARRAY */ + +/* + * This macro provides a facility to iterate over every vlan on a trunk while + * also modifying the number of vlans on the trunk. The iteration continues + * until some condition is met or there are no more vlans on the trunk. + */ +#ifdef VLAN_ARRAY +/* The VLAN_ARRAY case is simple -- just a for loop using the condition. */ +#define VLAN_FOREACH_UNTIL_SAFE(_ifv, _trunk, _cond) \ + size_t _i; \ + for (_i = 0; !(_cond) && _i < VLAN_ARRAY_SIZE; _i++) \ + if (((_ifv) = (_trunk)->vlans[_i])) +#else /* VLAN_ARRAY */ +/* + * The hash table case is more complicated. We allow for the hash table to be + * modified (i.e. vlans removed) while we are iterating over it. To allow for + * this we must restart the iteration every time we "touch" something during + * the iteration, since removal will resize the hash table and invalidate our + * current position. If acting on the touched element causes the trunk to be + * emptied, then iteration also stops. + */ +#define VLAN_FOREACH_UNTIL_SAFE(_ifv, _trunk, _cond) \ + size_t _i; \ + bool _touch = false; \ + for (_i = 0; \ + !(_cond) && _i < (1 << (_trunk)->hwidth); \ + _i = (_touch && ((_trunk) != NULL) ? 0 : _i + 1), _touch = false) \ + if (((_ifv) = LIST_FIRST(&(_trunk)->hash[_i])) != NULL && \ + (_touch = true)) +#endif /* VLAN_ARRAY */ + struct vlan_mc_entry { struct sockaddr_dl mc_addr; SLIST_ENTRY(vlan_mc_entry) mc_entries; @@ -125,6 +174,7 @@ struct ifvlan { uint16_t ifvm_vid; /* VLAN ID */ uint8_t ifvm_pcp; /* Priority Code Point (PCP). */ } ifv_mib; + struct task lladdr_task; SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; #ifndef VLAN_ARRAY LIST_ENTRY(ifvlan) ifv_list; @@ -175,33 +225,92 @@ static eventhandler_tag ifdetach_tag; static eventhandler_tag iflladdr_tag; /* - * We have a global mutex, that is used to serialize configuration - * changes and isn't used in normal packet delivery. + * if_vlan uses two module-level locks to allow concurrent modification of vlan + * interfaces and (mostly) allow for vlans to be destroyed while they are being + * used for tx/rx. To accomplish this in a way that has acceptable performance + * and cooperation with other parts of the network stack there is a + * non-sleepable rmlock(9) and an sx(9). Both locks are exclusively acquired + * when destroying a vlan interface, i.e. when the if_vlantrunk field of struct + * ifnet is de-allocated and NULL'd. Thus a reader holding either lock has a + * guarantee that the struct ifvlantrunk references a valid vlan trunk. * - * We also have a per-trunk rmlock(9), that is locked shared on packet - * processing and exclusive when configuration is changed. + * The performance-sensitive paths that warrant using the rmlock(9) are + * vlan_transmit and vlan_input. Both have to check for the vlan interface's + * existence using if_vlantrunk, and being in the network tx/rx paths the use + * of an rmlock(9) gives a measureable improvement in performance. + * + * The reason for having an sx(9) is mostly because there are still areas that + * must be sleepable and also have safe concurrent access to a vlan interface. + * Since the sx(9) exists, it is used by default in most paths unless sleeping + * is not permitted, or if it is not clear whether sleeping is permitted. * + * Note that despite these protections, there is still an inherent race in the + * destruction of vlans since there's no guarantee that the ifnet hasn't been + * freed/reused when the tx/rx functions are called by the stack. This can only + * be fixed by addressing ifnet's lifetime issues. + */ +#define _VLAN_RM_ID ifv_rm_lock +#define _VLAN_SX_ID ifv_sx + +static struct rmlock _VLAN_RM_ID; +static struct sx _VLAN_SX_ID; + +#define VLAN_LOCKING_INIT() \ + rm_init(&_VLAN_RM_ID, "vlan_rm"); \ + sx_init(&_VLAN_SX_ID, "vlan_sx") + +#define VLAN_LOCKING_DESTROY() \ + rm_destroy(&_VLAN_RM_ID); \ + sx_destroy(&_VLAN_SX_ID) + +#define _VLAN_RM_TRACKER _vlan_rm_tracker +#define VLAN_RLOCK() rm_rlock(&_VLAN_RM_ID, \ + &_VLAN_RM_TRACKER) +#define VLAN_RUNLOCK() rm_runlock(&_VLAN_RM_ID, \ + &_VLAN_RM_TRACKER) +#define VLAN_WLOCK() rm_wlock(&_VLAN_RM_ID) +#define VLAN_WUNLOCK() rm_wunlock(&_VLAN_RM_ID) +#define VLAN_RLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_RLOCKED) +#define VLAN_WLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_WLOCKED) +#define VLAN_RWLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_LOCKED) +#define VLAN_LOCK_READER struct rm_priotracker _VLAN_RM_TRACKER + +#define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) +#define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) +#define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) +#define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) +#define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) +#define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) +#define VLAN_SXLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_LOCKED) + + +/* + * We also have a per-trunk rmlock(9), that is locked shared on packet + * processing and exclusive when configuration is changed. Note: This should + * only be acquired while there is a shared lock on either of the global locks + * via VLAN_SLOCK or VLAN_RLOCK. Thus, an exclusive lock on the global locks + * makes a call to TRUNK_RLOCK/TRUNK_WLOCK technically superfluous. + */ +#define _TRUNK_RM_TRACKER _trunk_rm_tracker +#define TRUNK_LOCK_INIT(trunk) rm_init(&(trunk)->lock, vlanname) +#define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock) +#define TRUNK_RLOCK(trunk) rm_rlock(&(trunk)->lock, \ + &_TRUNK_RM_TRACKER) +#define TRUNK_WLOCK(trunk) rm_wlock(&(trunk)->lock) +#define TRUNK_RUNLOCK(trunk) rm_runlock(&(trunk)->lock, \ + &_TRUNK_RM_TRACKER) +#define TRUNK_WUNLOCK(trunk) rm_wunlock(&(trunk)->lock) +#define TRUNK_RLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED) +#define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_LOCKED) +#define TRUNK_WLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED) +#define TRUNK_LOCK_READER struct rm_priotracker _TRUNK_RM_TRACKER + +/* * The VLAN_ARRAY substitutes the dynamic hash with a static array * with 4096 entries. In theory this can give a boost in processing, - * however on practice it does not. Probably this is because array + * however in practice it does not. Probably this is because the array * is too big to fit into CPU cache. */ -static struct sx ifv_lock; -#define VLAN_LOCK_INIT() sx_init(&ifv_lock, "vlan_global") -#define VLAN_LOCK_DESTROY() sx_destroy(&ifv_lock) -#define VLAN_LOCK_ASSERT() sx_assert(&ifv_lock, SA_LOCKED) -#define VLAN_LOCK() sx_xlock(&ifv_lock) -#define VLAN_UNLOCK() sx_xunlock(&ifv_lock) -#define TRUNK_LOCK_INIT(trunk) rm_init(&(trunk)->lock, vlanname) -#define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock) -#define TRUNK_LOCK(trunk) rm_wlock(&(trunk)->lock) -#define TRUNK_UNLOCK(trunk) rm_wunlock(&(trunk)->lock) -#define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED) -#define TRUNK_RLOCK(trunk) rm_rlock(&(trunk)->lock, &tracker) -#define TRUNK_RUNLOCK(trunk) rm_runlock(&(trunk)->lock, &tracker) -#define TRUNK_LOCK_RASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED) -#define TRUNK_LOCK_READER struct rm_priotracker tracker - #ifndef VLAN_ARRAY static void vlan_inithash(struct ifvlantrunk *trunk); static void vlan_freehash(struct ifvlantrunk *trunk); @@ -241,6 +350,8 @@ static int vlan_clone_destroy(struct if_clone *, struct ifnet *); static void vlan_ifdetach(void *arg, struct ifnet *ifp); static void vlan_iflladdr(void *arg, struct ifnet *ifp); +static void vlan_lladdr_fn(void *arg, int pending); + static struct if_clone *vlan_cloner; #ifdef VIMAGE @@ -295,7 +406,7 @@ vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) int i, b; struct ifvlan *ifv2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; @@ -325,7 +436,7 @@ vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) int i, b; struct ifvlan *ifv2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; @@ -353,7 +464,7 @@ vlan_growhash(struct ifvlantrunk *trunk, int howmuch) struct ifvlanhead *hash2; int hwidth2, i, j, n, n2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); if (howmuch == 0) { @@ -399,7 +510,7 @@ vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid) { struct ifvlan *ifv; - TRUNK_LOCK_RASSERT(trunk); + TRUNK_RLOCK_ASSERT(trunk); LIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) if (ifv->ifv_vid == vid) @@ -469,12 +580,11 @@ vlan_inithash(struct ifvlantrunk *trunk) static void trunk_destroy(struct ifvlantrunk *trunk) { - VLAN_LOCK_ASSERT(); + VLAN_XLOCK_ASSERT(); + VLAN_WLOCK_ASSERT(); - TRUNK_LOCK(trunk); vlan_freehash(trunk); trunk->parent->if_vlantrunk = NULL; - TRUNK_UNLOCK(trunk); TRUNK_LOCK_DESTROY(trunk); if_rele(trunk->parent); free(trunk, M_VLAN); @@ -497,9 +607,15 @@ vlan_setmulti(struct ifnet *ifp) struct vlan_mc_entry *mc; int error; + /* + * XXX This stupidly needs the rmlock to avoid sleeping while holding + * the in6_multi_mtx (see in6_mc_join_locked). + */ + VLAN_RWLOCK_ASSERT(); + /* Find the parent. */ sc = ifp->if_softc; - TRUNK_LOCK_ASSERT(TRUNK(sc)); + TRUNK_WLOCK_ASSERT(TRUNK(sc)); ifp_p = PARENT(sc); CURVNET_SET_QUIET(ifp_p->if_vnet); @@ -546,36 +662,42 @@ static void vlan_iflladdr(void *arg __unused, struct ifnet *ifp) { struct ifvlan *ifv; -#ifndef VLAN_ARRAY - struct ifvlan *next; -#endif - int i; + struct ifnet *ifv_ifp; + struct ifvlantrunk *trunk; + struct sockaddr_dl *sdl; + VLAN_LOCK_READER; - /* - * Check if it's a trunk interface first of all - * to avoid needless locking. - */ - if (ifp->if_vlantrunk == NULL) + /* Need the rmlock since this is run on taskqueue_swi. */ + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); return; + } - VLAN_LOCK(); /* * OK, it's a trunk. Loop over and change all vlan's lladdrs on it. + * We need an exclusive lock here to prevent concurrent SIOCSIFLLADDR + * ioctl calls on the parent garbling the lladdr of the child vlan. */ -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if ((ifv = ifp->if_vlantrunk->vlans[i])) { -#else /* VLAN_ARRAY */ - for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) - LIST_FOREACH_SAFE(ifv, &ifp->if_vlantrunk->hash[i], ifv_list, next) { -#endif /* VLAN_ARRAY */ - VLAN_UNLOCK(); - if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp), - ifp->if_addrlen); - VLAN_LOCK(); - } - VLAN_UNLOCK(); - + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + /* + * Copy new new lladdr into the ifv_ifp, enqueue a task + * to actually call if_setlladdr. if_setlladdr needs to + * be deferred to a taskqueue because it will call into + * the if_vlan ioctl path and try to acquire the global + * lock. + */ + ifv_ifp = ifv->ifv_ifp; + bcopy(IF_LLADDR(ifp), IF_LLADDR(ifv_ifp), + ifp->if_addrlen); + sdl = (struct sockaddr_dl *)ifv_ifp->if_addr->ifa_addr; + sdl->sdl_alen = ifp->if_addrlen; + taskqueue_enqueue(taskqueue_thread, &ifv->lladdr_task); + } + TRUNK_WUNLOCK(trunk); + VLAN_RUNLOCK(); } /* @@ -589,46 +711,30 @@ static void vlan_ifdetach(void *arg __unused, struct ifnet *ifp) { struct ifvlan *ifv; - int i; - - /* - * Check if it's a trunk interface first of all - * to avoid needless locking. - */ - if (ifp->if_vlantrunk == NULL) - return; + struct ifvlantrunk *trunk; /* If the ifnet is just being renamed, don't do anything. */ if (ifp->if_flags & IFF_RENAMING) return; + VLAN_XLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_XUNLOCK(); + return; + } - VLAN_LOCK(); /* * OK, it's a trunk. Loop over and detach all vlan's on it. * Check trunk pointer after each vlan_unconfig() as it will * free it and set to NULL after the last vlan was detached. */ -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if ((ifv = ifp->if_vlantrunk->vlans[i])) { - vlan_unconfig_locked(ifv->ifv_ifp, 1); - if (ifp->if_vlantrunk == NULL) - break; - } -#else /* VLAN_ARRAY */ -restart: - for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) - if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) { - vlan_unconfig_locked(ifv->ifv_ifp, 1); - if (ifp->if_vlantrunk) - goto restart; /* trunk->hwidth can change */ - else - break; - } -#endif /* VLAN_ARRAY */ + VLAN_FOREACH_UNTIL_SAFE(ifv, ifp->if_vlantrunk, + ifp->if_vlantrunk == NULL) + vlan_unconfig_locked(ifv->ifv_ifp, 1); + /* Trunk should have been destroyed in vlan_unconfig(). */ KASSERT(ifp->if_vlantrunk == NULL, ("%s: purge failed", __func__)); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); } /* @@ -638,15 +744,18 @@ static struct ifnet * vlan_trunkdev(struct ifnet *ifp) { struct ifvlan *ifv; + VLAN_LOCK_READER; if (ifp->if_type != IFT_L2VLAN) return (NULL); + + /* Not clear if callers are sleepable, so acquire the rmlock. */ + VLAN_RLOCK(); ifv = ifp->if_softc; ifp = NULL; - VLAN_LOCK(); if (ifv->ifv_trunk) ifp = PARENT(ifv); - VLAN_UNLOCK(); + VLAN_RUNLOCK(); return (ifp); } @@ -708,17 +817,23 @@ vlan_devat(struct ifnet *ifp, uint16_t vid) { struct ifvlantrunk *trunk; struct ifvlan *ifv; + VLAN_LOCK_READER; TRUNK_LOCK_READER; + /* Not clear if callers are sleepable, so acquire the rmlock. */ + VLAN_RLOCK(); trunk = ifp->if_vlantrunk; - if (trunk == NULL) + if (trunk == NULL) { + VLAN_RUNLOCK(); return (NULL); + } ifp = NULL; TRUNK_RLOCK(trunk); ifv = vlan_gethash(trunk, vid); if (ifv) ifp = ifv->ifv_ifp; TRUNK_RUNLOCK(trunk); + VLAN_RUNLOCK(); return (ifp); } @@ -758,7 +873,7 @@ vlan_modevent(module_t mod, int type, void *data) vlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY); if (iflladdr_tag == NULL) return (ENOMEM); - VLAN_LOCK_INIT(); + VLAN_LOCKING_INIT(); vlan_input_p = vlan_input; vlan_link_state_p = vlan_link_state; vlan_trunk_cap_p = vlan_trunk_capabilities; @@ -795,7 +910,7 @@ vlan_modevent(module_t mod, int type, void *data) vlan_cookie_p = NULL; vlan_setcookie_p = NULL; vlan_devat_p = NULL; - VLAN_LOCK_DESTROY(); + VLAN_LOCKING_DESTROY(); if (bootverbose) printf("vlan: unloaded\n"); break; @@ -1016,9 +1131,6 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) return (error); } - - /* Update flags on the parent, if necessary. */ - vlan_setflags(ifp, 1); } return (0); @@ -1032,6 +1144,12 @@ vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) ether_ifdetach(ifp); /* first, remove it from system-wide lists */ vlan_unconfig(ifp); /* now it can be unconfigured and freed */ + /* + * We should have the only reference to the ifv now, so we can now + * drain any remaining lladdr task before freeing the ifnet and the + * ifvlan. + */ + taskqueue_drain(taskqueue_thread, &ifv->lladdr_task); if_free(ifp); free(ifv, M_VLAN); ifc_free_unit(ifc, unit); @@ -1058,8 +1176,16 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) struct m_tag *mtag; uint16_t tag; int error, len, mcast; + VLAN_LOCK_READER; + VLAN_RLOCK(); ifv = ifp->if_softc; + if (TRUNK(ifv) == NULL) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); + return (ENETDOWN); + } p = PARENT(ifv); len = m->m_pkthdr.len; mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; @@ -1071,8 +1197,9 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) * or parent's driver will cause a system crash. */ if (!UP_AND_RUNNING(p)) { - m_freem(m); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); return (ENETDOWN); } @@ -1100,6 +1227,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if (n > 0) { if_printf(ifp, "cannot pad short frame\n"); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); m_freem(m); return (0); } @@ -1125,6 +1253,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if (m == NULL) { if_printf(ifp, "unable to prepend VLAN header\n"); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); return (0); } } @@ -1139,6 +1268,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast); } else if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); return (error); } @@ -1153,13 +1283,20 @@ vlan_qflush(struct ifnet *ifp __unused) static void vlan_input(struct ifnet *ifp, struct mbuf *m) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; + VLAN_LOCK_READER; TRUNK_LOCK_READER; struct m_tag *mtag; uint16_t vid, tag; - KASSERT(trunk != NULL, ("%s: no trunk", __func__)); + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); + m_freem(m); + return; + } if (m->m_flags & M_VLANTAG) { /* @@ -1179,6 +1316,7 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) if (m->m_len < sizeof(*evl) && (m = m_pullup(m, sizeof(*evl))) == NULL) { if_printf(ifp, "cannot pullup VLAN header\n"); + VLAN_RUNLOCK(); return; } evl = mtod(m, struct ether_vlan_header *); @@ -1200,8 +1338,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) panic("%s: %s has unsupported if_type %u", __func__, ifp->if_xname, ifp->if_type); #endif - m_freem(m); if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } } @@ -1212,8 +1351,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) ifv = vlan_gethash(trunk, vid); if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { TRUNK_RUNLOCK(trunk); - m_freem(m); if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } TRUNK_RUNLOCK(trunk); @@ -1231,8 +1371,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN, sizeof(uint8_t), M_NOWAIT); if (mtag == NULL) { - m_freem(m); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } m_tag_prepend(m, mtag); @@ -1242,9 +1383,22 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) m->m_pkthdr.rcvif = ifv->ifv_ifp; if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1); + VLAN_RUNLOCK(); /* Pass it back through the parent's input routine. */ - (*ifp->if_input)(ifv->ifv_ifp, m); + (*ifv->ifv_ifp->if_input)(ifv->ifv_ifp, m); +} + +static void +vlan_lladdr_fn(void *arg, int pending __unused) +{ + struct ifvlan *ifv; + struct ifnet *ifp; + + ifv = (struct ifvlan *)arg; + ifp = ifv->ifv_ifp; + /* The ifv_ifp already has the lladdr copied in. */ + if_setlladdr(ifp, IF_LLADDR(ifp), ifp->if_addrlen); } static int @@ -1273,27 +1427,22 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) if (ifv->ifv_trunk) return (EBUSY); + /* Acquire rmlock after the branch so we can M_WAITOK. */ + VLAN_XLOCK(); if (p->if_vlantrunk == NULL) { trunk = malloc(sizeof(struct ifvlantrunk), M_VLAN, M_WAITOK | M_ZERO); vlan_inithash(trunk); - VLAN_LOCK(); - if (p->if_vlantrunk != NULL) { - /* A race that is very unlikely to be hit. */ - vlan_freehash(trunk); - free(trunk, M_VLAN); - goto exists; - } TRUNK_LOCK_INIT(trunk); - TRUNK_LOCK(trunk); + VLAN_WLOCK(); + TRUNK_WLOCK(trunk); p->if_vlantrunk = trunk; trunk->parent = p; if_ref(trunk->parent); } else { - VLAN_LOCK(); -exists: + VLAN_WLOCK(); trunk = p->if_vlantrunk; - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); } ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ @@ -1370,15 +1519,25 @@ exists: * Configure multicast addresses that may already be * joined on the vlan device. */ - (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ + (void)vlan_setmulti(ifp); + + TASK_INIT(&ifv->lladdr_task, 0, vlan_lladdr_fn, ifv); /* We are ready for operation now. */ ifp->if_drv_flags |= IFF_DRV_RUNNING; + + /* Update flags on the parent, if necessary. */ + vlan_setflags(ifp, 1); done: - TRUNK_UNLOCK(trunk); + /* + * We need to drop the non-sleepable rmlock so that the underlying + * devices can sleep in their vlan_config hooks. + */ + TRUNK_WUNLOCK(trunk); + VLAN_WUNLOCK(); if (error == 0) EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_vid); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); return (error); } @@ -1387,9 +1546,9 @@ static void vlan_unconfig(struct ifnet *ifp) { - VLAN_LOCK(); + VLAN_XLOCK(); vlan_unconfig_locked(ifp, 0); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); } static void @@ -1401,15 +1560,20 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) struct ifnet *parent; int error; - VLAN_LOCK_ASSERT(); + VLAN_XLOCK_ASSERT(); ifv = ifp->if_softc; trunk = ifv->ifv_trunk; parent = NULL; if (trunk != NULL) { - - TRUNK_LOCK(trunk); + /* + * Both vlan_transmit and vlan_input rely on the trunk fields + * being NULL to determine whether to bail, so we need to get + * an exclusive lock here to prevent them from using bad + * ifvlans. + */ + VLAN_WLOCK(); parent = trunk->parent; /* @@ -1439,7 +1603,14 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) } vlan_setflags(ifp, 0); /* clear special flags on parent */ + + /* + * The trunk lock isn't actually required here, but + * vlan_remhash expects it. + */ + TRUNK_WLOCK(trunk); vlan_remhash(trunk, ifv); + TRUNK_WUNLOCK(trunk); ifv->ifv_trunk = NULL; /* @@ -1447,17 +1618,9 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) */ if (trunk->refcnt == 0) { parent->if_vlantrunk = NULL; - /* - * XXXGL: If some ithread has already entered - * vlan_input() and is now blocked on the trunk - * lock, then it should preempt us right after - * unlock and finish its work. Then we will acquire - * lock again in trunk_destroy(). - */ - TRUNK_UNLOCK(trunk); trunk_destroy(trunk); - } else - TRUNK_UNLOCK(trunk); + } + VLAN_WUNLOCK(); } /* Disconnect from parent. */ @@ -1484,7 +1647,7 @@ vlan_setflag(struct ifnet *ifp, int flag, int status, struct ifvlan *ifv; int error; - /* XXX VLAN_LOCK_ASSERT(); */ + VLAN_SXLOCK_ASSERT(); ifv = ifp->if_softc; status = status ? (ifp->if_flags & flag) : 0; @@ -1532,36 +1695,41 @@ vlan_setflags(struct ifnet *ifp, int status) static void vlan_link_state(struct ifnet *ifp) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; - int i; + VLAN_LOCK_READER; - TRUNK_LOCK(trunk); -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if (trunk->vlans[i] != NULL) { - ifv = trunk->vlans[i]; -#else - for (i = 0; i < (1 << trunk->hwidth); i++) - LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) { -#endif - ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; - if_link_state_change(ifv->ifv_ifp, - trunk->parent->if_link_state); - } - TRUNK_UNLOCK(trunk); + /* Called from a taskqueue_swi task, so we cannot sleep. */ + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); + return; + } + + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; + if_link_state_change(ifv->ifv_ifp, + trunk->parent->if_link_state); + } + TRUNK_WUNLOCK(trunk); + VLAN_RUNLOCK(); } static void vlan_capabilities(struct ifvlan *ifv) { - struct ifnet *p = PARENT(ifv); - struct ifnet *ifp = ifv->ifv_ifp; + struct ifnet *p; + struct ifnet *ifp; struct ifnet_hw_tsomax hw_tsomax; int cap = 0, ena = 0, mena; u_long hwa = 0; - TRUNK_LOCK_ASSERT(TRUNK(ifv)); + VLAN_SXLOCK_ASSERT(); + TRUNK_WLOCK_ASSERT(TRUNK(ifv)); + p = PARENT(ifv); + ifp = ifv->ifv_ifp; /* Mask parent interface enabled capabilities disabled by user. */ mena = p->if_capenable & ifv->ifv_capenable; @@ -1651,22 +1819,21 @@ vlan_capabilities(struct ifvlan *ifv) static void vlan_trunk_capabilities(struct ifnet *ifp) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; - int i; - TRUNK_LOCK(trunk); -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if (trunk->vlans[i] != NULL) { - ifv = trunk->vlans[i]; -#else - for (i = 0; i < (1 << trunk->hwidth); i++) { - LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) -#endif - vlan_capabilities(ifv); + VLAN_SLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_SUNLOCK(); + return; + } + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + vlan_capabilities(ifv); } - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); + VLAN_SUNLOCK(); } static int @@ -1679,6 +1846,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifvlantrunk *trunk; struct vlanreq vlr; int error = 0; + VLAN_LOCK_READER; ifr = (struct ifreq *)data; ifa = (struct ifaddr *) data; @@ -1701,11 +1869,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } break; case SIOCGIFMEDIA: - VLAN_LOCK(); + VLAN_SLOCK(); if (TRUNK(ifv) != NULL) { p = PARENT(ifv); if_ref(p); - VLAN_UNLOCK(); error = (*p->if_ioctl)(p, SIOCGIFMEDIA, data); if_rele(p); /* Limit the result to the parent's current config. */ @@ -1721,9 +1888,9 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } } } else { - VLAN_UNLOCK(); error = EINVAL; } + VLAN_SUNLOCK(); break; case SIOCSIFMEDIA: @@ -1734,8 +1901,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) /* * Set the interface MTU. */ - VLAN_LOCK(); - if (TRUNK(ifv) != NULL) { + VLAN_SLOCK(); + trunk = TRUNK(ifv); + if (trunk != NULL) { + TRUNK_WLOCK(trunk); if (ifr->ifr_mtu > (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) || ifr->ifr_mtu < @@ -1743,9 +1912,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = EINVAL; else ifp->if_mtu = ifr->ifr_mtu; + TRUNK_WUNLOCK(trunk); } else error = EINVAL; - VLAN_UNLOCK(); + VLAN_SUNLOCK(); break; case SIOCSETVLAN: @@ -1776,11 +1946,6 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } error = vlan_config(ifv, p, vlr.vlr_tag); if_rele(p); - if (error) - break; - - /* Update flags on the parent, if necessary. */ - vlan_setflags(ifp, 1); break; case SIOCGETVLAN: @@ -1791,13 +1956,13 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } #endif bzero(&vlr, sizeof(vlr)); - VLAN_LOCK(); + VLAN_SLOCK(); if (TRUNK(ifv) != NULL) { strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, sizeof(vlr.vlr_parent)); vlr.vlr_tag = ifv->ifv_vid; } - VLAN_UNLOCK(); + VLAN_SUNLOCK(); error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); break; @@ -1806,8 +1971,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) * We should propagate selected flags to the parent, * e.g., promiscuous mode. */ + VLAN_XLOCK(); if (TRUNK(ifv) != NULL) error = vlan_setflags(ifp, 1); + VLAN_XUNLOCK(); break; case SIOCADDMULTI: @@ -1815,13 +1982,18 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) /* * If we don't have a parent, just remember the membership for * when we do. + * + * XXX We need the rmlock here to avoid sleeping while + * holding in6_multi_mtx. */ + VLAN_RLOCK(); trunk = TRUNK(ifv); if (trunk != NULL) { - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); error = vlan_setmulti(ifp); - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); } + VLAN_RUNLOCK(); break; case SIOCGVLANPCP: @@ -1853,15 +2025,15 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSIFCAP: - VLAN_LOCK(); + VLAN_SLOCK(); ifv->ifv_capenable = ifr->ifr_reqcap; trunk = TRUNK(ifv); if (trunk != NULL) { - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); vlan_capabilities(ifv); - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); } - VLAN_UNLOCK(); + VLAN_SUNLOCK(); break; default: diff --git a/freebsd/sys/net/iflib.h b/freebsd/sys/net/iflib.h index 6ac75dbb..7249686b 100644 --- a/freebsd/sys/net/iflib.h +++ b/freebsd/sys/net/iflib.h @@ -173,6 +173,11 @@ typedef struct pci_vendor_info { #define PVID_OEM(vendor, devid, svid, sdevid, revid, name) {vendor, devid, svid, sdevid, revid, 0, name} #define PVID_END {0, 0, 0, 0, 0, 0, NULL} +#define IFLIB_PNP_DESCR "U32:vendor;U32:device;U32:subvendor;U32:subdevice;" \ + "U32:revision;U32:class;D:human" +#define IFLIB_PNP_INFO(b, u, t) \ + MODULE_PNP_INFO(IFLIB_PNP_DESCR, b, u, t, sizeof(t[0]), nitems(t)) + typedef struct if_txrx { int (*ift_txd_encap) (void *, if_pkt_info_t); void (*ift_txd_flush) (void *, uint16_t, qidx_t pidx); @@ -305,6 +310,10 @@ typedef enum { * Interface doesn't align IP header */ #define IFLIB_DO_RX_FIXUP 0x40 +/* + * Driver needs csum zeroed for offloading + */ +#define IFLIB_NEED_ZERO_CSUM 0x80 diff --git a/freebsd/sys/net/route.h b/freebsd/sys/net/route.h index 444559b5..ae052f19 100644 --- a/freebsd/sys/net/route.h +++ b/freebsd/sys/net/route.h @@ -67,8 +67,6 @@ struct route { #define RT_MAY_LOOP_BIT 3 /* dst may require loop copy */ #define RT_HAS_HEADER_BIT 4 /* mbuf already have its header prepended */ -#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */ -#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */ #define RT_L2_ME (1 << RT_L2_ME_BIT) /* 0x0004 */ #define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) /* 0x0008 */ #define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) /* 0x0010 */ @@ -411,14 +409,8 @@ struct rt_addrinfo { #define RO_RTFREE(_ro) do { \ if ((_ro)->ro_rt) { \ - if ((_ro)->ro_flags & RT_NORTREF) { \ - (_ro)->ro_flags &= ~RT_NORTREF; \ - (_ro)->ro_rt = NULL; \ - (_ro)->ro_lle = NULL; \ - } else { \ - RT_LOCK((_ro)->ro_rt); \ - RTFREE_LOCKED((_ro)->ro_rt); \ - } \ + RT_LOCK((_ro)->ro_rt); \ + RTFREE_LOCKED((_ro)->ro_rt); \ } \ } while (0) |