Print this page
6601 Various GLD drivers return EINVAL instead of ENOTSUP for unused mac_prop_id_t's
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/vnic/vnic_dev.c
+++ new/usr/src/uts/common/io/vnic/vnic_dev.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2015 Joyent, Inc.
24 + * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <sys/types.h>
27 28 #include <sys/cred.h>
28 29 #include <sys/sysmacros.h>
29 30 #include <sys/conf.h>
30 31 #include <sys/cmn_err.h>
31 32 #include <sys/list.h>
32 33 #include <sys/ksynch.h>
33 34 #include <sys/kmem.h>
34 35 #include <sys/stream.h>
35 36 #include <sys/modctl.h>
36 37 #include <sys/ddi.h>
37 38 #include <sys/sunddi.h>
38 39 #include <sys/atomic.h>
39 40 #include <sys/stat.h>
40 41 #include <sys/modhash.h>
41 42 #include <sys/strsubr.h>
42 43 #include <sys/strsun.h>
43 44 #include <sys/dlpi.h>
44 45 #include <sys/mac.h>
45 46 #include <sys/mac_provider.h>
46 47 #include <sys/mac_client.h>
47 48 #include <sys/mac_client_priv.h>
48 49 #include <sys/mac_ether.h>
49 50 #include <sys/dls.h>
50 51 #include <sys/pattr.h>
51 52 #include <sys/time.h>
52 53 #include <sys/vlan.h>
53 54 #include <sys/vnic.h>
54 55 #include <sys/vnic_impl.h>
55 56 #include <sys/mac_flow_impl.h>
56 57 #include <inet/ip_impl.h>
57 58
58 59 /*
59 60 * Note that for best performance, the VNIC is a passthrough design.
60 61 * For each VNIC corresponds a MAC client of the underlying MAC (lower MAC).
61 62 * This MAC client is opened by the VNIC driver at VNIC creation,
62 63 * and closed when the VNIC is deleted.
63 64 * When a MAC client of the VNIC itself opens a VNIC, the MAC layer
64 65 * (upper MAC) detects that the MAC being opened is a VNIC. Instead
65 66 * of allocating a new MAC client, it asks the VNIC driver to return
66 67 * the lower MAC client handle associated with the VNIC, and that handle
67 68 * is returned to the upper MAC client directly. This allows access
68 69 * by upper MAC clients of the VNIC to have direct access to the lower
69 70 * MAC client for the control path and data path.
70 71 *
71 72 * Due to this passthrough, some of the entry points exported by the
72 73 * VNIC driver are never directly invoked. These entry points include
73 74 * vnic_m_start, vnic_m_stop, vnic_m_promisc, vnic_m_multicst, etc.
74 75 *
75 76 * VNICs support multiple upper mac clients to enable support for
76 77 * multiple MAC addresses on the VNIC. When the VNIC is created the
77 78 * initial mac client is the primary upper mac. Any additional mac
78 79 * clients are secondary macs.
79 80 */
80 81
81 82 static int vnic_m_start(void *);
82 83 static void vnic_m_stop(void *);
83 84 static int vnic_m_promisc(void *, boolean_t);
84 85 static int vnic_m_multicst(void *, boolean_t, const uint8_t *);
85 86 static int vnic_m_unicst(void *, const uint8_t *);
86 87 static int vnic_m_stat(void *, uint_t, uint64_t *);
87 88 static void vnic_m_ioctl(void *, queue_t *, mblk_t *);
88 89 static int vnic_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
89 90 const void *);
90 91 static int vnic_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
91 92 static void vnic_m_propinfo(void *, const char *, mac_prop_id_t,
92 93 mac_prop_info_handle_t);
93 94 static mblk_t *vnic_m_tx(void *, mblk_t *);
94 95 static boolean_t vnic_m_capab_get(void *, mac_capab_t, void *);
95 96 static void vnic_notify_cb(void *, mac_notify_type_t);
96 97 static void vnic_cleanup_secondary_macs(vnic_t *, int);
97 98
98 99 static kmem_cache_t *vnic_cache;
99 100 static krwlock_t vnic_lock;
100 101 static uint_t vnic_count;
101 102
102 103 #define ANCHOR_VNIC_MIN_MTU 576
103 104 #define ANCHOR_VNIC_MAX_MTU 9000
104 105
105 106 /* hash of VNICs (vnic_t's), keyed by VNIC id */
106 107 static mod_hash_t *vnic_hash;
107 108 #define VNIC_HASHSZ 64
108 109 #define VNIC_HASH_KEY(vnic_id) ((mod_hash_key_t)(uintptr_t)vnic_id)
109 110
110 111 #define VNIC_M_CALLBACK_FLAGS \
111 112 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
112 113
113 114 static mac_callbacks_t vnic_m_callbacks = {
114 115 VNIC_M_CALLBACK_FLAGS,
115 116 vnic_m_stat,
116 117 vnic_m_start,
117 118 vnic_m_stop,
118 119 vnic_m_promisc,
119 120 vnic_m_multicst,
120 121 vnic_m_unicst,
121 122 vnic_m_tx,
122 123 NULL,
123 124 vnic_m_ioctl,
124 125 vnic_m_capab_get,
125 126 NULL,
126 127 NULL,
127 128 vnic_m_setprop,
128 129 vnic_m_getprop,
129 130 vnic_m_propinfo
130 131 };
131 132
132 133 void
133 134 vnic_dev_init(void)
134 135 {
135 136 vnic_cache = kmem_cache_create("vnic_cache",
136 137 sizeof (vnic_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
137 138
138 139 vnic_hash = mod_hash_create_idhash("vnic_hash",
139 140 VNIC_HASHSZ, mod_hash_null_valdtor);
140 141
141 142 rw_init(&vnic_lock, NULL, RW_DEFAULT, NULL);
142 143
143 144 vnic_count = 0;
144 145 }
145 146
146 147 void
147 148 vnic_dev_fini(void)
148 149 {
149 150 ASSERT(vnic_count == 0);
150 151
151 152 rw_destroy(&vnic_lock);
152 153 mod_hash_destroy_idhash(vnic_hash);
153 154 kmem_cache_destroy(vnic_cache);
154 155 }
155 156
156 157 uint_t
157 158 vnic_dev_count(void)
158 159 {
159 160 return (vnic_count);
160 161 }
161 162
162 163 static vnic_ioc_diag_t
163 164 vnic_mac2vnic_diag(mac_diag_t diag)
164 165 {
165 166 switch (diag) {
166 167 case MAC_DIAG_MACADDR_NIC:
167 168 return (VNIC_IOC_DIAG_MACADDR_NIC);
168 169 case MAC_DIAG_MACADDR_INUSE:
169 170 return (VNIC_IOC_DIAG_MACADDR_INUSE);
170 171 case MAC_DIAG_MACADDR_INVALID:
171 172 return (VNIC_IOC_DIAG_MACADDR_INVALID);
172 173 case MAC_DIAG_MACADDRLEN_INVALID:
173 174 return (VNIC_IOC_DIAG_MACADDRLEN_INVALID);
174 175 case MAC_DIAG_MACFACTORYSLOTINVALID:
175 176 return (VNIC_IOC_DIAG_MACFACTORYSLOTINVALID);
176 177 case MAC_DIAG_MACFACTORYSLOTUSED:
177 178 return (VNIC_IOC_DIAG_MACFACTORYSLOTUSED);
178 179 case MAC_DIAG_MACFACTORYSLOTALLUSED:
179 180 return (VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED);
180 181 case MAC_DIAG_MACFACTORYNOTSUP:
181 182 return (VNIC_IOC_DIAG_MACFACTORYNOTSUP);
182 183 case MAC_DIAG_MACPREFIX_INVALID:
183 184 return (VNIC_IOC_DIAG_MACPREFIX_INVALID);
184 185 case MAC_DIAG_MACPREFIXLEN_INVALID:
185 186 return (VNIC_IOC_DIAG_MACPREFIXLEN_INVALID);
186 187 case MAC_DIAG_MACNO_HWRINGS:
187 188 return (VNIC_IOC_DIAG_NO_HWRINGS);
188 189 default:
189 190 return (VNIC_IOC_DIAG_NONE);
190 191 }
191 192 }
192 193
193 194 static int
194 195 vnic_unicast_add(vnic_t *vnic, vnic_mac_addr_type_t vnic_addr_type,
195 196 int *addr_slot, uint_t prefix_len, int *addr_len_ptr_arg,
196 197 uint8_t *mac_addr_arg, uint16_t flags, vnic_ioc_diag_t *diag,
197 198 uint16_t vid, boolean_t req_hwgrp_flag)
198 199 {
199 200 mac_diag_t mac_diag;
200 201 uint16_t mac_flags = 0;
201 202 int err;
202 203 uint_t addr_len;
203 204
204 205 if (flags & VNIC_IOC_CREATE_NODUPCHECK)
205 206 mac_flags |= MAC_UNICAST_NODUPCHECK;
206 207
207 208 switch (vnic_addr_type) {
208 209 case VNIC_MAC_ADDR_TYPE_FIXED:
209 210 case VNIC_MAC_ADDR_TYPE_VRID:
210 211 /*
211 212 * The MAC address value to assign to the VNIC
212 213 * is already provided in mac_addr_arg. addr_len_ptr_arg
213 214 * already contains the MAC address length.
214 215 */
215 216 break;
216 217
217 218 case VNIC_MAC_ADDR_TYPE_RANDOM:
218 219 /*
219 220 * Random MAC address. There are two sub-cases:
220 221 *
221 222 * 1 - If mac_len == 0, a new MAC address is generated.
222 223 * The length of the MAC address to generated depends
223 224 * on the type of MAC used. The prefix to use for the MAC
224 225 * address is stored in the most significant bytes
225 226 * of the mac_addr argument, and its length is specified
226 227 * by the mac_prefix_len argument. This prefix can
227 228 * correspond to a IEEE OUI in the case of Ethernet,
228 229 * for example.
229 230 *
230 231 * 2 - If mac_len > 0, the address was already picked
231 232 * randomly, and is now passed back during VNIC
232 233 * re-creation. The mac_addr argument contains the MAC
233 234 * address that was generated. We distinguish this
234 235 * case from the fixed MAC address case, since we
235 236 * want the user consumers to know, when they query
236 237 * the list of VNICs, that a VNIC was assigned a
237 238 * random MAC address vs assigned a fixed address
238 239 * specified by the user.
239 240 */
240 241
241 242 /*
242 243 * If it's a pre-generated address, we're done. mac_addr_arg
243 244 * and addr_len_ptr_arg already contain the MAC address
244 245 * value and length.
245 246 */
246 247 if (*addr_len_ptr_arg > 0)
247 248 break;
248 249
249 250 /* generate a new random MAC address */
250 251 if ((err = mac_addr_random(vnic->vn_mch,
251 252 prefix_len, mac_addr_arg, &mac_diag)) != 0) {
252 253 *diag = vnic_mac2vnic_diag(mac_diag);
253 254 return (err);
254 255 }
255 256 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
256 257 break;
257 258
258 259 case VNIC_MAC_ADDR_TYPE_FACTORY:
259 260 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
260 261 if (err != 0) {
261 262 if (err == EINVAL)
262 263 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTINVALID;
263 264 if (err == EBUSY)
264 265 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTUSED;
265 266 if (err == ENOSPC)
266 267 *diag = VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED;
267 268 return (err);
268 269 }
269 270
270 271 mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
271 272 mac_addr_arg, &addr_len, NULL, NULL);
272 273 *addr_len_ptr_arg = addr_len;
273 274 break;
274 275
275 276 case VNIC_MAC_ADDR_TYPE_AUTO:
276 277 /* first try to allocate a factory MAC address */
277 278 err = mac_addr_factory_reserve(vnic->vn_mch, addr_slot);
278 279 if (err == 0) {
279 280 mac_addr_factory_value(vnic->vn_lower_mh, *addr_slot,
280 281 mac_addr_arg, &addr_len, NULL, NULL);
281 282 vnic_addr_type = VNIC_MAC_ADDR_TYPE_FACTORY;
282 283 *addr_len_ptr_arg = addr_len;
283 284 break;
284 285 }
285 286
286 287 /*
287 288 * Allocating a factory MAC address failed, generate a
288 289 * random MAC address instead.
289 290 */
290 291 if ((err = mac_addr_random(vnic->vn_mch,
291 292 prefix_len, mac_addr_arg, &mac_diag)) != 0) {
292 293 *diag = vnic_mac2vnic_diag(mac_diag);
293 294 return (err);
294 295 }
295 296 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
296 297 vnic_addr_type = VNIC_MAC_ADDR_TYPE_RANDOM;
297 298 break;
298 299 case VNIC_MAC_ADDR_TYPE_PRIMARY:
299 300 /*
300 301 * We get the address here since we copy it in the
301 302 * vnic's vn_addr.
302 303 * We can't ask for hardware resources since we
303 304 * don't currently support hardware classification
304 305 * for these MAC clients.
305 306 */
306 307 if (req_hwgrp_flag) {
307 308 *diag = VNIC_IOC_DIAG_NO_HWRINGS;
308 309 return (ENOTSUP);
309 310 }
310 311 mac_unicast_primary_get(vnic->vn_lower_mh, mac_addr_arg);
311 312 *addr_len_ptr_arg = mac_addr_len(vnic->vn_lower_mh);
312 313 mac_flags |= MAC_UNICAST_VNIC_PRIMARY;
313 314 break;
314 315 }
315 316
316 317 vnic->vn_addr_type = vnic_addr_type;
317 318
318 319 err = mac_unicast_add(vnic->vn_mch, mac_addr_arg, mac_flags,
319 320 &vnic->vn_muh, vid, &mac_diag);
320 321 if (err != 0) {
321 322 if (vnic_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
322 323 /* release factory MAC address */
323 324 mac_addr_factory_release(vnic->vn_mch, *addr_slot);
324 325 }
325 326 *diag = vnic_mac2vnic_diag(mac_diag);
326 327 }
327 328
328 329 return (err);
329 330 }
330 331
331 332 /*
332 333 * Create a new VNIC upon request from administrator.
333 334 * Returns 0 on success, an errno on failure.
334 335 */
335 336 /* ARGSUSED */
336 337 int
337 338 vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
338 339 vnic_mac_addr_type_t *vnic_addr_type, int *mac_len, uchar_t *mac_addr,
339 340 int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
340 341 int af, mac_resource_props_t *mrp, uint32_t flags, vnic_ioc_diag_t *diag,
341 342 cred_t *credp)
342 343 {
343 344 vnic_t *vnic;
344 345 mac_register_t *mac;
345 346 int err;
346 347 boolean_t is_anchor = ((flags & VNIC_IOC_CREATE_ANCHOR) != 0);
347 348 char vnic_name[MAXNAMELEN];
348 349 const mac_info_t *minfop;
349 350 uint32_t req_hwgrp_flag = B_FALSE;
350 351
351 352 *diag = VNIC_IOC_DIAG_NONE;
352 353
353 354 rw_enter(&vnic_lock, RW_WRITER);
354 355
355 356 /* does a VNIC with the same id already exist? */
356 357 err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
357 358 (mod_hash_val_t *)&vnic);
358 359 if (err == 0) {
359 360 rw_exit(&vnic_lock);
360 361 return (EEXIST);
361 362 }
362 363
363 364 vnic = kmem_cache_alloc(vnic_cache, KM_NOSLEEP);
364 365 if (vnic == NULL) {
365 366 rw_exit(&vnic_lock);
366 367 return (ENOMEM);
367 368 }
368 369
369 370 bzero(vnic, sizeof (*vnic));
370 371
371 372 vnic->vn_id = vnic_id;
372 373 vnic->vn_link_id = linkid;
373 374 vnic->vn_vrid = vrid;
374 375 vnic->vn_af = af;
375 376
376 377 if (!is_anchor) {
377 378 if (linkid == DATALINK_INVALID_LINKID) {
378 379 err = EINVAL;
379 380 goto bail;
380 381 }
381 382
382 383 /*
383 384 * Open the lower MAC and assign its initial bandwidth and
384 385 * MAC address. We do this here during VNIC creation and
385 386 * do not wait until the upper MAC client open so that we
386 387 * can validate the VNIC creation parameters (bandwidth,
387 388 * MAC address, etc) and reserve a factory MAC address if
388 389 * one was requested.
389 390 */
390 391 err = mac_open_by_linkid(linkid, &vnic->vn_lower_mh);
391 392 if (err != 0)
392 393 goto bail;
393 394
394 395 /*
395 396 * VNIC(vlan) over VNICs(vlans) is not supported.
396 397 */
397 398 if (mac_is_vnic(vnic->vn_lower_mh)) {
398 399 err = EINVAL;
399 400 goto bail;
400 401 }
401 402
402 403 /* only ethernet support for now */
403 404 minfop = mac_info(vnic->vn_lower_mh);
404 405 if (minfop->mi_nativemedia != DL_ETHER) {
405 406 err = ENOTSUP;
406 407 goto bail;
407 408 }
408 409
409 410 (void) dls_mgmt_get_linkinfo(vnic_id, vnic_name, NULL, NULL,
410 411 NULL);
411 412 err = mac_client_open(vnic->vn_lower_mh, &vnic->vn_mch,
412 413 vnic_name, MAC_OPEN_FLAGS_IS_VNIC);
413 414 if (err != 0)
414 415 goto bail;
415 416
416 417 /* assign a MAC address to the VNIC */
417 418
418 419 err = vnic_unicast_add(vnic, *vnic_addr_type, mac_slot,
419 420 mac_prefix_len, mac_len, mac_addr, flags, diag, vid,
420 421 req_hwgrp_flag);
421 422 if (err != 0) {
422 423 vnic->vn_muh = NULL;
423 424 if (diag != NULL && req_hwgrp_flag)
424 425 *diag = VNIC_IOC_DIAG_NO_HWRINGS;
425 426 goto bail;
426 427 }
427 428
428 429 /* register to receive notification from underlying MAC */
429 430 vnic->vn_mnh = mac_notify_add(vnic->vn_lower_mh, vnic_notify_cb,
430 431 vnic);
431 432
432 433 *vnic_addr_type = vnic->vn_addr_type;
433 434 vnic->vn_addr_len = *mac_len;
434 435 vnic->vn_vid = vid;
435 436
436 437 bcopy(mac_addr, vnic->vn_addr, vnic->vn_addr_len);
437 438
438 439 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY)
439 440 vnic->vn_slot_id = *mac_slot;
440 441
441 442 /*
442 443 * Set the initial VNIC capabilities. If the VNIC is created
443 444 * over MACs which does not support nactive vlan, disable
444 445 * VNIC's hardware checksum capability if its VID is not 0,
445 446 * since the underlying MAC would get the hardware checksum
446 447 * offset wrong in case of VLAN packets.
447 448 */
448 449 if (vid == 0 || !mac_capab_get(vnic->vn_lower_mh,
449 450 MAC_CAPAB_NO_NATIVEVLAN, NULL)) {
450 451 if (!mac_capab_get(vnic->vn_lower_mh, MAC_CAPAB_HCKSUM,
451 452 &vnic->vn_hcksum_txflags))
452 453 vnic->vn_hcksum_txflags = 0;
453 454 } else {
454 455 vnic->vn_hcksum_txflags = 0;
455 456 }
456 457 }
457 458
458 459 /* register with the MAC module */
459 460 if ((mac = mac_alloc(MAC_VERSION)) == NULL)
460 461 goto bail;
461 462
462 463 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
463 464 mac->m_driver = vnic;
464 465 mac->m_dip = vnic_get_dip();
465 466 mac->m_instance = (uint_t)-1;
466 467 mac->m_src_addr = vnic->vn_addr;
467 468 mac->m_callbacks = &vnic_m_callbacks;
468 469
469 470 if (!is_anchor) {
470 471 /*
471 472 * If this is a VNIC based VLAN, then we check for the
472 473 * margin unless it has been created with the force
473 474 * flag. If we are configuring a VLAN over an etherstub,
474 475 * we don't check the margin even if force is not set.
475 476 */
476 477 if (vid == 0 || (flags & VNIC_IOC_CREATE_FORCE) != 0) {
477 478 if (vid != VLAN_ID_NONE)
478 479 vnic->vn_force = B_TRUE;
479 480 /*
480 481 * As the current margin size of the underlying mac is
481 482 * used to determine the margin size of the VNIC
482 483 * itself, request the underlying mac not to change
483 484 * to a smaller margin size.
484 485 */
485 486 err = mac_margin_add(vnic->vn_lower_mh,
486 487 &vnic->vn_margin, B_TRUE);
487 488 ASSERT(err == 0);
488 489 } else {
489 490 vnic->vn_margin = VLAN_TAGSZ;
490 491 err = mac_margin_add(vnic->vn_lower_mh,
491 492 &vnic->vn_margin, B_FALSE);
492 493 if (err != 0) {
493 494 mac_free(mac);
494 495 if (diag != NULL)
495 496 *diag = VNIC_IOC_DIAG_MACMARGIN_INVALID;
496 497 goto bail;
497 498 }
498 499 }
499 500
500 501 mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
501 502 &mac->m_max_sdu);
502 503 err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
503 504 if (err != 0) {
504 505 VERIFY(mac_margin_remove(vnic->vn_lower_mh,
505 506 vnic->vn_margin) == 0);
506 507 mac_free(mac);
507 508 if (diag != NULL)
508 509 *diag = VNIC_IOC_DIAG_MACMTU_INVALID;
509 510 goto bail;
510 511 }
511 512 vnic->vn_mtu = mac->m_max_sdu;
512 513 } else {
513 514 vnic->vn_margin = VLAN_TAGSZ;
514 515 mac->m_min_sdu = 1;
515 516 mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
516 517 vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
517 518 }
518 519
519 520 mac->m_margin = vnic->vn_margin;
520 521
521 522 err = mac_register(mac, &vnic->vn_mh);
522 523 mac_free(mac);
523 524 if (err != 0) {
524 525 if (!is_anchor) {
525 526 VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
526 527 vnic->vn_mtu) == 0);
527 528 VERIFY(mac_margin_remove(vnic->vn_lower_mh,
528 529 vnic->vn_margin) == 0);
529 530 }
530 531 goto bail;
531 532 }
532 533
533 534 /* Set the VNIC's MAC in the client */
534 535 if (!is_anchor) {
535 536 mac_set_upper_mac(vnic->vn_mch, vnic->vn_mh, mrp);
536 537
537 538 if (mrp != NULL) {
538 539 if ((mrp->mrp_mask & MRP_RX_RINGS) != 0 ||
539 540 (mrp->mrp_mask & MRP_TX_RINGS) != 0) {
540 541 req_hwgrp_flag = B_TRUE;
541 542 }
542 543 err = mac_client_set_resources(vnic->vn_mch, mrp);
543 544 if (err != 0) {
544 545 VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
545 546 vnic->vn_mtu) == 0);
546 547 VERIFY(mac_margin_remove(vnic->vn_lower_mh,
547 548 vnic->vn_margin) == 0);
548 549 (void) mac_unregister(vnic->vn_mh);
549 550 goto bail;
550 551 }
551 552 }
552 553 }
553 554
554 555 err = dls_devnet_create(vnic->vn_mh, vnic->vn_id, crgetzoneid(credp));
555 556 if (err != 0) {
556 557 VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
557 558 vnic->vn_margin) == 0);
558 559 if (!is_anchor) {
559 560 VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
560 561 vnic->vn_mtu) == 0);
561 562 VERIFY(mac_margin_remove(vnic->vn_lower_mh,
562 563 vnic->vn_margin) == 0);
563 564 }
564 565 (void) mac_unregister(vnic->vn_mh);
565 566 goto bail;
566 567 }
567 568
568 569 /* add new VNIC to hash table */
569 570 err = mod_hash_insert(vnic_hash, VNIC_HASH_KEY(vnic_id),
570 571 (mod_hash_val_t)vnic);
571 572 ASSERT(err == 0);
572 573 vnic_count++;
573 574
574 575 /*
575 576 * Now that we've enabled this VNIC, we should go through and update the
576 577 * link state by setting it to our parents.
577 578 */
578 579 vnic->vn_enabled = B_TRUE;
579 580
580 581 if (is_anchor) {
581 582 mac_link_update(vnic->vn_mh, LINK_STATE_UP);
582 583 } else {
583 584 mac_link_update(vnic->vn_mh,
584 585 mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
585 586 }
586 587
587 588 rw_exit(&vnic_lock);
588 589
589 590 return (0);
590 591
591 592 bail:
592 593 rw_exit(&vnic_lock);
593 594 if (!is_anchor) {
594 595 if (vnic->vn_mnh != NULL)
595 596 (void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
596 597 if (vnic->vn_muh != NULL)
597 598 (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
598 599 if (vnic->vn_mch != NULL)
599 600 mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
600 601 if (vnic->vn_lower_mh != NULL)
601 602 mac_close(vnic->vn_lower_mh);
602 603 }
603 604
604 605 kmem_cache_free(vnic_cache, vnic);
605 606 return (err);
606 607 }
607 608
608 609 /*
609 610 * Modify the properties of an existing VNIC.
610 611 */
611 612 /* ARGSUSED */
612 613 int
613 614 vnic_dev_modify(datalink_id_t vnic_id, uint_t modify_mask,
614 615 vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr,
615 616 uint_t mac_slot, mac_resource_props_t *mrp)
616 617 {
617 618 vnic_t *vnic = NULL;
618 619
619 620 rw_enter(&vnic_lock, RW_WRITER);
620 621
621 622 if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
622 623 (mod_hash_val_t *)&vnic) != 0) {
623 624 rw_exit(&vnic_lock);
624 625 return (ENOENT);
625 626 }
626 627
627 628 rw_exit(&vnic_lock);
628 629
629 630 return (0);
630 631 }
631 632
632 633 /* ARGSUSED */
633 634 int
634 635 vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
635 636 {
636 637 vnic_t *vnic = NULL;
637 638 mod_hash_val_t val;
638 639 datalink_id_t tmpid;
639 640 int rc;
640 641
641 642 rw_enter(&vnic_lock, RW_WRITER);
642 643
643 644 if (mod_hash_find(vnic_hash, VNIC_HASH_KEY(vnic_id),
644 645 (mod_hash_val_t *)&vnic) != 0) {
645 646 rw_exit(&vnic_lock);
646 647 return (ENOENT);
647 648 }
648 649
649 650 if ((rc = dls_devnet_destroy(vnic->vn_mh, &tmpid, B_TRUE)) != 0) {
650 651 rw_exit(&vnic_lock);
651 652 return (rc);
652 653 }
653 654
654 655 ASSERT(vnic_id == tmpid);
655 656
656 657 /*
657 658 * We cannot unregister the MAC yet. Unregistering would
658 659 * free up mac_impl_t which should not happen at this time.
659 660 * So disable mac_impl_t by calling mac_disable(). This will prevent
660 661 * any new claims on mac_impl_t.
661 662 */
662 663 if ((rc = mac_disable(vnic->vn_mh)) != 0) {
663 664 (void) dls_devnet_create(vnic->vn_mh, vnic_id,
664 665 crgetzoneid(credp));
665 666 rw_exit(&vnic_lock);
666 667 return (rc);
667 668 }
668 669
669 670 vnic_cleanup_secondary_macs(vnic, vnic->vn_nhandles);
670 671
671 672 vnic->vn_enabled = B_FALSE;
672 673 (void) mod_hash_remove(vnic_hash, VNIC_HASH_KEY(vnic_id), &val);
673 674 ASSERT(vnic == (vnic_t *)val);
674 675 vnic_count--;
675 676 rw_exit(&vnic_lock);
676 677
677 678 /*
678 679 * XXX-nicolas shouldn't have a void cast here, if it's
679 680 * expected that the function will never fail, then we should
680 681 * have an ASSERT().
681 682 */
682 683 (void) mac_unregister(vnic->vn_mh);
683 684
684 685 if (vnic->vn_lower_mh != NULL) {
685 686 /*
686 687 * Check if MAC address for the vnic was obtained from the
687 688 * factory MAC addresses. If yes, release it.
688 689 */
689 690 if (vnic->vn_addr_type == VNIC_MAC_ADDR_TYPE_FACTORY) {
690 691 (void) mac_addr_factory_release(vnic->vn_mch,
691 692 vnic->vn_slot_id);
692 693 }
693 694 (void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin);
694 695 (void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu);
695 696 (void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
696 697 (void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
697 698 mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
698 699 mac_close(vnic->vn_lower_mh);
699 700 }
700 701
701 702 kmem_cache_free(vnic_cache, vnic);
702 703 return (0);
703 704 }
704 705
705 706 /* ARGSUSED */
706 707 mblk_t *
707 708 vnic_m_tx(void *arg, mblk_t *mp_chain)
708 709 {
709 710 /*
710 711 * This function could be invoked for an anchor VNIC when sending
711 712 * broadcast and multicast packets, and unicast packets which did
712 713 * not match any local known destination.
713 714 */
714 715 freemsgchain(mp_chain);
715 716 return (NULL);
716 717 }
717 718
718 719 /*ARGSUSED*/
719 720 static void
720 721 vnic_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
721 722 {
722 723 miocnak(q, mp, 0, ENOTSUP);
723 724 }
724 725
725 726 /*
726 727 * This entry point cannot be passed-through, since it is invoked
727 728 * for the per-VNIC kstats which must be exported independently
728 729 * of the existence of VNIC MAC clients.
729 730 */
730 731 static int
731 732 vnic_m_stat(void *arg, uint_t stat, uint64_t *val)
732 733 {
733 734 vnic_t *vnic = arg;
734 735 int rval = 0;
735 736
736 737 if (vnic->vn_lower_mh == NULL) {
737 738 /*
738 739 * It's an anchor VNIC, which does not have any
739 740 * statistics in itself.
740 741 */
741 742 return (ENOTSUP);
742 743 }
743 744
744 745 /*
745 746 * ENOTSUP must be reported for unsupported stats, the VNIC
746 747 * driver reports a subset of the stats that would
747 748 * be returned by a real piece of hardware.
748 749 */
749 750
750 751 switch (stat) {
751 752 case MAC_STAT_LINK_STATE:
752 753 case MAC_STAT_LINK_UP:
753 754 case MAC_STAT_PROMISC:
754 755 case MAC_STAT_IFSPEED:
755 756 case MAC_STAT_MULTIRCV:
756 757 case MAC_STAT_MULTIXMT:
757 758 case MAC_STAT_BRDCSTRCV:
758 759 case MAC_STAT_BRDCSTXMT:
759 760 case MAC_STAT_OPACKETS:
760 761 case MAC_STAT_OBYTES:
761 762 case MAC_STAT_IERRORS:
762 763 case MAC_STAT_OERRORS:
763 764 case MAC_STAT_RBYTES:
764 765 case MAC_STAT_IPACKETS:
765 766 *val = mac_client_stat_get(vnic->vn_mch, stat);
766 767 break;
767 768 default:
768 769 rval = ENOTSUP;
769 770 }
770 771
771 772 return (rval);
772 773 }
773 774
774 775 /*
775 776 * Invoked by the upper MAC to retrieve the lower MAC client handle
776 777 * corresponding to a VNIC. A pointer to this function is obtained
777 778 * by the upper MAC via capability query.
778 779 *
779 780 * XXX-nicolas Note: this currently causes all VNIC MAC clients to
780 781 * receive the same MAC client handle for the same VNIC. This is ok
781 782 * as long as we have only one VNIC MAC client which sends and
782 783 * receives data, but we don't currently enforce this at the MAC layer.
783 784 */
784 785 static void *
785 786 vnic_mac_client_handle(void *vnic_arg)
786 787 {
787 788 vnic_t *vnic = vnic_arg;
788 789
789 790 return (vnic->vn_mch);
790 791 }
791 792
792 793 /*
793 794 * Invoked when updating the primary MAC so that the secondary MACs are
794 795 * kept in sync.
795 796 */
796 797 static void
797 798 vnic_mac_secondary_update(void *vnic_arg)
798 799 {
799 800 vnic_t *vn = vnic_arg;
800 801 int i;
801 802
802 803 for (i = 1; i <= vn->vn_nhandles; i++) {
803 804 mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
804 805 }
805 806 }
806 807
807 808 /*
808 809 * Return information about the specified capability.
809 810 */
810 811 /* ARGSUSED */
811 812 static boolean_t
812 813 vnic_m_capab_get(void *arg, mac_capab_t cap, void *cap_data)
813 814 {
814 815 vnic_t *vnic = arg;
815 816
816 817 switch (cap) {
817 818 case MAC_CAPAB_HCKSUM: {
818 819 uint32_t *hcksum_txflags = cap_data;
819 820
820 821 *hcksum_txflags = vnic->vn_hcksum_txflags &
821 822 (HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM |
822 823 HCKSUM_INET_PARTIAL);
823 824 break;
824 825 }
825 826 case MAC_CAPAB_VNIC: {
826 827 mac_capab_vnic_t *vnic_capab = cap_data;
827 828
828 829 if (vnic->vn_lower_mh == NULL) {
829 830 /*
830 831 * It's an anchor VNIC, we don't have an underlying
831 832 * NIC and MAC client handle.
832 833 */
833 834 return (B_FALSE);
834 835 }
835 836
836 837 if (vnic_capab != NULL) {
837 838 vnic_capab->mcv_arg = vnic;
838 839 vnic_capab->mcv_mac_client_handle =
839 840 vnic_mac_client_handle;
840 841 vnic_capab->mcv_mac_secondary_update =
841 842 vnic_mac_secondary_update;
842 843 }
843 844 break;
844 845 }
845 846 case MAC_CAPAB_ANCHOR_VNIC: {
846 847 /* since it's an anchor VNIC we don't have lower mac handle */
847 848 if (vnic->vn_lower_mh == NULL) {
848 849 ASSERT(vnic->vn_link_id == 0);
849 850 return (B_TRUE);
850 851 }
851 852 return (B_FALSE);
852 853 }
853 854 case MAC_CAPAB_NO_NATIVEVLAN:
854 855 return (B_FALSE);
855 856 case MAC_CAPAB_NO_ZCOPY:
856 857 return (B_TRUE);
857 858 case MAC_CAPAB_VRRP: {
858 859 mac_capab_vrrp_t *vrrp_capab = cap_data;
859 860
860 861 if (vnic->vn_vrid != 0) {
861 862 if (vrrp_capab != NULL)
862 863 vrrp_capab->mcv_af = vnic->vn_af;
863 864 return (B_TRUE);
864 865 }
865 866 return (B_FALSE);
866 867 }
867 868 default:
868 869 return (B_FALSE);
869 870 }
870 871 return (B_TRUE);
871 872 }
872 873
873 874 /* ARGSUSED */
874 875 static int
875 876 vnic_m_start(void *arg)
876 877 {
877 878 return (0);
878 879 }
879 880
880 881 /* ARGSUSED */
881 882 static void
882 883 vnic_m_stop(void *arg)
883 884 {
884 885 }
885 886
886 887 /* ARGSUSED */
887 888 static int
888 889 vnic_m_promisc(void *arg, boolean_t on)
889 890 {
890 891 return (0);
891 892 }
892 893
893 894 /* ARGSUSED */
894 895 static int
895 896 vnic_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
896 897 {
897 898 return (0);
898 899 }
899 900
900 901 static int
901 902 vnic_m_unicst(void *arg, const uint8_t *macaddr)
902 903 {
903 904 vnic_t *vnic = arg;
904 905
905 906 return (mac_vnic_unicast_set(vnic->vn_mch, macaddr));
906 907 }
907 908
908 909 static void
909 910 vnic_cleanup_secondary_macs(vnic_t *vn, int cnt)
910 911 {
911 912 int i;
912 913
913 914 /* Remove existing secondaries (primary is at 0) */
914 915 for (i = 1; i <= cnt; i++) {
915 916 mac_rx_clear(vn->vn_mc_handles[i]);
916 917
917 918 /* unicast handle might not have been set yet */
918 919 if (vn->vn_mu_handles[i] != NULL)
919 920 (void) mac_unicast_remove(vn->vn_mc_handles[i],
920 921 vn->vn_mu_handles[i]);
921 922
922 923 mac_secondary_cleanup(vn->vn_mc_handles[i]);
923 924
924 925 mac_client_close(vn->vn_mc_handles[i], MAC_CLOSE_FLAGS_IS_VNIC);
925 926
926 927 vn->vn_mu_handles[i] = NULL;
927 928 vn->vn_mc_handles[i] = NULL;
928 929 }
929 930
930 931 vn->vn_nhandles = 0;
931 932 }
932 933
933 934 /*
934 935 * Setup secondary MAC addresses on the vnic. Due to limitations in the mac
935 936 * code, each mac address must be associated with a mac_client (and the
936 937 * flow that goes along with the client) so we need to create those clients
937 938 * here.
938 939 */
939 940 static int
940 941 vnic_set_secondary_macs(vnic_t *vn, mac_secondary_addr_t *msa)
941 942 {
942 943 int i, err;
943 944 char primary_name[MAXNAMELEN];
944 945
945 946 /* First, remove pre-existing secondaries */
946 947 ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
947 948 vnic_cleanup_secondary_macs(vn, vn->vn_nhandles);
948 949
949 950 if (msa->ms_addrcnt == (uint32_t)-1)
950 951 msa->ms_addrcnt = 0;
951 952
952 953 vn->vn_nhandles = msa->ms_addrcnt;
953 954
954 955 (void) dls_mgmt_get_linkinfo(vn->vn_id, primary_name, NULL, NULL, NULL);
955 956
956 957 /*
957 958 * Now add the new secondary MACs
958 959 * Recall that the primary MAC address is the first element.
959 960 * The secondary clients are named after the primary with their
960 961 * index to distinguish them.
961 962 */
962 963 for (i = 1; i <= vn->vn_nhandles; i++) {
963 964 uint8_t *addr;
964 965 mac_diag_t mac_diag;
965 966 char secondary_name[MAXNAMELEN];
966 967
967 968 (void) snprintf(secondary_name, sizeof (secondary_name),
968 969 "%s%02d", primary_name, i);
969 970
970 971 err = mac_client_open(vn->vn_lower_mh, &vn->vn_mc_handles[i],
971 972 secondary_name, MAC_OPEN_FLAGS_IS_VNIC);
972 973 if (err != 0) {
973 974 /* Remove any that we successfully added */
974 975 vnic_cleanup_secondary_macs(vn, --i);
975 976 return (err);
976 977 }
977 978
978 979 /*
979 980 * Assign a MAC address to the VNIC
980 981 *
981 982 * Normally this would be done with vnic_unicast_add but since
982 983 * we know these are fixed adddresses, and since we need to
983 984 * save this in the proper array slot, we bypass that function
984 985 * and go direct.
985 986 */
986 987 addr = msa->ms_addrs[i - 1];
987 988 err = mac_unicast_add(vn->vn_mc_handles[i], addr, 0,
988 989 &vn->vn_mu_handles[i], vn->vn_vid, &mac_diag);
989 990 if (err != 0) {
990 991 /* Remove any that we successfully added */
991 992 vnic_cleanup_secondary_macs(vn, i);
992 993 return (err);
993 994 }
994 995
995 996 /*
996 997 * Setup the secondary the same way as the primary (i.e.
997 998 * receiver function/argument (e.g. i_dls_link_rx, mac_pkt_drop,
998 999 * etc.), the promisc list, and the resource controls).
999 1000 */
1000 1001 mac_secondary_dup(vn->vn_mc_handles[0], vn->vn_mc_handles[i]);
1001 1002 }
1002 1003
1003 1004 return (0);
1004 1005 }
1005 1006
1006 1007 static int
1007 1008 vnic_get_secondary_macs(vnic_t *vn, uint_t pr_valsize, void *pr_val)
1008 1009 {
1009 1010 int i;
1010 1011 mac_secondary_addr_t msa;
1011 1012
1012 1013 if (pr_valsize < sizeof (msa))
1013 1014 return (EINVAL);
1014 1015
1015 1016 /* Get existing addresses (primary is at 0) */
1016 1017 ASSERT(vn->vn_nhandles < MPT_MAXMACADDR);
1017 1018 for (i = 1; i <= vn->vn_nhandles; i++) {
1018 1019 ASSERT(vn->vn_mc_handles[i] != NULL);
1019 1020 mac_unicast_secondary_get(vn->vn_mc_handles[i],
1020 1021 msa.ms_addrs[i - 1]);
1021 1022 }
1022 1023 msa.ms_addrcnt = vn->vn_nhandles;
1023 1024
1024 1025 bcopy(&msa, pr_val, sizeof (msa));
1025 1026 return (0);
1026 1027 }
1027 1028
1028 1029 /*
1029 1030 * Callback functions for set/get of properties
1030 1031 */
1031 1032 /*ARGSUSED*/
1032 1033 static int
1033 1034 vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
1034 1035 uint_t pr_valsize, const void *pr_val)
1035 1036 {
1036 1037 int err = 0;
1037 1038 vnic_t *vn = m_driver;
1038 1039
1039 1040 switch (pr_num) {
1040 1041 case MAC_PROP_MTU: {
1041 1042 uint32_t mtu;
1042 1043
1043 1044 if (pr_valsize < sizeof (mtu)) {
1044 1045 err = EINVAL;
1045 1046 break;
1046 1047 }
1047 1048 bcopy(pr_val, &mtu, sizeof (mtu));
1048 1049
1049 1050 if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
1050 1051 if (mtu < ANCHOR_VNIC_MIN_MTU ||
1051 1052 mtu > ANCHOR_VNIC_MAX_MTU) {
1052 1053 err = EINVAL;
1053 1054 break;
1054 1055 }
1055 1056 } else {
1056 1057 err = mac_mtu_add(vn->vn_lower_mh, &mtu, B_FALSE);
1057 1058 /*
1058 1059 * If it's not supported to set a value here, translate
1059 1060 * that to EINVAL, so user land gets a better idea of
1060 1061 * what went wrong. This realistically means that they
1061 1062 * violated the output of prop info.
1062 1063 */
1063 1064 if (err == ENOTSUP)
1064 1065 err = EINVAL;
1065 1066 if (err != 0)
1066 1067 break;
1067 1068 VERIFY(mac_mtu_remove(vn->vn_lower_mh,
1068 1069 vn->vn_mtu) == 0);
1069 1070 }
1070 1071 vn->vn_mtu = mtu;
1071 1072 err = mac_maxsdu_update(vn->vn_mh, mtu);
1072 1073 break;
1073 1074 }
1074 1075 case MAC_PROP_SECONDARY_ADDRS: {
1075 1076 mac_secondary_addr_t msa;
1076 1077
1077 1078 bcopy(pr_val, &msa, sizeof (msa));
1078 1079 err = vnic_set_secondary_macs(vn, &msa);
1079 1080 break;
1080 1081 }
1081 1082 default:
1082 1083 err = ENOTSUP;
1083 1084 break;
1084 1085 }
1085 1086 return (err);
1086 1087 }
1087 1088
1088 1089 /* ARGSUSED */
1089 1090 static int
1090 1091 vnic_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
↓ open down ↓ |
1057 lines elided |
↑ open up ↑ |
1091 1092 uint_t pr_valsize, void *pr_val)
1092 1093 {
1093 1094 vnic_t *vn = arg;
1094 1095 int ret = 0;
1095 1096
1096 1097 switch (pr_num) {
1097 1098 case MAC_PROP_SECONDARY_ADDRS:
1098 1099 ret = vnic_get_secondary_macs(vn, pr_valsize, pr_val);
1099 1100 break;
1100 1101 default:
1101 - ret = EINVAL;
1102 + ret = ENOTSUP;
1102 1103 break;
1103 1104 }
1104 1105
1105 1106 return (ret);
1106 1107 }
1107 1108
1108 1109 /* ARGSUSED */
1109 1110 static void vnic_m_propinfo(void *m_driver, const char *pr_name,
1110 1111 mac_prop_id_t pr_num, mac_prop_info_handle_t prh)
1111 1112 {
1112 1113 vnic_t *vn = m_driver;
1113 1114
1114 1115 switch (pr_num) {
1115 1116 case MAC_PROP_MTU:
1116 1117 if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
1117 1118 mac_prop_info_set_range_uint32(prh,
1118 1119 ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU);
1119 1120 } else {
1120 1121 uint32_t max;
1121 1122 mac_perim_handle_t mph;
1122 1123 mac_propval_range_t range;
1123 1124
1124 1125 /*
1125 1126 * The valid range for a VNIC's MTU is the minimum that
1126 1127 * the device supports and the current value of the
1127 1128 * device. A VNIC cannot increase the current MTU of the
1128 1129 * device. Therefore we need to get the range from the
1129 1130 * propinfo endpoint and current mtu from the
1130 1131 * traditional property endpoint.
1131 1132 */
1132 1133 mac_perim_enter_by_mh(vn->vn_lower_mh, &mph);
1133 1134 if (mac_get_prop(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1134 1135 &max, sizeof (uint32_t)) != 0) {
1135 1136 mac_perim_exit(mph);
1136 1137 return;
1137 1138 }
1138 1139
1139 1140 range.mpr_count = 1;
1140 1141 if (mac_prop_info(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
1141 1142 NULL, 0, &range, NULL) != 0) {
1142 1143 mac_perim_exit(mph);
1143 1144 return;
1144 1145 }
1145 1146
1146 1147 mac_prop_info_set_default_uint32(prh, max);
1147 1148 mac_prop_info_set_range_uint32(prh,
1148 1149 range.mpr_range_uint32[0].mpur_min, max);
1149 1150 mac_perim_exit(mph);
1150 1151 }
1151 1152 break;
1152 1153 }
1153 1154 }
1154 1155
1155 1156
1156 1157 int
1157 1158 vnic_info(vnic_info_t *info, cred_t *credp)
1158 1159 {
1159 1160 vnic_t *vnic;
1160 1161 int err;
1161 1162
1162 1163 /* Make sure that the VNIC link is visible from the caller's zone. */
1163 1164 if (!dls_devnet_islinkvisible(info->vn_vnic_id, crgetzoneid(credp)))
1164 1165 return (ENOENT);
1165 1166
1166 1167 rw_enter(&vnic_lock, RW_WRITER);
1167 1168
1168 1169 err = mod_hash_find(vnic_hash, VNIC_HASH_KEY(info->vn_vnic_id),
1169 1170 (mod_hash_val_t *)&vnic);
1170 1171 if (err != 0) {
1171 1172 rw_exit(&vnic_lock);
1172 1173 return (ENOENT);
1173 1174 }
1174 1175
1175 1176 info->vn_link_id = vnic->vn_link_id;
1176 1177 info->vn_mac_addr_type = vnic->vn_addr_type;
1177 1178 info->vn_mac_len = vnic->vn_addr_len;
1178 1179 bcopy(vnic->vn_addr, info->vn_mac_addr, MAXMACADDRLEN);
1179 1180 info->vn_mac_slot = vnic->vn_slot_id;
1180 1181 info->vn_mac_prefix_len = 0;
1181 1182 info->vn_vid = vnic->vn_vid;
1182 1183 info->vn_force = vnic->vn_force;
1183 1184 info->vn_vrid = vnic->vn_vrid;
1184 1185 info->vn_af = vnic->vn_af;
1185 1186
1186 1187 bzero(&info->vn_resource_props, sizeof (mac_resource_props_t));
1187 1188 if (vnic->vn_mch != NULL)
1188 1189 mac_client_get_resources(vnic->vn_mch,
1189 1190 &info->vn_resource_props);
1190 1191
1191 1192 rw_exit(&vnic_lock);
1192 1193 return (0);
1193 1194 }
1194 1195
1195 1196 static void
1196 1197 vnic_notify_cb(void *arg, mac_notify_type_t type)
1197 1198 {
1198 1199 vnic_t *vnic = arg;
1199 1200
1200 1201 /*
1201 1202 * Do not deliver notifications if the vnic is not fully initialized
1202 1203 * or is in process of being torn down.
1203 1204 */
1204 1205 if (!vnic->vn_enabled)
1205 1206 return;
1206 1207
1207 1208 switch (type) {
1208 1209 case MAC_NOTE_UNICST:
1209 1210 /*
1210 1211 * Only the VLAN VNIC needs to be notified with primary MAC
1211 1212 * address change.
1212 1213 */
1213 1214 if (vnic->vn_addr_type != VNIC_MAC_ADDR_TYPE_PRIMARY)
1214 1215 return;
1215 1216
1216 1217 /* the unicast MAC address value */
1217 1218 mac_unicast_primary_get(vnic->vn_lower_mh, vnic->vn_addr);
1218 1219
1219 1220 /* notify its upper layer MAC about MAC address change */
1220 1221 mac_unicst_update(vnic->vn_mh, (const uint8_t *)vnic->vn_addr);
1221 1222 break;
1222 1223
1223 1224 case MAC_NOTE_LINK:
1224 1225 mac_link_update(vnic->vn_mh,
1225 1226 mac_client_stat_get(vnic->vn_mch, MAC_STAT_LINK_STATE));
1226 1227 break;
1227 1228
1228 1229 default:
1229 1230 break;
1230 1231 }
1231 1232 }
↓ open down ↓ |
120 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX