summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c127
-rw-r--r--usr/src/man/man1m/dladm.1m14
-rw-r--r--usr/src/uts/common/io/mac/mac_client.c132
-rw-r--r--usr/src/uts/common/io/vnic/vnic_dev.c191
-rw-r--r--usr/src/uts/common/sys/mac.h14
-rw-r--r--usr/src/uts/common/sys/mac_client.h5
-rw-r--r--usr/src/uts/common/sys/mac_client_priv.h4
-rw-r--r--usr/src/uts/common/sys/vnic_impl.h10
8 files changed, 463 insertions, 34 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
index 229a5fd83f..a2537aaa53 100644
--- a/usr/src/lib/libdladm/common/linkprop.c
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -65,6 +65,7 @@
#include <net/if_types.h>
#include <libinetutil.h>
#include <pool.h>
+#include <libdlaggr.h>
/*
* The linkprop get() callback.
@@ -149,18 +150,18 @@ static pd_getf_t get_zone, get_autopush, get_rate_mod, get_rate,
get_flowctl, get_maxbw, get_cpus, get_priority,
get_tagmode, get_range, get_stp, get_bridge_forward,
get_bridge_pvid, get_protection, get_rxrings,
- get_txrings, get_cntavail,
+ get_txrings, get_cntavail, get_secondary_macs,
get_allowedips, get_allowedcids, get_pool,
get_rings_range, get_linkmode_prop;
static pd_setf_t set_zone, set_rate, set_powermode, set_radio,
set_public_prop, set_resource, set_stp_prop,
- set_bridge_forward, set_bridge_pvid;
+ set_bridge_forward, set_bridge_pvid, set_secondary_macs;
static pd_checkf_t check_zone, check_autopush, check_rate, check_hoplimit,
check_encaplim, check_uint32, check_maxbw, check_cpus,
check_stp_prop, check_bridge_pvid, check_allowedips,
- check_allowedcids, check_rings,
+ check_allowedcids, check_secondary_macs, check_rings,
check_pool, check_prop;
struct prop_desc {
@@ -363,6 +364,9 @@ static link_attr_t link_attr[] = {
{ MAC_PROP_IB_LINKMODE, sizeof (uint32_t), "linkmode"},
+ { MAC_PROP_SECONDARY_ADDRS, sizeof (mac_secondary_addr_t),
+ "secondary-macs"},
+
{ MAC_PROP_PRIVATE, 0, "driver-private"}
};
@@ -443,6 +447,12 @@ static val_desc_t dladm_part_linkmode_vals[] = {
#define RESET_VAL ((uintptr_t)-1)
#define UNSPEC_VAL ((uintptr_t)-2)
+/*
+ * For the default, if defaults are not defined for the property,
+ * pd_defval.vd_name should be null. If the driver has to be contacted for the
+ * value, vd_name should be the empty string (""). Otherwise, dladm will
+ * just print whatever is in the table.
+ */
static prop_desc_t prop_table[] = {
{ "channel", { NULL, 0 },
NULL, 0, NULL, NULL,
@@ -506,6 +516,11 @@ static prop_desc_t prop_table[] = {
set_public_prop, NULL, get_flowctl, NULL,
0, DATALINK_CLASS_PHYS, DL_ETHER },
+ { "secondary-macs", { "--", 0 }, NULL, 0,
+ set_secondary_macs, NULL,
+ get_secondary_macs, check_secondary_macs, PD_CHECK_ALLOC,
+ DATALINK_CLASS_VNIC, DL_ETHER },
+
{ "adv_10gfdx_cap", { "", 0 },
link_01_vals, VALCNT(link_01_vals),
NULL, NULL, get_binary, NULL,
@@ -2797,6 +2812,106 @@ fail:
/* ARGSUSED */
static dladm_status_t
+get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
+ datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
+ datalink_media_t media, uint_t flags, uint_t *perm_flags)
+{
+ mac_secondary_addr_t sa;
+ dladm_status_t status;
+ int i;
+
+ status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
+ perm_flags, &sa, sizeof (sa));
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ if (sa.ms_addrcnt > *val_cnt)
+ return (DLADM_STATUS_BADVALCNT);
+
+ for (i = 0; i < sa.ms_addrcnt; i++) {
+ if (dladm_aggr_macaddr2str(
+ (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
+ NULL) {
+ *val_cnt = i;
+ return (DLADM_STATUS_NOMEM);
+ }
+ }
+ *val_cnt = sa.ms_addrcnt;
+ return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
+ datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
+ val_desc_t **vdpp, datalink_media_t media)
+{
+ dladm_status_t status;
+ uchar_t *addr;
+ uint_t len = 0;
+ int i;
+ uint_t val_cnt = *val_cntp;
+ val_desc_t *vdp = *vdpp;
+
+ if (val_cnt >= MPT_MAXMACADDR)
+ return (DLADM_STATUS_BADVALCNT);
+
+ for (i = 0; i < val_cnt; i++) {
+ addr = _link_aton(prop_val[i], (int *)&len);
+ if (addr == NULL) {
+ if (len == (uint_t)-1)
+ status = DLADM_STATUS_MACADDRINVAL;
+ else
+ status = DLADM_STATUS_NOMEM;
+ goto fail;
+ }
+
+ vdp[i].vd_val = (uintptr_t)addr;
+ }
+ return (DLADM_STATUS_OK);
+
+fail:
+ for (i = 0; i < val_cnt; i++) {
+ free((void *)vdp[i].vd_val);
+ vdp[i].vd_val = NULL;
+ }
+ return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
+ val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
+{
+ dladm_status_t status;
+ dld_ioc_macprop_t *dip;
+ int i;
+ mac_secondary_addr_t msa;
+
+ dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
+ &status);
+ if (dip == NULL)
+ return (status);
+
+ if (vdp->vd_val == 0) {
+ val_cnt = (uint_t)-1;
+ } else {
+ for (i = 0; i < val_cnt; i++) {
+ bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
+ MAXMACADDRLEN);
+ }
+ }
+ msa.ms_addrcnt = val_cnt;
+ bcopy(&msa, dip->pr_val, dip->pr_valsize);
+
+ status = i_dladm_macprop(handle, dip, B_TRUE);
+
+ free(dip);
+ return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
char **prop_val, uint_t *val_cnt, datalink_media_t media,
uint_t flags, uint_t *perm_flags)
@@ -4531,11 +4646,13 @@ dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
/*
* valcnt is always set to 1 by get_pool(), hence we need to check
- * for a non-null string to see if it is set. For protection and
- * allowed-ips, we can check either the *propval or the valcnt.
+ * for a non-null string to see if it is set. For protection,
+ * secondary-macs and allowed-ips, we can check either the *propval
+ * or the valcnt.
*/
if ((strcmp(prop_name, "pool") == 0 ||
strcmp(prop_name, "protection") == 0 ||
+ strcmp(prop_name, "secondary-macs") == 0 ||
strcmp(prop_name, "allowed-ips") == 0) &&
(strlen(*propvals) != 0)) {
*is_set = B_TRUE;
diff --git a/usr/src/man/man1m/dladm.1m b/usr/src/man/man1m/dladm.1m
index bf20443ad8..0434b69062 100644
--- a/usr/src/man/man1m/dladm.1m
+++ b/usr/src/man/man1m/dladm.1m
@@ -1,5 +1,6 @@
'\" te
.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright (c) 2014, Joyent, Inc. All Rights Reserved
.\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for permission to reproduce portions of its copyrighted documentation. Original documentation from The Open Group can be obtained online at http://www.opengroup.org/bookstore/.
.\" The Institute of Electrical and Electronics Engineers and The Open Group, have given us permission to reprint portions of their documentation. In the following statement, the phrase "this text" refers to portions of the system documentation. Portions of this text
.\" are reprinted and reproduced in electronic form in the Sun OS Reference Manual, from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of Electrical
@@ -8,7 +9,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DLADM 1M "Sep 23, 2009"
+.TH DLADM 1M "Jul 17, 2014"
.SH NAME
dladm \- administer data links
.SH SYNOPSIS
@@ -4821,6 +4822,17 @@ capabilities allowed by the device and the link partner.
.sp
.ne 2
.na
+\fB\fBsecondary-macs\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-seperated list of additional MAC addresses that are allowed on the
+interface.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBtagmode\fR\fR
.ad
.sp .6
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c
index dc1132941b..ae2a39ff49 100644
--- a/usr/src/uts/common/io/mac/mac_client.c
+++ b/usr/src/uts/common/io/mac/mac_client.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/*
@@ -84,13 +85,23 @@
* client opens a VNIC (upper MAC), the MAC layer detects that
* the MAC being opened is a VNIC, and gets the MAC client handle
* that the VNIC driver obtained from the lower MAC. This exchange
- * is doing through a private capability between the MAC layer
+ * is done through a private capability between the MAC layer
* and the VNIC driver. The upper MAC then returns that handle
* directly to its MAC client. Any operation done by the upper
* MAC client is now done on the lower MAC client handle, which
* allows the VNIC driver to be completely bypassed for the
* performance sensitive data-path.
*
+ * - Secondary MACs for VNICs:
+ *
+ * VNICs support multiple upper mac clients to enable support for
+ * multiple MAC addresses on the VNIC. When the VNIC is created the
+ * initial mac client is the primary upper mac. Any additional mac
+ * clients are secondary macs. These are kept in sync with the primary
+ * (for things such as the rx function and resource control settings)
+ * using the same private capability interface between the MAC layer
+ * and the VNIC layer.
+ *
*/
#include <sys/types.h>
@@ -148,6 +159,7 @@ static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t,
uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *);
static void mac_client_datapath_teardown(mac_client_handle_t,
mac_unicast_impl_t *, flow_entry_t *);
+static int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *);
/* ARGSUSED */
static int
@@ -266,6 +278,18 @@ mac_vnic_lower(mac_impl_t *mip)
}
/*
+ * Update the secondary macs
+ */
+void
+mac_vnic_secondary_update(mac_impl_t *mip)
+{
+ mac_capab_vnic_t cap;
+
+ VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap));
+ cap.mcv_mac_secondary_update(cap.mcv_arg);
+}
+
+/*
* Return the MAC client handle of the primary MAC client for the
* specified MAC instance, or NULL otherwise.
*/
@@ -1048,6 +1072,18 @@ mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr)
}
/*
+ * Return the secondary MAC address for the specified handle
+ */
+void
+mac_unicast_secondary_get(mac_client_handle_t mh, uint8_t *addr)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mh;
+
+ ASSERT(mcip->mci_unicast != NULL);
+ bcopy(mcip->mci_unicast->ma_addr, addr, mcip->mci_unicast->ma_len);
+}
+
+/*
* Return information about the use of the primary MAC address of the
* specified MAC instance:
*
@@ -1290,6 +1326,10 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
mip->mi_clients_list = mcip;
i_mac_perim_exit(mip);
*mchp = (mac_client_handle_t)mcip;
+
+ DTRACE_PROBE2(mac__client__open__nonallocated, mac_impl_t *,
+ mcip->mci_mip, mac_client_impl_t *, mcip);
+
return (err);
}
@@ -1394,10 +1434,6 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
if (share_desired)
i_mac_share_alloc(mcip);
- DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *,
- mcip->mci_mip, mac_client_impl_t *, mcip);
- *mchp = (mac_client_handle_t)mcip;
-
/*
* We will do mimimal datapath setup to allow a MAC client to
* transmit or receive non-unicast packets without waiting
@@ -1409,6 +1445,11 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
goto done;
}
}
+
+ DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *,
+ mcip->mci_mip, mac_client_impl_t *, mcip);
+
+ *mchp = (mac_client_handle_t)mcip;
i_mac_perim_exit(mip);
return (0);
@@ -1532,6 +1573,7 @@ mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg)
{
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
mac_impl_t *mip = mcip->mci_mip;
+ mac_impl_t *umip = mcip->mci_upper_mip;
/*
* Instead of adding an extra set of locks and refcnts in
@@ -1547,6 +1589,15 @@ mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg)
mcip->mci_rx_arg = arg;
mac_rx_client_restart(mch);
i_mac_perim_exit(mip);
+
+ /*
+ * If we're changing the rx function on the primary mac of a vnic,
+ * make sure any secondary macs on the vnic are updated as well.
+ */
+ if (umip != NULL) {
+ ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
+ mac_vnic_secondary_update(umip);
+ }
}
/*
@@ -1558,6 +1609,42 @@ mac_rx_clear(mac_client_handle_t mch)
mac_rx_set(mch, mac_pkt_drop, NULL);
}
+void
+mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch)
+{
+ mac_client_impl_t *smcip = (mac_client_impl_t *)smch;
+ mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch;
+ flow_entry_t *flent = dmcip->mci_flent;
+
+ /* This should only be called to setup secondary macs */
+ ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
+
+ mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg);
+ dmcip->mci_promisc_list = smcip->mci_promisc_list;
+
+ /*
+ * Duplicate the primary mac resources to the secondary.
+ * Since we already validated the resource controls when setting
+ * them on the primary, we can ignore errors here.
+ */
+ (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip));
+}
+
+/*
+ * Called when removing a secondary MAC. Currently only clears the promisc_list
+ * since we share the primary mac's promisc_list.
+ */
+void
+mac_secondary_cleanup(mac_client_handle_t mch)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ flow_entry_t *flent = mcip->mci_flent;
+
+ /* This should only be called for secondary macs */
+ ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0);
+ mcip->mci_promisc_list = NULL;
+}
+
/*
* Walk the MAC client subflow table and updates their priority values.
*/
@@ -1910,11 +1997,12 @@ mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp,
* mac_client_impl_t from the mac_impl_t (i.e if there are any cached
* properties before the flow entry for the unicast address was created).
*/
-int
+static int
mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
{
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip;
+ mac_impl_t *umip = mcip->mci_upper_mip;
int err = 0;
flow_entry_t *flent = mcip->mci_flent;
mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip);
@@ -1998,20 +2086,17 @@ mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
mac_flow_modify(mip->mi_flow_tab, flent, mrp);
if (mrp->mrp_mask & MRP_PRIORITY)
mac_update_subflow_priority(mcip);
+
+ /* Apply these resource settings to any secondary macs */
+ if (umip != NULL) {
+ ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
+ mac_vnic_secondary_update(umip);
+ }
}
kmem_free(omrp, sizeof (*omrp));
return (0);
}
-void
-mac_resource_ctl_get(mac_client_handle_t mch, mac_resource_props_t *mrp)
-{
- mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
- mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip);
-
- bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
-}
-
static int
mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr,
uint16_t vid, boolean_t is_primary, boolean_t first_flow,
@@ -3219,7 +3304,16 @@ mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type,
mutex_exit(mcbi->mcbi_lockp);
*mphp = (mac_promisc_handle_t)mpip;
+
+ if (mcip->mci_state_flags & MCIS_IS_VNIC) {
+ mac_impl_t *umip = mcip->mci_upper_mip;
+
+ ASSERT(umip != NULL);
+ mac_vnic_secondary_update(umip);
+ }
+
i_mac_perim_exit(mip);
+
return (0);
}
@@ -3258,6 +3352,14 @@ mac_promisc_remove(mac_promisc_handle_t mph)
} else {
mac_callback_remove_wait(&mip->mi_promisc_cb_info);
}
+
+ if (mcip->mci_state_flags & MCIS_IS_VNIC) {
+ mac_impl_t *umip = mcip->mci_upper_mip;
+
+ ASSERT(umip != NULL);
+ mac_vnic_secondary_update(umip);
+ }
+
mutex_exit(mcbi->mcbi_lockp);
mac_stop((mac_handle_t)mip);
diff --git a/usr/src/uts/common/io/vnic/vnic_dev.c b/usr/src/uts/common/io/vnic/vnic_dev.c
index 5c46901f36..2af812547e 100644
--- a/usr/src/uts/common/io/vnic/vnic_dev.c
+++ b/usr/src/uts/common/io/vnic/vnic_dev.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -70,6 +71,11 @@
* Due to this passthrough, some of the entry points exported by the
* VNIC driver are never directly invoked. These entry points include
* vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc.
+ *
+ * VNICs support multiple upper mac clients to enable support for
+ * multiple MAC addresses on the VNIC. When the VNIC is created the
+ * initial mac client is the primary upper mac. Any additional mac
+ * clients are secondary macs.
*/
static int vnic_m_start(void *);
@@ -81,11 +87,13 @@ static int vnic_m_stat(void *, uint_t, uint64_t *);
static void vnic_m_ioctl(void *, queue_t *, mblk_t *);
static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
const void *);
+static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
static void vnic_m_propinfo(void *, const char *, mac_prop_id_t,
mac_prop_info_handle_t);
static mblk_t *vnic_m_tx(void *, mblk_t *);
static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *);
static void vnic_notify_cb(void *, mac_notify_type_t);
+static void vnic_cleanup_secondary_macs(vnic_t *, int);
static kmem_cache_t *vnic_cache;
static krwlock_t vnic_lock;
@@ -100,7 +108,7 @@ static mod_hash_t *vnic_hash;
#define VNIC_HASH_KEY(vnic_id) ((mod_hash_key_t)(uintptr_t)vnic_id)
#define VNIC_M_CALLBACK_FLAGS \
- (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_PROPINFO)
+ (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
static mac_callbacks_t vnic_m_callbacks = {
VNIC_M_CALLBACK_FLAGS,
@@ -117,7 +125,7 @@ static mac_callbacks_t vnic_m_callbacks = {
NULL,
NULL,
vnic_m_setprop,
- NULL,
+ vnic_m_getprop,
vnic_m_propinfo
};
@@ -621,6 +629,8 @@ vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
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);
@@ -741,6 +751,20 @@ vnic_mac_client_handle(void *vnic_arg)
return (vnic->vn_mch);
}
+/*
+ * Invoked when updating the primary MAC so that the secondary MACs are
+ * kept in sync.
+ */
+static void
+vnic_mac_secondary_update(void *vnic_arg)
+{
+ vnic_t *vn = vnic_arg;
+ int i;
+
+ for (i = 1; i <= vn->vn_nhandles; i++) {
+ mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
+ }
+}
/*
* Return information about the specified capability.
@@ -775,6 +799,8 @@ vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data)
vnic_capab->mcv_arg = vnic;
vnic_capab->mcv_mac_client_handle =
vnic_mac_client_handle;
+ vnic_capab->mcv_mac_secondary_update =
+ vnic_mac_secondary_update;
}
break;
}
@@ -841,6 +867,126 @@ vnic_m_unicst(void *arg, const uint8_t *macaddr)
return (mac_vnic_unicast_set(vnic->vn_mch, macaddr));
}
+static void
+vnic_cleanup_secondary_macs(vnic_t *vn, int cnt)
+{
+ int i;
+
+ /* Remove existing secondaries (primary is at 0) */
+ for (i = 1; i <= cnt; i++) {
+ mac_rx_clear(vn->vn_mc_handles[i]);
+
+ /* unicast handle might not have been set yet */
+ if (vn->vn_mu_handles[i] != NULL)
+ (void) mac_unicast_remove(vn->vn_mc_handles[i],
+ vn->vn_mu_handles[i]);
+
+ mac_secondary_cleanup(vn->vn_mc_handles[i]);
+
+ mac_client_close(vn->vn_mc_handles[i], MAC_CLOSE_FLAGS_IS_VNIC);
+
+ vn->vn_mu_handles[i] = NULL;
+ vn->vn_mc_handles[i] = NULL;
+ }
+
+ vn->vn_nhandles = 0;
+}
+
+/*
+ * Setup secondary MAC addresses on the vnic. Due to limitations in the mac
+ * code, each mac address must be associated with a mac_client (and the
+ * flow that goes along with the client) so we need to create those clients
+ * here.
+ */
+static int
+vnic_set_secondary_macs(vnic_t *vn, mac_secondary_addr_t *msa)
+{
+ int i, err;
+ char primary_name[MAXNAMELEN];
+
+ /* First, remove pre-existing secondaries */
+ ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
+ vnic_cleanup_secondary_macs(vn, vn->vn_nhandles);
+
+ if (msa->ms_addrcnt == (uint32_t)-1)
+ msa->ms_addrcnt = 0;
+
+ vn->vn_nhandles = msa->ms_addrcnt;
+
+ (void) dls_mgmt_get_linkinfo(vn->vn_id, primary_name, NULL, NULL, NULL);
+
+ /*
+ * Now add the new secondary MACs
+ * Recall that the primary MAC address is the first element.
+ * The secondary clients are named after the primary with their
+ * index to distinguish them.
+ */
+ for (i = 1; i <= vn->vn_nhandles; i++) {
+ uint8_t *addr;
+ mac_diag_t mac_diag;
+ char secondary_name[MAXNAMELEN];
+
+ (void) snprintf(secondary_name, sizeof (secondary_name),
+ "%s%02d", primary_name, i);
+
+ err = mac_client_open(vn->vn_lower_mh, &vn->vn_mc_handles[i],
+ secondary_name, MAC_OPEN_FLAGS_IS_VNIC);
+ if (err != 0) {
+ /* Remove any that we successfully added */
+ vnic_cleanup_secondary_macs(vn, --i);
+ return (err);
+ }
+
+ /*
+ * Assign a MAC address to the VNIC
+ *
+ * Normally this would be done with vnic_unicast_add but since
+ * we know these are fixed adddresses, and since we need to
+ * save this in the proper array slot, we bypass that function
+ * and go direct.
+ */
+ addr = msa->ms_addrs[i - 1];
+ err = mac_unicast_add(vn->vn_mc_handles[i], addr, 0,
+ &vn->vn_mu_handles[i], vn->vn_vid, &mac_diag);
+ if (err != 0) {
+ /* Remove any that we successfully added */
+ vnic_cleanup_secondary_macs(vn, i);
+ return (err);
+ }
+
+ /*
+ * Setup the secondary the same way as the primary (i.e.
+ * receiver function/argument (e.g. i_dls_link_rx, mac_pkt_drop,
+ * etc.), the promisc list, and the resource controls).
+ */
+ mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
+ }
+
+ return (0);
+}
+
+static int
+vnic_get_secondary_macs(vnic_t *vn, uint_t pr_valsize, void *pr_val)
+{
+ int i;
+ mac_secondary_addr_t msa;
+
+ if (pr_valsize < sizeof (msa))
+ return (EINVAL);
+
+ /* Get existing addresses (primary is at 0) */
+ ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
+ for (i = 1; i <= vn->vn_nhandles; i++) {
+ ASSERT(vn->vn_mc_handles[i] != NULL);
+ mac_unicast_secondary_get(vn->vn_mc_handles[i],
+ msa.ms_addrs[i - 1]);
+ }
+ msa.ms_addrcnt = vn->vn_nhandles;
+
+ bcopy(&msa, pr_val, sizeof (msa));
+ return (0);
+}
+
/*
* Callback functions for set/get of properties
*/
@@ -849,17 +995,17 @@ static int
vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
uint_t pr_valsize, const void *pr_val)
{
- int err = ENOTSUP;
+ int err = 0;
vnic_t *vn = m_driver;
- /* allow setting MTU only on an etherstub */
- if (vn->vn_link_id != DATALINK_INVALID_LINKID)
- return (err);
-
switch (pr_num) {
case MAC_PROP_MTU: {
uint32_t mtu;
+ /* allow setting MTU only on an etherstub */
+ if (vn->vn_link_id != DATALINK_INVALID_LINKID)
+ return (err);
+
if (pr_valsize < sizeof (mtu)) {
err = EINVAL;
break;
@@ -872,13 +1018,41 @@ vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
err = mac_maxsdu_update(vn->vn_mh, mtu);
break;
}
+ case MAC_PROP_SECONDARY_ADDRS: {
+ mac_secondary_addr_t msa;
+
+ bcopy(pr_val, &msa, sizeof (msa));
+ err = vnic_set_secondary_macs(vn, &msa);
+ break;
+ }
default:
+ err = ENOTSUP;
break;
}
return (err);
}
/* ARGSUSED */
+static int
+vnic_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
+ uint_t pr_valsize, void *pr_val)
+{
+ vnic_t *vn = arg;
+ int ret = 0;
+
+ switch (pr_num) {
+ case MAC_PROP_SECONDARY_ADDRS:
+ ret = vnic_get_secondary_macs(vn, pr_valsize, pr_val);
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return (ret);
+}
+
+/* ARGSUSED */
static void vnic_m_propinfo(void *m_driver, const char *pr_name,
mac_prop_id_t pr_num, mac_prop_info_handle_t prh)
{
@@ -929,7 +1103,8 @@ vnic_info(vnic_info_t *info, cred_t *credp)
bzero(&info->vn_resource_props, sizeof (mac_resource_props_t));
if (vnic->vn_mch != NULL)
- mac_resource_ctl_get(vnic->vn_mch, &info->vn_resource_props);
+ mac_client_get_resources(vnic->vn_mch,
+ &info->vn_resource_props);
rw_exit(&vnic_lock);
return (0);
diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h
index 6876fccb1a..f1bfa1aec2 100644
--- a/usr/src/uts/common/sys/mac.h
+++ b/usr/src/uts/common/sys/mac.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#ifndef _SYS_MAC_H
@@ -128,6 +129,13 @@ typedef struct mac_propval_range_s {
*/
#define MAXMACADDRLEN 20
+#define MPT_MAXMACADDR 32
+
+typedef struct mac_secondary_addr_s {
+ uint32_t ms_addrcnt;
+ uint8_t ms_addrs[MPT_MAXMACADDR][MAXMACADDRLEN];
+} mac_secondary_addr_t;
+
typedef enum {
MAC_LOGTYPE_LINK = 1,
MAC_LOGTYPE_FLOW
@@ -205,6 +213,7 @@ typedef enum {
MAC_PROP_MAX_RXHWCLNT_AVAIL,
MAC_PROP_MAX_TXHWCLNT_AVAIL,
MAC_PROP_IB_LINKMODE,
+ MAC_PROP_SECONDARY_ADDRS,
MAC_PROP_PRIVATE = -1
} mac_prop_id_t;
@@ -312,13 +321,18 @@ typedef struct mac_info_s {
*
* This capability allows the MAC layer to detect when a VNIC is being
* access, and implement the required shortcuts.
+ *
+ * In addition, this capability is used to keep the VNIC's secondary
+ * mac_clients in sync when the primary MAC is updated.
*/
typedef void *(*mac_client_handle_fn_t)(void *);
+typedef void (*mac_client_update_fn_t)(void *);
typedef struct mac_capab_vnic_s {
void *mcv_arg;
mac_client_handle_fn_t mcv_mac_client_handle;
+ mac_client_update_fn_t mcv_mac_secondary_update;
} mac_capab_vnic_t;
typedef void (*mac_rename_fn_t)(const char *, void *);
diff --git a/usr/src/uts/common/sys/mac_client.h b/usr/src/uts/common/sys/mac_client.h
index 40cd15a1b8..0fc4939503 100644
--- a/usr/src/uts/common/sys/mac_client.h
+++ b/usr/src/uts/common/sys/mac_client.h
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
/*
@@ -135,6 +136,8 @@ extern void mac_multicast_remove(mac_client_handle_t, const uint8_t *);
extern void mac_rx_set(mac_client_handle_t, mac_rx_t, void *);
extern void mac_rx_clear(mac_client_handle_t);
+extern void mac_secondary_dup(mac_client_handle_t, mac_client_handle_t);
+extern void mac_secondary_cleanup(mac_client_handle_t);
extern mac_tx_cookie_t mac_tx(mac_client_handle_t, mblk_t *,
uintptr_t, uint16_t, mblk_t **);
extern boolean_t mac_tx_is_flow_blocked(mac_client_handle_t, mac_tx_cookie_t);
@@ -158,6 +161,8 @@ extern int mac_unicast_primary_set(mac_handle_t, const uint8_t *);
extern void mac_unicast_primary_get(mac_handle_t, uint8_t *);
extern void mac_unicast_primary_info(mac_handle_t, char *, boolean_t *);
+extern void mac_unicast_secondary_get(mac_client_handle_t, uint8_t *);
+
extern boolean_t mac_dst_get(mac_handle_t, uint8_t *);
extern int mac_addr_random(mac_client_handle_t, uint_t, uint8_t *,
diff --git a/usr/src/uts/common/sys/mac_client_priv.h b/usr/src/uts/common/sys/mac_client_priv.h
index 0ddc1f074d..bed2e293b3 100644
--- a/usr/src/uts/common/sys/mac_client_priv.h
+++ b/usr/src/uts/common/sys/mac_client_priv.h
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
/*
@@ -91,9 +92,6 @@ extern boolean_t mac_client_is_vlan_vnic(mac_client_handle_t);
extern void mac_client_poll_enable(mac_client_handle_t);
extern void mac_client_poll_disable(mac_client_handle_t);
-extern int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *);
-extern void mac_resource_ctl_get(mac_client_handle_t, mac_resource_props_t *);
-
/*
* Flow-related APIs for MAC clients.
*/
diff --git a/usr/src/uts/common/sys/vnic_impl.h b/usr/src/uts/common/sys/vnic_impl.h
index 2bb48a60c6..ffaa2939f5 100644
--- a/usr/src/uts/common/sys/vnic_impl.h
+++ b/usr/src/uts/common/sys/vnic_impl.h
@@ -21,6 +21,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2013 Joyent, Inc. All rights reserved.
*/
#ifndef _SYS_VNIC_IMPL_H
@@ -46,8 +47,10 @@ typedef struct vnic_s {
mac_handle_t vn_mh;
mac_handle_t vn_lower_mh;
- mac_client_handle_t vn_mch;
- mac_unicast_handle_t vn_muh;
+ uint_t vn_nhandles; /* # of secondary mac handles */
+ /* The primary handle is always the first element in the array */
+ mac_client_handle_t vn_mc_handles[MPT_MAXMACADDR];
+ mac_unicast_handle_t vn_mu_handles[MPT_MAXMACADDR];
uint32_t vn_margin;
int vn_slot_id;
vnic_mac_addr_type_t vn_addr_type;
@@ -63,6 +66,9 @@ typedef struct vnic_s {
uint32_t vn_hcksum_txflags;
} vnic_t;
+#define vn_mch vn_mc_handles[0]
+#define vn_muh vn_mu_handles[0]
+
extern int vnic_dev_create(datalink_id_t, datalink_id_t, vnic_mac_addr_type_t *,
int *, uchar_t *, int *, uint_t, uint16_t, vrid_t, int,
mac_resource_props_t *, uint32_t, vnic_ioc_diag_t *, cred_t *);