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