diff options
-rw-r--r-- | usr/src/uts/common/io/mac/mac_client.c | 765 | ||||
-rw-r--r-- | usr/src/uts/common/sys/mac_client.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/sys/mac_client_impl.h | 9 | ||||
-rw-r--r-- | usr/src/uts/common/xen/io/xnbo.c | 38 |
4 files changed, 533 insertions, 282 deletions
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c index f2a39bd6aa..a0adc31af8 100644 --- a/usr/src/uts/common/io/mac/mac_client.c +++ b/usr/src/uts/common/io/mac/mac_client.c @@ -1173,6 +1173,9 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, if (flags & MAC_OPEN_FLAGS_EXCLUSIVE) mcip->mci_state_flags |= MCIS_EXCLUSIVE; + if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) + mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; + mip->mi_clients_list = mcip; i_mac_perim_exit(mip); *mchp = (mac_client_handle_t)mcip; @@ -1185,9 +1188,14 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, mcip->mci_upper_mip = NULL; mcip->mci_rx_fn = mac_pkt_drop; mcip->mci_rx_arg = NULL; + mcip->mci_rx_p_fn = NULL; + mcip->mci_rx_p_arg = NULL; + mcip->mci_p_unicast_list = NULL; mcip->mci_direct_rx_fn = NULL; mcip->mci_direct_rx_arg = NULL; + mcip->mci_unicast_list = NULL; + if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0) mcip->mci_state_flags |= MCIS_IS_VNIC; @@ -1227,6 +1235,10 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, } (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name)); } + + if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) + mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; + /* the subflow table will be created dynamically */ mcip->mci_subflow_tab = NULL; mcip->mci_stat_multircv = 0; @@ -1615,6 +1627,185 @@ mac_update_single_active_client(mac_impl_t *mip) } /* + * Set up the data path. Called from i_mac_unicast_add after having + * done all the validations including making sure this is an active + * client (i.e that is ready to process packets.) + */ +static int +mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid, + uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary, + mac_unicast_impl_t *muip) +{ + mac_impl_t *mip = mcip->mci_mip; + boolean_t mac_started = B_FALSE; + boolean_t bcast_added = B_FALSE; + boolean_t nactiveclients_added = B_FALSE; + flow_entry_t *flent; + int err = 0; + + if ((err = mac_start((mac_handle_t)mip)) != 0) + goto bail; + + mac_started = B_TRUE; + + /* add the MAC client to the broadcast address group by default */ + if (mip->mi_type->mt_brdcst_addr != NULL) { + err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, + MAC_ADDRTYPE_BROADCAST); + if (err != 0) + goto bail; + bcast_added = B_TRUE; + } + + /* + * If this is the first unicast address addition for this + * client, reuse the pre-allocated larval flow entry associated with + * the MAC client. + */ + flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; + + /* We are configuring the unicast flow now */ + if (!MCIP_DATAPATH_SETUP(mcip)) { + + MAC_CLIENT_SET_PRIORITY_RANGE(mcip, + (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority : + MPL_LINK_DEFAULT); + + if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, + isprimary, B_TRUE, &flent, mrp)) != 0) + goto bail; + + mip->mi_nactiveclients++; + nactiveclients_added = B_TRUE; + + /* + * This will allocate the RX ring group if possible for the + * flow and program the software classifier as needed. + */ + if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) + goto bail; + + /* + * The unicast MAC address must have been added successfully. + */ + ASSERT(mcip->mci_unicast != NULL); + /* + * Push down the sub-flows that were defined on this link + * hitherto. The flows are added to the active flow table + * and SRS, softrings etc. are created as needed. + */ + mac_link_init_flows((mac_client_handle_t)mcip); + } else { + mac_address_t *map = mcip->mci_unicast; + + /* + * A unicast flow already exists for that MAC client, + * this flow must be the same mac address but with + * different VID. It has been checked by mac_addr_in_use(). + * + * We will use the SRS etc. from the mci_flent. Note that + * We don't need to create kstat for this as except for + * the fdesc, everything will be used from in the 1st flent. + */ + + if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { + err = EINVAL; + goto bail; + } + + if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, + isprimary, B_FALSE, &flent, NULL)) != 0) { + goto bail; + } + if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { + FLOW_FINAL_REFRELE(flent); + goto bail; + } + + /* update the multicast group for this vid */ + mac_client_bcast_refresh(mcip, mac_client_update_mcast, + (void *)flent, B_TRUE); + + } + + /* populate the shared MAC address */ + muip->mui_map = mcip->mci_unicast; + + rw_enter(&mcip->mci_rw_lock, RW_WRITER); + muip->mui_next = mcip->mci_unicast_list; + mcip->mci_unicast_list = muip; + rw_exit(&mcip->mci_rw_lock); + + + /* + * First add the flent to the flow list of this mcip. Then set + * the mip's mi_single_active_client if needed. The Rx path assumes + * that mip->mi_single_active_client will always have an associated + * flent. + */ + mac_client_add_to_flow_list(mcip, flent); + + if (nactiveclients_added) + mac_update_single_active_client(mip); + /* + * Trigger a renegotiation of the capabilities when the number of + * active clients changes from 1 to 2, since some of the capabilities + * might have to be disabled. Also send a MAC_NOTE_LINK notification + * to all the MAC clients whenever physical link is DOWN. + */ + if (mip->mi_nactiveclients == 2) { + mac_capab_update((mac_handle_t)mip); + mac_virtual_link_update(mip); + } + /* + * Now that the setup is complete, clear the INCIPIENT flag. + * The flag was set to avoid incoming packets seeing inconsistent + * structures while the setup was in progress. Clear the mci_tx_flag + * by calling mac_tx_client_block. It is possible that + * mac_unicast_remove was called prior to this mac_unicast_add which + * could have set the MCI_TX_QUIESCE flag. + */ + if (flent->fe_rx_ring_group != NULL) + mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); + FLOW_UNMARK(flent, FE_INCIPIENT); + FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); + mac_tx_client_unblock(mcip); + return (0); +bail: + if (bcast_added) + mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); + if (mac_started) + mac_stop((mac_handle_t)mip); + + if (nactiveclients_added) + mip->mi_nactiveclients--; + + kmem_free(muip, sizeof (mac_unicast_impl_t)); + return (err); +} + +/* + * Return the passive primary MAC client, if present. The passive client is + * a stand-by client that has the same unicast address as another that is + * currenly active. Once the active client goes away, the passive client + * becomes active. + */ +static mac_client_impl_t * +mac_get_passive_primary_client(mac_impl_t *mip) +{ + mac_client_impl_t *mcip; + + for (mcip = mip->mi_clients_list; mcip != NULL; + mcip = mcip->mci_client_next) { + if (mac_is_primary_client(mcip) && + (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { + return (mcip); + } + } + return (NULL); +} + +/* * Add a new unicast address to the MAC client. * * The MAC address can be specified either by value, or the MAC client @@ -1630,21 +1821,19 @@ int i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) { - mac_client_impl_t *mcip = (mac_client_impl_t *)mch; - mac_impl_t *mip = mcip->mci_mip; - mac_unicast_impl_t *muip; - flow_entry_t *flent; - int err; - uint_t mac_len = mip->mi_type->mt_addr_length; - boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); - boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); - boolean_t is_vnic_primary = (flags & MAC_UNICAST_VNIC_PRIMARY); - boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); - boolean_t bcast_added = B_FALSE; - boolean_t nactiveclients_added = B_FALSE; - boolean_t mac_started = B_FALSE; - boolean_t fastpath_disabled = B_FALSE; - mac_resource_props_t mrp; + mac_client_impl_t *mcip = (mac_client_impl_t *)mch; + mac_impl_t *mip = mcip->mci_mip; + int err; + uint_t mac_len = mip->mi_type->mt_addr_length; + boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); + boolean_t fastpath_disabled = B_FALSE; + boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); + boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); + mac_resource_props_t mrp; + boolean_t passive_client = B_FALSE; + mac_unicast_impl_t *muip; + boolean_t is_vnic_primary = + (flags & MAC_UNICAST_VNIC_PRIMARY); /* when VID is non-zero, the underlying MAC can not be VNIC */ ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0))); @@ -1663,6 +1852,8 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, */ if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && !is_vnic_primary) { + mac_unicast_impl_t *muip; + /* * The address is being set by the upper MAC client * of a VNIC. The MAC address was already set by the @@ -1689,10 +1880,20 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, /* * Ensure that the primary unicast address of the VNIC - * is added only once. + * is added only once unless we have the + * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not + * a passive MAC client). */ - if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) - return (EBUSY); + if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) { + if ((mcip->mci_flags & + MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || + (mcip->mci_flags & + MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { + return (EBUSY); + } + mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; + passive_client = B_TRUE; + } mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY; @@ -1703,6 +1904,12 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); muip->mui_vid = vid; *mah = (mac_unicast_handle_t)muip; + /* + * This will be used by the caller to defer setting the + * rx functions. + */ + if (passive_client) + return (EAGAIN); return (0); } @@ -1768,7 +1975,6 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, if (is_primary || is_vnic_primary) { mac_addr = mip->mi_addr; - check_dups = B_TRUE; } else { /* @@ -1777,7 +1983,7 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) { *diag = MAC_DIAG_MACADDR_INVALID; err = EINVAL; - goto bail; + goto bail_out; } /* @@ -1787,47 +1993,18 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) { *diag = MAC_DIAG_MACADDR_NIC; err = EINVAL; - goto bail; + goto bail_out; } } /* - * Make sure the MAC address is not already used by - * another MAC client defined on top of the same - * underlying NIC. - * xxx-venu mac_unicast_add doesnt' seem to be called - * with MAC_UNICAST_NODUPCHECK currently, if it does - * get called we need to do mac_addr_in_use() just - * to check for addr_in_use till 6697876 is fixed. - */ - if (check_dups && mac_addr_in_use(mip, mac_addr, vid)) { - *diag = MAC_DIAG_MACADDR_INUSE; - err = EEXIST; - goto bail; - } - - if ((err = mac_start((mac_handle_t)mip)) != 0) - goto bail; - - mac_started = B_TRUE; - - /* add the MAC client to the broadcast address group by default */ - if (mip->mi_type->mt_brdcst_addr != NULL) { - err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, - MAC_ADDRTYPE_BROADCAST); - if (err != 0) - goto bail; - bcast_added = B_TRUE; - } - - /* - * If this is the first unicast address addition for this - * client, reuse the pre-allocated larval flow entry associated with - * the MAC client. + * Set the flags here so that if this is a passive client, we + * can return and set it when we call mac_client_datapath_setup + * when this becomes the active client. If we defer to using these + * flags to mac_client_datapath_setup, then for a passive client, + * we'd have to store the flags somewhere (probably fe_flags) + * and then use it. */ - flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; - - /* We are configuring the unicast flow now */ if (!MCIP_DATAPATH_SETUP(mcip)) { if (is_unicast_hw) { /* @@ -1848,48 +2025,7 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; - - MAC_CLIENT_SET_PRIORITY_RANGE(mcip, - (mrp.mrp_mask & MRP_PRIORITY) ? mrp.mrp_priority : - MPL_LINK_DEFAULT); - - if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, - is_primary || is_vnic_primary, B_TRUE, &flent, &mrp)) != 0) - goto bail; - - mip->mi_nactiveclients++; - nactiveclients_added = B_TRUE; - - /* - * This will allocate the RX ring group if possible for the - * flow and program the software classifier as needed. - */ - if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) - goto bail; - - /* - * The unicast MAC address must have been added successfully. - */ - ASSERT(mcip->mci_unicast != NULL); - /* - * Push down the sub-flows that were defined on this link - * hitherto. The flows are added to the active flow table - * and SRS, softrings etc. are created as needed. - */ - mac_link_init_flows(mch); } else { - mac_address_t *map = mcip->mci_unicast; - - /* - * A unicast flow already exists for that MAC client, - * this flow must be the same mac address but with - * different VID. It has been checked by mac_addr_in_use(). - * - * We will use the SRS etc. from the mci_flent. Note that - * We don't need to create kstat for this as except for - * the fdesc, everything will be used from in the 1st flent. - */ - /* * Assert that the specified flags are consistent with the * flags specified by previous calls to mac_unicast_add(). @@ -1909,11 +2045,6 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 && (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0)); - if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { - err = EINVAL; - goto bail; - } - /* * Make sure the client is consistent about its requests * for MAC addresses. I.e. all requests from the clients @@ -1924,102 +2055,217 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, (mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 && is_unicast_hw) { err = EINVAL; - goto bail; + goto bail_out; } + } + /* + * Make sure the MAC address is not already used by + * another MAC client defined on top of the same + * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY + * set when we allow a passive client to be present which will + * be activated when the currently active client goes away - this + * works only with primary addresses. + */ + if ((check_dups || is_primary || is_vnic_primary) && + mac_addr_in_use(mip, mac_addr, vid)) { + /* + * Must have set the multiple primary address flag when + * we did a mac_client_open AND this should be a primary + * MAC client AND there should not already be a passive + * primary. If all is true then we let this succeed + * even if the address is a dup. + */ + if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || + (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 || + mac_get_passive_primary_client(mip) != NULL) { + *diag = MAC_DIAG_MACADDR_INUSE; + err = EEXIST; + goto bail_out; + } + ASSERT((mcip->mci_flags & + MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0); + mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; - if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, - is_primary || is_vnic_primary, B_FALSE, &flent, NULL)) != 0) - goto bail; + /* + * Stash the unicast address handle, we will use it when + * we set up the passive client. + */ + mcip->mci_p_unicast_list = muip; + *mah = (mac_unicast_handle_t)muip; + return (0); + } - if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { - FLOW_FINAL_REFRELE(flent); - goto bail; + err = mac_client_datapath_setup(mcip, vid, mac_addr, &mrp, + is_primary || is_vnic_primary, muip); + if (err != 0) + goto bail_out; + *mah = (mac_unicast_handle_t)muip; + return (0); + +bail_out: + if (fastpath_disabled) + mac_fastpath_enable((mac_handle_t)mip); + if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { + mip->mi_state_flags &= ~MIS_EXCLUSIVE; + if (mip->mi_state_flags & MIS_LEGACY) { + mip->mi_capab_legacy.ml_active_clear( + mip->mi_driver); } + } + kmem_free(muip, sizeof (mac_unicast_impl_t)); + return (err); +} - /* update the multicast group for this vid */ - mac_client_bcast_refresh(mcip, mac_client_update_mcast, - (void *)flent, B_TRUE); +/* + * Wrapper function to mac_unicast_add when we want to have the same mac + * client open for two instances, one that is currently active and another + * that will become active when the current one is removed. In this case + * mac_unicast_add will return EGAIN and we will save the rx function and + * arg which will be used when we activate the passive client in + * mac_unicast_remove. + */ +int +mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr, + uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag, + mac_rx_t rx_fn, void *arg) +{ + mac_client_impl_t *mcip = (mac_client_impl_t *)mch; + uint_t err; + err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); + if (err != 0 && err != EAGAIN) + return (err); + if (err == EAGAIN) { + if (rx_fn != NULL) { + mcip->mci_rx_p_fn = rx_fn; + mcip->mci_rx_p_arg = arg; + } + return (0); } + if (rx_fn != NULL) + mac_rx_set(mch, rx_fn, arg); + return (err); +} - /* populate the shared MAC address */ - muip->mui_map = mcip->mci_unicast; +int +mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, + mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) +{ + mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; + uint_t err; - rw_enter(&mcip->mci_rw_lock, RW_WRITER); - muip->mui_next = mcip->mci_unicast_list; - mcip->mci_unicast_list = muip; - rw_exit(&mcip->mci_rw_lock); + i_mac_perim_enter(mip); + err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); + i_mac_perim_exit(mip); - *mah = (mac_unicast_handle_t)muip; + return (err); +} + +void +mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip, + flow_entry_t *flent) +{ + mac_client_impl_t *mcip = (mac_client_impl_t *)mch; + mac_impl_t *mip = mcip->mci_mip; /* - * First add the flent to the flow list of this mcip. Then set - * the mip's mi_single_active_client if needed. The Rx path assumes - * that mip->mi_single_active_client will always have an associated - * flent. + * We would have initialized subflows etc. only if we brought up + * the primary client and set the unicast unicast address etc. + * Deactivate the flows. The flow entry will be removed from the + * active flow tables, and the associated SRS, softrings etc will + * be deleted. But the flow entry itself won't be destroyed, instead + * it will continue to be archived off the the global flow hash + * list, for a possible future activation when say IP is plumbed + * again. */ - mac_client_add_to_flow_list(mcip, flent); + mac_link_release_flows(mch); + + mip->mi_nactiveclients--; + mac_update_single_active_client(mip); + + /* Tear down the data path */ + mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); - if (nactiveclients_added) - mac_update_single_active_client(mip); /* - * Trigger a renegotiation of the capabilities when the number of - * active clients changes from 1 to 2, since some of the capabilities - * might have to be disabled. Also send a MAC_NOTE_LINK notification - * to all the MAC clients whenever physical link is DOWN. + * Prevent any future access to the flow entry through the mci_flent + * pointer by setting the mci_flent to NULL. Access to mci_flent in + * mac_bcast_send is also under mi_rw_lock. */ - if (mip->mi_nactiveclients == 2) { - mac_capab_update((mac_handle_t)mip); - mac_virtual_link_update(mip); - } + rw_enter(&mip->mi_rw_lock, RW_WRITER); + flent = mcip->mci_flent; + mac_client_remove_flow_from_list(mcip, flent); + + if (mcip->mci_state_flags & MCIS_DESC_LOGGED) + mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; + /* - * Now that the setup is complete, clear the INCIPIENT flag. - * The flag was set to avoid incoming packets seeing inconsistent - * structures while the setup was in progress. Clear the mci_tx_flag - * by calling mac_tx_client_block. It is possible that - * mac_unicast_remove was called prior to this mac_unicast_add which - * could have set the MCI_TX_QUIESCE flag. + * This is the last unicast address being removed and there shouldn't + * be any outbound data threads at this point coming down from mac + * clients. We have waited for the data threads to finish before + * starting dld_str_detach. Non-data threads must access TX SRS + * under mi_rw_lock. */ - if (flent->fe_rx_ring_group != NULL) - mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); - FLOW_UNMARK(flent, FE_INCIPIENT); - FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); - mac_tx_client_unblock(mcip); - return (0); -bail: - if (bcast_added) - mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); - if (mac_started) - mac_stop((mac_handle_t)mip); + rw_exit(&mip->mi_rw_lock); - if (nactiveclients_added) - mip->mi_nactiveclients--; + /* + * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might + * contain other flags, such as FE_CONDEMNED, which we need to + * cleared. We don't call mac_flow_cleanup() for this unicast + * flow as we have a already cleaned up SRSs etc. (via the teadown + * path). We just clear the stats and reset the initial callback + * function, the rest will be set when we call mac_flow_create, + * if at all. + */ + mutex_enter(&flent->fe_lock); + ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && + flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); + flent->fe_flags = FE_MC_NO_DATAPATH; + flow_stat_destroy(flent); + + /* Initialize the receiver function to a safe routine */ + flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; + flent->fe_cb_arg1 = NULL; + flent->fe_cb_arg2 = NULL; + + flent->fe_index = -1; + mutex_exit(&flent->fe_lock); + + if (mip->mi_type->mt_brdcst_addr != NULL) { + mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, + muip->mui_vid); + } + + if (mip->mi_nactiveclients == 1) { + mac_capab_update((mac_handle_t)mip); + mac_virtual_link_update(mip); + } if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { mip->mi_state_flags &= ~MIS_EXCLUSIVE; + if (mip->mi_state_flags & MIS_LEGACY) mip->mi_capab_legacy.ml_active_clear(mip->mi_driver); } - if (fastpath_disabled) - mac_fastpath_enable((mac_handle_t)mip); + mcip->mci_state_flags &= ~MCIS_UNICAST_HW; - kmem_free(muip, sizeof (mac_unicast_impl_t)); - return (err); -} + if (mcip->mci_state_flags & MCIS_TAG_DISABLE) + mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; -int -mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, - mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) -{ - mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; - uint_t err; + if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) + mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; - i_mac_perim_enter(mip); - err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); - i_mac_perim_exit(mip); + if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) + mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; - return (err); + kmem_free(muip, sizeof (mac_unicast_impl_t)); + + /* + * Disable fastpath if this is a VNIC or a VLAN. + */ + if (mcip->mci_state_flags & MCIS_IS_VNIC) + mac_fastpath_enable((mac_handle_t)mip); + mac_stop((mac_handle_t)mip); } /* @@ -2032,7 +2278,8 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah; mac_unicast_impl_t *pre; mac_impl_t *mip = mcip->mci_mip; - flow_entry_t *flent; + flow_entry_t *flent; + boolean_t isprimary = B_FALSE; i_mac_perim_enter(mip); if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) { @@ -2047,6 +2294,19 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) ASSERT(muip->mui_vid == 0); mac_tx_client_flush(mcip); + + if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { + mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; + if (mcip->mci_rx_p_fn != NULL) { + mac_rx_set(mch, mcip->mci_rx_p_fn, + mcip->mci_rx_p_arg); + mcip->mci_rx_p_fn = NULL; + mcip->mci_rx_p_arg = NULL; + } + kmem_free(muip, sizeof (mac_unicast_impl_t)); + i_mac_perim_exit(mip); + return (0); + } mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY; if (mcip->mci_state_flags & MCIS_TAG_DISABLE) @@ -2066,6 +2326,35 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) ASSERT(muip != NULL); /* + * We are removing a passive client, we haven't setup the datapath + * for this yet, so nothing much to do. + */ + if ((mcip->mci_state_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { + + ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0); + ASSERT(mcip->mci_p_unicast_list == muip); + + mcip->mci_p_unicast_list = NULL; + mcip->mci_rx_p_fn = NULL; + mcip->mci_rx_p_arg = NULL; + + mcip->mci_state_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; + mcip->mci_state_flags &= ~MCIS_UNICAST_HW; + + if (mcip->mci_state_flags & MCIS_TAG_DISABLE) + mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; + + if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) + mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; + + if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) + mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; + + kmem_free(muip, sizeof (mac_unicast_impl_t)); + i_mac_perim_exit(mip); + return (0); + } + /* * Remove the VID from the list of client's VIDs. */ pre = mcip->mci_unicast_list; @@ -2080,9 +2369,11 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) rw_exit(&mcip->mci_rw_lock); } - if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && muip->mui_vid == 0) + if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && + muip->mui_vid == 0) { mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY; - + isprimary = B_TRUE; + } if (!mac_client_single_rcvr(mcip)) { /* * This MAC client is shared by more than one unicast @@ -2122,108 +2413,52 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) FLOW_FINAL_REFRELE(flent); ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE)); - goto done; + /* + * Enable fastpath if this is a VNIC or a VLAN. + */ + if (mcip->mci_state_flags & MCIS_IS_VNIC) + mac_fastpath_enable((mac_handle_t)mip); + mac_stop((mac_handle_t)mip); + i_mac_perim_exit(mip); + return (0); } - /* - * We would have initialized subflows etc. only if we brought up - * the primary client and set the unicast unicast address etc. - * Deactivate the flows. The flow entry will be removed from the - * active flow tables, and the associated SRS, softrings etc will - * be deleted. But the flow entry itself won't be destroyed, instead - * it will continue to be archived off the the global flow hash - * list, for a possible future activation when say IP is plumbed - * again. - */ - mac_link_release_flows(mch); - - mip->mi_nactiveclients--; - mac_update_single_active_client(mip); - - /* Tear down the Data path */ - mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); + mac_client_datapath_teardown(mch, muip, flent); /* - * Prevent any future access to the flow entry through the mci_flent - * pointer by setting the mci_flent to NULL. Access to mci_flent in - * mac_bcast_send is also under mi_rw_lock. + * If we are removing the primary, check if we have a passive primary + * client that we need to activate now. */ - rw_enter(&mip->mi_rw_lock, RW_WRITER); - flent = mcip->mci_flent; - mac_client_remove_flow_from_list(mcip, flent); - - if (mcip->mci_state_flags & MCIS_DESC_LOGGED) - mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; - - /* - * This is the last unicast address being removed and there shouldn't - * be any outbound data threads at this point coming down from mac - * clients. We have waited for the data threads to finish before - * starting dld_str_detach. Non-data threads must access TX SRS - * under mi_rw_lock. - */ - rw_exit(&mip->mi_rw_lock); - - /* - * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might - * contain other flags, such as FE_CONDEMNED, which we need to - * cleared. We don't call mac_flow_cleanup() for this unicast - * flow as we have a already cleaned up SRSs etc. (via the teadown - * path). We just clear the stats and reset the initial callback - * function, the rest will be set when we call mac_flow_create, - * if at all. - */ - mutex_enter(&flent->fe_lock); - ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && - flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); - flent->fe_flags = FE_MC_NO_DATAPATH; - flow_stat_destroy(flent); - - /* Initialize the receiver function to a safe routine */ - flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; - flent->fe_cb_arg1 = NULL; - flent->fe_cb_arg2 = NULL; - - flent->fe_index = -1; - mutex_exit(&flent->fe_lock); - - if (mip->mi_type->mt_brdcst_addr != NULL) { - mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, - muip->mui_vid); - } - - if (mip->mi_nactiveclients == 1) { - mac_capab_update((mac_handle_t)mip); - mac_virtual_link_update(mip); + if (!isprimary) { + i_mac_perim_exit(mip); + return (0); } + mcip = mac_get_passive_primary_client(mip); + if (mcip != NULL) { + mac_resource_props_t mrp; + mac_unicast_impl_t *muip; - if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { - mip->mi_state_flags &= ~MIS_EXCLUSIVE; - - if (mip->mi_state_flags & MIS_LEGACY) - mip->mi_capab_legacy.ml_active_clear(mip->mi_driver); + mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; + bzero(&mrp, sizeof (mac_resource_props_t)); + /* + * Apply the property cached in the mac_impl_t to the + * primary mac client. + */ + mac_get_resources((mac_handle_t)mip, &mrp); + (void) mac_client_set_resources(mch, &mrp); + ASSERT(mcip->mci_p_unicast_list != NULL); + muip = mcip->mci_p_unicast_list; + mcip->mci_p_unicast_list = NULL; + if (mac_client_datapath_setup(mcip, VLAN_ID_NONE, + mip->mi_addr, &mrp, B_TRUE, muip) == 0) { + if (mcip->mci_rx_p_fn != NULL) { + mac_rx_set(mch, mcip->mci_rx_p_fn, + mcip->mci_rx_p_arg); + mcip->mci_rx_p_fn = NULL; + mcip->mci_rx_p_arg = NULL; + } + } } - - mcip->mci_state_flags &= ~MCIS_UNICAST_HW; - - if (mcip->mci_state_flags & MCIS_TAG_DISABLE) - mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; - - if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) - mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; - - if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) - mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; - - kmem_free(muip, sizeof (mac_unicast_impl_t)); - -done: - /* - * Disable fastpath if this is a VNIC or a VLAN. - */ - if (mcip->mci_state_flags & MCIS_IS_VNIC) - mac_fastpath_enable((mac_handle_t)mip); - mac_stop((mac_handle_t)mip); i_mac_perim_exit(mip); return (0); } diff --git a/usr/src/uts/common/sys/mac_client.h b/usr/src/uts/common/sys/mac_client.h index b98c6104f4..c7b1aa7edc 100644 --- a/usr/src/uts/common/sys/mac_client.h +++ b/usr/src/uts/common/sys/mac_client.h @@ -91,6 +91,7 @@ typedef enum { #define MAC_OPEN_FLAGS_SHARES_DESIRED 0x0010 #define MAC_OPEN_FLAGS_USE_DATALINK_NAME 0x0020 #define MAC_OPEN_FLAGS_REQ_HWRINGS 0x0040 +#define MAC_OPEN_FLAGS_MULTI_PRIMARY 0x0080 /* flags passed to mac_client_close */ #define MAC_CLOSE_FLAGS_IS_VNIC 0x0001 @@ -113,6 +114,8 @@ extern void mac_client_close(mac_client_handle_t, uint16_t); extern int mac_unicast_add(mac_client_handle_t, uint8_t *, uint16_t, mac_unicast_handle_t *, uint16_t, mac_diag_t *); +extern int mac_unicast_add_set_rx(mac_client_handle_t, uint8_t *, uint16_t, + mac_unicast_handle_t *, uint16_t, mac_diag_t *, mac_rx_t, void *); extern int mac_unicast_remove(mac_client_handle_t, mac_unicast_handle_t); extern int mac_multicast_add(mac_client_handle_t, const uint8_t *); diff --git a/usr/src/uts/common/sys/mac_client_impl.h b/usr/src/uts/common/sys/mac_client_impl.h index d4dd8853a6..c40c09ab04 100644 --- a/usr/src/uts/common/sys/mac_client_impl.h +++ b/usr/src/uts/common/sys/mac_client_impl.h @@ -52,8 +52,10 @@ typedef struct mac_unicast_impl_s { /* Protected by */ uint16_t mui_vid; /* SL */ } mac_unicast_impl_t; -#define MAC_CLIENT_FLAGS_PRIMARY 0X0001 -#define MAC_CLIENT_FLAGS_VNIC_PRIMARY 0x0002 +#define MAC_CLIENT_FLAGS_PRIMARY 0X0001 +#define MAC_CLIENT_FLAGS_VNIC_PRIMARY 0x0002 +#define MAC_CLIENT_FLAGS_MULTI_PRIMARY 0x0004 +#define MAC_CLIENT_FLAGS_PASSIVE_PRIMARY 0x0008 /* * One of these is instantiated per MAC client promiscuous callback. @@ -113,6 +115,9 @@ struct mac_client_impl_s { /* Protected by */ void *mci_rx_arg; /* Rx Quiescence */ mac_direct_rx_t mci_direct_rx_fn; /* SL */ void *mci_direct_rx_arg; /* SL */ + mac_rx_t mci_rx_p_fn; /* Rx Quiescence */ + void *mci_rx_p_arg; /* Rx Quiescence */ + void *mci_p_unicast_list; mac_cb_t *mci_promisc_list; /* mi_promisc_lock */ diff --git a/usr/src/uts/common/xen/io/xnbo.c b/usr/src/uts/common/xen/io/xnbo.c index 9a4a8a759e..d5f506a888 100644 --- a/usr/src/uts/common/xen/io/xnbo.c +++ b/usr/src/uts/common/xen/io/xnbo.c @@ -272,24 +272,24 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) return (B_FALSE); } + /* + * MAC_OPEN_FLAGS_MULTI_PRIMARY is relevant when we are migrating a + * guest on the localhost itself. In this case we would have the MAC + * client open for the guest being migrated *and* also for the + * migrated guest (i.e. the former will be active till the migration + * is complete when the latter will be activated). This flag states + * that it is OK for mac_unicast_add to add the primary MAC unicast + * address multiple times. + */ if (mac_client_open(xnbop->o_mh, &xnbop->o_mch, NULL, - MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) { + MAC_OPEN_FLAGS_USE_DATALINK_NAME | + MAC_OPEN_FLAGS_MULTI_PRIMARY) != 0) { cmn_err(CE_WARN, "xnbo_open_mac: " "error (%d) opening mac client", err); xnbo_close_mac(xnbop); return (B_FALSE); } - err = mac_unicast_add(xnbop->o_mch, NULL, MAC_UNICAST_PRIMARY, - &xnbop->o_mah, 0, &diag); - if (err != 0) { - cmn_err(CE_WARN, "xnbo_open_mac: " - "failed to get the primary MAC address of " - "%s: %d", mac, err); - xnbo_close_mac(xnbop); - return (B_FALSE); - } - /* * Should the receive path filter packets from the downstream * NIC before passing them to the peer? The default is "no". @@ -307,11 +307,19 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) * default is "no". */ if (xenbus_scanf(XBT_NULL, xsname, - "SUNW-need-promiscuous", "%d", &need_promiscuous) != 0) + "SUNW-need-promiscuous", "%d", &need_promiscuous) != 0) { need_promiscuous = 0; - if (need_promiscuous == 0) { - mac_rx_set(xnbop->o_mch, rx_fn, xnbp); - } else { + } + err = mac_unicast_add_set_rx(xnbop->o_mch, NULL, MAC_UNICAST_PRIMARY, + &xnbop->o_mah, 0, &diag, need_promiscuous == 0 ? rx_fn : + NULL, xnbp); + if (err != 0) { + cmn_err(CE_WARN, "xnbo_open_mac: failed to get the primary " + "MAC address of %s: %d", mac, err); + xnbo_close_mac(xnbop); + return (B_FALSE); + } + if (need_promiscuous != 0) { err = mac_promisc_add(xnbop->o_mch, MAC_CLIENT_PROMISC_ALL, rx_fn, xnbp, &xnbop->o_mphp, MAC_PROMISC_FLAGS_NO_TX_LOOP | MAC_PROMISC_FLAGS_VLAN_TAG_STRIP); |