Exemple #1
0
int
dls_vlan_destroy(const char *name)
{
	int		err;
	dls_vlan_t	*dvp;
	dls_link_t	*dlp;
	mod_hash_val_t	val;

	/*
	 * Find the dls_vlan_t in the global hash table.
	 */
	rw_enter(&i_dls_vlan_lock, RW_WRITER);

	err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name,
	    (mod_hash_val_t *)&dvp);
	if (err != 0) {
		err = ENOENT;
		goto done;
	}

	/*
	 * Check to see if it is referenced by any dls_impl_t.
	 */
	if (dvp->dv_ref != 0) {
		err = EBUSY;
		goto done;
	}

	/*
	 * Remove and destroy the hash table entry.
	 */
	err = mod_hash_remove(i_dls_vlan_hash, (mod_hash_key_t)name,
	    (mod_hash_val_t *)&val);
	ASSERT(err == 0);
	ASSERT(dvp == (dls_vlan_t *)val);

	ASSERT(i_dls_vlan_count > 0);
	i_dls_vlan_count--;

	/*
	 * Save a reference to dv_dlp before freeing the dls_vlan_t back
	 * to the cache.
	 */
	dlp = dvp->dv_dlp;
	kmem_cache_free(i_dls_vlan_cachep, dvp);

	/*
	 * Release the dls_link_t. This will destroy the dls_link_t and
	 * release the MAC if there are no more dls_vlan_t.
	 */
	dls_link_rele(dlp);
done:
	rw_exit(&i_dls_vlan_lock);
	return (err);
}
Exemple #2
0
/*
 * Find the given vlan id in the hash table.
 * Return: B_TRUE if the id is found; B_FALSE if not found.
 */
boolean_t
vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
{
	int		rv;
	mod_hash_val_t	vp;

	rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);

	if (rv != 0)
		return (B_FALSE);

	return (B_TRUE);
}
Exemple #3
0
static task_t *
task_find(taskid_t id, zoneid_t zoneid)
{
	task_t *tk;

	ASSERT(MUTEX_HELD(&task_hash_lock));

	if (mod_hash_find(task_hash, (mod_hash_key_t)(uintptr_t)id,
	    (mod_hash_val_t *)&tk) == MH_ERR_NOTFOUND ||
	    (zoneid != ALL_ZONES && zoneid != tk->tk_zone->zone_id))
		return (NULL);

	return (tk);
}
Exemple #4
0
uintptr_t
space_fetch(char *key)
{
	uintptr_t ptr = 0;
	mod_hash_val_t val;
	int rval;

	if (key) {
		rval = mod_hash_find(space_hash, (mod_hash_key_t)key, &val);
		if (rval == 0) {
			ptr = (uintptr_t)val;
		}
	}

	return (ptr);
}
/* ARGSUSED */
int
vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask,
    vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr,
    uint_t mac_slot, mac_resource_props_t *mrp)
{
	vnic_t *vnic = NULL;

	rw_enter(&vnic_lock, RW_WRITER);

	if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t *)&vnic) != 0) {
		rw_exit(&vnic_lock);
		return (ENOENT);
	}

	rw_exit(&vnic_lock);

	return (0);
}
int
vnic_info(vnic_info_t *info, cred_t *credp)
{
	vnic_t		*vnic;
	int		err;

	/* Make sure that the VNIC link is visible from the caller's zone. */
	if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp)))
		return (ENOENT);

	rw_enter(&vnic_lock, RW_WRITER);

	err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id),
	    (mod_hash_val_t *)&vnic);
	if (err != 0) {
		rw_exit(&vnic_lock);
		return (ENOENT);
	}

	info->vn_link_id = vnic->vn_link_id;
	info->vn_mac_addr_type = vnic->vn_addr_type;
	info->vn_mac_len = vnic->vn_addr_len;
	bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN);
	info->vn_mac_slot = vnic->vn_slot_id;
	info->vn_mac_prefix_len = 0;
	info->vn_vid = vnic->vn_vid;
	info->vn_force = vnic->vn_force;
	info->vn_vrid = vnic->vn_vrid;
	info->vn_af = vnic->vn_af;

	bzero(&info->vn_resource_props, sizeof (mac_resource_props_t));
	if (vnic->vn_mch != NULL)
		mac_client_get_resources(vnic->vn_mch,
		    &info->vn_resource_props);

	rw_exit(&vnic_lock);
	return (0);
}
/* ARGSUSED */
int
vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
{
	vnic_t *vnic = NULL;
	mod_hash_val_t val;
	datalink_id_t tmpid;
	int rc;

	rw_enter(&vnic_lock, RW_WRITER);

	if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t *)&vnic) != 0) {
		rw_exit(&vnic_lock);
		return (ENOENT);
	}

	if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) {
		rw_exit(&vnic_lock);
		return (rc);
	}

	ASSERT(vnic_id == tmpid);

	/*
	 * We cannot unregister the MAC yet. Unregistering would
	 * free up mac_impl_t which should not happen at this time.
	 * So disable mac_impl_t by calling mac_disable(). This will prevent
	 * any new claims on mac_impl_t.
	 */
	if ((rc = mac_disable(vnic->vn_mh)) != 0) {
		(void) dls_devnet_create(vnic->vn_mh, vnic_id,
		    crgetzoneid(credp));
		rw_exit(&vnic_lock);
		return (rc);
	}

	vnic_cleanup_secondary_macs(vnic, vnic->vn_nhandles);

	vnic->vn_enabled = B_FALSE;
	(void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val);
	ASSERT(vnic == (vnic_t *)val);
	vnic_count--;
	rw_exit(&vnic_lock);

	/*
	 * XXX-nicolas shouldn't have a void cast here, if it's
	 * expected that the function will never fail, then we should
	 * have an ASSERT().
	 */
	(void) mac_unregister(vnic->vn_mh);

	if (vnic->vn_lower_mh != NULL) {
		/*
		 * Check if MAC address for the vnic was obtained from the
		 * factory MAC addresses. If yes, release it.
		 */
		if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
			(void) mac_addr_factory_release(vnic->vn_mch,
			    vnic->vn_slot_id);
		}
		(void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin);
		(void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu);
		(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
		(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
		mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
		mac_close(vnic->vn_lower_mh);
	}

	kmem_cache_free(vnic_cache, vnic);
	return (0);
}
/* ARGSUSED */
int
vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
    vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr,
    int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
    int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag,
    cred_t *credp)
{
	vnic_t *vnic;
	mac_register_t *mac;
	int err;
	boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0);
	char vnic_name[MAXNAMELEN];
	const mac_info_t *minfop;
	uint32_t req_hwgrp_flag = B_FALSE;

	*diag = VNIC_IOC_DIAG_NONE;

	rw_enter(&vnic_lock, RW_WRITER);

	/* does a VNIC with the same id already exist? */
	err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t *)&vnic);
	if (err == 0) {
		rw_exit(&vnic_lock);
		return (EEXIST);
	}

	vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP);
	if (vnic == NULL) {
		rw_exit(&vnic_lock);
		return (ENOMEM);
	}

	bzero(vnic, sizeof (*vnic));

	vnic->vn_id = vnic_id;
	vnic->vn_link_id = linkid;
	vnic->vn_vrid = vrid;
	vnic->vn_af = af;

	if (!is_anchor) {
		if (linkid == DATALINK_INVALID_LINKID) {
			err = EINVAL;
			goto bail;
		}

		/*
		 * Open the lower MAC and assign its initial bandwidth and
		 * MAC address. We do this here during VNIC creation and
		 * do not wait until the upper MAC client open so that we
		 * can validate the VNIC creation parameters (bandwidth,
		 * MAC address, etc) and reserve a factory MAC address if
		 * one was requested.
		 */
		err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh);
		if (err != 0)
			goto bail;

		/*
		 * VNIC(vlan) over VNICs(vlans) is not supported.
		 */
		if (mac_is_vnic(vnic->vn_lower_mh)) {
			err = EINVAL;
			goto bail;
		}

		/* only ethernet support for now */
		minfop = mac_info(vnic->vn_lower_mh);
		if (minfop->mi_nativemedia != DL_ETHER) {
			err = ENOTSUP;
			goto bail;
		}

		(void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL,
		    NULL);
		err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch,
		    vnic_name, MAC_OPEN_FLAGS_IS_VNIC);
		if (err != 0)
			goto bail;

		/* assign a MAC address to the VNIC */

		err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot,
		    mac_prefix_len, mac_len, mac_addr, flags, diag, vid,
		    req_hwgrp_flag);
		if (err != 0) {
			vnic->vn_muh = NULL;
			if (diag != NULL && req_hwgrp_flag)
				*diag = VNIC_IOC_DIAG_NO_HWRINGS;
			goto bail;
		}

		/* register to receive notification from underlying MAC */
		vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb,
		    vnic);

		*vnic_addr_type = vnic->vn_addr_type;
		vnic->vn_addr_len = *mac_len;
		vnic->vn_vid = vid;

		bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len);

		if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY)
			vnic->vn_slot_id = *mac_slot;

		/*
		 * Set the initial VNIC capabilities. If the VNIC is created
		 * over MACs which does not support nactive vlan, disable
		 * VNIC's hardware checksum capability if its VID is not 0,
		 * since the underlying MAC would get the hardware checksum
		 * offset wrong in case of VLAN packets.
		 */
		if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh,
		    MAC_CAPAB_NO_NATIVEVLAN, NULL)) {
			if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM,
			    &vnic->vn_hcksum_txflags))
				vnic->vn_hcksum_txflags = 0;
		} else {
			vnic->vn_hcksum_txflags = 0;
		}
	}

	/* register with the MAC module */
	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
		goto bail;

	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
	mac->m_driver = vnic;
	mac->m_dip = vnic_get_dip();
	mac->m_instance = (uint_t)-1;
	mac->m_src_addr = vnic->vn_addr;
	mac->m_callbacks = &vnic_m_callbacks;

	if (!is_anchor) {
		/*
		 * If this is a VNIC based VLAN, then we check for the
		 * margin unless it has been created with the force
		 * flag. If we are configuring a VLAN over an etherstub,
		 * we don't check the margin even if force is not set.
		 */
		if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) {
			if (vid != VLAN_ID_NONE)
				vnic->vn_force = B_TRUE;
			/*
			 * As the current margin size of the underlying mac is
			 * used to determine the margin size of the VNIC
			 * itself, request the underlying mac not to change
			 * to a smaller margin size.
			 */
			err = mac_margin_add(vnic->vn_lower_mh,
			    &vnic->vn_margin, B_TRUE);
			ASSERT(err == 0);
		} else {
			vnic->vn_margin = VLAN_TAGSZ;
			err = mac_margin_add(vnic->vn_lower_mh,
			    &vnic->vn_margin, B_FALSE);
			if (err != 0) {
				mac_free(mac);
				if (diag != NULL)
					*diag = VNIC_IOC_DIAG_MACMARGIN_INVALID;
				goto bail;
			}
		}

		mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
		    &mac->m_max_sdu);
		err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
		if (err != 0) {
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
			mac_free(mac);
			if (diag != NULL)
				*diag = VNIC_IOC_DIAG_MACMTU_INVALID;
			goto bail;
		}
		vnic->vn_mtu = mac->m_max_sdu;
	} else {
		vnic->vn_margin = VLAN_TAGSZ;
		mac->m_min_sdu = 1;
		mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
		vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
	}

	mac->m_margin = vnic->vn_margin;

	err = mac_register(mac, &vnic->vn_mh);
	mac_free(mac);
	if (err != 0) {
		if (!is_anchor) {
			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
			    vnic->vn_mtu) == 0);
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
		}
		goto bail;
	}

	/* Set the VNIC's MAC in the client */
	if (!is_anchor) {
		mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp);

		if (mrp != NULL) {
			if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 ||
			    (mrp->mrp_mask & MRP_TX_RINGS) != 0) {
				req_hwgrp_flag = B_TRUE;
			}
			err = mac_client_set_resources(vnic->vn_mch, mrp);
			if (err != 0) {
				VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
				    vnic->vn_mtu) == 0);
				VERIFY(mac_margin_remove(vnic->vn_lower_mh,
				    vnic->vn_margin) == 0);
				(void) mac_unregister(vnic->vn_mh);
				goto bail;
			}
		}
	}

	err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp));
	if (err != 0) {
		VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
		    vnic->vn_margin) == 0);
		if (!is_anchor) {
			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
			    vnic->vn_mtu) == 0);
			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
			    vnic->vn_margin) == 0);
		}
		(void) mac_unregister(vnic->vn_mh);
		goto bail;
	}

	/* add new VNIC to hash table */
	err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id),
	    (mod_hash_val_t)vnic);
	ASSERT(err == 0);
	vnic_count++;

	/*
	 * Now that we've enabled this VNIC, we should go through and update the
	 * link state by setting it to our parents.
	 */
	vnic->vn_enabled = B_TRUE;

	if (is_anchor) {
		mac_link_update(vnic->vn_mh, LINK_STATE_UP);
	} else {
		mac_link_update(vnic->vn_mh,
		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
	}

	rw_exit(&vnic_lock);

	return (0);

bail:
	rw_exit(&vnic_lock);
	if (!is_anchor) {
		if (vnic->vn_mnh != NULL)
			(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
		if (vnic->vn_muh != NULL)
			(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
		if (vnic->vn_mch != NULL)
			mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
		if (vnic->vn_lower_mh != NULL)
			mac_close(vnic->vn_lower_mh);
	}

	kmem_cache_free(vnic_cache, vnic);
	return (err);
}
Exemple #9
0
int
dls_vlan_hold(const char *name, dls_vlan_t **dvpp, boolean_t create_vlan)
{
	int		err;
	dls_vlan_t	*dvp;
	dls_link_t	*dlp;
	boolean_t	vlan_created = B_FALSE;

again:
	rw_enter(&i_dls_vlan_lock, RW_WRITER);

	err = mod_hash_find(i_dls_vlan_hash, (mod_hash_key_t)name,
	    (mod_hash_val_t *)&dvp);
	if (err != 0) {
		char		mac[MAXNAMELEN];
		uint_t		index, ddi_inst, mac_ppa, len;
		uint16_t	vid;

		ASSERT(err == MH_ERR_NOTFOUND);

		vlan_created = B_FALSE;
		if (!create_vlan) {
			err = ENOENT;
			goto done;
		}

		/*
		 * Only create tagged vlans on demand.
		 * Note that if we get here, 'name' must be a sane
		 * value because it must have been derived from
		 * ddi_major_to_name().
		 */
		if (ddi_parse(name, mac, &index) != DDI_SUCCESS ||
		    (vid = DLS_PPA2VID(index)) == VLAN_ID_NONE ||
		    vid > VLAN_ID_MAX) {
			err = EINVAL;
			goto done;
		}

		mac_ppa = (uint_t)DLS_PPA2INST(index);
		if (strcmp(mac, "aggr") == 0)
			ddi_inst = 0;
		else
			ddi_inst = mac_ppa;

		len = strlen(mac);
		ASSERT(len < MAXNAMELEN);
		(void) snprintf(mac + len, MAXNAMELEN - len, "%d", mac_ppa);
		rw_exit(&i_dls_vlan_lock);

		if ((err = dls_vlan_create(name, mac, ddi_inst, vid)) != 0) {
			rw_enter(&i_dls_vlan_lock, RW_WRITER);
			goto done;
		}

		/*
		 * At this point someone else could do a dls_vlan_hold and
		 * dls_vlan_rele on this new vlan and causes it to be
		 * destroyed. This will at worst cause us to spin a few
		 * times.
		 */
		vlan_created = B_TRUE;
		goto again;
	}

	dlp = dvp->dv_dlp;

	if ((err = dls_mac_hold(dlp)) != 0)
		goto done;

	/*
	 * Do not allow the creation of tagged VLAN interfaces on
	 * non-Ethernet links.  Note that we cannot do this check in
	 * dls_vlan_create() nor in this function prior to the call to
	 * dls_mac_hold().  The reason is that before we do a
	 * dls_mac_hold(), we may not have opened the mac, and therefore do
	 * not know what kind of media the mac represents.  In other words,
	 * dls_mac_hold() assigns the dl_mip of the dls_link_t we're
	 * interested in.
	 */
	if (dvp->dv_id != VLAN_ID_NONE && dlp->dl_mip->mi_media != DL_ETHER) {
		dls_mac_rele(dlp);
		err = EINVAL;
		goto done;
	}

	if ((err = mac_start(dlp->dl_mh)) != 0) {
		dls_mac_rele(dlp);
		goto done;
	}

	if (dvp->dv_ref++ == 0)
		dls_mac_stat_create(dvp);

	*dvpp = dvp;
done:
	rw_exit(&i_dls_vlan_lock);

	/*
	 * We could be destroying a vlan created by another thread. This
	 * is ok because this other thread will just loop back up and
	 * recreate the vlan.
	 */
	if (err != 0 && vlan_created)
		(void) dls_vlan_destroy(name);
	return (err);
}
Exemple #10
0
/*
 * Forward pkts to any devices or interfaces which have registered
 * an interest in them (i.e. multicast groups).
 */
static int
vsw_forward_grp(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg)
{
	struct ether_header	*ehp = (struct ether_header *)mp->b_rptr;
	mfdb_ent_t		*entp = NULL;
	mfdb_ent_t		*tpp = NULL;
	vsw_port_t 		*port;
	uint64_t		key = 0;
	mblk_t			*nmp = NULL;
	mblk_t			*ret_m = NULL;
	boolean_t		check_if = B_TRUE;

	/*
	 * Convert address to hash table key
	 */
	KEY_HASH(key, &ehp->ether_dhost);

	D1(vswp, "%s: key 0x%llx", __func__, key);

	/*
	 * If pkt came from either a vnet or down the stack (if we are
	 * plumbed) and we are in layer 2 mode, then we send the pkt out
	 * over the physical adapter, and then check to see if any other
	 * vnets are interested in it.
	 */
	if ((vswp->smode & VSW_LAYER2) &&
	    ((caller == VSW_VNETPORT) || (caller == VSW_LOCALDEV))) {
		nmp = vsw_dupmsgchain(mp);
		if (nmp) {
			if ((ret_m = vsw_tx_msg(vswp, nmp, caller, arg))
			    != NULL) {
				DERR(vswp, "%s: dropping pkt(s) consisting of "
				    "%ld bytes of data for physical device",
				    __func__, MBLKL(ret_m));
				freemsgchain(ret_m);
			}
		}
	}

	READ_ENTER(&vswp->mfdbrw);
	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)key,
	    (mod_hash_val_t *)&entp) != 0) {
		D3(vswp, "%s: no table entry found for addr 0x%llx",
		    __func__, key);
	} else {
		/*
		 * Send to list of devices associated with this address...
		 */
		for (tpp = entp; tpp != NULL; tpp = tpp->nextp) {

			/* dont send to ourselves */
			if ((caller == VSW_VNETPORT) &&
			    (tpp->d_addr == (void *)arg)) {
				port = (vsw_port_t *)tpp->d_addr;
				D3(vswp, "%s: not sending to ourselves"
				    " : port %d", __func__, port->p_instance);
				continue;

			} else if ((caller == VSW_LOCALDEV) &&
			    (tpp->d_type == VSW_LOCALDEV)) {
				D2(vswp, "%s: not sending back up stack",
				    __func__);
				continue;
			}

			if (tpp->d_type == VSW_VNETPORT) {
				port = (vsw_port_t *)tpp->d_addr;
				D3(vswp, "%s: sending to port %ld for addr "
				    "0x%llx", __func__, port->p_instance, key);

				nmp = vsw_dupmsgchain(mp);
				if (nmp) {
					/*
					 * The vswp->mfdbrw is protecting the
					 * portp from getting destroyed here.
					 * So, no ref_cnt is incremented here.
					 */
					(void) vsw_portsend(port, nmp);
				}
			} else {
				vsw_mac_rx(vswp, NULL,
				    mp, VSW_MACRX_COPYMSG);
				D2(vswp, "%s: sending up stack"
				    " for addr 0x%llx", __func__, key);
				check_if = B_FALSE;
			}
		}
	}

	RW_EXIT(&vswp->mfdbrw);

	/*
	 * If the pkt came from either a vnet or from physical device,
	 * and if we havent already sent the pkt up the stack then we
	 * check now if we can/should (i.e. the interface is plumbed
	 * and in promisc mode).
	 */
	if ((check_if) &&
	    ((caller == VSW_VNETPORT) || (caller == VSW_PHYSDEV))) {
		vsw_mac_rx(vswp, NULL, mp,
		    VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG);
	}

	freemsgchain(mp);

	D1(vswp, "%s: exit", __func__);

	return (0);
}
Exemple #11
0
/*
 * Remove a multicast entry from the hashtable.
 *
 * Search hash table based on address. If match found, scan
 * list of ports associated with address. If specified port
 * found remove it from list.
 */
int
vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
{
	mfdb_ent_t	*ment = NULL;
	mfdb_ent_t	*curr_p, *prev_p;
	void		*tgt = NULL;

	D1(vswp, "%s: enter", __func__);

	if (devtype == VSW_VNETPORT) {
		tgt = (vsw_port_t *)arg;
		D2(vswp, "%s: removing port %d from mFDB for address"
		    " 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance, addr);
	} else {
		D2(vswp, "%s: removing entry", __func__);
		tgt = (void *)vswp;
	}

	WRITE_ENTER(&vswp->mfdbrw);
	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
	    (mod_hash_val_t *)&ment) != 0) {
		D2(vswp, "%s: address 0x%llx not in table", __func__, addr);
		RW_EXIT(&vswp->mfdbrw);
		return (1);
	}

	prev_p = curr_p = ment;

	while (curr_p != NULL) {
		if (curr_p->d_addr == (void *)tgt) {
			if (devtype == VSW_VNETPORT) {
				D2(vswp, "%s: port %d found", __func__,
				    ((vsw_port_t *)tgt)->p_instance);
			} else {
				D2(vswp, "%s: instance found", __func__);
			}

			if (prev_p == curr_p) {
				/*
				 * head of list, if no other element is in
				 * list then destroy this entry, otherwise
				 * just replace it with updated value.
				 */
				ment = curr_p->nextp;
				if (ment == NULL) {
					(void) mod_hash_destroy(vswp->mfdb,
					    (mod_hash_val_t)addr);
				} else {
					(void) mod_hash_replace(vswp->mfdb,
					    (mod_hash_key_t)addr,
					    (mod_hash_val_t)ment);
				}
			} else {
				/*
				 * Not head of list, no need to do
				 * replacement, just adjust list pointers.
				 */
				prev_p->nextp = curr_p->nextp;
			}
			break;
		}

		prev_p = curr_p;
		curr_p = curr_p->nextp;
	}

	RW_EXIT(&vswp->mfdbrw);

	D1(vswp, "%s: exit", __func__);

	if (curr_p == NULL)
		return (1);
	kmem_free(curr_p, sizeof (mfdb_ent_t));
	return (0);
}
Exemple #12
0
/*
 * Add a new multicast entry.
 *
 * Search hash table based on address. If match found then
 * update associated val (which is chain of ports), otherwise
 * create new key/val (addr/port) pair and insert into table.
 */
int
vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg)
{
	int		dup = 0;
	int		rv = 0;
	mfdb_ent_t	*ment = NULL;
	mfdb_ent_t	*tmp_ent = NULL;
	mfdb_ent_t	*new_ent = NULL;
	void		*tgt = NULL;

	if (devtype == VSW_VNETPORT) {
		/*
		 * Being invoked from a vnet.
		 */
		ASSERT(arg != NULL);
		tgt = arg;
		D2(NULL, "%s: port %d : address 0x%llx", __func__,
		    ((vsw_port_t *)arg)->p_instance, addr);
	} else {
		/*
		 * We are being invoked via the m_multicst mac entry
		 * point.
		 */
		D2(NULL, "%s: address 0x%llx", __func__, addr);
		tgt = (void *)vswp;
	}

	WRITE_ENTER(&vswp->mfdbrw);
	if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr,
	    (mod_hash_val_t *)&ment) != 0) {

		/* address not currently in table */
		ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
		ment->d_addr = (void *)tgt;
		ment->d_type = devtype;
		ment->nextp = NULL;

		if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr,
		    (mod_hash_val_t)ment) != 0) {
			DERR(vswp, "%s: hash table insertion failed", __func__);
			kmem_free(ment, sizeof (mfdb_ent_t));
			rv = 1;
		} else {
			D2(vswp, "%s: added initial entry for 0x%llx to "
			    "table", __func__, addr);
		}
	} else {
		/*
		 * Address in table. Check to see if specified port
		 * is already associated with the address. If not add
		 * it now.
		 */
		tmp_ent = ment;
		while (tmp_ent != NULL) {
			if (tmp_ent->d_addr == (void *)tgt) {
				if (devtype == VSW_VNETPORT) {
					DERR(vswp, "%s: duplicate port entry "
					    "found for portid %ld and key "
					    "0x%llx", __func__,
					    ((vsw_port_t *)arg)->p_instance,
					    addr);
				} else {
					DERR(vswp, "%s: duplicate entry found"
					    "for key 0x%llx", __func__, addr);
				}
				rv = 1;
				dup = 1;
				break;
			}
			tmp_ent = tmp_ent->nextp;
		}

		/*
		 * Port not on list so add it to end now.
		 */
		if (0 == dup) {
			D2(vswp, "%s: added entry for 0x%llx to table",
			    __func__, addr);
			new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP);
			new_ent->d_addr = (void *)tgt;
			new_ent->d_type = devtype;
			new_ent->nextp = NULL;

			tmp_ent = ment;
			while (tmp_ent->nextp != NULL)
				tmp_ent = tmp_ent->nextp;

			tmp_ent->nextp = new_ent;
		}
	}

	RW_EXIT(&vswp->mfdbrw);
	return (rv);
}
Exemple #13
0
/*
 * For unsolicited exchanges, FCoET is only responsible for allocation of
 * req_payload. FCT will allocate resp_payload after the exchange is
 * passed on.
 */
static fcoet_exchange_t *
fcoet_create_unsol_exchange(fcoe_frame_t *frm)
{
	uint8_t			 r_ctl;
	int			 cdb_size;
	fcoet_exchange_t	*xch, *xch_tmp;
	fct_cmd_t		*cmd;
	fcoe_fcp_cmnd_t		*ffc;
	uint32_t		task_expected_len = 0;

	r_ctl = FRM_R_CTL(frm);
	switch (r_ctl) {
	case 0x22:
		/*
		 * FCoET's unsolicited ELS
		 */
		cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
		    GET_STRUCT_SIZE(fcoet_exchange_t) +
		    frm->frm_payload_size, 0);
		if (cmd == NULL) {
			FCOET_EXT_LOG(0, "can't get cmd");
			return (NULL);
		}
		break;

	case 0x06:
		/*
		 * FCoET's unsolicited SCSI cmd
		 */
		cdb_size = 16;	/* need improve later */
		cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE,
		    FRM_S_ID(frm), frm->frm_payload, cdb_size,
		    STMF_TASK_EXT_NONE);
		if (cmd == NULL) {
			FCOET_EXT_LOG(0, "can't get fcp cmd");
			return (NULL);
		}
		ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
		task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl);
		break;

	default:
		FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl);
		return (NULL);
	}

	/*
	 * xch initialization
	 */
	xch = CMD2XCH(cmd);
	xch->xch_oxid = FRM_OXID(frm);
	xch->xch_flags = 0;
	xch->xch_ss = FRM2SS(frm);
	xch->xch_cmd = cmd;
	xch->xch_current_seq = NULL;
	xch->xch_left_data_size = 0;
	if (task_expected_len) {
		xch->xch_dbuf_num =
		    (task_expected_len + FCOET_MAX_DBUF_LEN - 1) /
		    FCOET_MAX_DBUF_LEN;
		xch->xch_dbufs =
		    kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *),
		    KM_SLEEP);
	}
	xch->xch_start_time = ddi_get_lbolt();
	do {
		xch->xch_rxid = atomic_add_16_nv(
		    &xch->xch_ss->ss_next_unsol_rxid, 1);
		if (xch->xch_rxid == 0xFFFF) {
			xch->xch_rxid = atomic_add_16_nv(
			    &xch->xch_ss->ss_next_unsol_rxid, 1);
		}
	} while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash,
	    (mod_hash_key_t)(intptr_t)xch->xch_rxid,
	    (mod_hash_val_t)&xch_tmp) == 0);

	xch->xch_sequence_no = 0;
	xch->xch_ref = 0;
	(void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash,
	    (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch);
	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;

	/*
	 * cmd initialization
	 */
	cmd->cmd_port = FRM2SS(frm)->ss_port;
	cmd->cmd_rp_handle = FCT_HANDLE_NONE;
	cmd->cmd_rportid = FRM_S_ID(frm);
	cmd->cmd_lportid = FRM_D_ID(frm);
	cmd->cmd_oxid = xch->xch_oxid;
	cmd->cmd_rxid = xch->xch_rxid;

	fcoet_init_tfm(frm, xch);
	return (xch);
}