Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_vlan.c
Show First 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | |||||
extern int vlan_mtag_pcp; | extern int vlan_mtag_pcp; | ||||
static const char vlanname[] = "vlan"; | static const char vlanname[] = "vlan"; | ||||
static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface"); | static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface"); | ||||
static eventhandler_tag ifdetach_tag; | static eventhandler_tag ifdetach_tag; | ||||
static eventhandler_tag iflladdr_tag; | static eventhandler_tag iflladdr_tag; | ||||
/* | /* | ||||
* if_vlan uses two module-level locks to allow concurrent modification of vlan | * if_vlan uses two module-level synchronizations primitives to allow concurrent | ||||
shurd: This comment needs to be updated. | |||||
* interfaces and (mostly) allow for vlans to be destroyed while they are being | * modification of vlan interfaces and (mostly) allow for vlans to be destroyed | ||||
* used for tx/rx. To accomplish this in a way that has acceptable performance | * while they are being used for tx/rx. To accomplish this in a way that has | ||||
* and cooperation with other parts of the network stack there is a | * acceptable performance and cooperation with other parts of the network stack | ||||
* non-sleepable rmlock(9) and an sx(9). Both locks are exclusively acquired | * there is a non-sleepable epoch(9) and an sx(9). | ||||
* 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. | |||||
* | * | ||||
* The performance-sensitive paths that warrant using the rmlock(9) are | * The performance-sensitive paths that warrant using the epoch(9) are | ||||
* vlan_transmit and vlan_input. Both have to check for the vlan interface's | * 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 | * existence using if_vlantrunk, and being in the network tx/rx paths the use | ||||
* of an rmlock(9) gives a measureable improvement in performance. | * of an epoch(9) gives a measureable improvement in performance. | ||||
* | * | ||||
* The reason for having an sx(9) is mostly because there are still areas that | * 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. | * 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 | * 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. | * 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_SX_ID ifv_sx | #define _VLAN_SX_ID ifv_sx | ||||
static struct sx _VLAN_SX_ID; | static struct sx _VLAN_SX_ID; | ||||
#define VLAN_LOCKING_INIT() \ | #define VLAN_LOCKING_INIT() \ | ||||
sx_init(&_VLAN_SX_ID, "vlan_sx") | sx_init(&_VLAN_SX_ID, "vlan_sx") | ||||
#define VLAN_LOCKING_DESTROY() \ | #define VLAN_LOCKING_DESTROY() \ | ||||
sx_destroy(&_VLAN_SX_ID) | sx_destroy(&_VLAN_SX_ID) | ||||
#define VLAN_RLOCK() NET_EPOCH_ENTER(); | #define VLAN_RLOCK() NET_EPOCH_ENTER(); | ||||
#define VLAN_RUNLOCK() NET_EPOCH_EXIT(); | #define VLAN_RUNLOCK() NET_EPOCH_EXIT(); | ||||
#define VLAN_RLOCK_ASSERT() MPASS(in_epoch(net_epoch_preempt)) | #define VLAN_RLOCK_ASSERT() MPASS(in_epoch(net_epoch_preempt)) | ||||
#define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) | #define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) | ||||
#define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) | #define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) | ||||
#define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) | #define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) | ||||
#define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) | #define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) | ||||
#define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) | #define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) | ||||
#define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) | #define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) | ||||
#define VLAN_SXLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_LOCKED) | #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 | * We also have a per-trunk mutex that should be acquired when changing | ||||
Not Done Inline ActionsThis comment also appears to be incorrect now. shurd: This comment also appears to be incorrect now. | |||||
* processing and exclusive when configuration is changed. Note: This should | * its state. | ||||
* 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_LOCK_INIT(trunk) mtx_init(&(trunk)->lock, vlanname, NULL, MTX_DEF) | #define TRUNK_LOCK_INIT(trunk) mtx_init(&(trunk)->lock, vlanname, NULL, MTX_DEF) | ||||
#define TRUNK_LOCK_DESTROY(trunk) mtx_destroy(&(trunk)->lock) | #define TRUNK_LOCK_DESTROY(trunk) mtx_destroy(&(trunk)->lock) | ||||
#define TRUNK_RLOCK(trunk) NET_EPOCH_ENTER() | #define TRUNK_RLOCK(trunk) NET_EPOCH_ENTER() | ||||
#define TRUNK_WLOCK(trunk) mtx_lock(&(trunk)->lock) | #define TRUNK_WLOCK(trunk) mtx_lock(&(trunk)->lock) | ||||
#define TRUNK_RUNLOCK(trunk) NET_EPOCH_EXIT(); | #define TRUNK_RUNLOCK(trunk) NET_EPOCH_EXIT(); | ||||
#define TRUNK_WUNLOCK(trunk) mtx_unlock(&(trunk)->lock) | #define TRUNK_WUNLOCK(trunk) mtx_unlock(&(trunk)->lock) | ||||
#define TRUNK_RLOCK_ASSERT(trunk) MPASS(in_epoch(net_epoch_preempt)) | #define TRUNK_RLOCK_ASSERT(trunk) MPASS(in_epoch(net_epoch_preempt)) | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) | vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) | ||||
{ | { | ||||
int i, b; | int i, b; | ||||
struct ifvlan *ifv2; | struct ifvlan *ifv2; | ||||
TRUNK_WLOCK_ASSERT(trunk); | VLAN_XLOCK_ASSERT(); | ||||
KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | ||||
b = 1 << trunk->hwidth; | b = 1 << trunk->hwidth; | ||||
i = HASH(ifv->ifv_vid, trunk->hmask); | i = HASH(ifv->ifv_vid, trunk->hmask); | ||||
CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) | CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) | ||||
if (ifv->ifv_vid == ifv2->ifv_vid) | if (ifv->ifv_vid == ifv2->ifv_vid) | ||||
return (EEXIST); | return (EEXIST); | ||||
Show All 13 Lines | |||||
} | } | ||||
static int | static int | ||||
vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) | vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) | ||||
{ | { | ||||
int i, b; | int i, b; | ||||
struct ifvlan *ifv2; | struct ifvlan *ifv2; | ||||
TRUNK_WLOCK_ASSERT(trunk); | VLAN_XLOCK_ASSERT(); | ||||
KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | ||||
b = 1 << trunk->hwidth; | b = 1 << trunk->hwidth; | ||||
i = HASH(ifv->ifv_vid, trunk->hmask); | i = HASH(ifv->ifv_vid, trunk->hmask); | ||||
CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) | CK_SLIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) | ||||
if (ifv2 == ifv) { | if (ifv2 == ifv) { | ||||
trunk->refcnt--; | trunk->refcnt--; | ||||
CK_SLIST_REMOVE(&trunk->hash[i], ifv2, ifvlan, ifv_list); | CK_SLIST_REMOVE(&trunk->hash[i], ifv2, ifvlan, ifv_list); | ||||
Show All 11 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
vlan_growhash(struct ifvlantrunk *trunk, int howmuch) | vlan_growhash(struct ifvlantrunk *trunk, int howmuch) | ||||
{ | { | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
struct ifvlanhead *hash2; | struct ifvlanhead *hash2; | ||||
int hwidth2, i, j, n, n2; | int hwidth2, i, j, n, n2; | ||||
TRUNK_WLOCK_ASSERT(trunk); | VLAN_XLOCK_ASSERT(); | ||||
KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); | ||||
if (howmuch == 0) { | if (howmuch == 0) { | ||||
/* Harmless yet obvious coding error */ | /* Harmless yet obvious coding error */ | ||||
printf("%s: howmuch is 0\n", __func__); | printf("%s: howmuch is 0\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
hwidth2 = trunk->hwidth + howmuch; | hwidth2 = trunk->hwidth + howmuch; | ||||
n = 1 << trunk->hwidth; | n = 1 << trunk->hwidth; | ||||
n2 = 1 << hwidth2; | n2 = 1 << hwidth2; | ||||
/* Do not shrink the table below the default */ | /* Do not shrink the table below the default */ | ||||
if (hwidth2 < VLAN_DEF_HWIDTH) | if (hwidth2 < VLAN_DEF_HWIDTH) | ||||
return; | return; | ||||
/* M_NOWAIT because we're called with trunk mutex held */ | hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_WAITOK); | ||||
Not Done Inline ActionsThis comment implies we can't wait here... is NET_EPOCH_WAIT() safe? shurd: This comment implies we can't wait here... is NET_EPOCH_WAIT() safe? | |||||
hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT); | |||||
if (hash2 == NULL) { | if (hash2 == NULL) { | ||||
printf("%s: out of memory -- hash size not changed\n", | printf("%s: out of memory -- hash size not changed\n", | ||||
__func__); | __func__); | ||||
return; /* We can live with the old hash table */ | return; /* We can live with the old hash table */ | ||||
} | } | ||||
for (j = 0; j < n2; j++) | for (j = 0; j < n2; j++) | ||||
CK_SLIST_INIT(&hash2[j]); | CK_SLIST_INIT(&hash2[j]); | ||||
for (i = 0; i < n; i++) | for (i = 0; i < n; i++) | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
vlan_setmulti(struct ifnet *ifp) | vlan_setmulti(struct ifnet *ifp) | ||||
{ | { | ||||
struct ifnet *ifp_p; | struct ifnet *ifp_p; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ifvlan *sc; | struct ifvlan *sc; | ||||
struct vlan_mc_entry *mc; | struct vlan_mc_entry *mc; | ||||
int error; | int error; | ||||
/* | |||||
* XXX This stupidly needs the rmlock to avoid sleeping while holding | |||||
* the in6_multi_mtx (see in6_mc_join_locked). | |||||
*/ | |||||
VLAN_XLOCK_ASSERT(); | VLAN_XLOCK_ASSERT(); | ||||
Not Done Inline ActionsObsolete comment? shurd: Obsolete comment? | |||||
/* Find the parent. */ | /* Find the parent. */ | ||||
sc = ifp->if_softc; | sc = ifp->if_softc; | ||||
ifp_p = PARENT(sc); | ifp_p = PARENT(sc); | ||||
CURVNET_SET_QUIET(ifp_p->if_vnet); | CURVNET_SET_QUIET(ifp_p->if_vnet); | ||||
/* First, remove any existing filter entries. */ | /* First, remove any existing filter entries. */ | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static struct ifnet * | static struct ifnet * | ||||
vlan_trunkdev(struct ifnet *ifp) | vlan_trunkdev(struct ifnet *ifp) | ||||
{ | { | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
if (ifp->if_type != IFT_L2VLAN) | if (ifp->if_type != IFT_L2VLAN) | ||||
return (NULL); | return (NULL); | ||||
/* Not clear if callers are sleepable, so acquire the rmlock. */ | |||||
VLAN_RLOCK(); | VLAN_RLOCK(); | ||||
Not Done Inline ActionsObsolete comment. shurd: Obsolete comment. | |||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
ifp = NULL; | ifp = NULL; | ||||
if (ifv->ifv_trunk) | if (ifv->ifv_trunk) | ||||
ifp = PARENT(ifv); | ifp = PARENT(ifv); | ||||
VLAN_RUNLOCK(); | VLAN_RUNLOCK(); | ||||
return (ifp); | return (ifp); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Return the vlan device present at the specific VID. | * Return the vlan device present at the specific VID. | ||||
*/ | */ | ||||
static struct ifnet * | static struct ifnet * | ||||
vlan_devat(struct ifnet *ifp, uint16_t vid) | vlan_devat(struct ifnet *ifp, uint16_t vid) | ||||
{ | { | ||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
/* Not clear if callers are sleepable, so acquire the rmlock. */ | |||||
VLAN_RLOCK(); | VLAN_RLOCK(); | ||||
Not Done Inline ActionsObsolete comment shurd: Obsolete comment | |||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) { | ||||
VLAN_RUNLOCK(); | VLAN_RUNLOCK(); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
ifp = NULL; | ifp = NULL; | ||||
ifv = vlan_gethash(trunk, vid); | ifv = vlan_gethash(trunk, vid); | ||||
if (ifv) | if (ifv) | ||||
▲ Show 20 Lines • Show All 311 Lines • ▼ Show 20 Lines | vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) | ||||
ether_ifdetach(ifp); /* first, remove it from system-wide lists */ | ether_ifdetach(ifp); /* first, remove it from system-wide lists */ | ||||
vlan_unconfig(ifp); /* now it can be unconfigured and freed */ | vlan_unconfig(ifp); /* now it can be unconfigured and freed */ | ||||
/* | /* | ||||
* We should have the only reference to the ifv now, so we can now | * 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 | * drain any remaining lladdr task before freeing the ifnet and the | ||||
* ifvlan. | * ifvlan. | ||||
*/ | */ | ||||
taskqueue_drain(taskqueue_thread, &ifv->lladdr_task); | taskqueue_drain(taskqueue_thread, &ifv->lladdr_task); | ||||
NET_EPOCH_WAIT(); | |||||
if_free(ifp); | if_free(ifp); | ||||
free(ifv, M_VLAN); | free(ifv, M_VLAN); | ||||
ifc_free_unit(ifc, unit); | ifc_free_unit(ifc, unit); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) | ||||
* Don't let the caller set up a VLAN VID with | * Don't let the caller set up a VLAN VID with | ||||
* anything except VLID bits. | * anything except VLID bits. | ||||
* VID numbers 0x0 and 0xFFF are reserved. | * VID numbers 0x0 and 0xFFF are reserved. | ||||
*/ | */ | ||||
if (vid == 0 || vid == 0xFFF || (vid & ~EVL_VLID_MASK)) | if (vid == 0 || vid == 0xFFF || (vid & ~EVL_VLID_MASK)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (ifv->ifv_trunk) | if (ifv->ifv_trunk) | ||||
return (EBUSY); | return (EBUSY); | ||||
/* Acquire rmlock after the branch so we can M_WAITOK. */ | |||||
VLAN_XLOCK(); | VLAN_XLOCK(); | ||||
Not Done Inline ActionsAnother comment about an rmlock. shurd: Another comment about an rmlock. | |||||
if (p->if_vlantrunk == NULL) { | if (p->if_vlantrunk == NULL) { | ||||
trunk = malloc(sizeof(struct ifvlantrunk), | trunk = malloc(sizeof(struct ifvlantrunk), | ||||
M_VLAN, M_WAITOK | M_ZERO); | M_VLAN, M_WAITOK | M_ZERO); | ||||
vlan_inithash(trunk); | vlan_inithash(trunk); | ||||
TRUNK_LOCK_INIT(trunk); | TRUNK_LOCK_INIT(trunk); | ||||
TRUNK_WLOCK(trunk); | TRUNK_WLOCK(trunk); | ||||
p->if_vlantrunk = trunk; | p->if_vlantrunk = trunk; | ||||
trunk->parent = p; | trunk->parent = p; | ||||
if_ref(trunk->parent); | if_ref(trunk->parent); | ||||
TRUNK_WUNLOCK(trunk); | |||||
} else { | } else { | ||||
trunk = p->if_vlantrunk; | trunk = p->if_vlantrunk; | ||||
TRUNK_WLOCK(trunk); | |||||
} | } | ||||
ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ | ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ | ||||
ifv->ifv_pcp = 0; /* Default: best effort delivery. */ | ifv->ifv_pcp = 0; /* Default: best effort delivery. */ | ||||
vlan_tag_recalculate(ifv); | vlan_tag_recalculate(ifv); | ||||
error = vlan_inshash(trunk, ifv); | error = vlan_inshash(trunk, ifv); | ||||
if (error) { | if (error) | ||||
TRUNK_WUNLOCK(trunk); | |||||
goto done; | goto done; | ||||
} | |||||
ifv->ifv_proto = ETHERTYPE_VLAN; | ifv->ifv_proto = ETHERTYPE_VLAN; | ||||
Not Done Inline ActionsIsn't VLAN_XUNLOCK(); needed here as well? shurd: Isn't VLAN_XUNLOCK(); needed here as well? | |||||
Not Done Inline Actionsit's handled at the jump target mmacy: it's handled at the jump target | |||||
ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; | ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; | ||||
ifv->ifv_mintu = ETHERMIN; | ifv->ifv_mintu = ETHERMIN; | ||||
ifv->ifv_pflags = 0; | ifv->ifv_pflags = 0; | ||||
ifv->ifv_capenable = -1; | ifv->ifv_capenable = -1; | ||||
/* | /* | ||||
* If the parent supports the VLAN_MTU capability, | * If the parent supports the VLAN_MTU capability, | ||||
* i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, | * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | #undef VLAN_COPY_FLAGS | ||||
TASK_INIT(&ifv->lladdr_task, 0, vlan_lladdr_fn, ifv); | TASK_INIT(&ifv->lladdr_task, 0, vlan_lladdr_fn, ifv); | ||||
/* We are ready for operation now. */ | /* We are ready for operation now. */ | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
/* Update flags on the parent, if necessary. */ | /* Update flags on the parent, if necessary. */ | ||||
vlan_setflags(ifp, 1); | vlan_setflags(ifp, 1); | ||||
TRUNK_WUNLOCK(trunk); | TRUNK_WUNLOCK(trunk); | ||||
Not Done Inline Actionsmy test machine panics at this line on vlan creation. Fatal trap 12: page fault while in kernel mode cpuid = 5; apic id = 0a fault virtual address = 0x20 fault code = supervisor read data, page not present instruction pointer = 0x20:0xffffffff80c22297 stack pointer = 0x28:0xfffffe00cedb05f0 frame pointer = 0x28:0xfffffe00cedb0600 code segment = base 0x0, limit 0xfffff, type 0x1b = DPL 0, pres 1, long 1, def32 0, gran 1 processor eflags = resume, IOPL = 0 current process = 2796 (ifconfig) [ thread pid 2796 tid 100788 ] Stopped at turnstile_broadcast+0x47: movq 0x20(%rbx,%rax,1),%rcx db> bt Tracing pid 2796 tid 100788 td 0xfffff80052ff0000 turnstile_broadcast() at turnstile_broadcast+0x47/frame 0xfffffe00cedb0600 __mtx_unlock_sleep() at __mtx_unlock_sleep+0xb9/frame 0xfffffe00cedb0630 vlan_config() at vlan_config+0x6c9/frame 0xfffffe00cedb0690 vlan_clone_create() at vlan_clone_create+0x2b9/frame 0xfffffe00cedb0700 if_clone_createif() at if_clone_createif+0x4a/frame 0xfffffe00cedb0750 ifioctl() at ifioctl+0x721/frame 0xfffffe00cedb0840 kern_ioctl() at kern_ioctl+0x26d/frame 0xfffffe00cedb08b0 sys_ioctl() at sys_ioctl+0x15e/frame 0xfffffe00cedb0980 amd64_syscall() at amd64_syscall+0x369/frame 0xfffffe00cedb0ab0 fast_syscall_common() at fast_syscall_common+0x101/frame 0xfffffe00cedb0ab0 --- syscall (54, FreeBSD ELF64, sys_ioctl), rip = 0x800465bba, rsp = 0x7fffffffe0c8, rbp = 0x7fffffffe0d0 --- ae: my test machine panics at this line on vlan creation.
It seems this unlock is redundant, since… | |||||
/* | /* | ||||
* Configure multicast addresses that may already be | * Configure multicast addresses that may already be | ||||
* joined on the vlan device. | * joined on the vlan device. | ||||
*/ | */ | ||||
(void)vlan_setmulti(ifp); | (void)vlan_setmulti(ifp); | ||||
done: | done: | ||||
if (error == 0) | if (error == 0) | ||||
Show All 22 Lines | vlan_unconfig_locked(struct ifnet *ifp, int departing) | ||||
int error; | int error; | ||||
VLAN_XLOCK_ASSERT(); | VLAN_XLOCK_ASSERT(); | ||||
ifv = ifp->if_softc; | ifv = ifp->if_softc; | ||||
trunk = ifv->ifv_trunk; | trunk = ifv->ifv_trunk; | ||||
parent = NULL; | parent = NULL; | ||||
if (trunk != NULL) { | if (trunk != NULL) { | ||||
/* | |||||
* 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. | |||||
*/ | |||||
parent = trunk->parent; | parent = trunk->parent; | ||||
Not Done Inline ActionsObsolete comment? We've already VLAN_XLOCK_ASSERT()ed, and we're not getting an exclusive lock here. shurd: Obsolete comment? We've already VLAN_XLOCK_ASSERT()ed, and we're not getting an exclusive lock… | |||||
/* | /* | ||||
* Since the interface is being unconfigured, we need to | * Since the interface is being unconfigured, we need to | ||||
* empty the list of multicast groups that we may have joined | * empty the list of multicast groups that we may have joined | ||||
* while we were alive from the parent's list. | * while we were alive from the parent's list. | ||||
*/ | */ | ||||
while ((mc = CK_SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { | while ((mc = CK_SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { | ||||
/* | /* | ||||
* If the parent interface is being detached, | * If the parent interface is being detached, | ||||
* all its multicast addresses have already | * all its multicast addresses have already | ||||
* been removed. Warn about errors if | * been removed. Warn about errors if | ||||
* if_delmulti() does fail, but don't abort as | * if_delmulti() does fail, but don't abort as | ||||
* all callers expect vlan destruction to | * all callers expect vlan destruction to | ||||
* succeed. | * succeed. | ||||
*/ | */ | ||||
if (!departing) { | if (!departing) { | ||||
error = if_delmulti(parent, | error = if_delmulti(parent, | ||||
(struct sockaddr *)&mc->mc_addr); | (struct sockaddr *)&mc->mc_addr); | ||||
if (error) | if (error) | ||||
if_printf(ifp, | if_printf(ifp, | ||||
"Failed to delete multicast address from parent: %d\n", | "Failed to delete multicast address from parent: %d\n", | ||||
error); | error); | ||||
} | } | ||||
CK_SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); | CK_SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); | ||||
NET_EPOCH_WAIT(); | |||||
free(mc, M_VLAN); | free(mc, M_VLAN); | ||||
} | } | ||||
vlan_setflags(ifp, 0); /* clear special flags on parent */ | 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); | vlan_remhash(trunk, ifv); | ||||
TRUNK_WUNLOCK(trunk); | |||||
ifv->ifv_trunk = NULL; | ifv->ifv_trunk = NULL; | ||||
/* | /* | ||||
* Check if we were the last. | * Check if we were the last. | ||||
*/ | */ | ||||
if (trunk->refcnt == 0) { | if (trunk->refcnt == 0) { | ||||
parent->if_vlantrunk = NULL; | parent->if_vlantrunk = NULL; | ||||
NET_EPOCH_WAIT(); | NET_EPOCH_WAIT(); | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
/* Inform all vlans that their parent has changed link state */ | /* Inform all vlans that their parent has changed link state */ | ||||
static void | static void | ||||
vlan_link_state(struct ifnet *ifp) | vlan_link_state(struct ifnet *ifp) | ||||
{ | { | ||||
struct ifvlantrunk *trunk; | struct ifvlantrunk *trunk; | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
/* Called from a taskqueue_swi task, so we cannot sleep. */ | /* Called from a taskqueue_swi task, so we cannot sleep. */ | ||||
Not Done Inline ActionsIs this comment correct? Won't TRUNK_WLOCK() sleep? shurd: Is this comment correct? Won't TRUNK_WLOCK() sleep? | |||||
Not Done Inline ActionsIt's a mutex. mmacy: It's a mutex. | |||||
VLAN_RLOCK(); | VLAN_RLOCK(); | ||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) { | ||||
VLAN_RUNLOCK(); | VLAN_RUNLOCK(); | ||||
return; | return; | ||||
} | } | ||||
TRUNK_WLOCK(trunk); | TRUNK_WLOCK(trunk); | ||||
Show All 11 Lines | |||||
{ | { | ||||
struct ifnet *p; | struct ifnet *p; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ifnet_hw_tsomax hw_tsomax; | struct ifnet_hw_tsomax hw_tsomax; | ||||
int cap = 0, ena = 0, mena; | int cap = 0, ena = 0, mena; | ||||
u_long hwa = 0; | u_long hwa = 0; | ||||
VLAN_SXLOCK_ASSERT(); | VLAN_SXLOCK_ASSERT(); | ||||
TRUNK_WLOCK_ASSERT(TRUNK(ifv)); | TRUNK_RLOCK_ASSERT(TRUNK(ifv)); | ||||
p = PARENT(ifv); | p = PARENT(ifv); | ||||
ifp = ifv->ifv_ifp; | ifp = ifv->ifv_ifp; | ||||
/* Mask parent interface enabled capabilities disabled by user. */ | /* Mask parent interface enabled capabilities disabled by user. */ | ||||
mena = p->if_capenable & ifv->ifv_capenable; | mena = p->if_capenable & ifv->ifv_capenable; | ||||
/* | /* | ||||
* If the parent interface can do checksum offloading | * If the parent interface can do checksum offloading | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | vlan_trunk_capabilities(struct ifnet *ifp) | ||||
struct ifvlan *ifv; | struct ifvlan *ifv; | ||||
VLAN_SLOCK(); | VLAN_SLOCK(); | ||||
trunk = ifp->if_vlantrunk; | trunk = ifp->if_vlantrunk; | ||||
if (trunk == NULL) { | if (trunk == NULL) { | ||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
return; | return; | ||||
} | } | ||||
TRUNK_WLOCK(trunk); | TRUNK_RLOCK(trunk); | ||||
VLAN_FOREACH(ifv, trunk) { | VLAN_FOREACH(ifv, trunk) { | ||||
vlan_capabilities(ifv); | vlan_capabilities(ifv); | ||||
} | } | ||||
TRUNK_WUNLOCK(trunk); | TRUNK_RUNLOCK(trunk); | ||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
} | } | ||||
static int | static int | ||||
vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) | ||||
{ | { | ||||
struct ifnet *p; | struct ifnet *p; | ||||
struct ifreq *ifr; | struct ifreq *ifr; | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | #endif | ||||
EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); | EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); | ||||
break; | break; | ||||
case SIOCSIFCAP: | case SIOCSIFCAP: | ||||
VLAN_SLOCK(); | VLAN_SLOCK(); | ||||
ifv->ifv_capenable = ifr->ifr_reqcap; | ifv->ifv_capenable = ifr->ifr_reqcap; | ||||
trunk = TRUNK(ifv); | trunk = TRUNK(ifv); | ||||
if (trunk != NULL) { | if (trunk != NULL) { | ||||
TRUNK_WLOCK(trunk); | TRUNK_RLOCK(trunk); | ||||
vlan_capabilities(ifv); | vlan_capabilities(ifv); | ||||
TRUNK_WUNLOCK(trunk); | TRUNK_RUNLOCK(trunk); | ||||
} | } | ||||
VLAN_SUNLOCK(); | VLAN_SUNLOCK(); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
Show All 19 Lines |
This comment needs to be updated.