diff options
author | dh155122 <none@none> | 2007-01-19 16:59:38 -0800 |
---|---|---|
committer | dh155122 <none@none> | 2007-01-19 16:59:38 -0800 |
commit | f4b3ec61df05330d25f55a36b975b4d7519fdeb1 (patch) | |
tree | 395c234b901886c84a82603a767e031fca136e09 /usr/src/uts/common/io | |
parent | 2e59fc6dac28cd69376c21d6b90a5624160ba94c (diff) | |
download | illumos-joyent-f4b3ec61df05330d25f55a36b975b4d7519fdeb1.tar.gz |
PSARC 2006/366 IP Instances
6289221 RFE: Need virtualized ip-stack for each local zone
6512601 panic in ipsec_in_tag - allocation failure
6514637 error message from dhcpagent: add_pkt_opt: option type 60 is missing required value
6364643 RFE: allow persistent setting of interface flags per zone
6307539 RFE: Invalid network address causes zone boot failure
5041214 Allow IPMP configuration with zones
5005887 RFE: zoneadmd should support plumbing an interface via DHCP
4991139 RFE: zones should provide a mechanism to configure a defaultrouter for a zone
6218378 zoneadmd doesn't set the netmask for non-loopback addresses hosted on lo0
4963280 zones: need to virtualize the IPv6 default address selection mechanism
4963285 zones: need support of stateless address autoconfiguration for IPv6
5048068 zones don't boot if one of its interfaces has failed
5057154 RFE: ability to change interface status from within a zone
4963287 zones should support the plumbing of the first (and only) logical interface
4978517 TCP privileged port space should be partitioned per zone
5023347 zones don't work well with network routes other than default
4963372 investigate whether global zone can act as a router for local zones
6378364 RFE: Allow each zone to have its own virtual IPFilter
Diffstat (limited to 'usr/src/uts/common/io')
-rw-r--r-- | usr/src/uts/common/io/aggr/aggr_send.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/dld/dld_drv.c | 101 | ||||
-rw-r--r-- | usr/src/uts/common/io/dld/dld_str.c | 79 | ||||
-rw-r--r-- | usr/src/uts/common/io/dls/dls.c | 32 | ||||
-rw-r--r-- | usr/src/uts/common/io/dls/dls_vlan.c | 280 | ||||
-rw-r--r-- | usr/src/uts/common/io/hook.c | 172 | ||||
-rw-r--r-- | usr/src/uts/common/io/ib/clients/rds/rdssubr.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/io/mac/mac.c | 27 | ||||
-rw-r--r-- | usr/src/uts/common/io/neti.c | 213 | ||||
-rw-r--r-- | usr/src/uts/common/io/sad.c | 88 | ||||
-rw-r--r-- | usr/src/uts/common/io/sad_conf.c | 73 | ||||
-rw-r--r-- | usr/src/uts/common/io/strplumb.c | 6 |
12 files changed, 857 insertions, 227 deletions
diff --git a/usr/src/uts/common/io/aggr/aggr_send.c b/usr/src/uts/common/io/aggr/aggr_send.c index 6c5787a297..974d6a1d36 100644 --- a/usr/src/uts/common/io/aggr/aggr_send.c +++ b/usr/src/uts/common/io/aggr/aggr_send.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +44,8 @@ #include <inet/ip6.h> #include <inet/tcp.h> #include <netinet/udp.h> +#include <inet/ipsec_impl.h> +#include <inet/sadb.h> #include <inet/ipsecesp.h> #include <inet/ipsecah.h> diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c index 778a73528d..e409e165f7 100644 --- a/usr/src/uts/common/io/dld/dld_drv.c +++ b/usr/src/uts/common/io/dld/dld_drv.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,6 +37,7 @@ #include <sys/dld.h> #include <sys/dld_impl.h> #include <sys/dls_impl.h> +#include <sys/vlan.h> #include <inet/common.h> /* @@ -486,6 +487,95 @@ failed: miocnak(q, mp, 0, err); } +/* + * DLDIOCHOLDVLAN + */ +static void +drv_hold_vlan(dld_ctl_str_t *ctls, mblk_t *mp) +{ + queue_t *q = ctls->cs_wq; + dld_hold_vlan_t *dhv; + mblk_t *nmp; + int err; + dls_vlan_t *dvp; + + nmp = mp->b_cont; + if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) { + err = EINVAL; + miocnak(q, mp, 0, err); + return; + } + dhv = (dld_hold_vlan_t *)nmp->b_rptr; + + if ((err = dls_vlan_hold(dhv->dhv_name, &dvp, B_TRUE)) != 0) { + miocnak(q, mp, 0, err); + return; + } + + if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid, + dhv->dhv_docheck)) != 0) + miocnak(q, mp, 0, err); + else + miocack(q, mp, 0, 0); +} + +/* + * DLDIOCRELEVLAN + */ +static void +drv_rele_vlan(dld_ctl_str_t *ctls, mblk_t *mp) +{ + queue_t *q = ctls->cs_wq; + dld_hold_vlan_t *dhv; + mblk_t *nmp; + int err; + + nmp = mp->b_cont; + if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) { + err = EINVAL; + miocnak(q, mp, 0, err); + return; + } + dhv = (dld_hold_vlan_t *)nmp->b_rptr; + + if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid, + dhv->dhv_docheck)) != 0) { + miocnak(q, mp, 0, err); + return; + } + + if ((err = dls_vlan_rele_by_name(dhv->dhv_name)) != 0) { + miocnak(q, mp, 0, err); + return; + } + + miocack(q, mp, 0, 0); +} + +/* + * DLDIOCZIDGET + */ +static void +drv_ioc_zid_get(dld_ctl_str_t *ctls, mblk_t *mp) +{ + queue_t *q = ctls->cs_wq; + dld_hold_vlan_t *dhv; + mblk_t *nmp; + int err; + + nmp = mp->b_cont; + if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) { + err = EINVAL; + miocnak(q, mp, 0, err); + return; + } + dhv = (dld_hold_vlan_t *)nmp->b_rptr; + + if ((err = dls_vlan_getzoneid(dhv->dhv_name, &dhv->dhv_zid)) != 0) + miocnak(q, mp, 0, err); + else + miocack(q, mp, sizeof (dld_hold_vlan_t), 0); +} /* * Process an IOCTL message received by the control node. @@ -512,6 +602,15 @@ drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) case DLDIOCSECOBJUNSET: drv_ioc_secobj_unset(ctls, mp); return; + case DLDIOCHOLDVLAN: + drv_hold_vlan(ctls, mp); + return; + case DLDIOCRELEVLAN: + drv_rele_vlan(ctls, mp); + return; + case DLDIOCZIDGET: + drv_ioc_zid_get(ctls, mp); + return; default: miocnak(ctls->cs_wq, mp, 0, ENOTSUP); return; diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c index 9ebffec151..377e8c3be0 100644 --- a/usr/src/uts/common/io/dld/dld_str.c +++ b/usr/src/uts/common/io/dld/dld_str.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -57,21 +57,15 @@ static void ioc_raw(dld_str_t *, mblk_t *); static void ioc_fast(dld_str_t *, mblk_t *); static void ioc(dld_str_t *, mblk_t *); static void dld_ioc(dld_str_t *, mblk_t *); -static minor_t dld_minor_hold(boolean_t); -static void dld_minor_rele(minor_t); static void str_mdata_raw_put(dld_str_t *, mblk_t *); static mblk_t *i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t); static mblk_t *i_dld_ether_header_strip_tag(mblk_t *); static uint32_t str_count; static kmem_cache_t *str_cachep; -static vmem_t *minor_arenap; static uint32_t minor_count; static mod_hash_t *str_hashp; -#define MINOR_TO_PTR(minor) ((void *)(uintptr_t)(minor)) -#define PTR_TO_MINOR(ptr) ((minor_t)(uintptr_t)(ptr)) - #define STR_HASHSZ 64 #define STR_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)(key)) @@ -213,9 +207,12 @@ dld_finddevinfo(dev_t dev) return (NULL); mod_hash_walk(str_hashp, i_dld_str_walker, &state); - return (state.ds_dip); -} + if (state.ds_dip != NULL || state.ds_minor <= DLD_MAX_MINOR) + return (state.ds_dip); + /* See if it's a minor node of a VLAN */ + return (dls_finddevinfo(dev)); +} /* * devo_getinfo: getinfo(9e) @@ -273,8 +270,6 @@ dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) major = getmajor(*devp); minor = getminor(*devp); - if (minor > DLD_MAX_MINOR) - return (ENODEV); /* * Create a new dld_str_t for the stream. This will grab a new minor @@ -291,8 +286,12 @@ dld_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) /* * Style 1 open */ + t_uscalar_t ppa; + + if ((dls_ppa_from_minor(minor, &ppa)) != 0) + goto failed; - if ((err = dld_str_attach(dsp, (t_uscalar_t)minor - 1)) != 0) + if ((err = dld_str_attach(dsp, ppa)) != 0) goto failed; ASSERT(dsp->ds_dlstate == DL_UNBOUND); } else { @@ -558,20 +557,10 @@ dld_str_init(void) ASSERT(str_cachep != NULL); /* - * Allocate a vmem arena to manage minor numbers. The range of the - * arena will be from DLD_MAX_MINOR + 1 to MAXMIN (maximum legal - * minor number). - */ - minor_arenap = vmem_create("dld_minor_arena", - MINOR_TO_PTR(DLD_MAX_MINOR + 1), MAXMIN, 1, NULL, NULL, NULL, 0, - VM_SLEEP | VMC_IDENTIFIER); - ASSERT(minor_arenap != NULL); - - /* * Create a hash table for maintaining dld_str_t's. * The ds_minor field (the clone minor number) of a dld_str_t * is used as a key for this hash table because this number is - * globally unique (allocated from "dld_minor_arena"). + * globally unique (allocated from "dls_minor_arena"). */ str_hashp = mod_hash_create_idhash("dld_str_hash", STR_HASHSZ, mod_hash_null_valdtor); @@ -599,7 +588,6 @@ dld_str_fini(void) * Destroy object cache. */ kmem_cache_destroy(str_cachep); - vmem_destroy(minor_arenap); mod_hash_destroy_idhash(str_hashp); return (0); } @@ -723,8 +711,11 @@ str_constructor(void *buf, void *cdrarg, int kmflags) /* * Allocate a new minor number. */ - if ((dsp->ds_minor = dld_minor_hold(kmflags == KM_SLEEP)) == 0) + atomic_add_32(&minor_count, 1); + if ((dsp->ds_minor = dls_minor_hold(kmflags == KM_SLEEP)) == 0) { + atomic_add_32(&minor_count, -1); return (-1); + } /* * Initialize the DLPI state machine. @@ -773,7 +764,8 @@ str_destructor(void *buf, void *cdrarg) /* * Release the minor number. */ - dld_minor_rele(dsp->ds_minor); + dls_minor_rele(dsp->ds_minor); + atomic_add_32(&minor_count, -1); ASSERT(!RW_LOCK_HELD(&dsp->ds_lock)); rw_destroy(&dsp->ds_lock); @@ -2089,38 +2081,3 @@ ioc(dld_str_t *dsp, mblk_t *mp) rw_exit(&dsp->ds_lock); mac_ioctl(mh, q, mp); } - -/* - * Allocate a new minor number. - */ -static minor_t -dld_minor_hold(boolean_t sleep) -{ - minor_t minor; - - /* - * Grab a value from the arena. - */ - atomic_add_32(&minor_count, 1); - if ((minor = PTR_TO_MINOR(vmem_alloc(minor_arenap, 1, - (sleep) ? VM_SLEEP : VM_NOSLEEP))) == 0) { - atomic_add_32(&minor_count, -1); - return (0); - } - - return (minor); -} - -/* - * Release a previously allocated minor number. - */ -static void -dld_minor_rele(minor_t minor) -{ - /* - * Return the value to the arena. - */ - vmem_free(minor_arenap, MINOR_TO_PTR(minor), 1); - - atomic_add_32(&minor_count, -1); -} diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c index a8e1089776..5049286781 100644 --- a/usr/src/uts/common/io/dls/dls.c +++ b/usr/src/uts/common/io/dls/dls.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,7 +53,6 @@ struct dls_kstats dls_kstat = { "soft_ring_pkt_drop", KSTAT_DATA_UINT32 }, }; - /* * Private functions. */ @@ -226,6 +225,17 @@ dls_open(const char *name, dls_channel_t *dcp) atomic_add_32(&i_dls_impl_count, 1); /* + * Set the di_zid to the zone id of current zone + */ + dip->di_zid = getzoneid(); + + /* + * Add this dls_impl_t to the list of the "opened stream" + * list of the corresponding dls_vlan_t + */ + dls_vlan_add_impl(dvp, dip); + + /* * Hand back a reference to the dls_impl_t. */ *dcp = (dls_channel_t)dip; @@ -277,6 +287,12 @@ dls_close(dls_channel_t dc) } dip->di_dmap = NULL; + /* + * Remove this dls_impl_t from the list of the "open streams" + * list of the corresponding dls_vlan_t + */ + dls_vlan_remove_impl(dvp, dip); + rw_exit(&(dip->di_lock)); /* @@ -870,3 +886,15 @@ dls_active_clear(dls_channel_t dc) out: rw_exit(&dip->di_lock); } + +dev_info_t * +dls_finddevinfo(dev_t dev) +{ + return (dls_vlan_finddevinfo(dev)); +} + +int +dls_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) +{ + return (dls_vlan_ppa_from_minor(minor, ppa)); +} diff --git a/usr/src/uts/common/io/dls/dls_vlan.c b/usr/src/uts/common/io/dls/dls_vlan.c index bea767627a..9d98659e50 100644 --- a/usr/src/uts/common/io/dls/dls_vlan.c +++ b/usr/src/uts/common/io/dls/dls_vlan.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +32,7 @@ #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/atomic.h> +#include <sys/mkdev.h> #include <sys/modhash.h> #include <sys/kstat.h> #include <sys/vlan.h> @@ -39,12 +40,18 @@ #include <sys/ctype.h> #include <sys/dls.h> #include <sys/dls_impl.h> +#include <sys/dld.h> static kmem_cache_t *i_dls_vlan_cachep; static mod_hash_t *i_dls_vlan_hash; +static mod_hash_t *i_dls_vlan_dev_hash; static krwlock_t i_dls_vlan_lock; static uint_t i_dls_vlan_count; +static vmem_t *minor_arenap; +#define MINOR_TO_PTR(minor) ((void *)(uintptr_t)(minor)) +#define PTR_TO_MINOR(ptr) ((minor_t)(uintptr_t)(ptr)) + #define VLAN_HASHSZ 67 /* prime */ /* @@ -90,8 +97,24 @@ dls_vlan_init(void) i_dls_vlan_hash = mod_hash_create_extended("dls_vlan_hash", VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); + /* + * Create a second hash table, keyed by minor, of dls_vlan_t. + * The number of the hash slots is the same. + */ + i_dls_vlan_dev_hash = mod_hash_create_idhash("dls_vlan_dev_hash", + VLAN_HASHSZ, mod_hash_null_valdtor); rw_init(&i_dls_vlan_lock, NULL, RW_DEFAULT, NULL); i_dls_vlan_count = 0; + + /* + * Allocate a vmem arena to manage minor numbers. The range of the + * arena will be from DLD_MAX_MINOR + 1 to MAXMIN (maximum legal + * minor number). + */ + minor_arenap = vmem_create("dls_minor_arena", + MINOR_TO_PTR(DLD_MAX_MINOR + 1), MAXMIN, 1, NULL, NULL, NULL, 0, + VM_SLEEP | VMC_IDENTIFIER); + ASSERT(minor_arenap != NULL); } int @@ -104,12 +127,15 @@ dls_vlan_fini(void) * Destroy the hash table */ mod_hash_destroy_hash(i_dls_vlan_hash); + mod_hash_destroy_hash(i_dls_vlan_dev_hash); rw_destroy(&i_dls_vlan_lock); /* * Destroy the kmem_cache. */ kmem_cache_destroy(i_dls_vlan_cachep); + + vmem_destroy(minor_arenap); return (0); } @@ -235,6 +261,8 @@ dls_vlan_hold(const char *name, dls_vlan_t **dvpp, boolean_t create_vlan) dls_vlan_t *dvp; dls_link_t *dlp; boolean_t vlan_created = B_FALSE; + uint16_t vid; + uint_t ddi_inst; again: rw_enter(&i_dls_vlan_lock, RW_WRITER); @@ -243,8 +271,7 @@ again: (mod_hash_val_t *)&dvp); if (err != 0) { char mac[MAXNAMELEN]; - uint_t index, ddi_inst, mac_ppa, len; - uint16_t vid; + uint_t index, mac_ppa, len; ASSERT(err == MH_ERR_NOTFOUND); @@ -298,6 +325,34 @@ again: if ((err = dls_mac_hold(dlp)) != 0) goto done; + /* Create a minor node for this VLAN */ + if (vid != 0 && vlan_created) { + /* A tagged VLAN */ + dvp->dv_minor = dls_minor_hold(B_TRUE); + dvp->dv_ppa = DLS_VIDINST2PPA(vid, ddi_inst); + + err = mod_hash_insert(i_dls_vlan_dev_hash, + (mod_hash_key_t)(uintptr_t)dvp->dv_minor, + (mod_hash_val_t)dvp); + ASSERT(err == 0); + + err = mac_vlan_create(dlp->dl_mh, name, dvp->dv_minor); + + if (err != 0) { + mod_hash_val_t val; + + err = mod_hash_remove(i_dls_vlan_dev_hash, + (mod_hash_key_t)(uintptr_t)dvp->dv_minor, + (mod_hash_val_t *)&val); + ASSERT(err == 0); + ASSERT(dvp == (dls_vlan_t *)val); + + dvp->dv_minor = 0; + dls_mac_rele(dlp); + goto done; + } + } + /* * Do not allow the creation of tagged VLAN interfaces on * non-Ethernet links. Note that we cannot do this check in @@ -348,6 +403,21 @@ dls_vlan_rele(dls_vlan_t *dvp) rw_enter(&i_dls_vlan_lock, RW_WRITER); dlp = dvp->dv_dlp; + /* a minor node has been created for this vlan */ + if (dvp->dv_ref == 1 && dvp->dv_minor > 0) { + int err; + mod_hash_val_t val; + + mac_vlan_remove(dlp->dl_mh, dvp->dv_name); + err = mod_hash_remove(i_dls_vlan_dev_hash, + (mod_hash_key_t)(uintptr_t)dvp->dv_minor, + (mod_hash_val_t *)&val); + ASSERT(err == 0); + ASSERT(dvp == (dls_vlan_t *)val); + dls_minor_rele(dvp->dv_minor); + dvp->dv_minor = 0; + } + mac_stop(dlp->dl_mh); dls_mac_rele(dlp); if (--dvp->dv_ref == 0) { @@ -401,3 +471,207 @@ dls_vlan_walk(int (*fn)(dls_vlan_t *, void *), void *arg) rw_exit(&i_dls_vlan_lock); return (state.rc); } + +int +dls_vlan_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) +{ + dls_vlan_t *dvp; + + if (minor <= DLD_MAX_MINOR) { + *ppa = (t_uscalar_t)minor - 1; + return (0); + } + + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + if (mod_hash_find(i_dls_vlan_dev_hash, (mod_hash_key_t)(uintptr_t)minor, + (mod_hash_val_t *)&dvp) != 0) { + rw_exit(&i_dls_vlan_lock); + return (ENOENT); + } + *ppa = dvp->dv_ppa; + + rw_exit(&i_dls_vlan_lock); + return (0); +} + +int +dls_vlan_rele_by_name(const char *name) +{ + dls_vlan_t *dvp; + dls_link_t *dlp; + boolean_t destroy_vlan = B_FALSE; + + rw_enter(&i_dls_vlan_lock, RW_WRITER); + + if (mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name, + (mod_hash_val_t *)&dvp) != 0) { + rw_exit(&i_dls_vlan_lock); + return (ENOENT); + } + + dlp = dvp->dv_dlp; + + /* a minor node has been created for this vlan */ + if (dvp->dv_ref == 1 && dvp->dv_minor > 0) { + int err; + mod_hash_val_t val; + + mac_vlan_remove(dlp->dl_mh, dvp->dv_name); + err = mod_hash_remove(i_dls_vlan_dev_hash, + (mod_hash_key_t)(uintptr_t)dvp->dv_minor, + (mod_hash_val_t *)&val); + ASSERT(err == 0); + ASSERT(dvp == (dls_vlan_t *)val); + dls_minor_rele(dvp->dv_minor); + dvp->dv_minor = 0; + } + + mac_stop(dlp->dl_mh); + dls_mac_rele(dlp); + if (--dvp->dv_ref == 0) { + dls_mac_stat_destroy(dvp); + /* Tagged vlans get destroyed when dv_ref drops to 0. */ + if (dvp->dv_id != 0) + destroy_vlan = B_TRUE; + } + rw_exit(&i_dls_vlan_lock); + if (destroy_vlan) + (void) dls_vlan_destroy(name); + + return (0); +} + +typedef struct dls_vlan_dip_state { + minor_t minor; + dev_info_t *dip; +} dls_vlan_dip_k_state_t; + +static int +dls_vlan_devinfo(dls_vlan_t *dvp, void *arg) +{ + dls_vlan_dip_k_state_t *statep = arg; + + if (dvp->dv_minor == statep->minor) { + dls_link_t *dlp = dvp->dv_dlp; + + if (dls_mac_hold(dlp) != 0) + return (0); + statep->dip = mac_devinfo_get(dlp->dl_mh); + dls_mac_rele(dlp); + + return (1); + } + + return (0); +} + +dev_info_t * +dls_vlan_finddevinfo(dev_t dev) +{ + dls_vlan_dip_k_state_t vlan_state; + + vlan_state.minor = getminor(dev); + vlan_state.dip = NULL; + + (void) dls_vlan_walk(dls_vlan_devinfo, &vlan_state); + return (vlan_state.dip); +} + +/* + * Allocate a new minor number. + */ +minor_t +dls_minor_hold(boolean_t sleep) +{ + /* + * Grab a value from the arena. + */ + return (PTR_TO_MINOR(vmem_alloc(minor_arenap, 1, + (sleep) ? VM_SLEEP : VM_NOSLEEP))); +} + +/* + * Release a previously allocated minor number. + */ +void +dls_minor_rele(minor_t minor) +{ + /* + * Return the value to the arena. + */ + vmem_free(minor_arenap, MINOR_TO_PTR(minor), 1); +} + +int +dls_vlan_setzoneid(char *name, zoneid_t zid, boolean_t docheck) +{ + int err; + dls_vlan_t *dvp; + + if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) + return (err); + + rw_enter(&i_dls_vlan_lock, RW_WRITER); + if (!docheck) { + dvp->dv_zid = zid; + } else { + dls_impl_t *dip; + + for (dip = dvp->dv_impl_list; dip != NULL; + dip = dip->di_next_impl) + if (dip->di_zid != zid) + break; + if (dip == NULL) + dvp->dv_zid = zid; + else + err = EBUSY; + } + rw_exit(&i_dls_vlan_lock); + + dls_vlan_rele(dvp); + return (err); +} + +int +dls_vlan_getzoneid(char *name, zoneid_t *zidp) +{ + int err; + dls_vlan_t *dvp; + + if ((err = dls_vlan_hold(name, &dvp, B_FALSE)) != 0) + return (err); + + *zidp = dvp->dv_zid; + + dls_vlan_rele(dvp); + + return (0); +} + +void +dls_vlan_add_impl(dls_vlan_t *dvp, dls_impl_t *dip) +{ + rw_enter(&i_dls_vlan_lock, RW_WRITER); + dip->di_next_impl = dvp->dv_impl_list; + dvp->dv_impl_list = dip; + rw_exit(&i_dls_vlan_lock); +} + + +void +dls_vlan_remove_impl(dls_vlan_t *dvp, dls_impl_t *dip) +{ + dls_impl_t **pp; + dls_impl_t *p; + + rw_enter(&i_dls_vlan_lock, RW_WRITER); + for (pp = &dvp->dv_impl_list; (p = *pp) != NULL; + pp = &(p->di_next_impl)) + if (p == dip) + break; + ASSERT(p != NULL); + *pp = p->di_next_impl; + p->di_next_impl = NULL; + rw_exit(&i_dls_vlan_lock); +} diff --git a/usr/src/uts/common/io/hook.c b/usr/src/uts/common/io/hook.c index 7e791647e4..323503498c 100644 --- a/usr/src/uts/common/io/hook.c +++ b/usr/src/uts/common/io/hook.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -54,19 +54,20 @@ static struct modlinkage modlinkage = { * Hook internal functions */ static hook_int_t *hook_copy(hook_t *src); -static hook_event_int_t *hook_event_checkdup(hook_event_t *he); +static hook_event_int_t *hook_event_checkdup(hook_event_t *he, + hook_stack_t *hks); static hook_event_int_t *hook_event_copy(hook_event_t *src); static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event); static void hook_event_free(hook_event_int_t *hei); static hook_family_int_t *hook_family_copy(hook_family_t *src); -static hook_family_int_t *hook_family_find(char *family); +static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks); static void hook_family_free(hook_family_int_t *hfi); static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h); static void hook_free(hook_int_t *hi); static void hook_init(void); - -static cvwaitlock_t familylock; /* global lock */ -static hook_family_int_head_t familylist; /* family list head */ +static void hook_fini(void); +static void *hook_stack_init(netstackid_t stackid, netstack_t *ns); +static void hook_stack_fini(netstackid_t stackid, void *arg); /* * Module entry points. @@ -74,15 +75,27 @@ static hook_family_int_head_t familylist; /* family list head */ int _init(void) { + int error; + hook_init(); - return (mod_install(&modlinkage)); + error = mod_install(&modlinkage); + if (error != 0) + hook_fini(); + + return (error); } int _fini(void) { - return (mod_remove(&modlinkage)); + int error; + + error = mod_remove(&modlinkage); + if (error == 0) + hook_fini(); + + return (error); } @@ -103,10 +116,63 @@ _info(struct modinfo *modinfop) static void hook_init(void) { - CVW_INIT(&familylock); - SLIST_INIT(&familylist); + /* + * We want to be informed each time a stack is created or + * destroyed in the kernel. + */ + netstack_register(NS_HOOK, hook_stack_init, NULL, + hook_stack_fini); +} + +/* + * Function: hook_fini + * Returns: None + * Parameters: None + * + * Deinitialize hooks + */ +static void +hook_fini(void) +{ + netstack_unregister(NS_HOOK); } +/* + * Initialize the hook stack instance. + */ +/*ARGSUSED*/ +static void * +hook_stack_init(netstackid_t stackid, netstack_t *ns) +{ + hook_stack_t *hks; + +#ifdef NS_DEBUG + printf("hook_stack_init(stack %d)\n", stackid); +#endif + + hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP); + hks->hk_netstack = ns; + + CVW_INIT(&hks->hks_familylock); + SLIST_INIT(&hks->hks_familylist); + + return (hks); +} + +/* + * Free the hook stack instance. + */ +/*ARGSUSED*/ +static void +hook_stack_fini(netstackid_t stackid, void *arg) +{ + hook_stack_t *hks = (hook_stack_t *)arg; +#ifdef NS_DEBUG + printf("hook_stack_fini(%p, stack %d)\n", arg, stackid); +#endif + CVW_DESTROY(&hks->hks_familylock); + kmem_free(hks, sizeof (*hks)); +} /* * Function: hook_run @@ -121,10 +187,11 @@ hook_init(void) * called more than once, simultaneously. */ int -hook_run(hook_event_token_t token, hook_data_t info) +hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns) { hook_int_t *hi; hook_event_int_t *hei; + hook_stack_t *hks = ns->netstack_hook; int rval = 0; ASSERT(token != NULL); @@ -135,7 +202,7 @@ hook_run(hook_event_token_t token, hook_data_t info) hook_data_t, info); /* Hold global read lock to ensure event will not be deleted */ - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); /* Hold event read lock to ensure hook will not be changed */ CVW_ENTER_READ(&hei->hei_lock); @@ -146,7 +213,7 @@ hook_run(hook_event_token_t token, hook_data_t info) hook_event_token_t, token, hook_data_t, info, hook_int_t *, hi); - rval = (*hi->hi_hook.h_func)(token, info); + rval = (*hi->hi_hook.h_func)(token, info, ns); DTRACE_PROBE4(hook__func__end, hook_event_token_t, token, hook_data_t, info, @@ -157,7 +224,7 @@ hook_run(hook_event_token_t token, hook_data_t info) } CVW_EXIT_READ(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); DTRACE_PROBE3(hook__run__end, hook_event_token_t, token, @@ -176,7 +243,7 @@ hook_run(hook_event_token_t token, hook_data_t info) * Add new family to family list */ hook_family_int_t * -hook_family_add(hook_family_t *hf) +hook_family_add(hook_family_t *hf, hook_stack_t *hks) { hook_family_int_t *hfi, *new; @@ -187,20 +254,22 @@ hook_family_add(hook_family_t *hf) if (new == NULL) return (NULL); - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* search family list */ - hfi = hook_family_find(hf->hf_name); + hfi = hook_family_find(hf->hf_name, hks); if (hfi != NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_family_free(new); return (NULL); } + new->hfi_ptr = (void *)hks; + /* Add to family list head */ - SLIST_INSERT_HEAD(&familylist, new, hfi_entry); + SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (new); } @@ -215,21 +284,23 @@ hook_family_add(hook_family_t *hf) int hook_family_remove(hook_family_int_t *hfi) { + hook_stack_t *hks; ASSERT(hfi != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* Check if there are events */ if (!SLIST_EMPTY(&hfi->hfi_head)) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (EBUSY); } /* Remove from family list */ - SLIST_REMOVE(&familylist, hfi, hook_family_int, hfi_entry); + SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, hfi_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_family_free(hfi); return (0); @@ -269,7 +340,6 @@ hook_family_copy(hook_family_t *src) /* - * Function: hook_family_find * Returns: internal family pointer - NULL = Not match * Parameters: family(I) - family name string * @@ -277,13 +347,13 @@ hook_family_copy(hook_family_t *src) * A lock on familylock must be held when called. */ static hook_family_int_t * -hook_family_find(char *family) +hook_family_find(char *family, hook_stack_t *hks) { hook_family_int_t *hfi = NULL; ASSERT(family != NULL); - SLIST_FOREACH(hfi, &familylist, hfi_entry) { + SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { if (strcmp(hfi->hfi_family.hf_name, family) == 0) break; } @@ -328,22 +398,24 @@ hook_family_free(hook_family_int_t *hfi) hook_event_int_t * hook_event_add(hook_family_int_t *hfi, hook_event_t *he) { + hook_stack_t *hks; hook_event_int_t *hei, *new; ASSERT(hfi != NULL); ASSERT(he != NULL); ASSERT(he->he_name != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; new = hook_event_copy(he); if (new == NULL) return (NULL); - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); /* Check whether this event pointer is already registered */ - hei = hook_event_checkdup(he); + hei = hook_event_checkdup(he, hks); if (hei != NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_event_free(new); return (NULL); } @@ -351,7 +423,7 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he) /* Add to event list head */ SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (new); } @@ -367,29 +439,31 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he) int hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) { + hook_stack_t *hks; hook_event_int_t *hei; ASSERT(hfi != NULL); ASSERT(he != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_WRITE(&familylock); + CVW_ENTER_WRITE(&hks->hks_familylock); hei = hook_event_find(hfi, he->he_name); if (hei == NULL) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (ENXIO); } /* Check if there are registered hooks for this event */ if (!TAILQ_EMPTY(&hei->hei_head)) { - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); return (EBUSY); } /* Remove from event list */ SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); - CVW_EXIT_WRITE(&familylock); + CVW_EXIT_WRITE(&hks->hks_familylock); hook_event_free(hei); return (0); @@ -405,14 +479,14 @@ hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) * A lock on familylock must be held when called. */ static hook_event_int_t * -hook_event_checkdup(hook_event_t *he) +hook_event_checkdup(hook_event_t *he, hook_stack_t *hks) { hook_family_int_t *hfi; hook_event_int_t *hei; ASSERT(he != NULL); - SLIST_FOREACH(hfi, &familylist, hfi_entry) { + SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) { SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { if (hei->hei_event == he) return (hei); @@ -456,7 +530,7 @@ hook_event_copy(hook_event_t *src) * event(I) - event name string * * Search event list with event name - * A lock on familylock must be held when called. + * A lock on hks->hks_familylock must be held when called. */ static hook_event_int_t * hook_event_find(hook_family_int_t *hfi, char *event) @@ -503,12 +577,14 @@ hook_event_free(hook_event_int_t *hei) int hook_register(hook_family_int_t *hfi, char *event, hook_t *h) { + hook_stack_t *hks; hook_event_int_t *hei; hook_int_t *hi, *new; ASSERT(hfi != NULL); ASSERT(event != NULL); ASSERT(h != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; /* Alloc hook_int_t and copy hook */ new = hook_copy(h); @@ -520,11 +596,11 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) * to hold global family write lock. Just get read lock here to * ensure event will not be removed when doing hooks operation */ - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (ENXIO); } @@ -535,7 +611,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) if (((hei->hei_event->he_flags & HOOK_RDONLY) == 0) && (!TAILQ_EMPTY(&hei->hei_head))) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (EEXIST); } @@ -543,7 +619,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) hi = hook_find(hei, h); if (hi != NULL) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(new); return (EEXIST); } @@ -553,7 +629,7 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) hei->hei_event->he_interested = B_TRUE; CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (0); } @@ -570,17 +646,19 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h) int hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) { + hook_stack_t *hks; hook_event_int_t *hei; hook_int_t *hi; ASSERT(hfi != NULL); ASSERT(h != NULL); + hks = (hook_stack_t *)hfi->hfi_ptr; - CVW_ENTER_READ(&familylock); + CVW_ENTER_READ(&hks->hks_familylock); hei = hook_event_find(hfi, event); if (hei == NULL) { - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (ENXIO); } @@ -590,7 +668,7 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) hi = hook_find(hei, h); if (hi == NULL) { CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); return (ENXIO); } @@ -601,7 +679,7 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) } CVW_EXIT_WRITE(&hei->hei_lock); - CVW_EXIT_READ(&familylock); + CVW_EXIT_READ(&hks->hks_familylock); hook_free(hi); return (0); diff --git a/usr/src/uts/common/io/ib/clients/rds/rdssubr.c b/usr/src/uts/common/io/ib/clients/rds/rdssubr.c index 0bff0a6187..8e57cb783d 100644 --- a/usr/src/uts/common/io/ib/clients/rds/rdssubr.c +++ b/usr/src/uts/common/io/ib/clients/rds/rdssubr.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -299,9 +299,14 @@ boolean_t rds_islocal(ipaddr_t addr) { ire_t *ire; + ip_stack_t *ipst; + + ipst = netstack_find_by_zoneid(GLOBAL_ZONEID)->netstack_ip; + ASSERT(ipst != NULL); ire = ire_ctable_lookup(addr, NULL, IRE_LOCAL | IRE_LOOPBACK | - IRE_BROADCAST, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE); + IRE_BROADCAST, NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst); + netstack_rele(ipst->ips_netstack); if (ire == NULL) return (B_FALSE); ire_refrele(ire); diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index 05d50006e2..f54607fca7 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,6 +42,7 @@ #include <sys/dls.h> #include <sys/dld.h> #include <sys/modctl.h> +#include <sys/fs/dv_node.h> #include <sys/atomic.h> #define IMPL_HASHSZ 67 /* prime */ @@ -1886,3 +1887,27 @@ done: mutex_exit(&i_mactype_lock); return (err); } + +int +mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + /* Create a style-1 DLPI device */ + if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor, + DDI_NT_NET, 0) != DDI_SUCCESS) { + return (-1); + } + return (0); +} + +void +mac_vlan_remove(mac_handle_t mh, const char *name) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + dev_info_t *dipp; + + ddi_remove_minor_node(mip->mi_dip, (char *)name); + dipp = ddi_get_parent(mip->mi_dip); + (void) devfs_clean(dipp, NULL, 0); +} diff --git a/usr/src/uts/common/io/neti.c b/usr/src/uts/common/io/neti.c index 3f7ae3c611..49a17ee91f 100644 --- a/usr/src/uts/common/io/neti.c +++ b/usr/src/uts/common/io/neti.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,11 +38,11 @@ #include <sys/neti.h> -static krwlock_t netlock; -static LIST_HEAD(netd_listhead, net_data) netd_head; /* list of net_data_t */ - static void net_init(); -static net_data_t net_find(const char *protocol); +static void net_fini(); +static net_data_t net_find(const char *protocol, neti_stack_t *ns); +static void *neti_stack_init(netstackid_t stackid, netstack_t *ns); +static void neti_stack_fini(netstackid_t stackid, void *arg); /* * Module linkage information for the kernel. @@ -64,16 +64,27 @@ static struct modlinkage modlinkage = { int _init(void) { + int error; + net_init(); - return (mod_install(&modlinkage)); + error = mod_install(&modlinkage); + if (error != 0) + net_fini(); + + return (error); } int _fini(void) { + int error; - return (mod_remove(&modlinkage)); + error = mod_remove(&modlinkage); + if (error == 0) + net_fini(); + + return (error); } @@ -88,20 +99,68 @@ _info(struct modinfo *modinfop) static void net_init() { + /* + * We want to be informed each time a stack is created or + * destroyed in the kernel. + */ + netstack_register(NS_NETI, neti_stack_init, NULL, + neti_stack_fini); +} + +static void +net_fini() +{ + netstack_unregister(NS_NETI); +} + + +/* + * Initialize the neti stack instance. + */ +/*ARGSUSED*/ +static void * +neti_stack_init(netstackid_t stackid, netstack_t *ns) +{ + neti_stack_t *nts; + +#ifdef NS_DEBUG + printf("neti_stack_init(stack %d)\n", stackid); +#endif + + nts = (neti_stack_t *)kmem_zalloc(sizeof (*nts), KM_SLEEP); + nts->nts_netstack = ns; + + rw_init(&nts->nts_netlock, NULL, RW_DRIVER, NULL); + LIST_INIT(&nts->nts_netd_head); + + return (nts); +} + - rw_init(&netlock, NULL, RW_DRIVER, NULL); - LIST_INIT(&netd_head); +/* + * Free the neti stack instance. + */ +/*ARGSUSED*/ +static void +neti_stack_fini(netstackid_t stackid, void *arg) +{ + neti_stack_t *nts = (neti_stack_t *)arg; +#ifdef NS_DEBUG + printf("neti_stack_fini(%p, stack %d)\n", arg, stackid); +#endif + rw_destroy(&nts->nts_netlock); + kmem_free(nts, sizeof (*nts)); } static net_data_t -net_find(const char *protocol) +net_find(const char *protocol, neti_stack_t *nts) { struct net_data *n; ASSERT(protocol != NULL); - LIST_FOREACH(n, &netd_head, netd_list) { + LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { ASSERT(n->netd_info.neti_protocol != NULL); if (strcmp(n->netd_info.neti_protocol, protocol) == 0) { break; @@ -111,33 +170,51 @@ net_find(const char *protocol) return (n); } +net_data_t +net_register(const net_info_t *info, netstackid_t nsid) +{ + netstack_t *ns; + net_data_t nd; + + ns = netstack_find_by_stackid(nsid); + nd = net_register_impl(info, ns); + netstack_rele(ns); + + return (nd); +} net_data_t -net_register(const net_info_t *info) +net_register_impl(const net_info_t *info, netstack_t *ns) { struct net_data *n, *new; + struct neti_stack *nts; ASSERT(info != NULL); + ASSERT(ns != NULL); + + nts = ns->netstack_neti; new = kmem_alloc(sizeof (*new), KM_SLEEP); new->netd_refcnt = 0; new->netd_hooks = NULL; new->netd_info = *info; + new->netd_netstack = ns; - rw_enter(&netlock, RW_WRITER); - n = net_find(info->neti_protocol); + rw_enter(&nts->nts_netlock, RW_WRITER); + n = net_find(info->neti_protocol, nts); if (n != NULL) { - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); kmem_free(new, sizeof (*new)); return (NULL); } - if (LIST_EMPTY(&netd_head)) - LIST_INSERT_HEAD(&netd_head, new, netd_list); + if (LIST_EMPTY(&nts->nts_netd_head)) + LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list); else - LIST_INSERT_AFTER(LIST_FIRST(&netd_head), new, netd_list); + LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head), + new, netd_list); - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); return (new); } @@ -145,36 +222,56 @@ net_register(const net_info_t *info) int net_unregister(net_data_t info) { + struct netstack *ns; + struct neti_stack *nts; + ns = info->netd_netstack; + nts = ns->netstack_neti; ASSERT(info != NULL); - rw_enter(&netlock, RW_WRITER); + rw_enter(&nts->nts_netlock, RW_WRITER); if (info->netd_refcnt != 0) { - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); return (EBUSY); } LIST_REMOVE(info, netd_list); - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); kmem_free(info, sizeof (struct net_data)); return (0); } +net_data_t +net_lookup(const char *protocol, netstackid_t nsid) +{ + netstack_t *ns; + net_data_t nd; + + ns = netstack_find_by_stackid(nsid); + nd = net_lookup_impl(protocol, ns); + netstack_rele(ns); + + return (nd); +} net_data_t -net_lookup(const char *protocol) +net_lookup_impl(const char *protocol, netstack_t *ns) { struct net_data *n; + struct neti_stack *nts; ASSERT(protocol != NULL); + ASSERT(ns != NULL); + + nts = ns->netstack_neti; - rw_enter(&netlock, RW_READER); - n = net_find(protocol); + rw_enter(&nts->nts_netlock, RW_READER); + n = net_find(protocol, nts); if (n != NULL) atomic_add_32((uint_t *)&n->netd_refcnt, 1); - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); return (n); } @@ -187,33 +284,57 @@ net_lookup(const char *protocol) int net_release(net_data_t info) { + struct netstack *ns; + struct neti_stack *nts; + + ns = info->netd_netstack; + nts = ns->netstack_neti; + ASSERT(info != NULL); - rw_enter(&netlock, RW_READER); + rw_enter(&nts->nts_netlock, RW_READER); ASSERT(info->netd_refcnt > 0); atomic_add_32((uint_t *)&info->netd_refcnt, -1); /* net_release has been called too many times */ if (info->netd_refcnt < 0) { - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); return (1); } - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); + return (0); } +net_data_t +net_walk(net_data_t info, netstackid_t nsid) +{ + netstack_t *ns; + net_data_t nd; + + ns = netstack_find_by_stackid(nsid); + nd = net_walk_impl(info, ns); + netstack_rele(ns); + + return (nd); +} net_data_t -net_walk(net_data_t info) +net_walk_impl(net_data_t info, netstack_t *ns) { struct net_data *n = NULL; boolean_t found = B_FALSE; + struct neti_stack *nts; + + ASSERT(ns != NULL); + + nts = ns->netstack_neti; if (info == NULL) found = B_TRUE; - rw_enter(&netlock, RW_READER); - LIST_FOREACH(n, &netd_head, netd_list) { + rw_enter(&nts->nts_netlock, RW_READER); + LIST_FOREACH(n, &nts->nts_netd_head, netd_list) { if (found) break; if (n == info) @@ -227,7 +348,8 @@ net_walk(net_data_t info) if (n != NULL) atomic_add_32((uint_t *)&n->netd_refcnt, 1); - rw_exit(&netlock); + rw_exit(&nts->nts_netlock); + return (n); } @@ -242,7 +364,8 @@ net_getifname(net_data_t info, phy_if_t phy_ifdata, ASSERT(info != NULL); - return (info->netd_info.neti_getifname(phy_ifdata, buffer, buflen)); + return (info->netd_info.neti_getifname(phy_ifdata, buffer, buflen, + info->netd_netstack)); } @@ -252,7 +375,8 @@ net_getmtu(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata) ASSERT(info != NULL); - return (info->netd_info.neti_getmtu(phy_ifdata, ifdata)); + return (info->netd_info.neti_getmtu(phy_ifdata, ifdata, + info->netd_netstack)); } @@ -262,7 +386,7 @@ net_getpmtuenabled(net_data_t info) ASSERT(info != NULL); - return (info->netd_info.neti_getpmtuenabled()); + return (info->netd_info.neti_getpmtuenabled(info->netd_netstack)); } @@ -274,7 +398,7 @@ net_getlifaddr(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata, ASSERT(info != NULL); return (info->netd_info.neti_getlifaddr(phy_ifdata, ifdata, - nelem, type, storage)); + nelem, type, storage, info->netd_netstack)); } @@ -284,7 +408,8 @@ net_phygetnext(net_data_t info, phy_if_t phy_ifdata) ASSERT(info != NULL); - return (info->netd_info.neti_phygetnext(phy_ifdata)); + return (info->netd_info.neti_phygetnext(phy_ifdata, + info->netd_netstack)); } @@ -294,7 +419,7 @@ net_phylookup(net_data_t info, const char *name) ASSERT(info != NULL); - return (info->netd_info.neti_phylookup(name)); + return (info->netd_info.neti_phylookup(name, info->netd_netstack)); } @@ -304,7 +429,8 @@ net_lifgetnext(net_data_t info, phy_if_t ifidx, lif_if_t ifdata) ASSERT(info != NULL); - return (info->netd_info.neti_lifgetnext(ifidx, ifdata)); + return (info->netd_info.neti_lifgetnext(ifidx, ifdata, + info->netd_netstack)); } @@ -314,7 +440,8 @@ net_inject(net_data_t info, inject_t style, net_inject_t *packet) ASSERT(info != NULL); - return (info->netd_info.neti_inject(style, packet)); + return (info->netd_info.neti_inject(style, packet, + info->netd_netstack)); } @@ -324,7 +451,7 @@ net_routeto(net_data_t info, struct sockaddr *address) ASSERT(info != NULL); - return (info->netd_info.neti_routeto(address)); + return (info->netd_info.neti_routeto(address, info->netd_netstack)); } @@ -373,7 +500,7 @@ net_register_family(net_data_t info, hook_family_t *hf) if (info->netd_hooks != NULL) return (EEXIST); - hfi = hook_family_add(hf); + hfi = hook_family_add(hf, info->netd_netstack->netstack_hook); if (hfi == NULL) return (EEXIST); diff --git a/usr/src/uts/common/io/sad.c b/usr/src/uts/common/io/sad.c index d8371327dc..de3e66130e 100644 --- a/usr/src/uts/common/io/sad.c +++ b/usr/src/uts/common/io/sad.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,6 +54,7 @@ #include <sys/modctl.h> #include <sys/priv_names.h> #include <sys/sysmacros.h> +#include <sys/zone.h> static int sadopen(queue_t *, dev_t *, int, int, cred_t *); static int sadclose(queue_t *, int, cred_t *); @@ -186,35 +187,45 @@ sadopen( cred_t *credp) /* user credentials */ { int i; + netstack_t *ns; + str_stack_t *ss; if (sflag) /* no longer called from clone driver */ return (EINVAL); + ns = netstack_find_by_cred(credp); + ASSERT(ns != NULL); + ss = ns->netstack_str; + ASSERT(ss != NULL); + /* * Both USRMIN and ADMMIN are clone interfaces. */ - for (i = 0; i < sadcnt; i++) - if (saddev[i].sa_qp == NULL) + for (i = 0; i < ss->ss_sadcnt; i++) + if (ss->ss_saddev[i].sa_qp == NULL) break; - if (i >= sadcnt) /* no such device */ + if (i >= ss->ss_sadcnt) { /* no such device */ + netstack_rele(ss->ss_netstack); return (ENXIO); - + } switch (getminor(*devp)) { case USRMIN: /* mere mortal */ - saddev[i].sa_flags = 0; + ss->ss_saddev[i].sa_flags = 0; break; case ADMMIN: /* privileged user */ - saddev[i].sa_flags = SADPRIV; + ss->ss_saddev[i].sa_flags = SADPRIV; break; default: + netstack_rele(ss->ss_netstack); return (EINVAL); } - saddev[i].sa_qp = qp; - qp->q_ptr = (caddr_t)&saddev[i]; - WR(qp)->q_ptr = (caddr_t)&saddev[i]; + ss->ss_saddev[i].sa_qp = qp; + ss->ss_saddev[i].sa_ss = ss; + qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; + WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; /* * NOTE: should the ADMMIN or USRMIN minors change @@ -244,6 +255,8 @@ sadclose( sadp = (struct saddev *)qp->q_ptr; sadp->sa_qp = NULL; sadp->sa_addr = NULL; + netstack_rele(sadp->sa_ss->ss_netstack); + sadp->sa_ss = NULL; qp->q_ptr = NULL; WR(qp)->q_ptr = NULL; return (0); @@ -382,6 +395,10 @@ apush_iocdata( struct saddev *sadp; uint_t size; dev_t dev; + str_stack_t *ss; + + sadp = (struct saddev *)qp->q_ptr; + ss = sadp->sa_ss; csp = (struct copyresp *)mp->b_rptr; if (csp->cp_rval) { /* if there was an error */ @@ -436,25 +453,26 @@ apush_iocdata( /* sanity check the request */ if (((ret = sad_ap_verify(ap)) != 0) || ((ret = valid_major(ap->ap_major)) != 0)) { - sad_ap_rele(ap); + sad_ap_rele(ap, ss); miocnak(qp, mp, 0, ret); return; } /* check for overlapping configs */ - mutex_enter(&sad_lock); - if ((ap_tmp = sad_ap_find(&ap->ap_common)) != NULL) { + mutex_enter(&ss->ss_sad_lock); + ap_tmp = sad_ap_find(&ap->ap_common, ss); + if (ap_tmp != NULL) { /* already configured */ - mutex_exit(&sad_lock); - sad_ap_rele(ap_tmp); - sad_ap_rele(ap); + mutex_exit(&ss->ss_sad_lock); + sad_ap_rele(ap_tmp, ss); + sad_ap_rele(ap, ss); miocnak(qp, mp, 0, EEXIST); return; } /* add the new config to our hash */ - sad_ap_insert(ap); - mutex_exit(&sad_lock); + sad_ap_insert(ap, ss); + mutex_exit(&ss->ss_sad_lock); miocack(qp, mp, 0, 0); return; @@ -466,7 +484,7 @@ apush_iocdata( } /* search for a matching config */ - if ((ap = sad_ap_find_by_dev(dev)) == NULL) { + if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { /* no config found */ miocnak(qp, mp, 0, ENODEV); return; @@ -479,7 +497,7 @@ apush_iocdata( */ if ((ap->ap_type == SAP_RANGE) && (ap->ap_minor != sap->sap_minor)) { - sad_ap_rele(ap); + sad_ap_rele(ap, ss); miocnak(qp, mp, 0, ERANGE); return; } @@ -490,7 +508,7 @@ apush_iocdata( */ if ((ap->ap_type == SAP_ALL) && (sap->sap_minor != 0)) { - sad_ap_rele(ap); + sad_ap_rele(ap, ss); miocnak(qp, mp, 0, EINVAL); return; } @@ -499,27 +517,27 @@ apush_iocdata( * make sure someone else hasn't already * removed this config from the hash. */ - mutex_enter(&sad_lock); - ap_tmp = sad_ap_find(&ap->ap_common); + mutex_enter(&ss->ss_sad_lock); + ap_tmp = sad_ap_find(&ap->ap_common, ss); if (ap_tmp != ap) { - mutex_exit(&sad_lock); - sad_ap_rele(ap_tmp); - sad_ap_rele(ap); + mutex_exit(&ss->ss_sad_lock); + sad_ap_rele(ap_tmp, ss); + sad_ap_rele(ap, ss); miocnak(qp, mp, 0, ENODEV); return; - } else + } /* remove the config from the hash and return */ - sad_ap_remove(ap); - mutex_exit(&sad_lock); + sad_ap_remove(ap, ss); + mutex_exit(&ss->ss_sad_lock); /* * Release thrice, once for sad_ap_find_by_dev(), * once for sad_ap_find(), and once to free. */ - sad_ap_rele(ap); - sad_ap_rele(ap); - sad_ap_rele(ap); + sad_ap_rele(ap, ss); + sad_ap_rele(ap, ss); + sad_ap_rele(ap, ss); miocack(qp, mp, 0, 0); return; } /* switch (sap_cmd) */ @@ -536,7 +554,7 @@ apush_iocdata( } /* search for a matching config */ - if ((ap = sad_ap_find_by_dev(dev)) == NULL) { + if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { /* no config found */ miocnak(qp, mp, 0, ENODEV); return; @@ -550,9 +568,10 @@ apush_iocdata( (void) strcpy(sap->sap_list[i], ap->ap_list[i]); for (; i < MAXAPUSH; i++) bzero(sap->sap_list[i], FMNAMESZ + 1); + mutex_exit(&ss->ss_sad_lock); /* release our hold on the config */ - sad_ap_rele(ap); + sad_ap_rele(ap, ss); /* copyout the results */ if (SAD_VER(csp->cp_cmd) == 1) @@ -560,7 +579,6 @@ apush_iocdata( else size = STRAPUSH_V0_LEN; - sadp = (struct saddev *)qp->q_ptr; mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, NULL); qreply(qp, mp); diff --git a/usr/src/uts/common/io/sad_conf.c b/usr/src/uts/common/io/sad_conf.c index 1611eaa18a..4560922f2d 100644 --- a/usr/src/uts/common/io/sad_conf.c +++ b/usr/src/uts/common/io/sad_conf.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,9 +37,6 @@ #include <sys/kmem.h> #include <sys/sysmacros.h> -struct saddev *saddev; /* sad device array */ -int sadcnt = 16; /* number of sad devices */ - /* * Currently we store all the sad data in a hash table keyed by major * number. This is far from ideal. It means that if a single device @@ -69,9 +66,6 @@ int sadcnt = 16; /* number of sad devices */ * for a given major number then there can't be any SAP_RANGE or SAP_ONE * nodes for that same major number. */ -kmutex_t sad_lock; /* protects sad_hash */ -static mod_hash_t *sad_hash; -static size_t sad_hash_nchains = 127; /* * Private Internal Interfaces @@ -207,59 +201,60 @@ sad_ap_alloc(void) } void -sad_ap_rele(struct autopush *ap) +sad_ap_rele(struct autopush *ap, str_stack_t *ss) { - mutex_enter(&sad_lock); + mutex_enter(&ss->ss_sad_lock); ASSERT(ap->ap_cnt > 0); if (--(ap->ap_cnt) == 0) { - mutex_exit(&sad_lock); + mutex_exit(&ss->ss_sad_lock); kmem_free(ap, sizeof (struct autopush)); } else { - mutex_exit(&sad_lock); + mutex_exit(&ss->ss_sad_lock); } } void -sad_ap_insert(struct autopush *ap) +sad_ap_insert(struct autopush *ap, str_stack_t *ss) { - ASSERT(MUTEX_HELD(&sad_lock)); + ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); ASSERT(sad_apc_verify(&ap->ap_common) == 0); - ASSERT(sad_ap_find(&ap->ap_common) == NULL); - (void) mod_hash_insert(sad_hash, &ap->ap_common, ap); + ASSERT(sad_ap_find(&ap->ap_common, ss) == NULL); + (void) mod_hash_insert(ss->ss_sad_hash, &ap->ap_common, ap); } void -sad_ap_remove(struct autopush *ap) +sad_ap_remove(struct autopush *ap, str_stack_t *ss) { struct autopush *ap_removed = NULL; - ASSERT(MUTEX_HELD(&sad_lock)); - (void) mod_hash_remove(sad_hash, &ap->ap_common, + ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); + (void) mod_hash_remove(ss->ss_sad_hash, &ap->ap_common, (mod_hash_val_t *)&ap_removed); ASSERT(ap == ap_removed); } struct autopush * -sad_ap_find(struct apcommon *apc) +sad_ap_find(struct apcommon *apc, str_stack_t *ss) { struct autopush *ap_result = NULL; - ASSERT(MUTEX_HELD(&sad_lock)); + ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); ASSERT(sad_apc_verify(apc) == 0); - (void) mod_hash_find(sad_hash, apc, (mod_hash_val_t *)&ap_result); + (void) mod_hash_find(ss->ss_sad_hash, apc, + (mod_hash_val_t *)&ap_result); if (ap_result != NULL) ap_result->ap_cnt++; return (ap_result); } struct autopush * -sad_ap_find_by_dev(dev_t dev) +sad_ap_find_by_dev(dev_t dev, str_stack_t *ss) { struct apcommon apc; struct autopush *ap_result; - ASSERT(MUTEX_NOT_HELD(&sad_lock)); + ASSERT(MUTEX_NOT_HELD(&ss->ss_sad_lock)); /* prepare an apcommon structure to search with */ apc.apc_cmd = SAP_ONE; @@ -274,17 +269,35 @@ sad_ap_find_by_dev(dev_t dev) apc.apc_npush = 1; apc.apc_lastminor = 0; - mutex_enter(&sad_lock); - ap_result = sad_ap_find(&apc); - mutex_exit(&sad_lock); + mutex_enter(&ss->ss_sad_lock); + ap_result = sad_ap_find(&apc, ss); + mutex_exit(&ss->ss_sad_lock); return (ap_result); } void -sad_initspace(void) +sad_initspace(str_stack_t *ss) { - saddev = kmem_zalloc(sadcnt * sizeof (struct saddev), KM_SLEEP); - sad_hash = mod_hash_create_extended("sad_hash", - sad_hash_nchains, mod_hash_null_keydtor, mod_hash_null_valdtor, + mutex_init(&ss->ss_sad_lock, NULL, MUTEX_DEFAULT, NULL); + ss->ss_sad_hash_nchains = 127; + ss->ss_sadcnt = 16; + + ss->ss_saddev = kmem_zalloc(ss->ss_sadcnt * sizeof (struct saddev), + KM_SLEEP); + ss->ss_sad_hash = mod_hash_create_extended("sad_hash", + ss->ss_sad_hash_nchains, mod_hash_null_keydtor, + mod_hash_null_valdtor, sad_hash_alg, NULL, sad_hash_keycmp, KM_SLEEP); } + +void +sad_freespace(str_stack_t *ss) +{ + kmem_free(ss->ss_saddev, ss->ss_sadcnt * sizeof (struct saddev)); + ss->ss_saddev = NULL; + + mod_hash_destroy_hash(ss->ss_sad_hash); + ss->ss_sad_hash = NULL; + + mutex_destroy(&ss->ss_sad_lock); +} diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index c7463832fc..7da86a44bb 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -628,6 +628,10 @@ strplumb(void) if ((err = ldi_ident_from_mod(&modlinkage, &li)) != 0) return (err); + /* + * Setup the TCP and SCTP default queues for the global stack. + * tcp/sctp_stack_init will do this for additional stack instances. + */ if ((err = strplumb_sctpq(li)) != 0) goto done; |