vsw_phys.c revision 51aa9d07dcd9c8ed955768d19058f8c15460fd7c
fb91fd8a302dfb13e250bbefb6a3970c2edc3ae3zf * CDDL HEADER START
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * The contents of this file are subject to the terms of the
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Common Development and Distribution License (the "License").
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * You may not use this file except in compliance with the License.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * See the License for the specific language governing permissions
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * and limitations under the License.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * When distributing Covered Code, include this CDDL HEADER in each
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If applicable, add the following below this CDDL HEADER, with the
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * fields enclosed by brackets "[]" replaced with your own identifying
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * information: Portions Copyright [yyyy] [name of copyright owner]
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * CDDL HEADER END
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Use is subject to license terms.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf#pragma ident "%Z%%M% %I% %E% SMI"
e07d9cb85217949d497b02d7211de8a197d2f2ebzf/* MAC Ring table functions. */
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void vsw_rx_queue_cb(void *, mac_resource_handle_t, mblk_t *);
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void vsw_rx_cb(void *, mac_resource_handle_t, mblk_t *);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf/* MAC layer routines */
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic mac_resource_handle_t vsw_mac_ring_add_cb(void *arg,
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic int vsw_set_hw_promisc(vsw_t *, vsw_port_t *, int);
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic int vsw_unset_hw_promisc(vsw_t *, vsw_port_t *, int);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf/* Support functions */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Tunables used in this file.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Check to see if the card supports the setting of multiple unicst
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * addresses.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 if card supports the programming of multiple unicast addresses,
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * otherwise returns 1.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (!mac_capab_get(vswp->mh, MAC_CAPAB_MULTIADDRESS, &vswp->maddr)) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
020c47705d28102a8df83a43ddf08e34dde21f22ql return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Program unicast and multicast addresses of vsw interface and the ports
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * into the physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* program unicst addr of vsw interface in the physdev */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (rv != 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf "!vsw%d: failed to program interface "
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Notify the MAC layer of the changed address.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* program mcast addrs of vsw interface in the physdev */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (mcap = vswp->mcap; mcap != NULL; mcap = mcap->nextp) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (rv == 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* program unicast address of ports in the physical device */
5644143a6cf1e70bc2e78d5140970830aae0e8cdQuaker Fang for (port = plist->head; port != NULL; port = port->p_next) {
5644143a6cf1e70bc2e78d5140970830aae0e8cdQuaker Fang if (port->addr_set != VSW_ADDR_UNSET) /* addr already set */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf "!vsw%d: port:%d failed to set unicast address\n",
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* program multicast addresses of ports in the physdev */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (port = plist->head; port != NULL; port = port->p_next) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (mcap = port->mcap; mcap != NULL; mcap = mcap->nextp) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (rv == 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* announce macaddr of vnets to the physical switch */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (port = plist->head; port != NULL; port = port->p_next) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Remove unicast and multicast addresses of vsw interface and the ports
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * from the physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Remove unicast addr of vsw interfce
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * from current physdev
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Remove mcast addrs of vsw interface
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * from current physdev
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (mcap = vswp->mcap; mcap != NULL; mcap = mcap->nextp) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Remove unicast address of ports from the current physical device
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (port = plist->head; port != NULL; port = port->p_next) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Remove address if was programmed into HW. */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Remove multicast addresses of ports from the current physdev */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (port = plist->head; port != NULL; port = port->p_next) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (mcap = port->mcap; mcap != NULL; mcap = mcap->nextp) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Open the underlying physical device for access in layer2 mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns:
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * 0 on success
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * EAGAIN if mac_open() fails due to the device being not available yet.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * EIO on any other failures.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* already open */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* exceeded max retries */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If mac_open() failed and the error indicates that either
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the dlmgmtd door or the device is not available yet, we
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * return EAGAIN to indicate that mac_open() needs to be
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * retried. For example, this may happen during boot up, if
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the required link aggregation groups(devices) have not
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * been created yet.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Close the underlying physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Link into the MAC layer to gain access to the services provided by
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the underlying physical device driver (which should also have
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * registered with the MAC layer).
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Only when in layer 2 mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf D2(vswp, "vsw_mac_attach: using device %s", vswp->physname);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Initialize the ring table.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Register our rx callback function.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Register our mac resource callback.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf mac_resource_set(vswp->mh, vsw_mac_ring_add_cb, (void *)vswp);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Get the ring resources available to us from
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the mac below us.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Just register our rx callback function
e07d9cb85217949d497b02d7211de8a197d2f2ebzf vswp->mrh = mac_rx_add(vswp->mh, vsw_rx_cb, (void *)vswp);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Get the MAC tx fn */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* start the interface */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf cmn_err(CE_WARN, "!vsw%d: Could not start mac interface",
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Depending on the mode specified, the capabilites and capacity
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * of the underlying device setup the physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in layer 3 mode, then do nothing.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in layer 2 programmed mode attempt to program the unicast address
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * associated with the port into the physical device. If this is not
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * possible due to resource exhaustion or simply because the device does
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * not support multiple unicast addresses then if required fallback onto
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * putting the card into promisc mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in promisc mode then simply set the card into promisc mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 success, 1 on failure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Attempt to program the unicast address into the HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Mark that attempt should be made to re-config sometime
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * in future if a port is deleted.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Only 1 mode specified, nothing more to do.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If promiscuous was next mode specified try to
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * set the card into that mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf "of device %s", ether_sprintf((void *)mac_addr.mma_addr),
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in layer 3 mode do nothing.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in layer 2 switched mode remove the address from the physical
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If in layer 2 promiscuous mode disable promisc mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 on success.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf switch (type) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* should never happen */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Attempt to program a unicast address into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 on sucess, 1 on failure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (rv == 0)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Its okay for the add to fail because we have exhausted
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * all the resouces in the hardware device. Any other error
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * we want to flag.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf "address %s into HW err (%d)",
e07d9cb85217949d497b02d7211de8a197d2f2ebzf vswp->instance, ether_sprintf((void *)mac->mma_addr), rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Remove a unicast mac address which has previously been programmed
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 on sucess, 1 on failure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (rv != 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf "from slot %d in device %s (err %d)",
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Set network card into promisc mode.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 on success, 1 on failure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzfvsw_set_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (mac_promisc_set(vswp->mh, B_TRUE, MAC_DEVPROMISC) != 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Turn off promiscuous mode on network card.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 on success, 1 on failure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzfvsw_unset_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf if (mac_promisc_set(vswp->mh, B_FALSE, MAC_DEVPROMISC) != 0) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * We are exiting promisc mode either because we were
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * only in promisc mode because we had failed over from
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * switched mode due to HW resource issues, or the user
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * wanted the card in promisc mode for all the ports and
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the last port is now being deleted. Tweak the message
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * accordingly.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Determine whether or not we are operating in our prefered
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * mode and if not whether the physical resources now allow us
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * to operate in it.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If a port is being removed should only be invoked after port has been
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * removed from the port list.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If we are in layer 2 (i.e. switched) or would like to be
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * in layer 2 then check if any ports or the vswitch itself
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * need to be programmed into the HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * This can happen in two cases - switched was specified as
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the prefered mode of operation but we exhausted the HW
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * resources and so failed over to the next specifed mode,
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * or switched was the only mode specified so after HW
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * resources were exhausted there was nothing more we
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * could do.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * First, attempt to set the vswitch mac address into HW,
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * if required.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Next, attempt to set any ports which have not yet been
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * programmed into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * By now we know that have programmed all desired ports etc
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * into HW, so safe to mark reconfiguration as complete.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Check to see if vsw itself is plumbed, and if so whether or not
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * its mac address should be written into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 if could set address, or didn't have to set it.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 1 if failed to set address.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (1);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If previously when plumbed had had to place
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * interface into promisc mode, now reverse that.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Note that interface will only actually be set into
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * non-promisc mode when last port/interface has been
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * programmed into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (0);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Scan the port list for any ports which have not yet been set
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * into HW. For those found attempt to program their mac addresses
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * into the physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 0 if able to program all required ports (can be 0) into HW.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns 1 if failed to set at least one mac address.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If when this port had first attached we had
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * had to place the interface into promisc mode,
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * then now reverse that.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Note that the interface will not actually
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * change to non-promisc mode until all ports
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * have been programmed.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (rv);
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzfvsw_mac_ring_tbl_entry_init(vsw_t *vswp, vsw_mac_ring_t *ringp)
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzf mutex_init(&vswp->mac_ring_lock, NULL, MUTEX_DRIVER, NULL);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf kmem_alloc(vsw_mac_rx_rings * sizeof (vsw_mac_ring_t), KM_SLEEP);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf vsw_mac_ring_tbl_entry_init(vswp, &vswp->mac_ring_tbl[i]);
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Destroy the queue.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Re-initialize the structure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Handle resource add callbacks from the driver below.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Check to make sure we have the correct resource type.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Find a open entry in the ring table.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Check for an empty slot, if found, then setup queue
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * and thread.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Create the queue for this ring.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Initialize the ring data structure.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Create the worker thread.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Make sure thread get's running state for
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * this ring.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * If the thread is not running, cleanup.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * No slots in the ring table available.
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Set the state to running, since the thread is now active.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Wait for work to do or the state has changed
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * to not running.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Process packets that we received from the interface.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* switch the chain of packets received */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * We are drained and signal we are done.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Exit lock and drain the remaining packets.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Exit the thread
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * static void
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * vsw_rx_queue_cb() - Receive callback routine when
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * vsw_multi_ring_enable is non-zero. Queue the packets
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * to a packet queue for a worker thread to process.
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzfvsw_rx_queue_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Find the last element in the mblk chain.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Get the queue for the packets */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Grab the lock such we can queue the packets.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Add the mblk chain to the queue. If there
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * is some mblks in the queue, then add the new
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * chain to the end.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Signal the worker thread that there is work to
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Let go of the lock and exit.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * receive callback routine. Invoked by MAC layer when there
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * are pkts being passed up from physical device.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * PERF: It may be more efficient when the card is in promisc
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * mode to check the dest address of the pkts here (against
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * the FDB) rather than checking later. Needs to be investigated.
e07d9cb85217949d497b02d7211de8a197d2f2ebzfstatic void
e07d9cb85217949d497b02d7211de8a197d2f2ebzfvsw_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* switch the chain of packets received */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf vswp->vsw_switch_frame(vswp, mp, VSW_PHYSDEV, NULL, NULL);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Send a message out over the physical device via the MAC layer.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Returns any mblks that it was unable to transmit.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf DERR(vswp, "vsw_tx_msg: dropping pkts: no tx routine avail");
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (mp);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf return (mp);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf#define ARH_FIXED_LEN 8 /* Length of fixed part of ARP header(see arp.h) */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Send a gratuitous RARP packet to notify the physical switch to update its
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * Layer2 forwarding table for the given mac address. This is done to allow the
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * switch to quickly learn the macaddr-port association when a guest is live
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * migrated or when vsw's physical device is changed dynamically. Any protocol
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * packet would serve this purpose, but we choose RARP, as it allows us to
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * The macaddr of vnet is retained across migration. Hence, we don't need to
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * update the arp cache of other hosts within the broadcast domain. Note that
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * it is harmless to send these RARP packets during normal port attach of a
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * client vnet. This can can be turned off if needed, by setting
e07d9cb85217949d497b02d7211de8a197d2f2ebzf * vsw_publish_macaddr_count to zero in /etc/system.
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Initialize eth header */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf bcopy(ðerbroadcastaddr, &ehp->ether_dhost, ETHERADDRL);
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Initialize arp packet */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header));
e07d9cb85217949d497b02d7211de8a197d2f2ebzf arh->ar_hrd = htons(ARPHRD_ETHER); /* Hardware type: ethernet */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf arh->ar_pro = htons(ETHERTYPE_IP); /* Protocol type: IP */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf arh->ar_hln = ETHERADDRL; /* Length of hardware address: 6 */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf arh->ar_op = htons(REVARP_REQUEST); /* Opcode: REVARP Request */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Sender's hardware address and protocol address */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* Target hardware address and protocol address */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf mp->b_wptr += ETHERMIN; /* total size is 42; round up to ETHERMIN */
e07d9cb85217949d497b02d7211de8a197d2f2ebzf for (count = 0; count < vsw_publish_macaddr_count; count++) {
e07d9cb85217949d497b02d7211de8a197d2f2ebzf /* transmit the packet */