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
vnic_dev_init(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
vnic_dev_fini(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
vnic_dev_count(void)159843e1988Sjohnlev vnic_dev_count(void)
160843e1988Sjohnlev {
161843e1988Sjohnlev return (vnic_count);
162843e1988Sjohnlev }
163843e1988Sjohnlev
164da14cebeSEric Cheng static vnic_ioc_diag_t
vnic_mac2vnic_diag(mac_diag_t diag)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
vnic_unicast_add(vnic_t * vnic,vnic_mac_addr_type_t vnic_addr_type,int * addr_slot,uint_t prefix_len,int * addr_len_ptr_arg,uint8_t * mac_addr_arg,uint16_t flags,vnic_ioc_diag_t * diag,uint16_t vid,boolean_t req_hwgrp_flag)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
vnic_dev_create(datalink_id_t vnic_id,datalink_id_t linkid,vnic_mac_addr_type_t * vnic_addr_type,int * mac_len,uchar_t * mac_addr,int * mac_slot,uint_t mac_prefix_len,uint16_t vid,vrid_t vrid,int af,mac_resource_props_t * mrp,uint32_t flags,vnic_ioc_diag_t * diag,cred_t * credp)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
vnic_dev_modify(datalink_id_t vnic_id,uint_t modify_mask,vnic_mac_addr_type_t mac_addr_type,uint_t mac_len,uchar_t * mac_addr,uint_t mac_slot,mac_resource_props_t * mrp)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
vnic_dev_delete(datalink_id_t vnic_id,uint32_t flags,cred_t * credp)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 *
vnic_m_tx(void * arg,mblk_t * mp_chain)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
vnic_m_ioctl(void * arg,queue_t * q,mblk_t * mp)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
vnic_m_stat(void * arg,uint_t stat,uint64_t * val)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 *
vnic_mac_client_handle(void * vnic_arg)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
vnic_mac_secondary_update(void * vnic_arg)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
vnic_m_capab_get(void * arg,mac_capab_t cap,void * cap_data)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
vnic_m_start(void * arg)877843e1988Sjohnlev vnic_m_start(void *arg)
878843e1988Sjohnlev {
879843e1988Sjohnlev return (0);
880843e1988Sjohnlev }
881843e1988Sjohnlev
882da14cebeSEric Cheng /* ARGSUSED */
883843e1988Sjohnlev static void
vnic_m_stop(void * arg)884843e1988Sjohnlev vnic_m_stop(void *arg)
885843e1988Sjohnlev {
886843e1988Sjohnlev }
887843e1988Sjohnlev
888843e1988Sjohnlev /* ARGSUSED */
889843e1988Sjohnlev static int
vnic_m_promisc(void * arg,boolean_t on)890843e1988Sjohnlev vnic_m_promisc(void *arg, boolean_t on)
891843e1988Sjohnlev {
892843e1988Sjohnlev return (0);
893843e1988Sjohnlev }
894843e1988Sjohnlev
895da14cebeSEric Cheng /* ARGSUSED */
896da14cebeSEric Cheng static int
vnic_m_multicst(void * arg,boolean_t add,const uint8_t * addrp)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
vnic_m_unicst(void * arg,const uint8_t * macaddr)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
vnic_cleanup_secondary_macs(vnic_t * vn,int cnt)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
vnic_set_secondary_macs(vnic_t * vn,mac_secondary_addr_t * msa)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
vnic_get_secondary_macs(vnic_t * vn,uint_t pr_valsize,void * pr_val)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
vnic_m_setprop(void * m_driver,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)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
vnic_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)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 */
vnic_m_propinfo(void * m_driver,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)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
vnic_info(vnic_info_t * info,cred_t * credp)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
vnic_notify_cb(void * arg,mac_notify_type_t type)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