1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <string.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <stropts.h> 33 #include <stdlib.h> 34 #include <errno.h> 35 #include <strings.h> 36 #include <libintl.h> 37 #include <net/if_types.h> 38 #include <net/if_dl.h> 39 #include <sys/dld.h> 40 #include <libdladm_impl.h> 41 #include <libdllink.h> 42 #include <libdlbridge.h> 43 #include <libdlvnic.h> 44 45 /* 46 * VNIC administration library. 47 */ 48 49 /* 50 * Default random MAC address prefix (locally administered). 51 */ 52 static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20}; 53 54 static dladm_status_t dladm_vnic_persist_conf(dladm_handle_t, 55 const char *name, dladm_vnic_attr_t *, 56 datalink_class_t); 57 static const char *dladm_vnic_macaddr2str(const uchar_t *, char *); 58 static dladm_status_t dladm_vnic_str2macaddr(const char *, uchar_t *); 59 60 /* 61 * Convert a diagnostic returned by the kernel into a dladm_status_t. 62 */ 63 static dladm_status_t 64 dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag) 65 { 66 switch (ioc_diag) { 67 case VNIC_IOC_DIAG_MACADDR_INVALID: 68 return (DLADM_STATUS_INVALIDMACADDR); 69 case VNIC_IOC_DIAG_MACADDRLEN_INVALID: 70 return (DLADM_STATUS_INVALIDMACADDRLEN); 71 case VNIC_IOC_DIAG_MACADDR_NIC: 72 return (DLADM_STATUS_INVALIDMACADDRNIC); 73 case VNIC_IOC_DIAG_MACADDR_INUSE: 74 return (DLADM_STATUS_INVALIDMACADDRINUSE); 75 case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID: 76 return (DLADM_STATUS_MACFACTORYSLOTINVALID); 77 case VNIC_IOC_DIAG_MACFACTORYSLOTUSED: 78 return (DLADM_STATUS_MACFACTORYSLOTUSED); 79 case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED: 80 return (DLADM_STATUS_MACFACTORYSLOTALLUSED); 81 case VNIC_IOC_DIAG_MACFACTORYNOTSUP: 82 return (DLADM_STATUS_MACFACTORYNOTSUP); 83 case VNIC_IOC_DIAG_MACPREFIX_INVALID: 84 return (DLADM_STATUS_INVALIDMACPREFIX); 85 case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID: 86 return (DLADM_STATUS_INVALIDMACPREFIXLEN); 87 case VNIC_IOC_DIAG_MACMARGIN_INVALID: 88 return (DLADM_STATUS_INVALID_MACMARGIN); 89 case VNIC_IOC_DIAG_NO_HWRINGS: 90 return (DLADM_STATUS_NO_HWRINGS); 91 } 92 return (DLADM_STATUS_OK); 93 } 94 95 /* 96 * Send a create command to the VNIC driver. 97 */ 98 dladm_status_t 99 i_dladm_vnic_create_sys(dladm_handle_t handle, dladm_vnic_attr_t *attr) 100 { 101 int rc; 102 vnic_ioc_create_t ioc; 103 dladm_status_t status = DLADM_STATUS_OK; 104 105 bzero(&ioc, sizeof (ioc)); 106 ioc.vc_vnic_id = attr->va_vnic_id; 107 ioc.vc_link_id = attr->va_link_id; 108 ioc.vc_mac_addr_type = attr->va_mac_addr_type; 109 ioc.vc_mac_len = attr->va_mac_len; 110 ioc.vc_mac_slot = attr->va_mac_slot; 111 ioc.vc_mac_prefix_len = attr->va_mac_prefix_len; 112 ioc.vc_vid = attr->va_vid; 113 ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0; 114 ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0; 115 116 if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0) 117 bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN); 118 bcopy(&attr->va_resource_props, &ioc.vc_resource_props, 119 sizeof (mac_resource_props_t)); 120 if (attr->va_link_id == DATALINK_INVALID_LINKID) 121 ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR; 122 123 rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_CREATE, &ioc); 124 if (rc < 0) 125 status = dladm_errno2status(errno); 126 127 if (status != DLADM_STATUS_OK) { 128 if (ioc.vc_diag != VNIC_IOC_DIAG_NONE) 129 status = dladm_vnic_diag2status(ioc.vc_diag); 130 } 131 if (status != DLADM_STATUS_OK) 132 return (status); 133 134 attr->va_mac_addr_type = ioc.vc_mac_addr_type; 135 switch (ioc.vc_mac_addr_type) { 136 case VNIC_MAC_ADDR_TYPE_FACTORY: 137 attr->va_mac_slot = ioc.vc_mac_slot; 138 break; 139 case VNIC_MAC_ADDR_TYPE_RANDOM: 140 bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN); 141 attr->va_mac_len = ioc.vc_mac_len; 142 break; 143 } 144 return (status); 145 } 146 147 /* 148 * Get the configuration information of the given VNIC. 149 */ 150 static dladm_status_t 151 i_dladm_vnic_info_active(dladm_handle_t handle, datalink_id_t linkid, 152 dladm_vnic_attr_t *attrp) 153 { 154 vnic_ioc_info_t ioc; 155 vnic_info_t *vnic; 156 int rc; 157 dladm_status_t status = DLADM_STATUS_OK; 158 159 bzero(&ioc, sizeof (ioc)); 160 vnic = &ioc.vi_info; 161 vnic->vn_vnic_id = linkid; 162 163 rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_INFO, &ioc); 164 if (rc != 0) { 165 status = dladm_errno2status(errno); 166 goto bail; 167 } 168 169 attrp->va_vnic_id = vnic->vn_vnic_id; 170 attrp->va_link_id = vnic->vn_link_id; 171 attrp->va_mac_addr_type = vnic->vn_mac_addr_type; 172 bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN); 173 attrp->va_mac_len = vnic->vn_mac_len; 174 attrp->va_mac_slot = vnic->vn_mac_slot; 175 attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len; 176 attrp->va_vid = vnic->vn_vid; 177 attrp->va_force = vnic->vn_force; 178 179 bail: 180 return (status); 181 } 182 183 static dladm_status_t 184 i_dladm_vnic_info_persist(dladm_handle_t handle, datalink_id_t linkid, 185 dladm_vnic_attr_t *attrp) 186 { 187 dladm_conf_t conf; 188 dladm_status_t status; 189 char macstr[ETHERADDRL * 3]; 190 uint64_t u64; 191 datalink_class_t class; 192 193 attrp->va_vnic_id = linkid; 194 if ((status = dladm_read_conf(handle, linkid, &conf)) != 195 DLADM_STATUS_OK) 196 return (status); 197 198 status = dladm_get_conf_field(handle, conf, FLINKOVER, &u64, 199 sizeof (u64)); 200 attrp->va_link_id = ((status == DLADM_STATUS_OK) ? 201 (datalink_id_t)u64 : DATALINK_INVALID_LINKID); 202 203 status = dladm_get_conf_field(handle, conf, FHWRINGS, 204 &attrp->va_hwrings, sizeof (boolean_t)); 205 206 if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) 207 goto done; 208 if (status == DLADM_STATUS_NOTFOUND) 209 attrp->va_hwrings = B_FALSE; 210 211 if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, 212 NULL, NULL, 0)) != DLADM_STATUS_OK) 213 goto done; 214 215 if (class == DATALINK_CLASS_VLAN) { 216 if (attrp->va_link_id == DATALINK_INVALID_LINKID) { 217 status = DLADM_STATUS_BADARG; 218 goto done; 219 } 220 attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY; 221 attrp->va_mac_len = 0; 222 } else { 223 status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64, 224 sizeof (u64)); 225 if (status != DLADM_STATUS_OK) 226 goto done; 227 228 attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64; 229 230 status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64, 231 sizeof (u64)); 232 attrp->va_mac_len = ((status == DLADM_STATUS_OK) ? 233 (uint_t)u64 : ETHERADDRL); 234 235 status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64, 236 sizeof (u64)); 237 attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ? 238 (int)u64 : -1); 239 240 status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN, 241 &u64, sizeof (u64)); 242 attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ? 243 (uint_t)u64 : sizeof (dladm_vnic_def_prefix)); 244 245 status = dladm_get_conf_field(handle, conf, FMACADDR, macstr, 246 sizeof (macstr)); 247 if (status != DLADM_STATUS_OK) 248 goto done; 249 250 status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr); 251 if (status != DLADM_STATUS_OK) 252 goto done; 253 } 254 255 status = dladm_get_conf_field(handle, conf, FVLANID, &u64, 256 sizeof (u64)); 257 attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0); 258 259 260 status = DLADM_STATUS_OK; 261 done: 262 dladm_destroy_conf(handle, conf); 263 return (status); 264 } 265 266 dladm_status_t 267 dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid, 268 dladm_vnic_attr_t *attrp, uint32_t flags) 269 { 270 if (flags == DLADM_OPT_ACTIVE) 271 return (i_dladm_vnic_info_active(handle, linkid, attrp)); 272 else if (flags == DLADM_OPT_PERSIST) 273 return (i_dladm_vnic_info_persist(handle, linkid, attrp)); 274 else 275 return (DLADM_STATUS_BADARG); 276 } 277 278 /* 279 * Remove a VNIC from the kernel. 280 */ 281 dladm_status_t 282 i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid) 283 { 284 vnic_ioc_delete_t ioc; 285 dladm_status_t status = DLADM_STATUS_OK; 286 int rc; 287 288 ioc.vd_vnic_id = linkid; 289 290 rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc); 291 if (rc < 0) 292 status = dladm_errno2status(errno); 293 294 return (status); 295 } 296 297 /* 298 * Convert between MAC address types and their string representations. 299 */ 300 301 typedef struct dladm_vnic_addr_type_s { 302 const char *va_str; 303 vnic_mac_addr_type_t va_type; 304 } dladm_vnic_addr_type_t; 305 306 static dladm_vnic_addr_type_t addr_types[] = { 307 {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 308 {"random", VNIC_MAC_ADDR_TYPE_RANDOM}, 309 {"factory", VNIC_MAC_ADDR_TYPE_FACTORY}, 310 {"auto", VNIC_MAC_ADDR_TYPE_AUTO}, 311 {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY} 312 }; 313 314 #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 315 316 static const char * 317 dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type) 318 { 319 int i; 320 321 for (i = 0; i < NADDR_TYPES; i++) { 322 if (type == addr_types[i].va_type) 323 return (addr_types[i].va_str); 324 } 325 return (NULL); 326 } 327 328 dladm_status_t 329 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 330 { 331 int i; 332 dladm_vnic_addr_type_t *type; 333 334 for (i = 0; i < NADDR_TYPES; i++) { 335 type = &addr_types[i]; 336 if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 337 *val = type->va_type; 338 return (DLADM_STATUS_OK); 339 } 340 } 341 return (DLADM_STATUS_BADARG); 342 } 343 344 /* 345 * Create a new VNIC / VLAN. Update the configuration file and bring it up. 346 */ 347 dladm_status_t 348 dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid, 349 vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 350 int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 351 datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags) 352 { 353 dladm_vnic_attr_t attr; 354 datalink_id_t vnic_id; 355 datalink_class_t class; 356 uint32_t media = DL_ETHER; 357 char name[MAXLINKNAMELEN]; 358 uchar_t tmp_addr[MAXMACADDRLEN]; 359 dladm_status_t status; 360 boolean_t is_vlan; 361 boolean_t is_etherstub; 362 int i; 363 boolean_t vnic_created = B_FALSE; 364 boolean_t conf_set = B_FALSE; 365 366 /* 367 * Sanity test arguments. 368 */ 369 if ((flags & DLADM_OPT_ACTIVE) == 0) 370 return (DLADM_STATUS_NOTSUP); 371 372 is_vlan = ((flags & DLADM_OPT_VLAN) != 0); 373 if (is_vlan && ((vid < 1 || vid > 4094))) 374 return (DLADM_STATUS_VIDINVAL); 375 376 is_etherstub = (linkid == DATALINK_INVALID_LINKID); 377 378 if (mac_len > MAXMACADDRLEN) 379 return (DLADM_STATUS_INVALIDMACADDRLEN); 380 381 if (!dladm_vnic_macaddrtype2str(mac_addr_type)) 382 return (DLADM_STATUS_INVALIDMACADDRTYPE); 383 384 /* 385 * If a random address might be generated, but no prefix 386 * was specified by the caller, use the default MAC address 387 * prefix. 388 */ 389 if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM || 390 mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) && 391 mac_prefix_len == 0) { 392 mac_prefix_len = sizeof (dladm_vnic_def_prefix); 393 mac_addr = tmp_addr; 394 bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len); 395 } 396 397 if ((flags & DLADM_OPT_ANCHOR) == 0) { 398 if ((status = dladm_datalink_id2info(handle, linkid, NULL, 399 &class, &media, NULL, 0)) != DLADM_STATUS_OK) 400 return (status); 401 402 if (class == DATALINK_CLASS_VNIC || 403 class == DATALINK_CLASS_VLAN) 404 return (DLADM_STATUS_BADARG); 405 } else { 406 /* it's an anchor VNIC */ 407 if (linkid != DATALINK_INVALID_LINKID || vid != 0) 408 return (DLADM_STATUS_BADARG); 409 } 410 411 if (vnic == NULL) { 412 flags |= DLADM_OPT_PREFIX; 413 (void) strlcpy(name, "vnic", sizeof (name)); 414 } else { 415 (void) strlcpy(name, vnic, sizeof (name)); 416 } 417 418 class = is_vlan ? DATALINK_CLASS_VLAN : 419 (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC); 420 if ((status = dladm_create_datalink_id(handle, name, class, 421 media, flags, &vnic_id)) != DLADM_STATUS_OK) 422 return (status); 423 424 if ((flags & DLADM_OPT_PREFIX) != 0) { 425 (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id); 426 flags &= ~DLADM_OPT_PREFIX; 427 } 428 429 bzero(&attr, sizeof (attr)); 430 431 /* Extract resource_ctl and cpu_list from proplist */ 432 if (proplist != NULL) { 433 status = dladm_link_proplist_extract(handle, proplist, 434 &attr.va_resource_props); 435 if (status != DLADM_STATUS_OK) 436 goto done; 437 } 438 439 attr.va_vnic_id = vnic_id; 440 attr.va_link_id = linkid; 441 attr.va_mac_addr_type = mac_addr_type; 442 attr.va_mac_len = mac_len; 443 if (mac_slot != NULL) 444 attr.va_mac_slot = *mac_slot; 445 if (mac_len > 0) 446 bcopy(mac_addr, attr.va_mac_addr, mac_len); 447 else if (mac_prefix_len > 0) 448 bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len); 449 attr.va_mac_prefix_len = mac_prefix_len; 450 attr.va_vid = vid; 451 attr.va_force = (flags & DLADM_OPT_FORCE) != 0; 452 attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0; 453 454 status = i_dladm_vnic_create_sys(handle, &attr); 455 if (status != DLADM_STATUS_OK) 456 goto done; 457 vnic_created = B_TRUE; 458 459 /* Save vnic configuration and its properties */ 460 if (!(flags & DLADM_OPT_PERSIST)) 461 goto done; 462 463 status = dladm_vnic_persist_conf(handle, name, &attr, class); 464 if (status != DLADM_STATUS_OK) 465 goto done; 466 conf_set = B_TRUE; 467 468 if (proplist != NULL) { 469 for (i = 0; i < proplist->al_count; i++) { 470 dladm_arg_info_t *aip = &proplist->al_info[i]; 471 472 status = dladm_set_linkprop(handle, vnic_id, 473 aip->ai_name, aip->ai_val, aip->ai_count, 474 DLADM_OPT_PERSIST); 475 if (status != DLADM_STATUS_OK) 476 break; 477 } 478 } 479 480 done: 481 if (status != DLADM_STATUS_OK) { 482 if (conf_set) 483 (void) dladm_remove_conf(handle, vnic_id); 484 if (vnic_created) 485 (void) i_dladm_vnic_delete_sys(handle, vnic_id); 486 (void) dladm_destroy_datalink_id(handle, vnic_id, flags); 487 } else { 488 if (vnic_id_out != NULL) 489 *vnic_id_out = vnic_id; 490 if (mac_slot != NULL) 491 *mac_slot = attr.va_mac_slot; 492 } 493 494 if (is_vlan) { 495 dladm_status_t stat2; 496 497 stat2 = dladm_bridge_refresh(handle, linkid); 498 if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK) 499 status = stat2; 500 } 501 return (status); 502 } 503 504 /* 505 * Delete a VNIC / VLAN. 506 */ 507 dladm_status_t 508 dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 509 { 510 dladm_status_t status; 511 datalink_class_t class; 512 dladm_vnic_attr_t attr; 513 514 if (flags == 0) 515 return (DLADM_STATUS_BADARG); 516 517 if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0) 518 != DLADM_STATUS_OK)) 519 return (DLADM_STATUS_BADARG); 520 521 if ((flags & DLADM_OPT_VLAN) != 0) { 522 if (class != DATALINK_CLASS_VLAN) 523 return (DLADM_STATUS_BADARG); 524 } else { 525 if (class != DATALINK_CLASS_VNIC && 526 class != DATALINK_CLASS_ETHERSTUB) 527 return (DLADM_STATUS_BADARG); 528 } 529 530 if ((flags & DLADM_OPT_ACTIVE) != 0) { 531 status = dladm_vnic_info(handle, linkid, &attr, 532 DLADM_OPT_ACTIVE); 533 if (status != DLADM_STATUS_OK) 534 return (status); 535 status = i_dladm_vnic_delete_sys(handle, linkid); 536 if (status == DLADM_STATUS_OK) { 537 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 538 DLADM_OPT_ACTIVE); 539 (void) dladm_destroy_datalink_id(handle, linkid, 540 DLADM_OPT_ACTIVE); 541 } else if (status != DLADM_STATUS_NOTFOUND || 542 !(flags & DLADM_OPT_PERSIST)) { 543 return (status); 544 } 545 } 546 if ((flags & DLADM_OPT_PERSIST) != 0) { 547 (void) dladm_destroy_datalink_id(handle, linkid, 548 DLADM_OPT_PERSIST); 549 (void) dladm_remove_conf(handle, linkid); 550 } 551 return (dladm_bridge_refresh(handle, linkid)); 552 } 553 554 static const char * 555 dladm_vnic_macaddr2str(const uchar_t *mac, char *buf) 556 { 557 static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 558 559 if (buf == NULL) 560 return (NULL); 561 562 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 563 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 564 else 565 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 566 567 return (buf); 568 } 569 570 static dladm_status_t 571 dladm_vnic_str2macaddr(const char *str, uchar_t *buf) 572 { 573 int len = 0; 574 uchar_t *b = _link_aton(str, &len); 575 576 if (b == NULL || len >= MAXMACADDRLEN) 577 return (DLADM_STATUS_BADARG); 578 579 bcopy(b, buf, len); 580 free(b); 581 return (DLADM_STATUS_OK); 582 } 583 584 585 static dladm_status_t 586 dladm_vnic_persist_conf(dladm_handle_t handle, const char *name, 587 dladm_vnic_attr_t *attrp, datalink_class_t class) 588 { 589 dladm_conf_t conf = DLADM_INVALID_CONF; 590 dladm_status_t status; 591 char macstr[ETHERADDRL * 3]; 592 uint64_t u64; 593 594 if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id, 595 class, DL_ETHER, &conf)) != DLADM_STATUS_OK) 596 return (status); 597 598 if (attrp->va_link_id != DATALINK_INVALID_LINKID) { 599 u64 = attrp->va_link_id; 600 status = dladm_set_conf_field(handle, conf, FLINKOVER, 601 DLADM_TYPE_UINT64, &u64); 602 if (status != DLADM_STATUS_OK) 603 goto done; 604 } 605 606 if (class != DATALINK_CLASS_VLAN) { 607 u64 = attrp->va_mac_addr_type; 608 status = dladm_set_conf_field(handle, conf, FMADDRTYPE, 609 DLADM_TYPE_UINT64, &u64); 610 if (status != DLADM_STATUS_OK) 611 goto done; 612 613 if (attrp->va_mac_len != ETHERADDRL) { 614 u64 = attrp->va_mac_len; 615 status = dladm_set_conf_field(handle, conf, FMADDRLEN, 616 DLADM_TYPE_UINT64, &u64); 617 if (status != DLADM_STATUS_OK) 618 goto done; 619 } 620 } 621 622 if (attrp->va_hwrings) { 623 boolean_t hwrings = attrp->va_hwrings; 624 status = dladm_set_conf_field(handle, conf, FHWRINGS, 625 DLADM_TYPE_BOOLEAN, &hwrings); 626 if (status != DLADM_STATUS_OK) 627 goto done; 628 } 629 630 if (class != DATALINK_CLASS_VLAN) { 631 if (attrp->va_mac_slot != -1) { 632 u64 = attrp->va_mac_slot; 633 status = dladm_set_conf_field(handle, conf, FMADDRSLOT, 634 DLADM_TYPE_UINT64, &u64); 635 if (status != DLADM_STATUS_OK) 636 goto done; 637 } 638 639 if (attrp->va_mac_prefix_len != 640 sizeof (dladm_vnic_def_prefix)) { 641 u64 = attrp->va_mac_prefix_len; 642 status = dladm_set_conf_field(handle, conf, 643 FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64); 644 if (status != DLADM_STATUS_OK) 645 goto done; 646 } 647 648 (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr); 649 status = dladm_set_conf_field(handle, conf, FMACADDR, 650 DLADM_TYPE_STR, macstr); 651 if (status != DLADM_STATUS_OK) 652 goto done; 653 } 654 655 if (attrp->va_vid != 0) { 656 u64 = attrp->va_vid; 657 status = dladm_set_conf_field(handle, conf, FVLANID, 658 DLADM_TYPE_UINT64, &u64); 659 if (status != DLADM_STATUS_OK) 660 goto done; 661 } 662 663 /* 664 * Commit the link configuration. 665 */ 666 status = dladm_write_conf(handle, conf); 667 668 done: 669 dladm_destroy_conf(handle, conf); 670 return (status); 671 } 672 673 typedef struct dladm_vnic_up_arg_s { 674 uint32_t flags; 675 dladm_status_t status; 676 } dladm_vnic_up_arg_t; 677 678 #define DLADM_VNIC_UP_FIRST_WALK 0x1 679 #define DLADM_VNIC_UP_SECOND_WALK 0x2 680 681 static int 682 i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 683 { 684 dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status); 685 dladm_vnic_attr_t attr; 686 dladm_status_t status; 687 dladm_arg_list_t *proplist; 688 uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags; 689 690 bzero(&attr, sizeof (attr)); 691 692 status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST); 693 if (status != DLADM_STATUS_OK) 694 goto done; 695 696 /* 697 * Create the vnics that request hardware group first 698 * Create the vnics that don't request hardware group in the second walk 699 */ 700 if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) || 701 (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings)) 702 goto done; 703 704 /* Get all properties for this vnic */ 705 status = dladm_link_get_proplist(handle, linkid, &proplist); 706 if (status != DLADM_STATUS_OK) 707 goto done; 708 709 if (proplist != NULL) { 710 status = dladm_link_proplist_extract(handle, proplist, 711 &attr.va_resource_props); 712 } 713 714 status = i_dladm_vnic_create_sys(handle, &attr); 715 if (status == DLADM_STATUS_OK) { 716 status = dladm_up_datalink_id(handle, linkid); 717 if (status != DLADM_STATUS_OK) 718 (void) i_dladm_vnic_delete_sys(handle, linkid); 719 } 720 721 done: 722 *statusp = status; 723 return (DLADM_WALK_CONTINUE); 724 } 725 726 dladm_status_t 727 dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 728 { 729 dladm_vnic_up_arg_t vnic_arg; 730 datalink_class_t class; 731 732 class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN : 733 (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB); 734 735 if (linkid == DATALINK_ALL_LINKID) { 736 vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK; 737 (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle, 738 &vnic_arg, class, DATALINK_ANY_MEDIATYPE, 739 DLADM_OPT_PERSIST); 740 vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK; 741 (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle, 742 &vnic_arg, class, DATALINK_ANY_MEDIATYPE, 743 DLADM_OPT_PERSIST); 744 return (DLADM_STATUS_OK); 745 } else { 746 (void) i_dladm_vnic_up(handle, linkid, &vnic_arg); 747 return (vnic_arg.status); 748 } 749 } 750