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 char linkover[MAXLINKNAMELEN]; 191 uint64_t u64; 192 datalink_class_t class; 193 194 attrp->va_vnic_id = linkid; 195 if ((status = dladm_read_conf(handle, linkid, &conf)) != 196 DLADM_STATUS_OK) 197 return (status); 198 199 status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover, 200 sizeof (linkover)); 201 if (status != DLADM_STATUS_OK) { 202 /* 203 * This isn't an error, etherstubs don't have a FLINKOVER 204 * property. 205 */ 206 attrp->va_link_id = DATALINK_INVALID_LINKID; 207 } else { 208 if ((status = dladm_name2info(handle, linkover, 209 &attrp->va_link_id, NULL, NULL, NULL)) != DLADM_STATUS_OK) 210 goto done; 211 } 212 213 status = dladm_get_conf_field(handle, conf, FHWRINGS, 214 &attrp->va_hwrings, sizeof (boolean_t)); 215 216 if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) 217 goto done; 218 if (status == DLADM_STATUS_NOTFOUND) 219 attrp->va_hwrings = B_FALSE; 220 221 if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, 222 NULL, NULL, 0)) != DLADM_STATUS_OK) 223 goto done; 224 225 if (class == DATALINK_CLASS_VLAN) { 226 if (attrp->va_link_id == DATALINK_INVALID_LINKID) { 227 status = DLADM_STATUS_BADARG; 228 goto done; 229 } 230 attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY; 231 attrp->va_mac_len = 0; 232 } else { 233 status = dladm_get_conf_field(handle, conf, FMADDRTYPE, &u64, 234 sizeof (u64)); 235 if (status != DLADM_STATUS_OK) 236 goto done; 237 238 attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64; 239 240 status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64, 241 sizeof (u64)); 242 attrp->va_mac_len = ((status == DLADM_STATUS_OK) ? 243 (uint_t)u64 : ETHERADDRL); 244 245 status = dladm_get_conf_field(handle, conf, FMADDRSLOT, &u64, 246 sizeof (u64)); 247 attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ? 248 (int)u64 : -1); 249 250 status = dladm_get_conf_field(handle, conf, FMADDRPREFIXLEN, 251 &u64, sizeof (u64)); 252 attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ? 253 (uint_t)u64 : sizeof (dladm_vnic_def_prefix)); 254 255 status = dladm_get_conf_field(handle, conf, FMACADDR, macstr, 256 sizeof (macstr)); 257 if (status != DLADM_STATUS_OK) 258 goto done; 259 260 status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr); 261 if (status != DLADM_STATUS_OK) 262 goto done; 263 } 264 265 status = dladm_get_conf_field(handle, conf, FVLANID, &u64, 266 sizeof (u64)); 267 attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0); 268 269 270 status = DLADM_STATUS_OK; 271 done: 272 dladm_destroy_conf(handle, conf); 273 return (status); 274 } 275 276 dladm_status_t 277 dladm_vnic_info(dladm_handle_t handle, datalink_id_t linkid, 278 dladm_vnic_attr_t *attrp, uint32_t flags) 279 { 280 if (flags == DLADM_OPT_ACTIVE) 281 return (i_dladm_vnic_info_active(handle, linkid, attrp)); 282 else if (flags == DLADM_OPT_PERSIST) 283 return (i_dladm_vnic_info_persist(handle, linkid, attrp)); 284 else 285 return (DLADM_STATUS_BADARG); 286 } 287 288 /* 289 * Remove a VNIC from the kernel. 290 */ 291 dladm_status_t 292 i_dladm_vnic_delete_sys(dladm_handle_t handle, datalink_id_t linkid) 293 { 294 vnic_ioc_delete_t ioc; 295 dladm_status_t status = DLADM_STATUS_OK; 296 int rc; 297 298 ioc.vd_vnic_id = linkid; 299 300 rc = ioctl(dladm_dld_fd(handle), VNIC_IOC_DELETE, &ioc); 301 if (rc < 0) 302 status = dladm_errno2status(errno); 303 304 return (status); 305 } 306 307 /* 308 * Convert between MAC address types and their string representations. 309 */ 310 311 typedef struct dladm_vnic_addr_type_s { 312 const char *va_str; 313 vnic_mac_addr_type_t va_type; 314 } dladm_vnic_addr_type_t; 315 316 static dladm_vnic_addr_type_t addr_types[] = { 317 {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 318 {"random", VNIC_MAC_ADDR_TYPE_RANDOM}, 319 {"factory", VNIC_MAC_ADDR_TYPE_FACTORY}, 320 {"auto", VNIC_MAC_ADDR_TYPE_AUTO}, 321 {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY} 322 }; 323 324 #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 325 326 static const char * 327 dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type) 328 { 329 int i; 330 331 for (i = 0; i < NADDR_TYPES; i++) { 332 if (type == addr_types[i].va_type) 333 return (addr_types[i].va_str); 334 } 335 return (NULL); 336 } 337 338 dladm_status_t 339 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 340 { 341 int i; 342 dladm_vnic_addr_type_t *type; 343 344 for (i = 0; i < NADDR_TYPES; i++) { 345 type = &addr_types[i]; 346 if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 347 *val = type->va_type; 348 return (DLADM_STATUS_OK); 349 } 350 } 351 return (DLADM_STATUS_BADARG); 352 } 353 354 /* 355 * Create a new VNIC / VLAN. Update the configuration file and bring it up. 356 */ 357 dladm_status_t 358 dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid, 359 vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 360 int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 361 datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags) 362 { 363 dladm_vnic_attr_t attr; 364 datalink_id_t vnic_id; 365 datalink_class_t class; 366 uint32_t media = DL_ETHER; 367 char name[MAXLINKNAMELEN]; 368 uchar_t tmp_addr[MAXMACADDRLEN]; 369 dladm_status_t status; 370 boolean_t is_vlan; 371 boolean_t is_etherstub; 372 int i; 373 boolean_t vnic_created = B_FALSE; 374 boolean_t conf_set = B_FALSE; 375 376 /* 377 * Sanity test arguments. 378 */ 379 if ((flags & DLADM_OPT_ACTIVE) == 0) 380 return (DLADM_STATUS_NOTSUP); 381 382 is_vlan = ((flags & DLADM_OPT_VLAN) != 0); 383 if (is_vlan && ((vid < 1 || vid > 4094))) 384 return (DLADM_STATUS_VIDINVAL); 385 386 is_etherstub = (linkid == DATALINK_INVALID_LINKID); 387 388 if (mac_len > MAXMACADDRLEN) 389 return (DLADM_STATUS_INVALIDMACADDRLEN); 390 391 if (!dladm_vnic_macaddrtype2str(mac_addr_type)) 392 return (DLADM_STATUS_INVALIDMACADDRTYPE); 393 394 /* 395 * If a random address might be generated, but no prefix 396 * was specified by the caller, use the default MAC address 397 * prefix. 398 */ 399 if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM || 400 mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) && 401 mac_prefix_len == 0) { 402 mac_prefix_len = sizeof (dladm_vnic_def_prefix); 403 mac_addr = tmp_addr; 404 bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len); 405 } 406 407 if ((flags & DLADM_OPT_ANCHOR) == 0) { 408 if ((status = dladm_datalink_id2info(handle, linkid, NULL, 409 &class, &media, NULL, 0)) != DLADM_STATUS_OK) 410 return (status); 411 412 if (class == DATALINK_CLASS_VNIC || 413 class == DATALINK_CLASS_VLAN) 414 return (DLADM_STATUS_BADARG); 415 } else { 416 /* it's an anchor VNIC */ 417 if (linkid != DATALINK_INVALID_LINKID || vid != 0) 418 return (DLADM_STATUS_BADARG); 419 } 420 421 if (vnic == NULL) { 422 flags |= DLADM_OPT_PREFIX; 423 (void) strlcpy(name, "vnic", sizeof (name)); 424 } else { 425 (void) strlcpy(name, vnic, sizeof (name)); 426 } 427 428 class = is_vlan ? DATALINK_CLASS_VLAN : 429 (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC); 430 if ((status = dladm_create_datalink_id(handle, name, class, 431 media, flags, &vnic_id)) != DLADM_STATUS_OK) 432 return (status); 433 434 if ((flags & DLADM_OPT_PREFIX) != 0) { 435 (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id); 436 flags &= ~DLADM_OPT_PREFIX; 437 } 438 439 bzero(&attr, sizeof (attr)); 440 441 /* Extract resource_ctl and cpu_list from proplist */ 442 if (proplist != NULL) { 443 status = dladm_link_proplist_extract(handle, proplist, 444 &attr.va_resource_props); 445 if (status != DLADM_STATUS_OK) 446 goto done; 447 } 448 449 attr.va_vnic_id = vnic_id; 450 attr.va_link_id = linkid; 451 attr.va_mac_addr_type = mac_addr_type; 452 attr.va_mac_len = mac_len; 453 if (mac_slot != NULL) 454 attr.va_mac_slot = *mac_slot; 455 if (mac_len > 0) 456 bcopy(mac_addr, attr.va_mac_addr, mac_len); 457 else if (mac_prefix_len > 0) 458 bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len); 459 attr.va_mac_prefix_len = mac_prefix_len; 460 attr.va_vid = vid; 461 attr.va_force = (flags & DLADM_OPT_FORCE) != 0; 462 attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0; 463 464 status = i_dladm_vnic_create_sys(handle, &attr); 465 if (status != DLADM_STATUS_OK) 466 goto done; 467 vnic_created = B_TRUE; 468 469 /* Save vnic configuration and its properties */ 470 if (!(flags & DLADM_OPT_PERSIST)) 471 goto done; 472 473 status = dladm_vnic_persist_conf(handle, name, &attr, class); 474 if (status != DLADM_STATUS_OK) 475 goto done; 476 conf_set = B_TRUE; 477 478 if (proplist != NULL) { 479 for (i = 0; i < proplist->al_count; i++) { 480 dladm_arg_info_t *aip = &proplist->al_info[i]; 481 482 status = dladm_set_linkprop(handle, vnic_id, 483 aip->ai_name, aip->ai_val, aip->ai_count, 484 DLADM_OPT_PERSIST); 485 if (status != DLADM_STATUS_OK) 486 break; 487 } 488 } 489 490 done: 491 if (status != DLADM_STATUS_OK) { 492 if (conf_set) 493 (void) dladm_remove_conf(handle, vnic_id); 494 if (vnic_created) 495 (void) i_dladm_vnic_delete_sys(handle, vnic_id); 496 (void) dladm_destroy_datalink_id(handle, vnic_id, flags); 497 } else { 498 if (vnic_id_out != NULL) 499 *vnic_id_out = vnic_id; 500 if (mac_slot != NULL) 501 *mac_slot = attr.va_mac_slot; 502 } 503 504 if (is_vlan) { 505 dladm_status_t stat2; 506 507 stat2 = dladm_bridge_refresh(handle, linkid); 508 if (status == DLADM_STATUS_OK && stat2 != DLADM_STATUS_OK) 509 status = stat2; 510 } 511 return (status); 512 } 513 514 /* 515 * Delete a VNIC / VLAN. 516 */ 517 dladm_status_t 518 dladm_vnic_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 519 { 520 dladm_status_t status; 521 datalink_class_t class; 522 523 if (flags == 0) 524 return (DLADM_STATUS_BADARG); 525 526 if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 0) 527 != DLADM_STATUS_OK)) 528 return (DLADM_STATUS_BADARG); 529 530 if ((flags & DLADM_OPT_VLAN) != 0) { 531 if (class != DATALINK_CLASS_VLAN) 532 return (DLADM_STATUS_BADARG); 533 } else { 534 if (class != DATALINK_CLASS_VNIC && 535 class != DATALINK_CLASS_ETHERSTUB) 536 return (DLADM_STATUS_BADARG); 537 } 538 539 if ((flags & DLADM_OPT_ACTIVE) != 0) { 540 status = i_dladm_vnic_delete_sys(handle, linkid); 541 if (status == DLADM_STATUS_OK) { 542 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 543 DLADM_OPT_ACTIVE); 544 (void) dladm_destroy_datalink_id(handle, linkid, 545 DLADM_OPT_ACTIVE); 546 } else if (status != DLADM_STATUS_NOTFOUND || 547 !(flags & DLADM_OPT_PERSIST)) { 548 return (status); 549 } 550 } 551 if ((flags & DLADM_OPT_PERSIST) != 0) { 552 (void) dladm_remove_conf(handle, linkid); 553 (void) dladm_destroy_datalink_id(handle, linkid, 554 DLADM_OPT_PERSIST); 555 } 556 return (dladm_bridge_refresh(handle, linkid)); 557 } 558 559 static const char * 560 dladm_vnic_macaddr2str(const uchar_t *mac, char *buf) 561 { 562 static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 563 564 if (buf == NULL) 565 return (NULL); 566 567 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 568 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 569 else 570 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 571 572 return (buf); 573 } 574 575 static dladm_status_t 576 dladm_vnic_str2macaddr(const char *str, uchar_t *buf) 577 { 578 int len = 0; 579 uchar_t *b = _link_aton(str, &len); 580 581 if (b == NULL || len >= MAXMACADDRLEN) 582 return (DLADM_STATUS_BADARG); 583 584 bcopy(b, buf, len); 585 free(b); 586 return (DLADM_STATUS_OK); 587 } 588 589 590 static dladm_status_t 591 dladm_vnic_persist_conf(dladm_handle_t handle, const char *name, 592 dladm_vnic_attr_t *attrp, datalink_class_t class) 593 { 594 dladm_conf_t conf = DLADM_INVALID_CONF; 595 dladm_status_t status; 596 char macstr[ETHERADDRL * 3]; 597 char linkover[MAXLINKNAMELEN]; 598 uint64_t u64; 599 600 if ((status = dladm_create_conf(handle, name, attrp->va_vnic_id, 601 class, DL_ETHER, &conf)) != DLADM_STATUS_OK) 602 return (status); 603 604 if (attrp->va_link_id != DATALINK_INVALID_LINKID) { 605 status = dladm_datalink_id2info(handle, attrp->va_link_id, NULL, 606 NULL, NULL, linkover, sizeof (linkover)); 607 if (status != DLADM_STATUS_OK) 608 goto done; 609 status = dladm_set_conf_field(handle, conf, FLINKOVER, 610 DLADM_TYPE_STR, linkover); 611 if (status != DLADM_STATUS_OK) 612 goto done; 613 } 614 615 if (class != DATALINK_CLASS_VLAN) { 616 u64 = attrp->va_mac_addr_type; 617 status = dladm_set_conf_field(handle, conf, FMADDRTYPE, 618 DLADM_TYPE_UINT64, &u64); 619 if (status != DLADM_STATUS_OK) 620 goto done; 621 622 if (attrp->va_mac_len != ETHERADDRL) { 623 u64 = attrp->va_mac_len; 624 status = dladm_set_conf_field(handle, conf, FMADDRLEN, 625 DLADM_TYPE_UINT64, &u64); 626 if (status != DLADM_STATUS_OK) 627 goto done; 628 } 629 } 630 631 if (attrp->va_hwrings) { 632 boolean_t hwrings = attrp->va_hwrings; 633 status = dladm_set_conf_field(handle, conf, FHWRINGS, 634 DLADM_TYPE_BOOLEAN, &hwrings); 635 if (status != DLADM_STATUS_OK) 636 goto done; 637 } 638 639 if (class != DATALINK_CLASS_VLAN) { 640 if (attrp->va_mac_slot != -1) { 641 u64 = attrp->va_mac_slot; 642 status = dladm_set_conf_field(handle, conf, FMADDRSLOT, 643 DLADM_TYPE_UINT64, &u64); 644 if (status != DLADM_STATUS_OK) 645 goto done; 646 } 647 648 if (attrp->va_mac_prefix_len != 649 sizeof (dladm_vnic_def_prefix)) { 650 u64 = attrp->va_mac_prefix_len; 651 status = dladm_set_conf_field(handle, conf, 652 FMADDRPREFIXLEN, DLADM_TYPE_UINT64, &u64); 653 if (status != DLADM_STATUS_OK) 654 goto done; 655 } 656 657 (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr); 658 status = dladm_set_conf_field(handle, conf, FMACADDR, 659 DLADM_TYPE_STR, macstr); 660 if (status != DLADM_STATUS_OK) 661 goto done; 662 } 663 664 if (attrp->va_vid != 0) { 665 u64 = attrp->va_vid; 666 status = dladm_set_conf_field(handle, conf, FVLANID, 667 DLADM_TYPE_UINT64, &u64); 668 if (status != DLADM_STATUS_OK) 669 goto done; 670 } 671 672 /* 673 * Commit the link configuration. 674 */ 675 status = dladm_write_conf(handle, conf); 676 677 done: 678 dladm_destroy_conf(handle, conf); 679 return (status); 680 } 681 682 typedef struct dladm_vnic_up_arg_s { 683 uint32_t flags; 684 dladm_status_t status; 685 } dladm_vnic_up_arg_t; 686 687 #define DLADM_VNIC_UP_FIRST_WALK 0x1 688 #define DLADM_VNIC_UP_SECOND_WALK 0x2 689 690 static int 691 i_dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 692 { 693 dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status); 694 dladm_vnic_attr_t attr; 695 dladm_status_t status; 696 dladm_arg_list_t *proplist; 697 uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags; 698 699 bzero(&attr, sizeof (attr)); 700 701 status = dladm_vnic_info(handle, linkid, &attr, DLADM_OPT_PERSIST); 702 if (status != DLADM_STATUS_OK) 703 goto done; 704 705 /* 706 * Create the vnics that request hardware group first 707 * Create the vnics that don't request hardware group in the second walk 708 */ 709 if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) || 710 (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings)) 711 goto done; 712 713 /* Get all properties for this vnic */ 714 status = dladm_link_get_proplist(handle, linkid, &proplist); 715 if (status != DLADM_STATUS_OK) 716 goto done; 717 718 if (proplist != NULL) { 719 status = dladm_link_proplist_extract(handle, proplist, 720 &attr.va_resource_props); 721 } 722 723 status = i_dladm_vnic_create_sys(handle, &attr); 724 if (status == DLADM_STATUS_OK) { 725 status = dladm_up_datalink_id(handle, linkid); 726 if (status != DLADM_STATUS_OK) 727 (void) i_dladm_vnic_delete_sys(handle, linkid); 728 } 729 730 done: 731 *statusp = status; 732 return (DLADM_WALK_CONTINUE); 733 } 734 735 dladm_status_t 736 dladm_vnic_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 737 { 738 dladm_vnic_up_arg_t vnic_arg; 739 datalink_class_t class; 740 741 class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN : 742 (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB); 743 744 if (linkid == DATALINK_ALL_LINKID) { 745 vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK; 746 (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle, 747 &vnic_arg, class, DATALINK_ANY_MEDIATYPE, 748 DLADM_OPT_PERSIST); 749 vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK; 750 (void) dladm_walk_datalink_id(i_dladm_vnic_up, handle, 751 &vnic_arg, class, DATALINK_ANY_MEDIATYPE, 752 DLADM_OPT_PERSIST); 753 return (DLADM_STATUS_OK); 754 } else { 755 (void) i_dladm_vnic_up(handle, linkid, &vnic_arg); 756 return (vnic_arg.status); 757 } 758 } 759