xref: /titanic_52/usr/src/uts/common/io/vnic/vnic_dev.c (revision 098d2c7517cab63b47f653aef0a18e99f344ccfc)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev /*
229056fcebSCathy Zhou  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23bf773d37SRobert Mustacchi  * Copyright 2015 Joyent, Inc.
24238d8f47SDale Ghent  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
25843e1988Sjohnlev  */
26843e1988Sjohnlev 
27843e1988Sjohnlev #include <sys/types.h>
282b24ab6bSSebastien Roy #include <sys/cred.h>
29843e1988Sjohnlev #include <sys/sysmacros.h>
30843e1988Sjohnlev #include <sys/conf.h>
31843e1988Sjohnlev #include <sys/cmn_err.h>
32843e1988Sjohnlev #include <sys/list.h>
33843e1988Sjohnlev #include <sys/ksynch.h>
34843e1988Sjohnlev #include <sys/kmem.h>
35843e1988Sjohnlev #include <sys/stream.h>
36843e1988Sjohnlev #include <sys/modctl.h>
37843e1988Sjohnlev #include <sys/ddi.h>
38843e1988Sjohnlev #include <sys/sunddi.h>
39843e1988Sjohnlev #include <sys/atomic.h>
40843e1988Sjohnlev #include <sys/stat.h>
41843e1988Sjohnlev #include <sys/modhash.h>
42843e1988Sjohnlev #include <sys/strsubr.h>
43843e1988Sjohnlev #include <sys/strsun.h>
44843e1988Sjohnlev #include <sys/dlpi.h>
45843e1988Sjohnlev #include <sys/mac.h>
46da14cebeSEric Cheng #include <sys/mac_provider.h>
47da14cebeSEric Cheng #include <sys/mac_client.h>
48da14cebeSEric Cheng #include <sys/mac_client_priv.h>
49843e1988Sjohnlev #include <sys/mac_ether.h>
50d62bc4baSyz147064 #include <sys/dls.h>
51843e1988Sjohnlev #include <sys/pattr.h>
52da14cebeSEric Cheng #include <sys/time.h>
53da14cebeSEric Cheng #include <sys/vlan.h>
54843e1988Sjohnlev #include <sys/vnic.h>
55843e1988Sjohnlev #include <sys/vnic_impl.h>
56*098d2c75SRobert Mustacchi #include <sys/mac_impl.h>
57da14cebeSEric Cheng #include <sys/mac_flow_impl.h>
58843e1988Sjohnlev #include <inet/ip_impl.h>
59843e1988Sjohnlev 
60da14cebeSEric Cheng /*
61da14cebeSEric Cheng  * Note that for best performance, the VNIC is a passthrough design.
62da14cebeSEric Cheng  * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC).
63da14cebeSEric Cheng  * This MAC client is opened by the VNIC driver at VNIC creation,
64da14cebeSEric Cheng  * and closed when the VNIC is deleted.
65da14cebeSEric Cheng  * When a MAC client of the VNIC itself opens a VNIC, the MAC layer
66da14cebeSEric Cheng  * (upper MAC) detects that the MAC being opened is a VNIC. Instead
67da14cebeSEric Cheng  * of allocating a new MAC client, it asks the VNIC driver to return
68da14cebeSEric Cheng  * the lower MAC client handle associated with the VNIC, and that handle
69da14cebeSEric Cheng  * is returned to the upper MAC client directly. This allows access
70da14cebeSEric Cheng  * by upper MAC clients of the VNIC to have direct access to the lower
71da14cebeSEric Cheng  * MAC client for the control path and data path.
72da14cebeSEric Cheng  *
73da14cebeSEric Cheng  * Due to this passthrough, some of the entry points exported by the
74da14cebeSEric Cheng  * VNIC driver are never directly invoked. These entry points include
75da14cebeSEric Cheng  * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc.
761a41ca23SJerry Jelinek  *
771a41ca23SJerry Jelinek  * VNICs support multiple upper mac clients to enable support for
781a41ca23SJerry Jelinek  * multiple MAC addresses on the VNIC. When the VNIC is created the
791a41ca23SJerry Jelinek  * initial mac client is the primary upper mac. Any additional mac
801a41ca23SJerry Jelinek  * clients are secondary macs.
81da14cebeSEric Cheng  */
82da14cebeSEric Cheng 
83843e1988Sjohnlev static int vnic_m_start(void *);
84843e1988Sjohnlev static void vnic_m_stop(void *);
85843e1988Sjohnlev static int vnic_m_promisc(void *, boolean_t);
86843e1988Sjohnlev static int vnic_m_multicst(void *, boolean_t, const uint8_t *);
87843e1988Sjohnlev static int vnic_m_unicst(void *, const uint8_t *);
88843e1988Sjohnlev static int vnic_m_stat(void *, uint_t, uint64_t *);
89da14cebeSEric Cheng static void vnic_m_ioctl(void *, queue_t *, mblk_t *);
90ab6f61efSGirish Moodalbail static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
91ab6f61efSGirish Moodalbail     const void *);
921a41ca23SJerry Jelinek static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
930dc2366fSVenugopal Iyer static void vnic_m_propinfo(void *, const char *, mac_prop_id_t,
940dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
95843e1988Sjohnlev static mblk_t *vnic_m_tx(void *, mblk_t *);
96843e1988Sjohnlev static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *);
97843e1988Sjohnlev static void vnic_notify_cb(void *, mac_notify_type_t);
981a41ca23SJerry Jelinek static void vnic_cleanup_secondary_macs(vnic_t *, int);
99843e1988Sjohnlev 
100843e1988Sjohnlev static kmem_cache_t	*vnic_cache;
101843e1988Sjohnlev static krwlock_t	vnic_lock;
102843e1988Sjohnlev static uint_t		vnic_count;
103843e1988Sjohnlev 
104f0f2c3a5SGirish Moodalbail #define	ANCHOR_VNIC_MIN_MTU	576
105f0f2c3a5SGirish Moodalbail #define	ANCHOR_VNIC_MAX_MTU	9000
106f0f2c3a5SGirish Moodalbail 
107843e1988Sjohnlev /* hash of VNICs (vnic_t's), keyed by VNIC id */
108843e1988Sjohnlev static mod_hash_t	*vnic_hash;
109843e1988Sjohnlev #define	VNIC_HASHSZ	64
110843e1988Sjohnlev #define	VNIC_HASH_KEY(vnic_id)	((mod_hash_key_t)(uintptr_t)vnic_id)
111843e1988Sjohnlev 
112ab6f61efSGirish Moodalbail #define	VNIC_M_CALLBACK_FLAGS	\
1131a41ca23SJerry Jelinek 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
114843e1988Sjohnlev 
115843e1988Sjohnlev static mac_callbacks_t vnic_m_callbacks = {
116843e1988Sjohnlev 	VNIC_M_CALLBACK_FLAGS,
117843e1988Sjohnlev 	vnic_m_stat,
118843e1988Sjohnlev 	vnic_m_start,
119843e1988Sjohnlev 	vnic_m_stop,
120843e1988Sjohnlev 	vnic_m_promisc,
121843e1988Sjohnlev 	vnic_m_multicst,
122843e1988Sjohnlev 	vnic_m_unicst,
123843e1988Sjohnlev 	vnic_m_tx,
1240dc2366fSVenugopal Iyer 	NULL,
125da14cebeSEric Cheng 	vnic_m_ioctl,
126ab6f61efSGirish Moodalbail 	vnic_m_capab_get,
127ab6f61efSGirish Moodalbail 	NULL,
128ab6f61efSGirish Moodalbail 	NULL,
129ab6f61efSGirish Moodalbail 	vnic_m_setprop,
1301a41ca23SJerry Jelinek 	vnic_m_getprop,
1310dc2366fSVenugopal Iyer 	vnic_m_propinfo
132843e1988Sjohnlev };
133843e1988Sjohnlev 
134843e1988Sjohnlev void
135843e1988Sjohnlev vnic_dev_init(void)
136843e1988Sjohnlev {
137843e1988Sjohnlev 	vnic_cache = kmem_cache_create("vnic_cache",
138843e1988Sjohnlev 	    sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
139843e1988Sjohnlev 
140843e1988Sjohnlev 	vnic_hash = mod_hash_create_idhash("vnic_hash",
141843e1988Sjohnlev 	    VNIC_HASHSZ, mod_hash_null_valdtor);
142843e1988Sjohnlev 
143843e1988Sjohnlev 	rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL);
144843e1988Sjohnlev 
145843e1988Sjohnlev 	vnic_count = 0;
146843e1988Sjohnlev }
147843e1988Sjohnlev 
148843e1988Sjohnlev void
149843e1988Sjohnlev vnic_dev_fini(void)
150843e1988Sjohnlev {
151843e1988Sjohnlev 	ASSERT(vnic_count == 0);
152843e1988Sjohnlev 
153843e1988Sjohnlev 	rw_destroy(&vnic_lock);
154843e1988Sjohnlev 	mod_hash_destroy_idhash(vnic_hash);
155843e1988Sjohnlev 	kmem_cache_destroy(vnic_cache);
156843e1988Sjohnlev }
157843e1988Sjohnlev 
158843e1988Sjohnlev uint_t
159843e1988Sjohnlev vnic_dev_count(void)
160843e1988Sjohnlev {
161843e1988Sjohnlev 	return (vnic_count);
162843e1988Sjohnlev }
163843e1988Sjohnlev 
164da14cebeSEric Cheng static vnic_ioc_diag_t
165da14cebeSEric Cheng vnic_mac2vnic_diag(mac_diag_t diag)
166843e1988Sjohnlev {
167da14cebeSEric Cheng 	switch (diag) {
168da14cebeSEric Cheng 	case MAC_DIAG_MACADDR_NIC:
169da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACADDR_NIC);
170da14cebeSEric Cheng 	case MAC_DIAG_MACADDR_INUSE:
171da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACADDR_INUSE);
172da14cebeSEric Cheng 	case MAC_DIAG_MACADDR_INVALID:
173da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACADDR_INVALID);
174da14cebeSEric Cheng 	case MAC_DIAG_MACADDRLEN_INVALID:
175da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACADDRLEN_INVALID);
176da14cebeSEric Cheng 	case MAC_DIAG_MACFACTORYSLOTINVALID:
177da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID);
178da14cebeSEric Cheng 	case MAC_DIAG_MACFACTORYSLOTUSED:
179da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED);
180da14cebeSEric Cheng 	case MAC_DIAG_MACFACTORYSLOTALLUSED:
181da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED);
182da14cebeSEric Cheng 	case MAC_DIAG_MACFACTORYNOTSUP:
183da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACFACTORYNOTSUP);
184da14cebeSEric Cheng 	case MAC_DIAG_MACPREFIX_INVALID:
185da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACPREFIX_INVALID);
186da14cebeSEric Cheng 	case MAC_DIAG_MACPREFIXLEN_INVALID:
187da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID);
188da14cebeSEric Cheng 	case MAC_DIAG_MACNO_HWRINGS:
189da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_NO_HWRINGS);
190da14cebeSEric Cheng 	default:
191da14cebeSEric Cheng 		return (VNIC_IOC_DIAG_NONE);
192da14cebeSEric Cheng 	}
193da14cebeSEric Cheng }
194da14cebeSEric Cheng 
195da14cebeSEric Cheng static int
196da14cebeSEric Cheng vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type,
197da14cebeSEric Cheng     int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg,
198da14cebeSEric Cheng     uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag,
1990dc2366fSVenugopal Iyer     uint16_t vid, boolean_t req_hwgrp_flag)
200da14cebeSEric Cheng {
201da14cebeSEric Cheng 	mac_diag_t mac_diag;
202da14cebeSEric Cheng 	uint16_t mac_flags = 0;
203843e1988Sjohnlev 	int err;
204da14cebeSEric Cheng 	uint_t addr_len;
205843e1988Sjohnlev 
206da14cebeSEric Cheng 	if (flags & VNIC_IOC_CREATE_NODUPCHECK)
207da14cebeSEric Cheng 		mac_flags |= MAC_UNICAST_NODUPCHECK;
208843e1988Sjohnlev 
209da14cebeSEric Cheng 	switch (vnic_addr_type) {
210da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_FIXED:
2111cb875aeSCathy Zhou 	case VNIC_MAC_ADDR_TYPE_VRID:
212da14cebeSEric Cheng 		/*
213da14cebeSEric Cheng 		 * The MAC address value to assign to the VNIC
214da14cebeSEric Cheng 		 * is already provided in mac_addr_arg. addr_len_ptr_arg
215da14cebeSEric Cheng 		 * already contains the MAC address length.
216da14cebeSEric Cheng 		 */
217da14cebeSEric Cheng 		break;
218843e1988Sjohnlev 
219da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_RANDOM:
220da14cebeSEric Cheng 		/*
221da14cebeSEric Cheng 		 * Random MAC address. There are two sub-cases:
222da14cebeSEric Cheng 		 *
223da14cebeSEric Cheng 		 * 1 - If mac_len == 0, a new MAC address is generated.
224da14cebeSEric Cheng 		 *	The length of the MAC address to generated depends
225da14cebeSEric Cheng 		 *	on the type of MAC used. The prefix to use for the MAC
226da14cebeSEric Cheng 		 *	address is stored in the most significant bytes
227da14cebeSEric Cheng 		 *	of the mac_addr argument, and its length is specified
228da14cebeSEric Cheng 		 *	by the mac_prefix_len argument. This prefix can
229da14cebeSEric Cheng 		 *	correspond to a IEEE OUI in the case of Ethernet,
230da14cebeSEric Cheng 		 *	for example.
231da14cebeSEric Cheng 		 *
232da14cebeSEric Cheng 		 * 2 - If mac_len > 0, the address was already picked
233da14cebeSEric Cheng 		 *	randomly, and is now passed back during VNIC
234da14cebeSEric Cheng 		 *	re-creation. The mac_addr argument contains the MAC
235da14cebeSEric Cheng 		 *	address that was generated. We distinguish this
236da14cebeSEric Cheng 		 *	case from the fixed MAC address case, since we
237da14cebeSEric Cheng 		 *	want the user consumers to know, when they query
238da14cebeSEric Cheng 		 *	the list of VNICs, that a VNIC was assigned a
239da14cebeSEric Cheng 		 *	random MAC address vs assigned a fixed address
240da14cebeSEric Cheng 		 *	specified by the user.
241da14cebeSEric Cheng 		 */
242843e1988Sjohnlev 
243d62bc4baSyz147064 		/*
244da14cebeSEric Cheng 		 * If it's a pre-generated address, we're done. mac_addr_arg
245da14cebeSEric Cheng 		 * and addr_len_ptr_arg already contain the MAC address
246da14cebeSEric Cheng 		 * value and length.
247d62bc4baSyz147064 		 */
248da14cebeSEric Cheng 		if (*addr_len_ptr_arg > 0)
249da14cebeSEric Cheng 			break;
250d62bc4baSyz147064 
251da14cebeSEric Cheng 		/* generate a new random MAC address */
252da14cebeSEric Cheng 		if ((err = mac_addr_random(vnic->vn_mch,
253da14cebeSEric Cheng 		    prefix_len, mac_addr_arg, &mac_diag)) != 0) {
254da14cebeSEric Cheng 			*diag = vnic_mac2vnic_diag(mac_diag);
255843e1988Sjohnlev 			return (err);
256843e1988Sjohnlev 		}
257da14cebeSEric Cheng 		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
258da14cebeSEric Cheng 		break;
259843e1988Sjohnlev 
260da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_FACTORY:
261da14cebeSEric Cheng 		err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
262843e1988Sjohnlev 		if (err != 0) {
263da14cebeSEric Cheng 			if (err == EINVAL)
264da14cebeSEric Cheng 				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID;
265da14cebeSEric Cheng 			if (err == EBUSY)
266da14cebeSEric Cheng 				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED;
267da14cebeSEric Cheng 			if (err == ENOSPC)
268da14cebeSEric Cheng 				*diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED;
269843e1988Sjohnlev 			return (err);
270843e1988Sjohnlev 		}
271843e1988Sjohnlev 
272da14cebeSEric Cheng 		mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
273da14cebeSEric Cheng 		    mac_addr_arg, &addr_len, NULL, NULL);
274da14cebeSEric Cheng 		*addr_len_ptr_arg = addr_len;
275da14cebeSEric Cheng 		break;
276843e1988Sjohnlev 
277da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_AUTO:
278da14cebeSEric Cheng 		/* first try to allocate a factory MAC address */
279da14cebeSEric Cheng 		err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
280da14cebeSEric Cheng 		if (err == 0) {
281da14cebeSEric Cheng 			mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
282da14cebeSEric Cheng 			    mac_addr_arg, &addr_len, NULL, NULL);
283da14cebeSEric Cheng 			vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY;
284da14cebeSEric Cheng 			*addr_len_ptr_arg = addr_len;
285da14cebeSEric Cheng 			break;
286843e1988Sjohnlev 		}
287843e1988Sjohnlev 
288843e1988Sjohnlev 		/*
289da14cebeSEric Cheng 		 * Allocating a factory MAC address failed, generate a
290da14cebeSEric Cheng 		 * random MAC address instead.
291843e1988Sjohnlev 		 */
292da14cebeSEric Cheng 		if ((err = mac_addr_random(vnic->vn_mch,
293da14cebeSEric Cheng 		    prefix_len, mac_addr_arg, &mac_diag)) != 0) {
294da14cebeSEric Cheng 			*diag = vnic_mac2vnic_diag(mac_diag);
295da14cebeSEric Cheng 			return (err);
296da14cebeSEric Cheng 		}
297da14cebeSEric Cheng 		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
298da14cebeSEric Cheng 		vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM;
299da14cebeSEric Cheng 		break;
300da14cebeSEric Cheng 	case VNIC_MAC_ADDR_TYPE_PRIMARY:
301da14cebeSEric Cheng 		/*
302da14cebeSEric Cheng 		 * We get the address here since we copy it in the
303da14cebeSEric Cheng 		 * vnic's vn_addr.
3040dc2366fSVenugopal Iyer 		 * We can't ask for hardware resources since we
3050dc2366fSVenugopal Iyer 		 * don't currently support hardware classification
3060dc2366fSVenugopal Iyer 		 * for these MAC clients.
307da14cebeSEric Cheng 		 */
3080dc2366fSVenugopal Iyer 		if (req_hwgrp_flag) {
3090dc2366fSVenugopal Iyer 			*diag = VNIC_IOC_DIAG_NO_HWRINGS;
3100dc2366fSVenugopal Iyer 			return (ENOTSUP);
3110dc2366fSVenugopal Iyer 		}
312da14cebeSEric Cheng 		mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg);
313da14cebeSEric Cheng 		*addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
314da14cebeSEric Cheng 		mac_flags |= MAC_UNICAST_VNIC_PRIMARY;
315da14cebeSEric Cheng 		break;
316843e1988Sjohnlev 	}
317843e1988Sjohnlev 
318da14cebeSEric Cheng 	vnic->vn_addr_type = vnic_addr_type;
319da14cebeSEric Cheng 
320da14cebeSEric Cheng 	err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags,
321da14cebeSEric Cheng 	    &vnic->vn_muh, vid, &mac_diag);
322da14cebeSEric Cheng 	if (err != 0) {
323da14cebeSEric Cheng 		if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
324da14cebeSEric Cheng 			/* release factory MAC address */
325da14cebeSEric Cheng 			mac_addr_factory_release(vnic->vn_mch, *addr_slot);
326da14cebeSEric Cheng 		}
327da14cebeSEric Cheng 		*diag = vnic_mac2vnic_diag(mac_diag);
328843e1988Sjohnlev 	}
329843e1988Sjohnlev 
330843e1988Sjohnlev 	return (err);
331843e1988Sjohnlev }
332843e1988Sjohnlev 
333843e1988Sjohnlev /*
334843e1988Sjohnlev  * Create a new VNIC upon request from administrator.
335843e1988Sjohnlev  * Returns 0 on success, an errno on failure.
336843e1988Sjohnlev  */
337da14cebeSEric Cheng /* ARGSUSED */
338843e1988Sjohnlev int
339da14cebeSEric Cheng vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
340da14cebeSEric Cheng     vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr,
3411cb875aeSCathy Zhou     int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
3421cb875aeSCathy Zhou     int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag,
3432b24ab6bSSebastien Roy     cred_t *credp)
344843e1988Sjohnlev {
345da14cebeSEric Cheng 	vnic_t *vnic;
346843e1988Sjohnlev 	mac_register_t *mac;
347843e1988Sjohnlev 	int err;
348da14cebeSEric Cheng 	boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0);
349da14cebeSEric Cheng 	char vnic_name[MAXNAMELEN];
350da14cebeSEric Cheng 	const mac_info_t *minfop;
3510dc2366fSVenugopal Iyer 	uint32_t req_hwgrp_flag = B_FALSE;
352843e1988Sjohnlev 
353da14cebeSEric Cheng 	*diag = VNIC_IOC_DIAG_NONE;
354843e1988Sjohnlev 
355843e1988Sjohnlev 	rw_enter(&vnic_lock, RW_WRITER);
356843e1988Sjohnlev 
357843e1988Sjohnlev 	/* does a VNIC with the same id already exist? */
358843e1988Sjohnlev 	err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
359843e1988Sjohnlev 	    (mod_hash_val_t *)&vnic);
360843e1988Sjohnlev 	if (err == 0) {
361843e1988Sjohnlev 		rw_exit(&vnic_lock);
362843e1988Sjohnlev 		return (EEXIST);
363843e1988Sjohnlev 	}
364843e1988Sjohnlev 
365843e1988Sjohnlev 	vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP);
366843e1988Sjohnlev 	if (vnic == NULL) {
367843e1988Sjohnlev 		rw_exit(&vnic_lock);
368843e1988Sjohnlev 		return (ENOMEM);
369843e1988Sjohnlev 	}
370843e1988Sjohnlev 
371da14cebeSEric Cheng 	bzero(vnic, sizeof (*vnic));
372da14cebeSEric Cheng 
373da14cebeSEric Cheng 	vnic->vn_id = vnic_id;
374da14cebeSEric Cheng 	vnic->vn_link_id = linkid;
3751cb875aeSCathy Zhou 	vnic->vn_vrid = vrid;
3761cb875aeSCathy Zhou 	vnic->vn_af = af;
377da14cebeSEric Cheng 
378da14cebeSEric Cheng 	if (!is_anchor) {
379da14cebeSEric Cheng 		if (linkid == DATALINK_INVALID_LINKID) {
380da14cebeSEric Cheng 			err = EINVAL;
381da14cebeSEric Cheng 			goto bail;
382843e1988Sjohnlev 		}
383843e1988Sjohnlev 
384da14cebeSEric Cheng 		/*
385da14cebeSEric Cheng 		 * Open the lower MAC and assign its initial bandwidth and
386da14cebeSEric Cheng 		 * MAC address. We do this here during VNIC creation and
387da14cebeSEric Cheng 		 * do not wait until the upper MAC client open so that we
388da14cebeSEric Cheng 		 * can validate the VNIC creation parameters (bandwidth,
389da14cebeSEric Cheng 		 * MAC address, etc) and reserve a factory MAC address if
390da14cebeSEric Cheng 		 * one was requested.
391da14cebeSEric Cheng 		 */
392da14cebeSEric Cheng 		err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh);
393da14cebeSEric Cheng 		if (err != 0)
394843e1988Sjohnlev 			goto bail;
395da14cebeSEric Cheng 
396da14cebeSEric Cheng 		/*
397da14cebeSEric Cheng 		 * VNIC(vlan) over VNICs(vlans) is not supported.
398da14cebeSEric Cheng 		 */
399da14cebeSEric Cheng 		if (mac_is_vnic(vnic->vn_lower_mh)) {
400da14cebeSEric Cheng 			err = EINVAL;
401da14cebeSEric Cheng 			goto bail;
402da14cebeSEric Cheng 		}
403da14cebeSEric Cheng 
404da14cebeSEric Cheng 		/* only ethernet support for now */
405da14cebeSEric Cheng 		minfop = mac_info(vnic->vn_lower_mh);
406da14cebeSEric Cheng 		if (minfop->mi_nativemedia != DL_ETHER) {
407da14cebeSEric Cheng 			err = ENOTSUP;
408da14cebeSEric Cheng 			goto bail;
409da14cebeSEric Cheng 		}
410da14cebeSEric Cheng 
411da14cebeSEric Cheng 		(void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL,
412da14cebeSEric Cheng 		    NULL);
413da14cebeSEric Cheng 		err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch,
4140dc2366fSVenugopal Iyer 		    vnic_name, MAC_OPEN_FLAGS_IS_VNIC);
415da14cebeSEric Cheng 		if (err != 0)
416da14cebeSEric Cheng 			goto bail;
417da14cebeSEric Cheng 
418da14cebeSEric Cheng 		/* assign a MAC address to the VNIC */
419da14cebeSEric Cheng 
420da14cebeSEric Cheng 		err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot,
4210dc2366fSVenugopal Iyer 		    mac_prefix_len, mac_len, mac_addr, flags, diag, vid,
4220dc2366fSVenugopal Iyer 		    req_hwgrp_flag);
423da14cebeSEric Cheng 		if (err != 0) {
424da14cebeSEric Cheng 			vnic->vn_muh = NULL;
4250dc2366fSVenugopal Iyer 			if (diag != NULL && req_hwgrp_flag)
426da14cebeSEric Cheng 				*diag = VNIC_IOC_DIAG_NO_HWRINGS;
427da14cebeSEric Cheng 			goto bail;
428da14cebeSEric Cheng 		}
429da14cebeSEric Cheng 
430da14cebeSEric Cheng 		/* register to receive notification from underlying MAC */
431da14cebeSEric Cheng 		vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb,
432da14cebeSEric Cheng 		    vnic);
433da14cebeSEric Cheng 
434da14cebeSEric Cheng 		*vnic_addr_type = vnic->vn_addr_type;
435da14cebeSEric Cheng 		vnic->vn_addr_len = *mac_len;
436da14cebeSEric Cheng 		vnic->vn_vid = vid;
437da14cebeSEric Cheng 
438da14cebeSEric Cheng 		bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len);
439da14cebeSEric Cheng 
440da14cebeSEric Cheng 		if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY)
441da14cebeSEric Cheng 			vnic->vn_slot_id = *mac_slot;
442843e1988Sjohnlev 
4439056fcebSCathy Zhou 		/*
4449056fcebSCathy Zhou 		 * Set the initial VNIC capabilities. If the VNIC is created
4459056fcebSCathy Zhou 		 * over MACs which does not support nactive vlan, disable
4469056fcebSCathy Zhou 		 * VNIC's hardware checksum capability if its VID is not 0,
4479056fcebSCathy Zhou 		 * since the underlying MAC would get the hardware checksum
4489056fcebSCathy Zhou 		 * offset wrong in case of VLAN packets.
4499056fcebSCathy Zhou 		 */
4509056fcebSCathy Zhou 		if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh,
4519056fcebSCathy Zhou 		    MAC_CAPAB_NO_NATIVEVLAN, NULL)) {
452da14cebeSEric Cheng 			if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM,
453843e1988Sjohnlev 			    &vnic->vn_hcksum_txflags))
454843e1988Sjohnlev 				vnic->vn_hcksum_txflags = 0;
4559056fcebSCathy Zhou 		} else {
4569056fcebSCathy Zhou 			vnic->vn_hcksum_txflags = 0;
4579056fcebSCathy Zhou 		}
458da14cebeSEric Cheng 	}
459843e1988Sjohnlev 
460843e1988Sjohnlev 	/* register with the MAC module */
461843e1988Sjohnlev 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
462843e1988Sjohnlev 		goto bail;
463843e1988Sjohnlev 
464843e1988Sjohnlev 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
465843e1988Sjohnlev 	mac->m_driver = vnic;
466843e1988Sjohnlev 	mac->m_dip = vnic_get_dip();
467d62bc4baSyz147064 	mac->m_instance = (uint_t)-1;
468843e1988Sjohnlev 	mac->m_src_addr = vnic->vn_addr;
469843e1988Sjohnlev 	mac->m_callbacks = &vnic_m_callbacks;
470843e1988Sjohnlev 
471da14cebeSEric Cheng 	if (!is_anchor) {
472d62bc4baSyz147064 		/*
473da14cebeSEric Cheng 		 * If this is a VNIC based VLAN, then we check for the
474da14cebeSEric Cheng 		 * margin unless it has been created with the force
475da14cebeSEric Cheng 		 * flag. If we are configuring a VLAN over an etherstub,
476da14cebeSEric Cheng 		 * we don't check the margin even if force is not set.
477d62bc4baSyz147064 		 */
478da14cebeSEric Cheng 		if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) {
479da14cebeSEric Cheng 			if (vid != VLAN_ID_NONE)
480da14cebeSEric Cheng 				vnic->vn_force = B_TRUE;
481da14cebeSEric Cheng 			/*
482da14cebeSEric Cheng 			 * As the current margin size of the underlying mac is
483da14cebeSEric Cheng 			 * used to determine the margin size of the VNIC
484da14cebeSEric Cheng 			 * itself, request the underlying mac not to change
485da14cebeSEric Cheng 			 * to a smaller margin size.
486da14cebeSEric Cheng 			 */
487da14cebeSEric Cheng 			err = mac_margin_add(vnic->vn_lower_mh,
488da14cebeSEric Cheng 			    &vnic->vn_margin, B_TRUE);
489da14cebeSEric Cheng 			ASSERT(err == 0);
490da14cebeSEric Cheng 		} else {
491da14cebeSEric Cheng 			vnic->vn_margin = VLAN_TAGSZ;
492da14cebeSEric Cheng 			err = mac_margin_add(vnic->vn_lower_mh,
493da14cebeSEric Cheng 			    &vnic->vn_margin, B_FALSE);
494da14cebeSEric Cheng 			if (err != 0) {
495da14cebeSEric Cheng 				mac_free(mac);
496da14cebeSEric Cheng 				if (diag != NULL)
497da14cebeSEric Cheng 					*diag = VNIC_IOC_DIAG_MACMARGIN_INVALID;
498843e1988Sjohnlev 				goto bail;
499da14cebeSEric Cheng 			}
500da14cebeSEric Cheng 		}
501da14cebeSEric Cheng 
502da14cebeSEric Cheng 		mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
503da14cebeSEric Cheng 		    &mac->m_max_sdu);
504a776d98eSRobert Mustacchi 		err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
505a776d98eSRobert Mustacchi 		if (err != 0) {
506a776d98eSRobert Mustacchi 			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
507a776d98eSRobert Mustacchi 			    vnic->vn_margin) == 0);
508a776d98eSRobert Mustacchi 			mac_free(mac);
509a776d98eSRobert Mustacchi 			if (diag != NULL)
510a776d98eSRobert Mustacchi 				*diag = VNIC_IOC_DIAG_MACMTU_INVALID;
511a776d98eSRobert Mustacchi 			goto bail;
512a776d98eSRobert Mustacchi 		}
513a776d98eSRobert Mustacchi 		vnic->vn_mtu = mac->m_max_sdu;
514da14cebeSEric Cheng 	} else {
515da14cebeSEric Cheng 		vnic->vn_margin = VLAN_TAGSZ;
516dcb12fb7SRobert Mustacchi 		mac->m_min_sdu = 1;
517f0f2c3a5SGirish Moodalbail 		mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
518a776d98eSRobert Mustacchi 		vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
519da14cebeSEric Cheng 	}
520da14cebeSEric Cheng 
521d62bc4baSyz147064 	mac->m_margin = vnic->vn_margin;
522da14cebeSEric Cheng 
523d62bc4baSyz147064 	err = mac_register(mac, &vnic->vn_mh);
524d62bc4baSyz147064 	mac_free(mac);
525d62bc4baSyz147064 	if (err != 0) {
526a776d98eSRobert Mustacchi 		if (!is_anchor) {
527a776d98eSRobert Mustacchi 			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
528a776d98eSRobert Mustacchi 			    vnic->vn_mtu) == 0);
529a776d98eSRobert Mustacchi 			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
530d62bc4baSyz147064 			    vnic->vn_margin) == 0);
531a776d98eSRobert Mustacchi 		}
532d62bc4baSyz147064 		goto bail;
533d62bc4baSyz147064 	}
534d62bc4baSyz147064 
535da14cebeSEric Cheng 	/* Set the VNIC's MAC in the client */
53654ba2481SMax Bruning 	if (!is_anchor) {
5370dc2366fSVenugopal Iyer 		mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp);
538da14cebeSEric Cheng 
53954ba2481SMax Bruning 		if (mrp != NULL) {
54054ba2481SMax Bruning 			if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 ||
54154ba2481SMax Bruning 			    (mrp->mrp_mask & MRP_TX_RINGS) != 0) {
54254ba2481SMax Bruning 				req_hwgrp_flag = B_TRUE;
54354ba2481SMax Bruning 			}
54454ba2481SMax Bruning 			err = mac_client_set_resources(vnic->vn_mch, mrp);
54554ba2481SMax Bruning 			if (err != 0) {
546a776d98eSRobert Mustacchi 				VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
547a776d98eSRobert Mustacchi 				    vnic->vn_mtu) == 0);
548a776d98eSRobert Mustacchi 				VERIFY(mac_margin_remove(vnic->vn_lower_mh,
549a776d98eSRobert Mustacchi 				    vnic->vn_margin) == 0);
55054ba2481SMax Bruning 				(void) mac_unregister(vnic->vn_mh);
55154ba2481SMax Bruning 				goto bail;
55254ba2481SMax Bruning 			}
55354ba2481SMax Bruning 		}
55454ba2481SMax Bruning 	}
55554ba2481SMax Bruning 
5562b24ab6bSSebastien Roy 	err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp));
5572b24ab6bSSebastien Roy 	if (err != 0) {
558da14cebeSEric Cheng 		VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
559d62bc4baSyz147064 		    vnic->vn_margin) == 0);
560a776d98eSRobert Mustacchi 		if (!is_anchor) {
561a776d98eSRobert Mustacchi 			VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
562a776d98eSRobert Mustacchi 			    vnic->vn_mtu) == 0);
563a776d98eSRobert Mustacchi 			VERIFY(mac_margin_remove(vnic->vn_lower_mh,
564a776d98eSRobert Mustacchi 			    vnic->vn_margin) == 0);
565a776d98eSRobert Mustacchi 		}
566d62bc4baSyz147064 		(void) mac_unregister(vnic->vn_mh);
567d62bc4baSyz147064 		goto bail;
568d62bc4baSyz147064 	}
569843e1988Sjohnlev 
570843e1988Sjohnlev 	/* add new VNIC to hash table */
571843e1988Sjohnlev 	err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id),
572843e1988Sjohnlev 	    (mod_hash_val_t)vnic);
573843e1988Sjohnlev 	ASSERT(err == 0);
574843e1988Sjohnlev 	vnic_count++;
575843e1988Sjohnlev 
576bf773d37SRobert Mustacchi 	/*
577bf773d37SRobert Mustacchi 	 * Now that we've enabled this VNIC, we should go through and update the
578bf773d37SRobert Mustacchi 	 * link state by setting it to our parents.
579bf773d37SRobert Mustacchi 	 */
5802c4ec682SEric Cheng 	vnic->vn_enabled = B_TRUE;
581bf773d37SRobert Mustacchi 
582bf773d37SRobert Mustacchi 	if (is_anchor) {
583bf773d37SRobert Mustacchi 		mac_link_update(vnic->vn_mh, LINK_STATE_UP);
584bf773d37SRobert Mustacchi 	} else {
585bf773d37SRobert Mustacchi 		mac_link_update(vnic->vn_mh,
586bf773d37SRobert Mustacchi 		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
587bf773d37SRobert Mustacchi 	}
588bf773d37SRobert Mustacchi 
589843e1988Sjohnlev 	rw_exit(&vnic_lock);
590843e1988Sjohnlev 
591843e1988Sjohnlev 	return (0);
592843e1988Sjohnlev 
593843e1988Sjohnlev bail:
594843e1988Sjohnlev 	rw_exit(&vnic_lock);
595da14cebeSEric Cheng 	if (!is_anchor) {
596da14cebeSEric Cheng 		if (vnic->vn_mnh != NULL)
597da14cebeSEric Cheng 			(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
598da14cebeSEric Cheng 		if (vnic->vn_muh != NULL)
599da14cebeSEric Cheng 			(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
600da14cebeSEric Cheng 		if (vnic->vn_mch != NULL)
601da14cebeSEric Cheng 			mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
602da14cebeSEric Cheng 		if (vnic->vn_lower_mh != NULL)
603da14cebeSEric Cheng 			mac_close(vnic->vn_lower_mh);
604843e1988Sjohnlev 	}
605843e1988Sjohnlev 
606da14cebeSEric Cheng 	kmem_cache_free(vnic_cache, vnic);
607843e1988Sjohnlev 	return (err);
608843e1988Sjohnlev }
609843e1988Sjohnlev 
610843e1988Sjohnlev /*
611843e1988Sjohnlev  * Modify the properties of an existing VNIC.
612843e1988Sjohnlev  */
613843e1988Sjohnlev /* ARGSUSED */
614843e1988Sjohnlev int
615d62bc4baSyz147064 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask,
616da14cebeSEric Cheng     vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr,
617da14cebeSEric Cheng     uint_t mac_slot, mac_resource_props_t *mrp)
618843e1988Sjohnlev {
619843e1988Sjohnlev 	vnic_t *vnic = NULL;
620843e1988Sjohnlev 
621843e1988Sjohnlev 	rw_enter(&vnic_lock, RW_WRITER);
622843e1988Sjohnlev 
623843e1988Sjohnlev 	if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
624843e1988Sjohnlev 	    (mod_hash_val_t *)&vnic) != 0) {
625843e1988Sjohnlev 		rw_exit(&vnic_lock);
626843e1988Sjohnlev 		return (ENOENT);
627843e1988Sjohnlev 	}
628843e1988Sjohnlev 
629843e1988Sjohnlev 	rw_exit(&vnic_lock);
630843e1988Sjohnlev 
631da14cebeSEric Cheng 	return (0);
632843e1988Sjohnlev }
633843e1988Sjohnlev 
634da14cebeSEric Cheng /* ARGSUSED */
635843e1988Sjohnlev int
6362b24ab6bSSebastien Roy vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
637843e1988Sjohnlev {
638843e1988Sjohnlev 	vnic_t *vnic = NULL;
639843e1988Sjohnlev 	mod_hash_val_t val;
640d62bc4baSyz147064 	datalink_id_t tmpid;
641843e1988Sjohnlev 	int rc;
642843e1988Sjohnlev 
643843e1988Sjohnlev 	rw_enter(&vnic_lock, RW_WRITER);
644843e1988Sjohnlev 
645843e1988Sjohnlev 	if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
646843e1988Sjohnlev 	    (mod_hash_val_t *)&vnic) != 0) {
647843e1988Sjohnlev 		rw_exit(&vnic_lock);
648843e1988Sjohnlev 		return (ENOENT);
649843e1988Sjohnlev 	}
650843e1988Sjohnlev 
651da14cebeSEric Cheng 	if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) {
652d62bc4baSyz147064 		rw_exit(&vnic_lock);
653d62bc4baSyz147064 		return (rc);
654d62bc4baSyz147064 	}
655d62bc4baSyz147064 
656d62bc4baSyz147064 	ASSERT(vnic_id == tmpid);
657d62bc4baSyz147064 
658843e1988Sjohnlev 	/*
659843e1988Sjohnlev 	 * We cannot unregister the MAC yet. Unregistering would
660843e1988Sjohnlev 	 * free up mac_impl_t which should not happen at this time.
661da14cebeSEric Cheng 	 * So disable mac_impl_t by calling mac_disable(). This will prevent
662da14cebeSEric Cheng 	 * any new claims on mac_impl_t.
663843e1988Sjohnlev 	 */
664da14cebeSEric Cheng 	if ((rc = mac_disable(vnic->vn_mh)) != 0) {
6652b24ab6bSSebastien Roy 		(void) dls_devnet_create(vnic->vn_mh, vnic_id,
6662b24ab6bSSebastien Roy 		    crgetzoneid(credp));
667843e1988Sjohnlev 		rw_exit(&vnic_lock);
668da14cebeSEric Cheng 		return (rc);
669843e1988Sjohnlev 	}
670843e1988Sjohnlev 
6711a41ca23SJerry Jelinek 	vnic_cleanup_secondary_macs(vnic, vnic->vn_nhandles);
6721a41ca23SJerry Jelinek 
6732c4ec682SEric Cheng 	vnic->vn_enabled = B_FALSE;
674843e1988Sjohnlev 	(void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val);
675843e1988Sjohnlev 	ASSERT(vnic == (vnic_t *)val);
676843e1988Sjohnlev 	vnic_count--;
677843e1988Sjohnlev 	rw_exit(&vnic_lock);
678da14cebeSEric Cheng 
679da14cebeSEric Cheng 	/*
680da14cebeSEric Cheng 	 * XXX-nicolas shouldn't have a void cast here, if it's
681da14cebeSEric Cheng 	 * expected that the function will never fail, then we should
682da14cebeSEric Cheng 	 * have an ASSERT().
683da14cebeSEric Cheng 	 */
684da14cebeSEric Cheng 	(void) mac_unregister(vnic->vn_mh);
685da14cebeSEric Cheng 
686da14cebeSEric Cheng 	if (vnic->vn_lower_mh != NULL) {
687da14cebeSEric Cheng 		/*
688da14cebeSEric Cheng 		 * Check if MAC address for the vnic was obtained from the
689da14cebeSEric Cheng 		 * factory MAC addresses. If yes, release it.
690da14cebeSEric Cheng 		 */
691da14cebeSEric Cheng 		if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
692da14cebeSEric Cheng 			(void) mac_addr_factory_release(vnic->vn_mch,
693da14cebeSEric Cheng 			    vnic->vn_slot_id);
694da14cebeSEric Cheng 		}
695da14cebeSEric Cheng 		(void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin);
696a776d98eSRobert Mustacchi 		(void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu);
697da14cebeSEric Cheng 		(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
698da14cebeSEric Cheng 		(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
699da14cebeSEric Cheng 		mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
700da14cebeSEric Cheng 		mac_close(vnic->vn_lower_mh);
701da14cebeSEric Cheng 	}
702da14cebeSEric Cheng 
703da14cebeSEric Cheng 	kmem_cache_free(vnic_cache, vnic);
704843e1988Sjohnlev 	return (0);
705843e1988Sjohnlev }
706843e1988Sjohnlev 
707da14cebeSEric Cheng /* ARGSUSED */
708843e1988Sjohnlev mblk_t *
709843e1988Sjohnlev vnic_m_tx(void *arg, mblk_t *mp_chain)
710843e1988Sjohnlev {
711843e1988Sjohnlev 	/*
712da14cebeSEric Cheng 	 * This function could be invoked for an anchor VNIC when sending
713da14cebeSEric Cheng 	 * broadcast and multicast packets, and unicast packets which did
714da14cebeSEric Cheng 	 * not match any local known destination.
715843e1988Sjohnlev 	 */
716da14cebeSEric Cheng 	freemsgchain(mp_chain);
717da14cebeSEric Cheng 	return (NULL);
718843e1988Sjohnlev }
719843e1988Sjohnlev 
720843e1988Sjohnlev /*ARGSUSED*/
721843e1988Sjohnlev static void
722da14cebeSEric Cheng vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
723843e1988Sjohnlev {
724da14cebeSEric Cheng 	miocnak(q, mp, 0, ENOTSUP);
725843e1988Sjohnlev }
726843e1988Sjohnlev 
727da14cebeSEric Cheng /*
728da14cebeSEric Cheng  * This entry point cannot be passed-through, since it is invoked
729da14cebeSEric Cheng  * for the per-VNIC kstats which must be exported independently
730da14cebeSEric Cheng  * of the existence of VNIC MAC clients.
731da14cebeSEric Cheng  */
732843e1988Sjohnlev static int
733843e1988Sjohnlev vnic_m_stat(void *arg, uint_t stat, uint64_t *val)
734843e1988Sjohnlev {
735843e1988Sjohnlev 	vnic_t *vnic = arg;
736843e1988Sjohnlev 	int rval = 0;
737843e1988Sjohnlev 
738da14cebeSEric Cheng 	if (vnic->vn_lower_mh == NULL) {
739da14cebeSEric Cheng 		/*
740da14cebeSEric Cheng 		 * It's an anchor VNIC, which does not have any
741da14cebeSEric Cheng 		 * statistics in itself.
742da14cebeSEric Cheng 		 */
743da14cebeSEric Cheng 		return (ENOTSUP);
744da14cebeSEric Cheng 	}
745da14cebeSEric Cheng 
746da14cebeSEric Cheng 	/*
747da14cebeSEric Cheng 	 * ENOTSUP must be reported for unsupported stats, the VNIC
748da14cebeSEric Cheng 	 * driver reports a subset of the stats that would
749da14cebeSEric Cheng 	 * be returned by a real piece of hardware.
750da14cebeSEric Cheng 	 */
751843e1988Sjohnlev 
752843e1988Sjohnlev 	switch (stat) {
753da14cebeSEric Cheng 	case MAC_STAT_LINK_STATE:
754da14cebeSEric Cheng 	case MAC_STAT_LINK_UP:
755da14cebeSEric Cheng 	case MAC_STAT_PROMISC:
756843e1988Sjohnlev 	case MAC_STAT_IFSPEED:
757843e1988Sjohnlev 	case MAC_STAT_MULTIRCV:
758843e1988Sjohnlev 	case MAC_STAT_MULTIXMT:
759da14cebeSEric Cheng 	case MAC_STAT_BRDCSTRCV:
760843e1988Sjohnlev 	case MAC_STAT_BRDCSTXMT:
761843e1988Sjohnlev 	case MAC_STAT_OPACKETS:
762da14cebeSEric Cheng 	case MAC_STAT_OBYTES:
763da14cebeSEric Cheng 	case MAC_STAT_IERRORS:
764da14cebeSEric Cheng 	case MAC_STAT_OERRORS:
765da14cebeSEric Cheng 	case MAC_STAT_RBYTES:
766da14cebeSEric Cheng 	case MAC_STAT_IPACKETS:
767da14cebeSEric Cheng 		*val = mac_client_stat_get(vnic->vn_mch, stat);
768843e1988Sjohnlev 		break;
769843e1988Sjohnlev 	default:
770843e1988Sjohnlev 		rval = ENOTSUP;
771843e1988Sjohnlev 	}
772843e1988Sjohnlev 
773843e1988Sjohnlev 	return (rval);
774843e1988Sjohnlev }
775843e1988Sjohnlev 
776843e1988Sjohnlev /*
777da14cebeSEric Cheng  * Invoked by the upper MAC to retrieve the lower MAC client handle
778da14cebeSEric Cheng  * corresponding to a VNIC. A pointer to this function is obtained
779da14cebeSEric Cheng  * by the upper MAC via capability query.
780da14cebeSEric Cheng  *
781da14cebeSEric Cheng  * XXX-nicolas Note: this currently causes all VNIC MAC clients to
782da14cebeSEric Cheng  * receive the same MAC client handle for the same VNIC. This is ok
783da14cebeSEric Cheng  * as long as we have only one VNIC MAC client which sends and
784da14cebeSEric Cheng  * receives data, but we don't currently enforce this at the MAC layer.
785da14cebeSEric Cheng  */
786da14cebeSEric Cheng static void *
787da14cebeSEric Cheng vnic_mac_client_handle(void *vnic_arg)
788da14cebeSEric Cheng {
789da14cebeSEric Cheng 	vnic_t *vnic = vnic_arg;
790da14cebeSEric Cheng 
791da14cebeSEric Cheng 	return (vnic->vn_mch);
792da14cebeSEric Cheng }
793da14cebeSEric Cheng 
7941a41ca23SJerry Jelinek /*
7951a41ca23SJerry Jelinek  * Invoked when updating the primary MAC so that the secondary MACs are
7961a41ca23SJerry Jelinek  * kept in sync.
7971a41ca23SJerry Jelinek  */
7981a41ca23SJerry Jelinek static void
7991a41ca23SJerry Jelinek vnic_mac_secondary_update(void *vnic_arg)
8001a41ca23SJerry Jelinek {
8011a41ca23SJerry Jelinek 	vnic_t *vn = vnic_arg;
8021a41ca23SJerry Jelinek 	int i;
8031a41ca23SJerry Jelinek 
8041a41ca23SJerry Jelinek 	for (i = 1; i <= vn->vn_nhandles; i++) {
8051a41ca23SJerry Jelinek 		mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
8061a41ca23SJerry Jelinek 	}
8071a41ca23SJerry Jelinek }
808da14cebeSEric Cheng 
809da14cebeSEric Cheng /*
810843e1988Sjohnlev  * Return information about the specified capability.
811843e1988Sjohnlev  */
812843e1988Sjohnlev /* ARGSUSED */
813843e1988Sjohnlev static boolean_t
814843e1988Sjohnlev vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data)
815843e1988Sjohnlev {
816843e1988Sjohnlev 	vnic_t *vnic = arg;
817843e1988Sjohnlev 
818843e1988Sjohnlev 	switch (cap) {
819843e1988Sjohnlev 	case MAC_CAPAB_HCKSUM: {
820843e1988Sjohnlev 		uint32_t *hcksum_txflags = cap_data;
821843e1988Sjohnlev 
822843e1988Sjohnlev 		*hcksum_txflags = vnic->vn_hcksum_txflags &
823843e1988Sjohnlev 		    (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM |
824843e1988Sjohnlev 		    HCKSUM_INET_PARTIAL);
825843e1988Sjohnlev 		break;
826843e1988Sjohnlev 	}
827da14cebeSEric Cheng 	case MAC_CAPAB_VNIC: {
828da14cebeSEric Cheng 		mac_capab_vnic_t *vnic_capab = cap_data;
829da14cebeSEric Cheng 
830da14cebeSEric Cheng 		if (vnic->vn_lower_mh == NULL) {
831da14cebeSEric Cheng 			/*
832da14cebeSEric Cheng 			 * It's an anchor VNIC, we don't have an underlying
833da14cebeSEric Cheng 			 * NIC and MAC client handle.
834da14cebeSEric Cheng 			 */
835da14cebeSEric Cheng 			return (B_FALSE);
836da14cebeSEric Cheng 		}
837da14cebeSEric Cheng 
838da14cebeSEric Cheng 		if (vnic_capab != NULL) {
839da14cebeSEric Cheng 			vnic_capab->mcv_arg = vnic;
840da14cebeSEric Cheng 			vnic_capab->mcv_mac_client_handle =
841da14cebeSEric Cheng 			    vnic_mac_client_handle;
8421a41ca23SJerry Jelinek 			vnic_capab->mcv_mac_secondary_update =
8431a41ca23SJerry Jelinek 			    vnic_mac_secondary_update;
844da14cebeSEric Cheng 		}
845da14cebeSEric Cheng 		break;
846da14cebeSEric Cheng 	}
847da14cebeSEric Cheng 	case MAC_CAPAB_ANCHOR_VNIC: {
848da14cebeSEric Cheng 		/* since it's an anchor VNIC we don't have lower mac handle */
849da14cebeSEric Cheng 		if (vnic->vn_lower_mh == NULL) {
850da14cebeSEric Cheng 			ASSERT(vnic->vn_link_id == 0);
851da14cebeSEric Cheng 			return (B_TRUE);
852da14cebeSEric Cheng 		}
853da14cebeSEric Cheng 		return (B_FALSE);
854da14cebeSEric Cheng 	}
855da14cebeSEric Cheng 	case MAC_CAPAB_NO_NATIVEVLAN:
8569056fcebSCathy Zhou 		return (B_FALSE);
857da14cebeSEric Cheng 	case MAC_CAPAB_NO_ZCOPY:
858da14cebeSEric Cheng 		return (B_TRUE);
8591cb875aeSCathy Zhou 	case MAC_CAPAB_VRRP: {
8601cb875aeSCathy Zhou 		mac_capab_vrrp_t *vrrp_capab = cap_data;
8611cb875aeSCathy Zhou 
8621cb875aeSCathy Zhou 		if (vnic->vn_vrid != 0) {
8631cb875aeSCathy Zhou 			if (vrrp_capab != NULL)
8641cb875aeSCathy Zhou 				vrrp_capab->mcv_af = vnic->vn_af;
8651cb875aeSCathy Zhou 			return (B_TRUE);
8661cb875aeSCathy Zhou 		}
8671cb875aeSCathy Zhou 		return (B_FALSE);
8681cb875aeSCathy Zhou 	}
869843e1988Sjohnlev 	default:
870843e1988Sjohnlev 		return (B_FALSE);
871843e1988Sjohnlev 	}
872843e1988Sjohnlev 	return (B_TRUE);
873843e1988Sjohnlev }
874843e1988Sjohnlev 
875da14cebeSEric Cheng /* ARGSUSED */
876843e1988Sjohnlev static int
877843e1988Sjohnlev vnic_m_start(void *arg)
878843e1988Sjohnlev {
879843e1988Sjohnlev 	return (0);
880843e1988Sjohnlev }
881843e1988Sjohnlev 
882da14cebeSEric Cheng /* ARGSUSED */
883843e1988Sjohnlev static void
884843e1988Sjohnlev vnic_m_stop(void *arg)
885843e1988Sjohnlev {
886843e1988Sjohnlev }
887843e1988Sjohnlev 
888843e1988Sjohnlev /* ARGSUSED */
889843e1988Sjohnlev static int
890843e1988Sjohnlev vnic_m_promisc(void *arg, boolean_t on)
891843e1988Sjohnlev {
892843e1988Sjohnlev 	return (0);
893843e1988Sjohnlev }
894843e1988Sjohnlev 
895da14cebeSEric Cheng /* ARGSUSED */
896da14cebeSEric Cheng static int
897da14cebeSEric Cheng vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
898843e1988Sjohnlev {
899da14cebeSEric Cheng 	return (0);
900843e1988Sjohnlev }
901843e1988Sjohnlev 
902da14cebeSEric Cheng static int
903da14cebeSEric Cheng vnic_m_unicst(void *arg, const uint8_t *macaddr)
904da14cebeSEric Cheng {
905da14cebeSEric Cheng 	vnic_t *vnic = arg;
906da14cebeSEric Cheng 
907da14cebeSEric Cheng 	return (mac_vnic_unicast_set(vnic->vn_mch, macaddr));
908da14cebeSEric Cheng }
909da14cebeSEric Cheng 
9101a41ca23SJerry Jelinek static void
9111a41ca23SJerry Jelinek vnic_cleanup_secondary_macs(vnic_t *vn, int cnt)
9121a41ca23SJerry Jelinek {
9131a41ca23SJerry Jelinek 	int i;
9141a41ca23SJerry Jelinek 
9151a41ca23SJerry Jelinek 	/* Remove existing secondaries (primary is at 0) */
9161a41ca23SJerry Jelinek 	for (i = 1; i <= cnt; i++) {
9171a41ca23SJerry Jelinek 		mac_rx_clear(vn->vn_mc_handles[i]);
9181a41ca23SJerry Jelinek 
9191a41ca23SJerry Jelinek 		/* unicast handle might not have been set yet */
9201a41ca23SJerry Jelinek 		if (vn->vn_mu_handles[i] != NULL)
9211a41ca23SJerry Jelinek 			(void) mac_unicast_remove(vn->vn_mc_handles[i],
9221a41ca23SJerry Jelinek 			    vn->vn_mu_handles[i]);
9231a41ca23SJerry Jelinek 
9241a41ca23SJerry Jelinek 		mac_secondary_cleanup(vn->vn_mc_handles[i]);
9251a41ca23SJerry Jelinek 
9261a41ca23SJerry Jelinek 		mac_client_close(vn->vn_mc_handles[i], MAC_CLOSE_FLAGS_IS_VNIC);
9271a41ca23SJerry Jelinek 
9281a41ca23SJerry Jelinek 		vn->vn_mu_handles[i] = NULL;
9291a41ca23SJerry Jelinek 		vn->vn_mc_handles[i] = NULL;
9301a41ca23SJerry Jelinek 	}
9311a41ca23SJerry Jelinek 
9321a41ca23SJerry Jelinek 	vn->vn_nhandles = 0;
9331a41ca23SJerry Jelinek }
9341a41ca23SJerry Jelinek 
9351a41ca23SJerry Jelinek /*
9361a41ca23SJerry Jelinek  * Setup secondary MAC addresses on the vnic. Due to limitations in the mac
9371a41ca23SJerry Jelinek  * code, each mac address must be associated with a mac_client (and the
9381a41ca23SJerry Jelinek  * flow that goes along with the client) so we need to create those clients
9391a41ca23SJerry Jelinek  * here.
9401a41ca23SJerry Jelinek  */
9411a41ca23SJerry Jelinek static int
9421a41ca23SJerry Jelinek vnic_set_secondary_macs(vnic_t *vn, mac_secondary_addr_t *msa)
9431a41ca23SJerry Jelinek {
9441a41ca23SJerry Jelinek 	int i, err;
9451a41ca23SJerry Jelinek 	char primary_name[MAXNAMELEN];
9461a41ca23SJerry Jelinek 
9471a41ca23SJerry Jelinek 	/* First, remove pre-existing secondaries */
9481a41ca23SJerry Jelinek 	ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
9491a41ca23SJerry Jelinek 	vnic_cleanup_secondary_macs(vn, vn->vn_nhandles);
9501a41ca23SJerry Jelinek 
9511a41ca23SJerry Jelinek 	if (msa->ms_addrcnt == (uint32_t)-1)
9521a41ca23SJerry Jelinek 		msa->ms_addrcnt = 0;
9531a41ca23SJerry Jelinek 
9541a41ca23SJerry Jelinek 	vn->vn_nhandles = msa->ms_addrcnt;
9551a41ca23SJerry Jelinek 
9561a41ca23SJerry Jelinek 	(void) dls_mgmt_get_linkinfo(vn->vn_id, primary_name, NULL, NULL, NULL);
9571a41ca23SJerry Jelinek 
9581a41ca23SJerry Jelinek 	/*
9591a41ca23SJerry Jelinek 	 * Now add the new secondary MACs
9601a41ca23SJerry Jelinek 	 * Recall that the primary MAC address is the first element.
9611a41ca23SJerry Jelinek 	 * The secondary clients are named after the primary with their
9621a41ca23SJerry Jelinek 	 * index to distinguish them.
9631a41ca23SJerry Jelinek 	 */
9641a41ca23SJerry Jelinek 	for (i = 1; i <= vn->vn_nhandles; i++) {
9651a41ca23SJerry Jelinek 		uint8_t *addr;
9661a41ca23SJerry Jelinek 		mac_diag_t mac_diag;
9671a41ca23SJerry Jelinek 		char secondary_name[MAXNAMELEN];
9681a41ca23SJerry Jelinek 
9691a41ca23SJerry Jelinek 		(void) snprintf(secondary_name, sizeof (secondary_name),
9701a41ca23SJerry Jelinek 		    "%s%02d", primary_name, i);
9711a41ca23SJerry Jelinek 
9721a41ca23SJerry Jelinek 		err = mac_client_open(vn->vn_lower_mh, &vn->vn_mc_handles[i],
9731a41ca23SJerry Jelinek 		    secondary_name, MAC_OPEN_FLAGS_IS_VNIC);
9741a41ca23SJerry Jelinek 		if (err != 0) {
9751a41ca23SJerry Jelinek 			/* Remove any that we successfully added */
9761a41ca23SJerry Jelinek 			vnic_cleanup_secondary_macs(vn, --i);
9771a41ca23SJerry Jelinek 			return (err);
9781a41ca23SJerry Jelinek 		}
9791a41ca23SJerry Jelinek 
9801a41ca23SJerry Jelinek 		/*
9811a41ca23SJerry Jelinek 		 * Assign a MAC address to the VNIC
9821a41ca23SJerry Jelinek 		 *
9831a41ca23SJerry Jelinek 		 * Normally this would be done with vnic_unicast_add but since
9841a41ca23SJerry Jelinek 		 * we know these are fixed adddresses, and since we need to
9851a41ca23SJerry Jelinek 		 * save this in the proper array slot, we bypass that function
9861a41ca23SJerry Jelinek 		 * and go direct.
9871a41ca23SJerry Jelinek 		 */
9881a41ca23SJerry Jelinek 		addr = msa->ms_addrs[i - 1];
9891a41ca23SJerry Jelinek 		err = mac_unicast_add(vn->vn_mc_handles[i], addr, 0,
9901a41ca23SJerry Jelinek 		    &vn->vn_mu_handles[i], vn->vn_vid, &mac_diag);
9911a41ca23SJerry Jelinek 		if (err != 0) {
9921a41ca23SJerry Jelinek 			/* Remove any that we successfully added */
9931a41ca23SJerry Jelinek 			vnic_cleanup_secondary_macs(vn, i);
9941a41ca23SJerry Jelinek 			return (err);
9951a41ca23SJerry Jelinek 		}
9961a41ca23SJerry Jelinek 
9971a41ca23SJerry Jelinek 		/*
9981a41ca23SJerry Jelinek 		 * Setup the secondary the same way as the primary (i.e.
9991a41ca23SJerry Jelinek 		 * receiver function/argument (e.g. i_dls_link_rx, mac_pkt_drop,
10001a41ca23SJerry Jelinek 		 * etc.), the promisc list, and the resource controls).
10011a41ca23SJerry Jelinek 		 */
10021a41ca23SJerry Jelinek 		mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
10031a41ca23SJerry Jelinek 	}
10041a41ca23SJerry Jelinek 
10051a41ca23SJerry Jelinek 	return (0);
10061a41ca23SJerry Jelinek }
10071a41ca23SJerry Jelinek 
10081a41ca23SJerry Jelinek static int
10091a41ca23SJerry Jelinek vnic_get_secondary_macs(vnic_t *vn, uint_t pr_valsize, void *pr_val)
10101a41ca23SJerry Jelinek {
10111a41ca23SJerry Jelinek 	int i;
10121a41ca23SJerry Jelinek 	mac_secondary_addr_t msa;
10131a41ca23SJerry Jelinek 
10141a41ca23SJerry Jelinek 	if (pr_valsize < sizeof (msa))
10151a41ca23SJerry Jelinek 		return (EINVAL);
10161a41ca23SJerry Jelinek 
10171a41ca23SJerry Jelinek 	/* Get existing addresses (primary is at 0) */
10181a41ca23SJerry Jelinek 	ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
10191a41ca23SJerry Jelinek 	for (i = 1; i <= vn->vn_nhandles; i++) {
10201a41ca23SJerry Jelinek 		ASSERT(vn->vn_mc_handles[i] != NULL);
10211a41ca23SJerry Jelinek 		mac_unicast_secondary_get(vn->vn_mc_handles[i],
10221a41ca23SJerry Jelinek 		    msa.ms_addrs[i - 1]);
10231a41ca23SJerry Jelinek 	}
10241a41ca23SJerry Jelinek 	msa.ms_addrcnt = vn->vn_nhandles;
10251a41ca23SJerry Jelinek 
10261a41ca23SJerry Jelinek 	bcopy(&msa, pr_val, sizeof (msa));
10271a41ca23SJerry Jelinek 	return (0);
10281a41ca23SJerry Jelinek }
10291a41ca23SJerry Jelinek 
1030ab6f61efSGirish Moodalbail /*
1031ab6f61efSGirish Moodalbail  * Callback functions for set/get of properties
1032ab6f61efSGirish Moodalbail  */
1033ab6f61efSGirish Moodalbail /*ARGSUSED*/
1034ab6f61efSGirish Moodalbail static int
1035ab6f61efSGirish Moodalbail vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
1036ab6f61efSGirish Moodalbail     uint_t pr_valsize, const void *pr_val)
1037ab6f61efSGirish Moodalbail {
10381a41ca23SJerry Jelinek 	int 		err = 0;
1039ab6f61efSGirish Moodalbail 	vnic_t		*vn = m_driver;
1040ab6f61efSGirish Moodalbail 
1041ab6f61efSGirish Moodalbail 	switch (pr_num) {
1042ab6f61efSGirish Moodalbail 	case MAC_PROP_MTU: {
1043ab6f61efSGirish Moodalbail 		uint32_t	mtu;
1044ab6f61efSGirish Moodalbail 
1045ab6f61efSGirish Moodalbail 		if (pr_valsize < sizeof (mtu)) {
1046ab6f61efSGirish Moodalbail 			err = EINVAL;
1047ab6f61efSGirish Moodalbail 			break;
1048ab6f61efSGirish Moodalbail 		}
1049ab6f61efSGirish Moodalbail 		bcopy(pr_val, &mtu, sizeof (mtu));
1050a776d98eSRobert Mustacchi 
1051a776d98eSRobert Mustacchi 		if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
1052a776d98eSRobert Mustacchi 			if (mtu < ANCHOR_VNIC_MIN_MTU ||
1053a776d98eSRobert Mustacchi 			    mtu > ANCHOR_VNIC_MAX_MTU) {
1054f0f2c3a5SGirish Moodalbail 				err = EINVAL;
1055f0f2c3a5SGirish Moodalbail 				break;
1056f0f2c3a5SGirish Moodalbail 			}
1057a776d98eSRobert Mustacchi 		} else {
1058a776d98eSRobert Mustacchi 			err = mac_mtu_add(vn->vn_lower_mh, &mtu, B_FALSE);
1059a776d98eSRobert Mustacchi 			/*
1060a776d98eSRobert Mustacchi 			 * If it's not supported to set a value here, translate
1061a776d98eSRobert Mustacchi 			 * that to EINVAL, so user land gets a better idea of
1062a776d98eSRobert Mustacchi 			 * what went wrong. This realistically means that they
1063a776d98eSRobert Mustacchi 			 * violated the output of prop info.
1064a776d98eSRobert Mustacchi 			 */
1065a776d98eSRobert Mustacchi 			if (err == ENOTSUP)
1066a776d98eSRobert Mustacchi 				err = EINVAL;
1067a776d98eSRobert Mustacchi 			if (err != 0)
1068a776d98eSRobert Mustacchi 				break;
1069a776d98eSRobert Mustacchi 			VERIFY(mac_mtu_remove(vn->vn_lower_mh,
1070a776d98eSRobert Mustacchi 			    vn->vn_mtu) == 0);
1071a776d98eSRobert Mustacchi 		}
1072a776d98eSRobert Mustacchi 		vn->vn_mtu = mtu;
1073ab6f61efSGirish Moodalbail 		err = mac_maxsdu_update(vn->vn_mh, mtu);
1074ab6f61efSGirish Moodalbail 		break;
1075ab6f61efSGirish Moodalbail 	}
1076*098d2c75SRobert Mustacchi 	case MAC_PROP_VN_PROMISC_FILTERED: {
1077*098d2c75SRobert Mustacchi 		boolean_t filtered;
1078*098d2c75SRobert Mustacchi 
1079*098d2c75SRobert Mustacchi 		if (pr_valsize < sizeof (filtered)) {
1080*098d2c75SRobert Mustacchi 			err = EINVAL;
1081*098d2c75SRobert Mustacchi 			break;
1082*098d2c75SRobert Mustacchi 		}
1083*098d2c75SRobert Mustacchi 
1084*098d2c75SRobert Mustacchi 		bcopy(pr_val, &filtered, sizeof (filtered));
1085*098d2c75SRobert Mustacchi 		mac_set_promisc_filtered(vn->vn_mch, filtered);
1086*098d2c75SRobert Mustacchi 		break;
1087*098d2c75SRobert Mustacchi 	}
10881a41ca23SJerry Jelinek 	case MAC_PROP_SECONDARY_ADDRS: {
10891a41ca23SJerry Jelinek 		mac_secondary_addr_t msa;
10901a41ca23SJerry Jelinek 
10911a41ca23SJerry Jelinek 		bcopy(pr_val, &msa, sizeof (msa));
10921a41ca23SJerry Jelinek 		err = vnic_set_secondary_macs(vn, &msa);
10931a41ca23SJerry Jelinek 		break;
10941a41ca23SJerry Jelinek 	}
1095ab6f61efSGirish Moodalbail 	default:
10961a41ca23SJerry Jelinek 		err = ENOTSUP;
1097ab6f61efSGirish Moodalbail 		break;
1098ab6f61efSGirish Moodalbail 	}
1099ab6f61efSGirish Moodalbail 	return (err);
1100ab6f61efSGirish Moodalbail }
1101ab6f61efSGirish Moodalbail 
1102ab6f61efSGirish Moodalbail /* ARGSUSED */
11031a41ca23SJerry Jelinek static int
11041a41ca23SJerry Jelinek vnic_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
11051a41ca23SJerry Jelinek     uint_t pr_valsize, void *pr_val)
11061a41ca23SJerry Jelinek {
11071a41ca23SJerry Jelinek 	vnic_t		*vn = arg;
11081a41ca23SJerry Jelinek 	int 		ret = 0;
1109*098d2c75SRobert Mustacchi 	boolean_t	out;
11101a41ca23SJerry Jelinek 
11111a41ca23SJerry Jelinek 	switch (pr_num) {
1112*098d2c75SRobert Mustacchi 	case MAC_PROP_VN_PROMISC_FILTERED:
1113*098d2c75SRobert Mustacchi 		out = mac_get_promisc_filtered(vn->vn_mch);
1114*098d2c75SRobert Mustacchi 		ASSERT(pr_valsize >= sizeof (boolean_t));
1115*098d2c75SRobert Mustacchi 		bcopy(&out, pr_val, sizeof (boolean_t));
1116*098d2c75SRobert Mustacchi 		break;
11171a41ca23SJerry Jelinek 	case MAC_PROP_SECONDARY_ADDRS:
11181a41ca23SJerry Jelinek 		ret = vnic_get_secondary_macs(vn, pr_valsize, pr_val);
11191a41ca23SJerry Jelinek 		break;
11201a41ca23SJerry Jelinek 	default:
1121238d8f47SDale Ghent 		ret = ENOTSUP;
11221a41ca23SJerry Jelinek 		break;
11231a41ca23SJerry Jelinek 	}
11241a41ca23SJerry Jelinek 
11251a41ca23SJerry Jelinek 	return (ret);
11261a41ca23SJerry Jelinek }
11271a41ca23SJerry Jelinek 
11281a41ca23SJerry Jelinek /* ARGSUSED */
11290dc2366fSVenugopal Iyer static void vnic_m_propinfo(void *m_driver, const char *pr_name,
11300dc2366fSVenugopal Iyer     mac_prop_id_t pr_num, mac_prop_info_handle_t prh)
1131ab6f61efSGirish Moodalbail {
1132f0f2c3a5SGirish Moodalbail 	vnic_t		*vn = m_driver;
1133f0f2c3a5SGirish Moodalbail 
1134f0f2c3a5SGirish Moodalbail 	switch (pr_num) {
1135f0f2c3a5SGirish Moodalbail 	case MAC_PROP_MTU:
1136a776d98eSRobert Mustacchi 		if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
11370dc2366fSVenugopal Iyer 			mac_prop_info_set_range_uint32(prh,
11380dc2366fSVenugopal Iyer 			    ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU);
1139a776d98eSRobert Mustacchi 		} else {
1140a776d98eSRobert Mustacchi 			uint32_t		max;
1141a776d98eSRobert Mustacchi 			mac_perim_handle_t	mph;
1142a776d98eSRobert Mustacchi 			mac_propval_range_t	range;
1143a776d98eSRobert Mustacchi 
1144a776d98eSRobert Mustacchi 			/*
1145a776d98eSRobert Mustacchi 			 * The valid range for a VNIC's MTU is the minimum that
1146a776d98eSRobert Mustacchi 			 * the device supports and the current value of the
1147a776d98eSRobert Mustacchi 			 * device. A VNIC cannot increase the current MTU of the
1148a776d98eSRobert Mustacchi 			 * device. Therefore we need to get the range from the
1149a776d98eSRobert Mustacchi 			 * propinfo endpoint and current mtu from the
1150a776d98eSRobert Mustacchi 			 * traditional property endpoint.
1151a776d98eSRobert Mustacchi 			 */
1152a776d98eSRobert Mustacchi 			mac_perim_enter_by_mh(vn->vn_lower_mh, &mph);
1153a776d98eSRobert Mustacchi 			if (mac_get_prop(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1154a776d98eSRobert Mustacchi 			    &max, sizeof (uint32_t)) != 0) {
1155a776d98eSRobert Mustacchi 				mac_perim_exit(mph);
1156a776d98eSRobert Mustacchi 				return;
1157a776d98eSRobert Mustacchi 			}
1158a776d98eSRobert Mustacchi 
1159a776d98eSRobert Mustacchi 			range.mpr_count = 1;
1160a776d98eSRobert Mustacchi 			if (mac_prop_info(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1161a776d98eSRobert Mustacchi 			    NULL, 0, &range, NULL) != 0) {
1162a776d98eSRobert Mustacchi 				mac_perim_exit(mph);
1163a776d98eSRobert Mustacchi 				return;
1164a776d98eSRobert Mustacchi 			}
1165a776d98eSRobert Mustacchi 
1166a776d98eSRobert Mustacchi 			mac_prop_info_set_default_uint32(prh, max);
1167a776d98eSRobert Mustacchi 			mac_prop_info_set_range_uint32(prh,
1168a776d98eSRobert Mustacchi 			    range.mpr_range_uint32[0].mpur_min, max);
1169a776d98eSRobert Mustacchi 			mac_perim_exit(mph);
1170a776d98eSRobert Mustacchi 		}
1171f0f2c3a5SGirish Moodalbail 		break;
1172ab6f61efSGirish Moodalbail 	}
1173f0f2c3a5SGirish Moodalbail }
1174ab6f61efSGirish Moodalbail 
11750dc2366fSVenugopal Iyer 
1176da14cebeSEric Cheng int
11772b24ab6bSSebastien Roy vnic_info(vnic_info_t *info, cred_t *credp)
1178843e1988Sjohnlev {
1179843e1988Sjohnlev 	vnic_t		*vnic;
1180da14cebeSEric Cheng 	int		err;
1181843e1988Sjohnlev 
11822b24ab6bSSebastien Roy 	/* Make sure that the VNIC link is visible from the caller's zone. */
11832b24ab6bSSebastien Roy 	if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp)))
11842b24ab6bSSebastien Roy 		return (ENOENT);
11852b24ab6bSSebastien Roy 
1186da14cebeSEric Cheng 	rw_enter(&vnic_lock, RW_WRITER);
1187843e1988Sjohnlev 
1188da14cebeSEric Cheng 	err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id),
1189da14cebeSEric Cheng 	    (mod_hash_val_t *)&vnic);
1190da14cebeSEric Cheng 	if (err != 0) {
1191da14cebeSEric Cheng 		rw_exit(&vnic_lock);
1192da14cebeSEric Cheng 		return (ENOENT);
1193d62bc4baSyz147064 	}
1194843e1988Sjohnlev 
1195da14cebeSEric Cheng 	info->vn_link_id = vnic->vn_link_id;
1196da14cebeSEric Cheng 	info->vn_mac_addr_type = vnic->vn_addr_type;
1197da14cebeSEric Cheng 	info->vn_mac_len = vnic->vn_addr_len;
1198da14cebeSEric Cheng 	bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN);
1199da14cebeSEric Cheng 	info->vn_mac_slot = vnic->vn_slot_id;
1200da14cebeSEric Cheng 	info->vn_mac_prefix_len = 0;
1201da14cebeSEric Cheng 	info->vn_vid = vnic->vn_vid;
1202da14cebeSEric Cheng 	info->vn_force = vnic->vn_force;
12031cb875aeSCathy Zhou 	info->vn_vrid = vnic->vn_vrid;
12041cb875aeSCathy Zhou 	info->vn_af = vnic->vn_af;
1205843e1988Sjohnlev 
1206da14cebeSEric Cheng 	bzero(&info->vn_resource_props, sizeof (mac_resource_props_t));
1207da14cebeSEric Cheng 	if (vnic->vn_mch != NULL)
12081a41ca23SJerry Jelinek 		mac_client_get_resources(vnic->vn_mch,
12091a41ca23SJerry Jelinek 		    &info->vn_resource_props);
1210843e1988Sjohnlev 
1211da14cebeSEric Cheng 	rw_exit(&vnic_lock);
1212da14cebeSEric Cheng 	return (0);
1213843e1988Sjohnlev }
1214843e1988Sjohnlev 
1215843e1988Sjohnlev static void
1216843e1988Sjohnlev vnic_notify_cb(void *arg, mac_notify_type_t type)
1217843e1988Sjohnlev {
1218da14cebeSEric Cheng 	vnic_t *vnic = arg;
1219843e1988Sjohnlev 
1220843e1988Sjohnlev 	/*
12212c4ec682SEric Cheng 	 * Do not deliver notifications if the vnic is not fully initialized
12222c4ec682SEric Cheng 	 * or is in process of being torn down.
12232c4ec682SEric Cheng 	 */
12242c4ec682SEric Cheng 	if (!vnic->vn_enabled)
12252c4ec682SEric Cheng 		return;
12262c4ec682SEric Cheng 
12272c4ec682SEric Cheng 	switch (type) {
12282c4ec682SEric Cheng 	case MAC_NOTE_UNICST:
12292c4ec682SEric Cheng 		/*
1230da14cebeSEric Cheng 		 * Only the VLAN VNIC needs to be notified with primary MAC
1231da14cebeSEric Cheng 		 * address change.
1232843e1988Sjohnlev 		 */
1233da14cebeSEric Cheng 		if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY)
1234da14cebeSEric Cheng 			return;
1235843e1988Sjohnlev 
1236da14cebeSEric Cheng 		/*  the unicast MAC address value */
1237da14cebeSEric Cheng 		mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr);
1238843e1988Sjohnlev 
1239da14cebeSEric Cheng 		/* notify its upper layer MAC about MAC address change */
1240da14cebeSEric Cheng 		mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr);
12411d03c31eSjohnlev 		break;
12422c4ec682SEric Cheng 
12432c4ec682SEric Cheng 	case MAC_NOTE_LINK:
12442c4ec682SEric Cheng 		mac_link_update(vnic->vn_mh,
12452c4ec682SEric Cheng 		    mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
12462c4ec682SEric Cheng 		break;
12472c4ec682SEric Cheng 
1248da14cebeSEric Cheng 	default:
1249843e1988Sjohnlev 		break;
1250843e1988Sjohnlev 	}
1251843e1988Sjohnlev }
1252