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 <string.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <stropts.h> 32 #include <ctype.h> 33 #include <errno.h> 34 #include <stdlib.h> 35 #include <door.h> 36 #include <sys/mman.h> 37 #include <libscf.h> 38 #include <libscf_priv.h> 39 #include <libdllink.h> 40 #include <libdlbridge.h> 41 #include <libdladm_impl.h> 42 #include <stp_in.h> 43 #include <net/bridge.h> 44 #include <net/trill.h> 45 #include <sys/socket.h> 46 #include <sys/dld_ioc.h> 47 48 /* 49 * Bridge Administration Library. 50 * 51 * This library is used by administration tools such as dladm(1M) to configure 52 * bridges, and by the bridge daemon to retrieve configuration information. 53 */ 54 55 #define BRIDGE_SVC_NAME "network/bridge" 56 #define TRILL_SVC_NAME "network/routing/trill" 57 58 #define DEFAULT_TIMEOUT 60000000 59 #define INIT_WAIT_USECS 50000 60 #define MAXPORTS 256 61 62 typedef struct scf_state { 63 scf_handle_t *ss_handle; 64 scf_instance_t *ss_inst; 65 scf_service_t *ss_svc; 66 scf_snapshot_t *ss_snap; 67 scf_propertygroup_t *ss_pg; 68 scf_property_t *ss_prop; 69 } scf_state_t; 70 71 static void 72 shut_down_scf(scf_state_t *sstate) 73 { 74 scf_instance_destroy(sstate->ss_inst); 75 (void) scf_handle_unbind(sstate->ss_handle); 76 scf_handle_destroy(sstate->ss_handle); 77 } 78 79 static char * 80 alloc_fmri(const char *service, const char *instance_name) 81 { 82 ssize_t max_fmri; 83 char *fmri; 84 85 /* If the limit is unknown, then use an arbitrary value */ 86 if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1) 87 max_fmri = 1024; 88 if ((fmri = malloc(max_fmri)) != NULL) { 89 (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service, 90 instance_name); 91 } 92 return (fmri); 93 } 94 95 /* 96 * Start up SCF and bind the requested instance alone. 97 */ 98 static int 99 bind_instance(const char *service, const char *instance_name, 100 scf_state_t *sstate) 101 { 102 char *fmri = NULL; 103 104 (void) memset(sstate, 0, sizeof (*sstate)); 105 106 if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 107 return (-1); 108 109 if (scf_handle_bind(sstate->ss_handle) != 0) 110 goto failure; 111 sstate->ss_inst = scf_instance_create(sstate->ss_handle); 112 if (sstate->ss_inst == NULL) 113 goto failure; 114 115 fmri = alloc_fmri(service, instance_name); 116 117 if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL, 118 sstate->ss_inst, NULL, NULL, 119 SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) 120 goto failure; 121 free(fmri); 122 return (0); 123 124 failure: 125 free(fmri); 126 shut_down_scf(sstate); 127 return (-1); 128 } 129 130 /* 131 * Start up SCF and an exact FMRI. This is used for creating new instances and 132 * enable/disable actions. 133 */ 134 static dladm_status_t 135 exact_instance(const char *fmri, scf_state_t *sstate) 136 { 137 dladm_status_t status; 138 139 (void) memset(sstate, 0, sizeof (*sstate)); 140 141 if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 142 return (DLADM_STATUS_NOMEM); 143 144 status = DLADM_STATUS_FAILED; 145 if (scf_handle_bind(sstate->ss_handle) != 0) 146 goto failure; 147 sstate->ss_svc = scf_service_create(sstate->ss_handle); 148 if (sstate->ss_svc == NULL) 149 goto failure; 150 if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, 151 sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 152 if (scf_error() == SCF_ERROR_NOT_FOUND) 153 status = DLADM_STATUS_OPTMISSING; 154 goto failure; 155 } 156 sstate->ss_inst = scf_instance_create(sstate->ss_handle); 157 if (sstate->ss_inst == NULL) 158 goto failure; 159 return (DLADM_STATUS_OK); 160 161 failure: 162 shut_down_scf(sstate); 163 return (status); 164 } 165 166 static void 167 drop_composed(scf_state_t *sstate) 168 { 169 scf_property_destroy(sstate->ss_prop); 170 scf_pg_destroy(sstate->ss_pg); 171 scf_snapshot_destroy(sstate->ss_snap); 172 } 173 174 /* 175 * This function sets up a composed view of the configuration information for 176 * the specified instance. When this is done, the get_property() function 177 * should be able to return individual parameters. 178 */ 179 static int 180 get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate) 181 { 182 sstate->ss_snap = NULL; 183 sstate->ss_pg = NULL; 184 sstate->ss_prop = NULL; 185 186 if (snap) { 187 sstate->ss_snap = scf_snapshot_create(sstate->ss_handle); 188 if (sstate->ss_snap == NULL) 189 goto failure; 190 if (scf_instance_get_snapshot(sstate->ss_inst, "running", 191 sstate->ss_snap) != 0) 192 goto failure; 193 } 194 if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL) 195 goto failure; 196 if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg, 197 sstate->ss_pg) != 0) 198 goto failure; 199 if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) == 200 NULL) 201 goto failure; 202 return (0); 203 204 failure: 205 drop_composed(sstate); 206 return (-1); 207 } 208 209 static int 210 get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer) 211 { 212 scf_value_t *val; 213 int retv; 214 215 if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 216 return (-1); 217 if ((val = scf_value_create(sstate->ss_handle)) == NULL) 218 return (-1); 219 220 if (scf_property_get_value(sstate->ss_prop, val) == 0 && 221 scf_value_get_count(val, answer) == 0) 222 retv = 0; 223 else 224 retv = -1; 225 scf_value_destroy(val); 226 return (retv); 227 } 228 229 static int 230 get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer) 231 { 232 scf_value_t *val; 233 int retv; 234 uint8_t bval; 235 236 if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 237 return (-1); 238 if ((val = scf_value_create(sstate->ss_handle)) == NULL) 239 return (-1); 240 241 if (scf_property_get_value(sstate->ss_prop, val) == 0 && 242 scf_value_get_boolean(val, &bval) == 0) { 243 retv = 0; 244 *answer = bval != 0; 245 } else { 246 retv = -1; 247 } 248 scf_value_destroy(val); 249 return (retv); 250 } 251 252 static dladm_status_t 253 bridge_door_call(const char *instname, bridge_door_type_t dtype, 254 datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp, 255 boolean_t is_list) 256 { 257 char doorname[MAXPATHLEN]; 258 int did, retv, etmp; 259 bridge_door_cmd_t *bdc; 260 door_arg_t arg; 261 262 (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME, 263 instname); 264 265 /* Knock on the door */ 266 did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK); 267 if (did == -1) 268 return (dladm_errno2status(errno)); 269 270 if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) { 271 (void) close(did); 272 return (DLADM_STATUS_NOMEM); 273 } 274 bdc->bdc_type = dtype; 275 bdc->bdc_linkid = linkid; 276 if (inlen != 0) 277 (void) memcpy(bdc + 1, *bufp, inlen); 278 279 (void) memset(&arg, 0, sizeof (arg)); 280 arg.data_ptr = (char *)bdc; 281 arg.data_size = sizeof (*bdc) + inlen; 282 arg.rbuf = *bufp; 283 arg.rsize = *buflenp; 284 285 /* The door_call function doesn't restart, so take care of that */ 286 do { 287 errno = 0; 288 if ((retv = door_call(did, &arg)) == 0) 289 break; 290 } while (errno == EINTR); 291 292 /* If we get an unexpected response, then return an error */ 293 if (retv == 0) { 294 /* The daemon returns a single int for errors */ 295 /* LINTED: pointer alignment */ 296 if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) { 297 retv = -1; 298 /* LINTED: pointer alignment */ 299 errno = *(int *)arg.rbuf; 300 } 301 /* Terminated daemon returns with zero data */ 302 if (arg.data_size == 0) { 303 retv = -1; 304 errno = EBADF; 305 } 306 } 307 308 if (retv == 0) { 309 if (arg.rbuf != *bufp) { 310 if (is_list) { 311 void *newp; 312 313 newp = realloc(*bufp, arg.data_size); 314 if (newp == NULL) { 315 retv = -1; 316 } else { 317 *bufp = newp; 318 (void) memcpy(*bufp, arg.rbuf, 319 arg.data_size); 320 } 321 } 322 (void) munmap(arg.rbuf, arg.rsize); 323 } 324 if (is_list) { 325 *buflenp = arg.data_size; 326 } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) { 327 errno = EINVAL; 328 retv = -1; 329 } 330 } 331 332 etmp = errno; 333 (void) close(did); 334 335 /* Revoked door is the same as no door at all */ 336 if (etmp == EBADF) 337 etmp = ENOENT; 338 339 return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp)); 340 } 341 342 /* 343 * Wrapper function for making per-port calls. 344 */ 345 static dladm_status_t 346 port_door_call(dladm_handle_t handle, datalink_id_t linkid, 347 bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen) 348 { 349 char bridge[MAXLINKNAMELEN]; 350 dladm_status_t status; 351 352 status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 353 if (status != DLADM_STATUS_OK) 354 return (status); 355 return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen, 356 B_FALSE)); 357 } 358 359 static dladm_status_t 360 bridge_refresh(const char *bridge) 361 { 362 dladm_status_t status; 363 int twoints[2]; 364 void *bdptr; 365 size_t buflen; 366 char *fmri; 367 int refresh_count; 368 369 buflen = sizeof (twoints); 370 bdptr = twoints; 371 status = bridge_door_call(bridge, bdcBridgeGetRefreshCount, 372 DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE); 373 if (status == DLADM_STATUS_NOTFOUND) 374 return (DLADM_STATUS_OK); 375 if (status != DLADM_STATUS_OK) 376 return (status); 377 refresh_count = twoints[0]; 378 if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL) 379 return (DLADM_STATUS_NOMEM); 380 status = smf_refresh_instance(fmri) == 0 ? 381 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 382 free(fmri); 383 if (status == DLADM_STATUS_OK) { 384 int i = 0; 385 386 /* 387 * SMF doesn't give any synchronous behavior or dependency 388 * ordering for refresh operations, so we have to invent our 389 * own mechanism here. Get the refresh counter from the 390 * daemon, and wait for it to change. It's not pretty, but 391 * it's sufficient. 392 */ 393 while (++i <= 10) { 394 buflen = sizeof (twoints); 395 bdptr = twoints; 396 status = bridge_door_call(bridge, 397 bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID, 398 &bdptr, 0, &buflen, B_FALSE); 399 if (status != DLADM_STATUS_OK) 400 break; 401 if (twoints[0] != refresh_count) 402 break; 403 (void) usleep(100000); 404 } 405 fmri = alloc_fmri(TRILL_SVC_NAME, bridge); 406 if (fmri == NULL) 407 return (DLADM_STATUS_NOMEM); 408 status = smf_refresh_instance(fmri) == 0 || 409 scf_error() == SCF_ERROR_NOT_FOUND ? 410 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 411 free(fmri); 412 } 413 return (status); 414 } 415 416 /* 417 * Look up bridge property values from SCF and return them. 418 */ 419 dladm_status_t 420 dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg, 421 dladm_bridge_prot_t *brprotp) 422 { 423 scf_state_t sstate; 424 uint64_t value; 425 boolean_t trill_enabled; 426 427 cfg->field_mask = 0; 428 cfg->bridge_priority = DEF_BR_PRIO; 429 cfg->max_age = DEF_BR_MAXAGE; 430 cfg->hello_time = DEF_BR_HELLOT; 431 cfg->forward_delay = DEF_BR_FWDELAY; 432 cfg->force_version = DEF_FORCE_VERS; 433 434 (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name)); 435 436 *brprotp = DLADM_BRIDGE_PROT_STP; 437 438 /* It's ok for this to be missing; it's installed separately */ 439 if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) { 440 trill_enabled = B_FALSE; 441 if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) == 442 0) { 443 (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 444 &trill_enabled); 445 if (trill_enabled) 446 *brprotp = DLADM_BRIDGE_PROT_TRILL; 447 drop_composed(&sstate); 448 } 449 if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE, 450 &sstate) == 0) { 451 (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 452 &trill_enabled); 453 if (trill_enabled) 454 *brprotp = DLADM_BRIDGE_PROT_TRILL; 455 drop_composed(&sstate); 456 } 457 shut_down_scf(&sstate); 458 } 459 460 cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ? 461 STP_ENABLED : STP_DISABLED; 462 cfg->field_mask |= BR_CFG_STATE; 463 464 if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 465 return (DLADM_STATUS_REPOSITORYINVAL); 466 467 if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 468 shut_down_scf(&sstate); 469 return (DLADM_STATUS_REPOSITORYINVAL); 470 } 471 472 if (get_count("priority", &sstate, &value) == 0) { 473 cfg->bridge_priority = value; 474 cfg->field_mask |= BR_CFG_PRIO; 475 } 476 if (get_count("max-age", &sstate, &value) == 0) { 477 cfg->max_age = value / IEEE_TIMER_SCALE; 478 cfg->field_mask |= BR_CFG_AGE; 479 } 480 if (get_count("hello-time", &sstate, &value) == 0) { 481 cfg->hello_time = value / IEEE_TIMER_SCALE; 482 cfg->field_mask |= BR_CFG_HELLO; 483 } 484 if (get_count("forward-delay", &sstate, &value) == 0) { 485 cfg->forward_delay = value / IEEE_TIMER_SCALE; 486 cfg->field_mask |= BR_CFG_DELAY; 487 } 488 if (get_count("force-protocol", &sstate, &value) == 0) { 489 cfg->force_version = value; 490 cfg->field_mask |= BR_CFG_FORCE_VER; 491 } 492 493 drop_composed(&sstate); 494 shut_down_scf(&sstate); 495 return (DLADM_STATUS_OK); 496 } 497 498 /* 499 * Retrieve special non-settable and undocumented parameters. 500 */ 501 dladm_status_t 502 dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp, 503 uint32_t *tablemaxp) 504 { 505 scf_state_t sstate; 506 uint64_t value; 507 508 *debugp = B_FALSE; 509 *tablemaxp = 10000; 510 511 if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 512 return (DLADM_STATUS_REPOSITORYINVAL); 513 514 if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 515 shut_down_scf(&sstate); 516 return (DLADM_STATUS_REPOSITORYINVAL); 517 } 518 519 (void) get_boolean("debug", &sstate, debugp); 520 if (get_count("table-maximum", &sstate, &value) == 0) 521 *tablemaxp = (uint32_t)value; 522 523 drop_composed(&sstate); 524 shut_down_scf(&sstate); 525 return (DLADM_STATUS_OK); 526 } 527 528 static boolean_t 529 set_count_property(scf_handle_t *handle, scf_transaction_t *tran, 530 const char *propname, uint64_t propval) 531 { 532 scf_transaction_entry_t *entry; 533 scf_value_t *value = NULL; 534 535 if ((entry = scf_entry_create(handle)) == NULL) 536 return (B_FALSE); 537 538 if ((value = scf_value_create(handle)) == NULL) 539 goto out; 540 if (scf_transaction_property_new(tran, entry, propname, 541 SCF_TYPE_COUNT) != 0 && 542 scf_transaction_property_change(tran, entry, propname, 543 SCF_TYPE_COUNT) != 0) 544 goto out; 545 scf_value_set_count(value, propval); 546 if (scf_entry_add_value(entry, value) == 0) 547 return (B_TRUE); 548 549 out: 550 if (value != NULL) 551 scf_value_destroy(value); 552 553 scf_entry_destroy_children(entry); 554 scf_entry_destroy(entry); 555 556 return (B_FALSE); 557 } 558 559 static boolean_t 560 set_string_property(scf_handle_t *handle, scf_transaction_t *tran, 561 const char *propname, const char *propval) 562 { 563 scf_transaction_entry_t *entry; 564 scf_value_t *value = NULL; 565 566 if ((entry = scf_entry_create(handle)) == NULL) 567 return (B_FALSE); 568 569 if ((value = scf_value_create(handle)) == NULL) 570 goto out; 571 if (scf_transaction_property_new(tran, entry, propname, 572 SCF_TYPE_ASTRING) != 0 && 573 scf_transaction_property_change(tran, entry, propname, 574 SCF_TYPE_ASTRING) != 0) 575 goto out; 576 if (scf_value_set_astring(value, propval) != 0) 577 goto out; 578 if (scf_entry_add_value(entry, value) == 0) 579 return (B_TRUE); 580 581 out: 582 if (value != NULL) 583 scf_value_destroy(value); 584 585 scf_entry_destroy_children(entry); 586 scf_entry_destroy(entry); 587 588 return (B_FALSE); 589 } 590 591 static boolean_t 592 set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran, 593 const char *propname, const char *propval) 594 { 595 scf_transaction_entry_t *entry; 596 scf_value_t *value = NULL; 597 598 if ((entry = scf_entry_create(handle)) == NULL) 599 return (B_FALSE); 600 601 if ((value = scf_value_create(handle)) == NULL) 602 goto out; 603 if (scf_transaction_property_new(tran, entry, propname, 604 SCF_TYPE_FMRI) != 0 && 605 scf_transaction_property_change(tran, entry, propname, 606 SCF_TYPE_FMRI) != 0) 607 goto out; 608 if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0) 609 goto out; 610 if (scf_entry_add_value(entry, value) == 0) 611 return (B_TRUE); 612 613 out: 614 if (value != NULL) 615 scf_value_destroy(value); 616 617 scf_entry_destroy_children(entry); 618 scf_entry_destroy(entry); 619 620 return (B_FALSE); 621 } 622 623 static dladm_status_t 624 dladm_bridge_persist_conf(dladm_handle_t handle, const char *link, 625 datalink_id_t linkid) 626 { 627 dladm_conf_t conf = DLADM_INVALID_CONF; 628 dladm_status_t status; 629 630 status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE, 631 DL_ETHER, &conf); 632 if (status == DLADM_STATUS_OK) { 633 /* 634 * Create the datalink entry for the bridge. Note that all of 635 * the real configuration information is in SMF. 636 */ 637 status = dladm_write_conf(handle, conf); 638 dladm_destroy_conf(handle, conf); 639 } 640 return (status); 641 } 642 643 /* Convert bridge protection option string to dladm_bridge_prot_t */ 644 dladm_status_t 645 dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp) 646 { 647 if (strcmp(str, "stp") == 0) 648 *brprotp = DLADM_BRIDGE_PROT_STP; 649 else if (strcmp(str, "trill") == 0) 650 *brprotp = DLADM_BRIDGE_PROT_TRILL; 651 else 652 return (DLADM_STATUS_BADARG); 653 return (DLADM_STATUS_OK); 654 } 655 656 /* Convert bridge protection option from dladm_bridge_prot_t to string */ 657 const char * 658 dladm_bridge_prot2str(dladm_bridge_prot_t brprot) 659 { 660 switch (brprot) { 661 case DLADM_BRIDGE_PROT_STP: 662 return ("stp"); 663 case DLADM_BRIDGE_PROT_TRILL: 664 return ("trill"); 665 default: 666 return ("unknown"); 667 } 668 } 669 670 static dladm_status_t 671 enable_instance(const char *service_name, const char *instance) 672 { 673 dladm_status_t status; 674 char *fmri = alloc_fmri(service_name, instance); 675 676 if (fmri == NULL) 677 return (DLADM_STATUS_NOMEM); 678 status = smf_enable_instance(fmri, 0) == 0 ? 679 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 680 free(fmri); 681 return (status); 682 } 683 684 /* 685 * Shut down a possibly-running service instance. If this is a permanent 686 * change, then delete it from the system. 687 */ 688 static dladm_status_t 689 shut_down_instance(const char *service_name, const char *instance, 690 uint32_t flags) 691 { 692 dladm_status_t status; 693 char *fmri = alloc_fmri(service_name, instance); 694 char *state; 695 scf_state_t sstate; 696 697 if (fmri == NULL) 698 return (DLADM_STATUS_NOMEM); 699 700 if (smf_disable_instance(fmri, 701 flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) { 702 useconds_t usecs, umax; 703 704 /* If we can disable, then wait for it to happen. */ 705 umax = DEFAULT_TIMEOUT; 706 for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) { 707 state = smf_get_state(fmri); 708 if (state != NULL && 709 strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 710 break; 711 free(state); 712 usecs *= 2; 713 if (usecs > umax) 714 usecs = umax; 715 (void) usleep(usecs); 716 } 717 if (umax == 0) { 718 state = smf_get_state(fmri); 719 if (state != NULL && 720 strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 721 umax = 1; 722 } 723 free(state); 724 status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED; 725 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 726 free(fmri); 727 return (DLADM_STATUS_OK); 728 } else { 729 status = DLADM_STATUS_FAILED; 730 } 731 732 free(fmri); 733 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) && 734 bind_instance(service_name, instance, &sstate) == 0) { 735 (void) scf_instance_delete(sstate.ss_inst); 736 shut_down_scf(&sstate); 737 } 738 739 return (status); 740 } 741 742 static dladm_status_t 743 disable_trill(const char *instance, uint32_t flags) 744 { 745 return (shut_down_instance(TRILL_SVC_NAME, instance, flags)); 746 } 747 748 /* 749 * To enable TRILL, we must create a new instance of the TRILL service, then 750 * add proper dependencies to it, and finally mark it as enabled. The 751 * dependencies will keep it from going on-line until the bridge is running. 752 */ 753 static dladm_status_t 754 enable_trill(const char *instance) 755 { 756 dladm_status_t status = DLADM_STATUS_FAILED; 757 char *fmri = NULL; 758 scf_state_t sstate; 759 scf_transaction_t *tran = NULL; 760 boolean_t new_instance = B_FALSE; 761 boolean_t new_pg = B_FALSE; 762 int rv; 763 764 /* 765 * This check is here in case the user has installed and then removed 766 * the package. SMF should remove the manifest, but currently does 767 * not. 768 */ 769 if (access("/usr/sbin/trilld", F_OK) != 0) 770 return (DLADM_STATUS_OPTMISSING); 771 772 if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) != 773 DLADM_STATUS_OK) 774 goto out; 775 776 status = DLADM_STATUS_FAILED; 777 if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) != 778 0) { 779 if (scf_service_add_instance(sstate.ss_svc, instance, 780 sstate.ss_inst) != 0) 781 goto out; 782 new_instance = B_TRUE; 783 } 784 785 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 786 goto out; 787 788 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 789 goto out; 790 791 if (scf_instance_get_pg(sstate.ss_inst, "bridging", 792 sstate.ss_pg) == 0) { 793 status = DLADM_STATUS_OK; 794 goto out; 795 } 796 797 if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL) 798 goto out; 799 800 if (scf_instance_add_pg(sstate.ss_inst, "bridging", 801 SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0) 802 goto out; 803 804 new_pg = B_TRUE; 805 do { 806 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 807 goto out; 808 809 if (!set_string_property(sstate.ss_handle, tran, 810 SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL)) 811 goto out; 812 if (!set_string_property(sstate.ss_handle, tran, 813 SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART)) 814 goto out; 815 if (!set_string_property(sstate.ss_handle, tran, 816 SCF_PROPERTY_TYPE, "service")) 817 goto out; 818 if (!set_fmri_property(sstate.ss_handle, tran, 819 SCF_PROPERTY_ENTITIES, fmri)) 820 goto out; 821 822 rv = scf_transaction_commit(tran); 823 scf_transaction_reset(tran); 824 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 825 goto out; 826 } while (rv == 0); 827 if (rv != 1) 828 goto out; 829 830 status = DLADM_STATUS_OK; 831 832 out: 833 free(fmri); 834 if (tran != NULL) { 835 scf_transaction_destroy_children(tran); 836 scf_transaction_destroy(tran); 837 } 838 839 if (status != DLADM_STATUS_OK && new_pg) 840 (void) scf_pg_delete(sstate.ss_pg); 841 842 drop_composed(&sstate); 843 844 /* 845 * If we created an instance and then failed, then remove the instance 846 * from the system. 847 */ 848 if (status != DLADM_STATUS_OK && new_instance) 849 (void) scf_instance_delete(sstate.ss_inst); 850 851 shut_down_scf(&sstate); 852 853 if (status == DLADM_STATUS_OK) 854 status = enable_instance(TRILL_SVC_NAME, instance); 855 856 return (status); 857 } 858 859 /* 860 * Create a new bridge or modify an existing one. Update the SMF configuration 861 * and add links. 862 * 863 * Input timer values are in IEEE scaled (* 256) format. 864 */ 865 dladm_status_t 866 dladm_bridge_configure(dladm_handle_t handle, const char *name, 867 const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags) 868 { 869 dladm_status_t status; 870 scf_state_t sstate; 871 scf_transaction_t *tran = NULL; 872 boolean_t new_instance = B_FALSE; 873 boolean_t new_pg = B_FALSE; 874 datalink_id_t linkid = DATALINK_INVALID_LINKID; 875 char linkname[MAXLINKNAMELEN]; 876 int rv; 877 878 if (!dladm_valid_bridgename(name)) 879 return (DLADM_STATUS_FAILED); 880 881 if (flags & DLADM_OPT_CREATE) { 882 /* 883 * This check is here in case the user has installed and then 884 * removed the package. SMF should remove the manifest, but 885 * currently does not. 886 */ 887 if (access("/usr/lib/bridged", F_OK) != 0) 888 return (DLADM_STATUS_OPTMISSING); 889 890 (void) snprintf(linkname, sizeof (linkname), "%s0", name); 891 status = dladm_create_datalink_id(handle, linkname, 892 DATALINK_CLASS_BRIDGE, DL_ETHER, 893 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid); 894 if (status != DLADM_STATUS_OK) 895 return (status); 896 897 if ((flags & DLADM_OPT_PERSIST) && 898 (status = dladm_bridge_persist_conf(handle, linkname, 899 linkid) != DLADM_STATUS_OK)) 900 goto dladm_fail; 901 } 902 903 if (brprot == DLADM_BRIDGE_PROT_TRILL) 904 status = enable_trill(name); 905 else 906 status = disable_trill(name, flags); 907 if (status != DLADM_STATUS_OK) 908 goto dladm_fail; 909 910 if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) != 911 DLADM_STATUS_OK) 912 goto out; 913 914 /* set up for a series of scf calls */ 915 status = DLADM_STATUS_FAILED; 916 917 if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) == 918 0) { 919 if (flags & DLADM_OPT_CREATE) { 920 status = DLADM_STATUS_EXIST; 921 goto out; 922 } 923 } else { 924 if (!(flags & DLADM_OPT_CREATE)) { 925 status = DLADM_STATUS_NOTFOUND; 926 goto out; 927 } 928 if (scf_service_add_instance(sstate.ss_svc, name, 929 sstate.ss_inst) != 0) 930 goto out; 931 new_instance = B_TRUE; 932 } 933 934 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 935 goto out; 936 937 if (cfg->field_mask & BR_CFG_ALL) { 938 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 939 goto out; 940 if (scf_instance_add_pg(sstate.ss_inst, "config", 941 SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 942 new_pg = B_TRUE; 943 } else if (scf_instance_get_pg(sstate.ss_inst, "config", 944 sstate.ss_pg) != 0) { 945 goto out; 946 } 947 do { 948 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 949 goto out; 950 951 if ((cfg->field_mask & BR_CFG_PRIO) && 952 !set_count_property(sstate.ss_handle, tran, 953 "priority", cfg->bridge_priority)) 954 goto out; 955 if ((cfg->field_mask & BR_CFG_AGE) && 956 !set_count_property(sstate.ss_handle, tran, 957 "max-age", cfg->max_age * IEEE_TIMER_SCALE)) 958 goto out; 959 if ((cfg->field_mask & BR_CFG_HELLO) && 960 !set_count_property(sstate.ss_handle, tran, 961 "hello-time", cfg->hello_time * IEEE_TIMER_SCALE)) 962 goto out; 963 if ((cfg->field_mask & BR_CFG_DELAY) && 964 !set_count_property(sstate.ss_handle, tran, 965 "forward-delay", 966 cfg->forward_delay * IEEE_TIMER_SCALE)) 967 goto out; 968 if ((cfg->field_mask & BR_CFG_FORCE_VER) && 969 !set_count_property(sstate.ss_handle, tran, 970 "force-protocol", cfg->force_version)) 971 goto out; 972 973 rv = scf_transaction_commit(tran); 974 scf_transaction_reset(tran); 975 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 976 goto out; 977 } while (rv == 0); 978 if (rv != 1) 979 goto out; 980 } 981 982 /* 983 * If we're modifying an existing and running bridge, then tell the 984 * daemon to update the requested values. 985 */ 986 if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE)) 987 status = bridge_refresh(name); 988 else 989 status = DLADM_STATUS_OK; 990 991 out: 992 if (tran != NULL) { 993 scf_transaction_destroy_children(tran); 994 scf_transaction_destroy(tran); 995 } 996 997 if (status != DLADM_STATUS_OK && new_pg) 998 (void) scf_pg_delete(sstate.ss_pg); 999 1000 drop_composed(&sstate); 1001 1002 /* 1003 * If we created an instance and then failed, then remove the instance 1004 * from the system. 1005 */ 1006 if (status != DLADM_STATUS_OK && new_instance) 1007 (void) scf_instance_delete(sstate.ss_inst); 1008 1009 shut_down_scf(&sstate); 1010 1011 /* 1012 * Remove the bridge linkid if we've allocated one in this function but 1013 * we've failed to set up the SMF properties. 1014 */ 1015 dladm_fail: 1016 if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) { 1017 (void) dladm_remove_conf(handle, linkid); 1018 (void) dladm_destroy_datalink_id(handle, linkid, flags); 1019 } 1020 1021 return (status); 1022 } 1023 1024 /* 1025 * Enable a newly-created bridge in SMF by creating "general/enabled" and 1026 * deleting any "general_ovr/enabled" (used for temporary services). 1027 */ 1028 dladm_status_t 1029 dladm_bridge_enable(const char *name) 1030 { 1031 return (enable_instance(BRIDGE_SVC_NAME, name)); 1032 } 1033 1034 /* 1035 * Set a link as a member of a bridge, or remove bridge membership. If the 1036 * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running. 1037 * In all other cases, we must tell the daemon to add or delete the link in 1038 * order to stay in sync. 1039 */ 1040 dladm_status_t 1041 dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid, 1042 const char *bridge) 1043 { 1044 dladm_status_t status; 1045 dladm_conf_t conf; 1046 char oldbridge[MAXLINKNAMELEN]; 1047 boolean_t has_oldbridge; 1048 boolean_t changed = B_FALSE; 1049 1050 if (*bridge != '\0' && !dladm_valid_bridgename(bridge)) 1051 return (DLADM_STATUS_FAILED); 1052 1053 if ((status = dladm_read_conf(handle, linkid, &conf)) != 1054 DLADM_STATUS_OK) 1055 return (status); 1056 1057 has_oldbridge = B_FALSE; 1058 status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge, 1059 sizeof (oldbridge)); 1060 if (status == DLADM_STATUS_OK) { 1061 /* 1062 * Don't allow a link to be reassigned directly from one bridge 1063 * to another. It must be removed first. 1064 */ 1065 if (*oldbridge != '\0' && *bridge != '\0') { 1066 status = DLADM_STATUS_EXIST; 1067 goto out; 1068 } 1069 has_oldbridge = B_TRUE; 1070 } else if (status != DLADM_STATUS_NOTFOUND) { 1071 goto out; 1072 } 1073 1074 if (*bridge != '\0') { 1075 status = dladm_set_conf_field(handle, conf, FBRIDGE, 1076 DLADM_TYPE_STR, bridge); 1077 changed = B_TRUE; 1078 } else if (has_oldbridge) { 1079 status = dladm_unset_conf_field(handle, conf, FBRIDGE); 1080 changed = B_TRUE; 1081 } else { 1082 status = DLADM_STATUS_OK; 1083 goto out; 1084 } 1085 if (status == DLADM_STATUS_OK) 1086 status = dladm_write_conf(handle, conf); 1087 1088 out: 1089 dladm_destroy_conf(handle, conf); 1090 if (changed && status == DLADM_STATUS_OK) { 1091 if (bridge[0] == '\0') 1092 bridge = oldbridge; 1093 status = bridge_refresh(bridge); 1094 } 1095 return (status); 1096 } 1097 1098 /* 1099 * Get the name of the bridge of which the given linkid is a member. 1100 */ 1101 dladm_status_t 1102 dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge, 1103 size_t bridgelen) 1104 { 1105 dladm_status_t status; 1106 dladm_conf_t conf; 1107 1108 if ((status = dladm_read_conf(handle, linkid, &conf)) != 1109 DLADM_STATUS_OK) 1110 return (status); 1111 1112 *bridge = '\0'; 1113 status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen); 1114 if (status == DLADM_STATUS_OK && *bridge == '\0') 1115 status = DLADM_STATUS_NOTFOUND; 1116 1117 dladm_destroy_conf(handle, conf); 1118 return (status); 1119 } 1120 1121 dladm_status_t 1122 dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid) 1123 { 1124 char bridge[MAXLINKNAMELEN]; 1125 dladm_status_t status; 1126 1127 status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 1128 if (status == DLADM_STATUS_NOTFOUND) 1129 return (DLADM_STATUS_OK); 1130 if (status == DLADM_STATUS_OK) 1131 status = bridge_refresh(bridge); 1132 return (status); 1133 } 1134 1135 typedef struct bridge_held_arg_s { 1136 const char *bha_bridge; 1137 boolean_t bha_isheld; 1138 } bridge_held_arg_t; 1139 1140 static int 1141 i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1142 { 1143 dladm_status_t status = DLADM_STATUS_FAILED; 1144 dladm_conf_t conf; 1145 char bridge[MAXLINKNAMELEN]; 1146 bridge_held_arg_t *bha = arg; 1147 1148 if ((status = dladm_read_conf(handle, linkid, &conf)) != 1149 DLADM_STATUS_OK) 1150 return (DLADM_WALK_CONTINUE); 1151 status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, 1152 sizeof (bridge)); 1153 if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) { 1154 bha->bha_isheld = B_TRUE; 1155 dladm_destroy_conf(handle, conf); 1156 return (DLADM_WALK_TERMINATE); 1157 } else { 1158 dladm_destroy_conf(handle, conf); 1159 return (DLADM_WALK_CONTINUE); 1160 } 1161 } 1162 1163 /* 1164 * Delete a previously created bridge. 1165 */ 1166 dladm_status_t 1167 dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags) 1168 { 1169 datalink_id_t linkid; 1170 datalink_class_t class; 1171 dladm_status_t status; 1172 char linkname[MAXLINKNAMELEN]; 1173 1174 if (!dladm_valid_bridgename(bridge)) 1175 return (DLADM_STATUS_LINKINVAL); 1176 1177 /* Get the datalink ID for this bridge */ 1178 (void) snprintf(linkname, sizeof (linkname), "%s0", bridge); 1179 if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) != 1180 DLADM_STATUS_OK) 1181 linkid = DATALINK_INVALID_LINKID; 1182 else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1183 NULL, 0) != DLADM_STATUS_OK) 1184 linkid = DATALINK_INVALID_LINKID; 1185 else if (class != DATALINK_CLASS_BRIDGE) 1186 return (DLADM_STATUS_BADARG); 1187 1188 if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID) 1189 return (DLADM_STATUS_BADARG); 1190 1191 if (flags & DLADM_OPT_PERSIST) { 1192 bridge_held_arg_t arg; 1193 1194 arg.bha_bridge = bridge; 1195 arg.bha_isheld = B_FALSE; 1196 1197 /* 1198 * See whether there are any persistent links using this 1199 * bridge. If so, we fail the operation. 1200 */ 1201 (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle, 1202 &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 1203 DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET, 1204 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1205 if (arg.bha_isheld) 1206 return (DLADM_STATUS_LINKBUSY); 1207 } 1208 1209 if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK) 1210 goto out; 1211 1212 /* Disable or remove the SMF instance */ 1213 status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags); 1214 if (status != DLADM_STATUS_OK) 1215 goto out; 1216 1217 if (flags & DLADM_OPT_ACTIVE) { 1218 /* 1219 * Delete ACTIVE linkprop now that daemon is gone. 1220 */ 1221 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 1222 DLADM_OPT_ACTIVE); 1223 (void) dladm_destroy_datalink_id(handle, linkid, 1224 DLADM_OPT_ACTIVE); 1225 } 1226 1227 if (flags & DLADM_OPT_PERSIST) { 1228 (void) dladm_remove_conf(handle, linkid); 1229 (void) dladm_destroy_datalink_id(handle, linkid, 1230 DLADM_OPT_PERSIST); 1231 } 1232 1233 out: 1234 1235 return (status); 1236 } 1237 1238 /* Check if given name is valid for bridges */ 1239 boolean_t 1240 dladm_valid_bridgename(const char *bridge) 1241 { 1242 size_t len = strnlen(bridge, MAXLINKNAMELEN); 1243 const char *cp; 1244 1245 if (len == MAXLINKNAMELEN) 1246 return (B_FALSE); 1247 1248 /* 1249 * The bridge name cannot start or end with a digit. 1250 */ 1251 if (isdigit(bridge[0]) || isdigit(bridge[len - 1])) 1252 return (B_FALSE); 1253 1254 /* 1255 * The legal characters within a bridge name are: 1256 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 1257 */ 1258 for (cp = bridge; *cp != '\0'; cp++) { 1259 if (!isalnum(*cp) && *cp != '_') 1260 return (B_FALSE); 1261 } 1262 1263 return (B_TRUE); 1264 } 1265 1266 /* 1267 * Convert a bridge-related observability node name back into the name of the 1268 * bridge. Returns B_FALSE without making changes if the input name is not in 1269 * a legal format. 1270 */ 1271 boolean_t 1272 dladm_observe_to_bridge(char *link) 1273 { 1274 int llen; 1275 1276 llen = strnlen(link, MAXLINKNAMELEN); 1277 if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2])) 1278 return (B_FALSE); 1279 link[llen - 1] = '\0'; 1280 return (B_TRUE); 1281 } 1282 1283 /* 1284 * Get bridge property values from the running daemon and return them in a 1285 * common structure. 1286 */ 1287 dladm_status_t 1288 dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg, 1289 dladm_bridge_prot_t *brprotp) 1290 { 1291 dladm_status_t status; 1292 bridge_door_cfg_t bdcf; 1293 bridge_door_cfg_t *bdcfp = &bdcf; 1294 size_t buflen = sizeof (bdcf); 1295 1296 status = bridge_door_call(instname, bdcBridgeGetConfig, 1297 DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE); 1298 if (status == DLADM_STATUS_OK) { 1299 *smcfg = bdcfp->bdcf_cfg; 1300 *brprotp = bdcfp->bdcf_prot; 1301 } else { 1302 smcfg->field_mask = 0; 1303 *brprotp = DLADM_BRIDGE_PROT_STP; 1304 } 1305 return (status); 1306 } 1307 1308 /* 1309 * Get bridge state from the running daemon and return in structure borrowed 1310 * from librstp. 1311 */ 1312 dladm_status_t 1313 dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep) 1314 { 1315 size_t buflen = sizeof (*statep); 1316 1317 return (bridge_door_call(instname, bdcBridgeGetState, 1318 DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE)); 1319 } 1320 1321 /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */ 1322 datalink_id_t * 1323 dladm_bridge_get_portlist(const char *instname, uint_t *nports) 1324 { 1325 size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t); 1326 int *rbuf; 1327 1328 if ((rbuf = malloc(buflen)) == NULL) 1329 return (NULL); 1330 if (bridge_door_call(instname, bdcBridgeGetPorts, 1331 DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) != 1332 DLADM_STATUS_OK) { 1333 free(rbuf); 1334 return (NULL); 1335 } else { 1336 /* 1337 * Returns an array of datalink_id_t values for all the ports 1338 * part of the bridge instance. First entry in the array is the 1339 * number of ports. 1340 */ 1341 *nports = *rbuf; 1342 return ((datalink_id_t *)(rbuf + 1)); 1343 } 1344 } 1345 1346 void 1347 dladm_bridge_free_portlist(datalink_id_t *dlp) 1348 { 1349 free((int *)dlp - 1); 1350 } 1351 1352 /* Retrieve Bridge port configuration values */ 1353 dladm_status_t 1354 dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid, 1355 int field, int *valuep) 1356 { 1357 UID_STP_PORT_CFG_T portcfg; 1358 dladm_status_t status; 1359 1360 status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg, 1361 0, sizeof (portcfg)); 1362 if (status != DLADM_STATUS_OK) 1363 return (status); 1364 1365 switch (field) { 1366 case PT_CFG_COST: 1367 *valuep = portcfg.admin_port_path_cost; 1368 break; 1369 case PT_CFG_PRIO: 1370 *valuep = portcfg.port_priority; 1371 break; 1372 case PT_CFG_P2P: 1373 *valuep = portcfg.admin_point2point; 1374 break; 1375 case PT_CFG_EDGE: 1376 *valuep = portcfg.admin_edge; 1377 break; 1378 case PT_CFG_NON_STP: 1379 *valuep = !portcfg.admin_non_stp; 1380 break; 1381 case PT_CFG_MCHECK: 1382 *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0; 1383 break; 1384 } 1385 return (status); 1386 } 1387 1388 /* Retreive Bridge port status (disabled, bad SDU etc.) */ 1389 dladm_status_t 1390 dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid, 1391 UID_STP_PORT_STATE_T *spsp) 1392 { 1393 return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0, 1394 sizeof (*spsp))); 1395 } 1396 1397 /* Retrieve Bridge forwarding status of the given link */ 1398 dladm_status_t 1399 dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid, 1400 uint_t *valuep) 1401 { 1402 int twoints[2]; 1403 dladm_status_t status; 1404 1405 status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints, 1406 0, sizeof (twoints)); 1407 if (status == DLADM_STATUS_OK) 1408 *valuep = twoints[0]; 1409 return (status); 1410 } 1411 1412 /* Retrieve Bridge forwarding table entries */ 1413 bridge_listfwd_t * 1414 dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge, 1415 uint_t *nfwd) 1416 { 1417 bridge_listfwd_t *blf = NULL, *newblf, blfread; 1418 uint_t nblf = 0, maxblf = 0; 1419 static uint8_t zero_addr[ETHERADDRL]; 1420 int rc; 1421 1422 (void) memset(&blfread, 0, sizeof (blfread)); 1423 (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name), 1424 "%s0", bridge); 1425 for (;;) { 1426 if (nblf >= maxblf) { 1427 maxblf = maxblf == 0 ? 64 : (maxblf << 1); 1428 newblf = realloc(blf, maxblf * sizeof (*blf)); 1429 if (newblf == NULL) { 1430 free(blf); 1431 blf = NULL; 1432 break; 1433 } 1434 blf = newblf; 1435 } 1436 rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread); 1437 if (rc != 0) { 1438 free(blf); 1439 blf = NULL; 1440 break; 1441 } 1442 if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0) 1443 break; 1444 blf[nblf++] = blfread; 1445 } 1446 if (blf != NULL) 1447 *nfwd = nblf; 1448 return (blf); 1449 } 1450 1451 void 1452 dladm_bridge_free_fwdtable(bridge_listfwd_t *blf) 1453 { 1454 free(blf); 1455 } 1456 1457 /* Retrieve list of TRILL nicknames from the TRILL module */ 1458 trill_listnick_t * 1459 dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick) 1460 { 1461 int fd; 1462 char brcopy[MAXLINKNAMELEN]; 1463 trill_listnick_t *tln = NULL, *newtln, tlnread; 1464 uint_t ntln = 0, maxtln = 0; 1465 1466 if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1) 1467 return (NULL); 1468 (void) strlcpy(brcopy, bridge, sizeof (brcopy)); 1469 if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) { 1470 (void) close(fd); 1471 return (NULL); 1472 } 1473 (void) memset(&tlnread, 0, sizeof (tlnread)); 1474 for (;;) { 1475 if (ntln >= maxtln) { 1476 maxtln = maxtln == 0 ? 64 : (maxtln << 1); 1477 newtln = realloc(tln, maxtln * sizeof (*tln)); 1478 if (newtln == NULL) { 1479 free(tln); 1480 tln = NULL; 1481 break; 1482 } 1483 tln = newtln; 1484 } 1485 if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) { 1486 free(tln); 1487 tln = NULL; 1488 break; 1489 } 1490 if (tlnread.tln_nick == 0) 1491 break; 1492 tln[ntln++] = tlnread; 1493 } 1494 (void) close(fd); 1495 if (tln != NULL) 1496 *nnick = ntln; 1497 return (tln); 1498 } 1499 1500 void 1501 dladm_bridge_free_trillnick(trill_listnick_t *tln) 1502 { 1503 free(tln); 1504 } 1505 1506 /* Retrieve any stored TRILL nickname from TRILL SMF service */ 1507 uint16_t 1508 dladm_bridge_get_nick(const char *bridge) 1509 { 1510 scf_state_t sstate; 1511 uint64_t value; 1512 uint16_t nickname = RBRIDGE_NICKNAME_NONE; 1513 1514 if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0) 1515 return (nickname); 1516 1517 if (get_composed_properties("config", B_TRUE, &sstate) == 0 && 1518 get_count("nickname", &sstate, &value) == 0) 1519 nickname = value; 1520 shut_down_scf(&sstate); 1521 return (nickname); 1522 } 1523 1524 /* Stores TRILL nickname in SMF configuraiton for the TRILL service */ 1525 void 1526 dladm_bridge_set_nick(const char *bridge, uint16_t nick) 1527 { 1528 scf_state_t sstate; 1529 scf_transaction_t *tran = NULL; 1530 boolean_t new_pg = B_FALSE; 1531 int rv = 0; 1532 char *fmri; 1533 1534 if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK) 1535 return; 1536 1537 if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) != 1538 0) 1539 goto out; 1540 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 1541 goto out; 1542 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 1543 goto out; 1544 if (scf_instance_add_pg(sstate.ss_inst, "config", 1545 SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 1546 new_pg = B_TRUE; 1547 } else if (scf_instance_get_pg(sstate.ss_inst, "config", 1548 sstate.ss_pg) != 0) { 1549 goto out; 1550 } 1551 do { 1552 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 1553 goto out; 1554 if (!set_count_property(sstate.ss_handle, tran, "nickname", 1555 nick)) 1556 goto out; 1557 rv = scf_transaction_commit(tran); 1558 scf_transaction_reset(tran); 1559 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 1560 goto out; 1561 } while (rv == 0); 1562 1563 out: 1564 if (tran != NULL) { 1565 scf_transaction_destroy_children(tran); 1566 scf_transaction_destroy(tran); 1567 } 1568 1569 if (rv != 1 && new_pg) 1570 (void) scf_pg_delete(sstate.ss_pg); 1571 1572 drop_composed(&sstate); 1573 shut_down_scf(&sstate); 1574 if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) { 1575 (void) smf_refresh_instance(fmri); 1576 free(fmri); 1577 } 1578 } 1579