summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-09 13:04:41 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:37 +0200
commite4a8065910cd6b2e7e0448cc6431ca2906322389 (patch)
tree73492991cfa40f994c20d761d476e6bc16304536 /freebsd/sys/net
parentUpdate to FreeBSD head 2017-08-01 (diff)
downloadrtems-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.c10
-rw-r--r--freebsd/sys/net/ieee8023ad_lacp.c6
-rw-r--r--freebsd/sys/net/if.c2
-rw-r--r--freebsd/sys/net/if_bridge.c1
-rw-r--r--freebsd/sys/net/if_enc.c49
-rw-r--r--freebsd/sys/net/if_var.h10
-rw-r--r--freebsd/sys/net/if_vlan.c526
-rw-r--r--freebsd/sys/net/iflib.h9
-rw-r--r--freebsd/sys/net/route.h12
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)