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.
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.
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]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
37 #include <libscf_priv.h>
38 #include <libdllink.h>
39 #include <libdlbridge.h>
40 #include <libdladm_impl.h>
42 #include <net/bridge.h>
43 #include <net/trill.h>
44 #include <sys/socket.h>
45 #include <sys/dld_ioc.h>
48 * Bridge Administration Library.
50 * This library is used by administration tools such as dladm(1M) to configure
51 * bridges, and by the bridge daemon to retrieve configuration information.
54 #define BRIDGE_SVC_NAME "network/bridge"
55 #define TRILL_SVC_NAME "network/routing/trill"
57 #define DEFAULT_TIMEOUT 60000000
58 #define INIT_WAIT_USECS 50000
61 typedef struct scf_state
{
62 scf_handle_t
*ss_handle
;
63 scf_instance_t
*ss_inst
;
64 scf_service_t
*ss_svc
;
65 scf_snapshot_t
*ss_snap
;
66 scf_propertygroup_t
*ss_pg
;
67 scf_property_t
*ss_prop
;
71 shut_down_scf(scf_state_t
*sstate
)
73 scf_instance_destroy(sstate
->ss_inst
);
74 (void) scf_handle_unbind(sstate
->ss_handle
);
75 scf_handle_destroy(sstate
->ss_handle
);
79 alloc_fmri(const char *service
, const char *instance_name
)
84 /* If the limit is unknown, then use an arbitrary value */
85 if ((max_fmri
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
)) == -1)
87 if ((fmri
= malloc(max_fmri
)) != NULL
) {
88 (void) snprintf(fmri
, max_fmri
, "svc:/%s:%s", service
,
95 * Start up SCF and bind the requested instance alone.
98 bind_instance(const char *service
, const char *instance_name
,
103 (void) memset(sstate
, 0, sizeof (*sstate
));
105 if ((sstate
->ss_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
108 if (scf_handle_bind(sstate
->ss_handle
) != 0)
110 sstate
->ss_inst
= scf_instance_create(sstate
->ss_handle
);
111 if (sstate
->ss_inst
== NULL
)
114 fmri
= alloc_fmri(service
, instance_name
);
116 if (scf_handle_decode_fmri(sstate
->ss_handle
, fmri
, NULL
, NULL
,
117 sstate
->ss_inst
, NULL
, NULL
,
118 SCF_DECODE_FMRI_REQUIRE_INSTANCE
) != 0)
125 shut_down_scf(sstate
);
130 * Start up SCF and an exact FMRI. This is used for creating new instances and
131 * enable/disable actions.
133 static dladm_status_t
134 exact_instance(const char *fmri
, scf_state_t
*sstate
)
136 dladm_status_t status
;
138 (void) memset(sstate
, 0, sizeof (*sstate
));
140 if ((sstate
->ss_handle
= scf_handle_create(SCF_VERSION
)) == NULL
)
141 return (DLADM_STATUS_NOMEM
);
143 status
= DLADM_STATUS_FAILED
;
144 if (scf_handle_bind(sstate
->ss_handle
) != 0)
146 sstate
->ss_svc
= scf_service_create(sstate
->ss_handle
);
147 if (sstate
->ss_svc
== NULL
)
149 if (scf_handle_decode_fmri(sstate
->ss_handle
, fmri
, NULL
,
150 sstate
->ss_svc
, NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
151 if (scf_error() == SCF_ERROR_NOT_FOUND
)
152 status
= DLADM_STATUS_OPTMISSING
;
155 sstate
->ss_inst
= scf_instance_create(sstate
->ss_handle
);
156 if (sstate
->ss_inst
== NULL
)
158 return (DLADM_STATUS_OK
);
161 shut_down_scf(sstate
);
166 drop_composed(scf_state_t
*sstate
)
168 scf_property_destroy(sstate
->ss_prop
);
169 scf_pg_destroy(sstate
->ss_pg
);
170 scf_snapshot_destroy(sstate
->ss_snap
);
174 * This function sets up a composed view of the configuration information for
175 * the specified instance. When this is done, the get_property() function
176 * should be able to return individual parameters.
179 get_composed_properties(const char *lpg
, boolean_t snap
, scf_state_t
*sstate
)
181 sstate
->ss_snap
= NULL
;
182 sstate
->ss_pg
= NULL
;
183 sstate
->ss_prop
= NULL
;
186 sstate
->ss_snap
= scf_snapshot_create(sstate
->ss_handle
);
187 if (sstate
->ss_snap
== NULL
)
189 if (scf_instance_get_snapshot(sstate
->ss_inst
, "running",
190 sstate
->ss_snap
) != 0)
193 if ((sstate
->ss_pg
= scf_pg_create(sstate
->ss_handle
)) == NULL
)
195 if (scf_instance_get_pg_composed(sstate
->ss_inst
, sstate
->ss_snap
, lpg
,
198 if ((sstate
->ss_prop
= scf_property_create(sstate
->ss_handle
)) ==
204 drop_composed(sstate
);
209 get_count(const char *lprop
, scf_state_t
*sstate
, uint64_t *answer
)
214 if (scf_pg_get_property(sstate
->ss_pg
, lprop
, sstate
->ss_prop
) != 0)
216 if ((val
= scf_value_create(sstate
->ss_handle
)) == NULL
)
219 if (scf_property_get_value(sstate
->ss_prop
, val
) == 0 &&
220 scf_value_get_count(val
, answer
) == 0)
224 scf_value_destroy(val
);
229 get_boolean(const char *lprop
, scf_state_t
*sstate
, boolean_t
*answer
)
235 if (scf_pg_get_property(sstate
->ss_pg
, lprop
, sstate
->ss_prop
) != 0)
237 if ((val
= scf_value_create(sstate
->ss_handle
)) == NULL
)
240 if (scf_property_get_value(sstate
->ss_prop
, val
) == 0 &&
241 scf_value_get_boolean(val
, &bval
) == 0) {
247 scf_value_destroy(val
);
251 static dladm_status_t
252 bridge_door_call(const char *instname
, bridge_door_type_t dtype
,
253 datalink_id_t linkid
, void **bufp
, size_t inlen
, size_t *buflenp
,
256 char doorname
[MAXPATHLEN
];
258 bridge_door_cmd_t
*bdc
;
261 (void) snprintf(doorname
, sizeof (doorname
), "%s/%s", DOOR_DIRNAME
,
264 /* Knock on the door */
265 did
= open(doorname
, O_RDONLY
| O_NOFOLLOW
| O_NONBLOCK
);
267 return (dladm_errno2status(errno
));
269 if ((bdc
= malloc(sizeof (*bdc
) + inlen
)) == NULL
) {
271 return (DLADM_STATUS_NOMEM
);
273 bdc
->bdc_type
= dtype
;
274 bdc
->bdc_linkid
= linkid
;
276 (void) memcpy(bdc
+ 1, *bufp
, inlen
);
278 (void) memset(&arg
, 0, sizeof (arg
));
279 arg
.data_ptr
= (char *)bdc
;
280 arg
.data_size
= sizeof (*bdc
) + inlen
;
282 arg
.rsize
= *buflenp
;
284 /* The door_call function doesn't restart, so take care of that */
287 if ((retv
= door_call(did
, &arg
)) == 0)
289 } while (errno
== EINTR
);
291 /* If we get an unexpected response, then return an error */
293 /* The daemon returns a single int for errors */
294 /* LINTED: pointer alignment */
295 if (arg
.data_size
== sizeof (int) && *(int *)arg
.rbuf
!= 0) {
297 /* LINTED: pointer alignment */
298 errno
= *(int *)arg
.rbuf
;
300 /* Terminated daemon returns with zero data */
301 if (arg
.data_size
== 0) {
308 if (arg
.rbuf
!= *bufp
) {
312 newp
= realloc(*bufp
, arg
.data_size
);
317 (void) memcpy(*bufp
, arg
.rbuf
,
321 (void) munmap(arg
.rbuf
, arg
.rsize
);
324 *buflenp
= arg
.data_size
;
325 } else if (arg
.data_size
!= *buflenp
|| arg
.rbuf
!= *bufp
) {
334 /* Revoked door is the same as no door at all */
338 return (retv
== 0 ? DLADM_STATUS_OK
: dladm_errno2status(etmp
));
342 * Wrapper function for making per-port calls.
344 static dladm_status_t
345 port_door_call(dladm_handle_t handle
, datalink_id_t linkid
,
346 bridge_door_type_t dtype
, void *buf
, size_t inlen
, size_t buflen
)
348 char bridge
[MAXLINKNAMELEN
];
349 dladm_status_t status
;
351 status
= dladm_bridge_getlink(handle
, linkid
, bridge
, sizeof (bridge
));
352 if (status
!= DLADM_STATUS_OK
)
354 return (bridge_door_call(bridge
, dtype
, linkid
, &buf
, inlen
, &buflen
,
358 static dladm_status_t
359 bridge_refresh(const char *bridge
)
361 dladm_status_t status
;
368 buflen
= sizeof (twoints
);
370 status
= bridge_door_call(bridge
, bdcBridgeGetRefreshCount
,
371 DATALINK_INVALID_LINKID
, &bdptr
, 0, &buflen
, B_FALSE
);
372 if (status
== DLADM_STATUS_NOTFOUND
)
373 return (DLADM_STATUS_OK
);
374 if (status
!= DLADM_STATUS_OK
)
376 refresh_count
= twoints
[0];
377 if ((fmri
= alloc_fmri(BRIDGE_SVC_NAME
, bridge
)) == NULL
)
378 return (DLADM_STATUS_NOMEM
);
379 status
= smf_refresh_instance(fmri
) == 0 ?
380 DLADM_STATUS_OK
: DLADM_STATUS_FAILED
;
382 if (status
== DLADM_STATUS_OK
) {
386 * SMF doesn't give any synchronous behavior or dependency
387 * ordering for refresh operations, so we have to invent our
388 * own mechanism here. Get the refresh counter from the
389 * daemon, and wait for it to change. It's not pretty, but
393 buflen
= sizeof (twoints
);
395 status
= bridge_door_call(bridge
,
396 bdcBridgeGetRefreshCount
, DATALINK_INVALID_LINKID
,
397 &bdptr
, 0, &buflen
, B_FALSE
);
398 if (status
!= DLADM_STATUS_OK
)
400 if (twoints
[0] != refresh_count
)
402 (void) usleep(100000);
404 fmri
= alloc_fmri(TRILL_SVC_NAME
, bridge
);
406 return (DLADM_STATUS_NOMEM
);
407 status
= smf_refresh_instance(fmri
) == 0 ||
408 scf_error() == SCF_ERROR_NOT_FOUND
?
409 DLADM_STATUS_OK
: DLADM_STATUS_FAILED
;
416 * Look up bridge property values from SCF and return them.
419 dladm_bridge_get_properties(const char *instance_name
, UID_STP_CFG_T
*cfg
,
420 dladm_bridge_prot_t
*brprotp
)
424 boolean_t trill_enabled
;
427 cfg
->bridge_priority
= DEF_BR_PRIO
;
428 cfg
->max_age
= DEF_BR_MAXAGE
;
429 cfg
->hello_time
= DEF_BR_HELLOT
;
430 cfg
->forward_delay
= DEF_BR_FWDELAY
;
431 cfg
->force_version
= DEF_FORCE_VERS
;
433 (void) strlcpy(cfg
->vlan_name
, instance_name
, sizeof (cfg
->vlan_name
));
435 *brprotp
= DLADM_BRIDGE_PROT_STP
;
437 /* It's ok for this to be missing; it's installed separately */
438 if (bind_instance(TRILL_SVC_NAME
, instance_name
, &sstate
) == 0) {
439 trill_enabled
= B_FALSE
;
440 if (get_composed_properties(SCF_PG_GENERAL
, B_FALSE
, &sstate
) ==
442 (void) get_boolean(SCF_PROPERTY_ENABLED
, &sstate
,
445 *brprotp
= DLADM_BRIDGE_PROT_TRILL
;
446 drop_composed(&sstate
);
448 if (get_composed_properties(SCF_PG_GENERAL_OVR
, B_FALSE
,
450 (void) get_boolean(SCF_PROPERTY_ENABLED
, &sstate
,
453 *brprotp
= DLADM_BRIDGE_PROT_TRILL
;
454 drop_composed(&sstate
);
456 shut_down_scf(&sstate
);
459 cfg
->stp_enabled
= (*brprotp
== DLADM_BRIDGE_PROT_STP
) ?
460 STP_ENABLED
: STP_DISABLED
;
461 cfg
->field_mask
|= BR_CFG_STATE
;
463 if (bind_instance(BRIDGE_SVC_NAME
, instance_name
, &sstate
) != 0)
464 return (DLADM_STATUS_REPOSITORYINVAL
);
466 if (get_composed_properties("config", B_TRUE
, &sstate
) != 0) {
467 shut_down_scf(&sstate
);
468 return (DLADM_STATUS_REPOSITORYINVAL
);
471 if (get_count("priority", &sstate
, &value
) == 0) {
472 cfg
->bridge_priority
= value
;
473 cfg
->field_mask
|= BR_CFG_PRIO
;
475 if (get_count("max-age", &sstate
, &value
) == 0) {
476 cfg
->max_age
= value
/ IEEE_TIMER_SCALE
;
477 cfg
->field_mask
|= BR_CFG_AGE
;
479 if (get_count("hello-time", &sstate
, &value
) == 0) {
480 cfg
->hello_time
= value
/ IEEE_TIMER_SCALE
;
481 cfg
->field_mask
|= BR_CFG_HELLO
;
483 if (get_count("forward-delay", &sstate
, &value
) == 0) {
484 cfg
->forward_delay
= value
/ IEEE_TIMER_SCALE
;
485 cfg
->field_mask
|= BR_CFG_DELAY
;
487 if (get_count("force-protocol", &sstate
, &value
) == 0) {
488 cfg
->force_version
= value
;
489 cfg
->field_mask
|= BR_CFG_FORCE_VER
;
492 drop_composed(&sstate
);
493 shut_down_scf(&sstate
);
494 return (DLADM_STATUS_OK
);
498 * Retrieve special non-settable and undocumented parameters.
501 dladm_bridge_get_privprop(const char *instance_name
, boolean_t
*debugp
,
510 if (bind_instance(BRIDGE_SVC_NAME
, instance_name
, &sstate
) != 0)
511 return (DLADM_STATUS_REPOSITORYINVAL
);
513 if (get_composed_properties("config", B_TRUE
, &sstate
) != 0) {
514 shut_down_scf(&sstate
);
515 return (DLADM_STATUS_REPOSITORYINVAL
);
518 (void) get_boolean("debug", &sstate
, debugp
);
519 if (get_count("table-maximum", &sstate
, &value
) == 0)
520 *tablemaxp
= (uint32_t)value
;
522 drop_composed(&sstate
);
523 shut_down_scf(&sstate
);
524 return (DLADM_STATUS_OK
);
528 set_count_property(scf_handle_t
*handle
, scf_transaction_t
*tran
,
529 const char *propname
, uint64_t propval
)
531 scf_transaction_entry_t
*entry
;
532 scf_value_t
*value
= NULL
;
534 if ((entry
= scf_entry_create(handle
)) == NULL
)
537 if ((value
= scf_value_create(handle
)) == NULL
)
539 if (scf_transaction_property_new(tran
, entry
, propname
,
540 SCF_TYPE_COUNT
) != 0 &&
541 scf_transaction_property_change(tran
, entry
, propname
,
542 SCF_TYPE_COUNT
) != 0)
544 scf_value_set_count(value
, propval
);
545 if (scf_entry_add_value(entry
, value
) == 0)
550 scf_value_destroy(value
);
552 scf_entry_destroy_children(entry
);
553 scf_entry_destroy(entry
);
559 set_string_property(scf_handle_t
*handle
, scf_transaction_t
*tran
,
560 const char *propname
, const char *propval
)
562 scf_transaction_entry_t
*entry
;
563 scf_value_t
*value
= NULL
;
565 if ((entry
= scf_entry_create(handle
)) == NULL
)
568 if ((value
= scf_value_create(handle
)) == NULL
)
570 if (scf_transaction_property_new(tran
, entry
, propname
,
571 SCF_TYPE_ASTRING
) != 0 &&
572 scf_transaction_property_change(tran
, entry
, propname
,
573 SCF_TYPE_ASTRING
) != 0)
575 if (scf_value_set_astring(value
, propval
) != 0)
577 if (scf_entry_add_value(entry
, value
) == 0)
582 scf_value_destroy(value
);
584 scf_entry_destroy_children(entry
);
585 scf_entry_destroy(entry
);
591 set_fmri_property(scf_handle_t
*handle
, scf_transaction_t
*tran
,
592 const char *propname
, const char *propval
)
594 scf_transaction_entry_t
*entry
;
595 scf_value_t
*value
= NULL
;
597 if ((entry
= scf_entry_create(handle
)) == NULL
)
600 if ((value
= scf_value_create(handle
)) == NULL
)
602 if (scf_transaction_property_new(tran
, entry
, propname
,
603 SCF_TYPE_FMRI
) != 0 &&
604 scf_transaction_property_change(tran
, entry
, propname
,
607 if (scf_value_set_from_string(value
, SCF_TYPE_FMRI
, propval
) != 0)
609 if (scf_entry_add_value(entry
, value
) == 0)
614 scf_value_destroy(value
);
616 scf_entry_destroy_children(entry
);
617 scf_entry_destroy(entry
);
622 static dladm_status_t
623 dladm_bridge_persist_conf(dladm_handle_t handle
, const char *link
,
624 datalink_id_t linkid
)
627 dladm_status_t status
;
629 status
= dladm_create_conf(handle
, link
, linkid
, DATALINK_CLASS_BRIDGE
,
631 if (status
== DLADM_STATUS_OK
) {
633 * Create the datalink entry for the bridge. Note that all of
634 * the real configuration information is in SMF.
636 status
= dladm_write_conf(handle
, conf
);
637 dladm_destroy_conf(handle
, conf
);
642 /* Convert bridge protection option string to dladm_bridge_prot_t */
644 dladm_bridge_str2prot(const char *str
, dladm_bridge_prot_t
*brprotp
)
646 if (strcmp(str
, "stp") == 0)
647 *brprotp
= DLADM_BRIDGE_PROT_STP
;
648 else if (strcmp(str
, "trill") == 0)
649 *brprotp
= DLADM_BRIDGE_PROT_TRILL
;
651 return (DLADM_STATUS_BADARG
);
652 return (DLADM_STATUS_OK
);
655 /* Convert bridge protection option from dladm_bridge_prot_t to string */
657 dladm_bridge_prot2str(dladm_bridge_prot_t brprot
)
660 case DLADM_BRIDGE_PROT_STP
:
662 case DLADM_BRIDGE_PROT_TRILL
:
669 static dladm_status_t
670 enable_instance(const char *service_name
, const char *instance
)
672 dladm_status_t status
;
673 char *fmri
= alloc_fmri(service_name
, instance
);
676 return (DLADM_STATUS_NOMEM
);
677 status
= smf_enable_instance(fmri
, 0) == 0 ?
678 DLADM_STATUS_OK
: DLADM_STATUS_FAILED
;
684 * Shut down a possibly-running service instance. If this is a permanent
685 * change, then delete it from the system.
687 static dladm_status_t
688 shut_down_instance(const char *service_name
, const char *instance
,
691 dladm_status_t status
;
692 char *fmri
= alloc_fmri(service_name
, instance
);
697 return (DLADM_STATUS_NOMEM
);
699 if (smf_disable_instance(fmri
,
700 flags
& DLADM_OPT_PERSIST
? 0 : SMF_TEMPORARY
) == 0) {
701 useconds_t usecs
, umax
;
703 /* If we can disable, then wait for it to happen. */
704 umax
= DEFAULT_TIMEOUT
;
705 for (usecs
= INIT_WAIT_USECS
; umax
!= 0; umax
-= usecs
) {
706 state
= smf_get_state(fmri
);
708 strcmp(state
, SCF_STATE_STRING_DISABLED
) == 0)
714 (void) usleep(usecs
);
717 state
= smf_get_state(fmri
);
719 strcmp(state
, SCF_STATE_STRING_DISABLED
) == 0)
723 status
= umax
!= 0 ? DLADM_STATUS_OK
: DLADM_STATUS_FAILED
;
724 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
726 return (DLADM_STATUS_OK
);
728 status
= DLADM_STATUS_FAILED
;
732 if (status
== DLADM_STATUS_OK
&& (flags
& DLADM_OPT_PERSIST
) &&
733 bind_instance(service_name
, instance
, &sstate
) == 0) {
734 (void) scf_instance_delete(sstate
.ss_inst
);
735 shut_down_scf(&sstate
);
741 static dladm_status_t
742 disable_trill(const char *instance
, uint32_t flags
)
744 return (shut_down_instance(TRILL_SVC_NAME
, instance
, flags
));
748 * To enable TRILL, we must create a new instance of the TRILL service, then
749 * add proper dependencies to it, and finally mark it as enabled. The
750 * dependencies will keep it from going on-line until the bridge is running.
752 static dladm_status_t
753 enable_trill(const char *instance
)
755 dladm_status_t status
= DLADM_STATUS_FAILED
;
758 scf_transaction_t
*tran
= NULL
;
759 boolean_t new_instance
= B_FALSE
;
760 boolean_t new_pg
= B_FALSE
;
764 * This check is here in case the user has installed and then removed
765 * the package. SMF should remove the manifest, but currently does
768 if (access("/usr/sbin/trilld", F_OK
) != 0)
769 return (DLADM_STATUS_OPTMISSING
);
771 if ((status
= exact_instance(TRILL_SVC_NAME
, &sstate
)) !=
775 status
= DLADM_STATUS_FAILED
;
776 if (scf_service_get_instance(sstate
.ss_svc
, instance
, sstate
.ss_inst
) !=
778 if (scf_service_add_instance(sstate
.ss_svc
, instance
,
779 sstate
.ss_inst
) != 0)
781 new_instance
= B_TRUE
;
784 if ((tran
= scf_transaction_create(sstate
.ss_handle
)) == NULL
)
787 if ((sstate
.ss_pg
= scf_pg_create(sstate
.ss_handle
)) == NULL
)
790 if (scf_instance_get_pg(sstate
.ss_inst
, "bridging",
791 sstate
.ss_pg
) == 0) {
792 status
= DLADM_STATUS_OK
;
796 if ((fmri
= alloc_fmri(BRIDGE_SVC_NAME
, instance
)) == NULL
)
799 if (scf_instance_add_pg(sstate
.ss_inst
, "bridging",
800 SCF_GROUP_DEPENDENCY
, 0, sstate
.ss_pg
) != 0)
805 if (scf_transaction_start(tran
, sstate
.ss_pg
) != 0)
808 if (!set_string_property(sstate
.ss_handle
, tran
,
809 SCF_PROPERTY_GROUPING
, SCF_DEP_REQUIRE_ALL
))
811 if (!set_string_property(sstate
.ss_handle
, tran
,
812 SCF_PROPERTY_RESTART_ON
, SCF_DEP_RESET_ON_RESTART
))
814 if (!set_string_property(sstate
.ss_handle
, tran
,
815 SCF_PROPERTY_TYPE
, "service"))
817 if (!set_fmri_property(sstate
.ss_handle
, tran
,
818 SCF_PROPERTY_ENTITIES
, fmri
))
821 rv
= scf_transaction_commit(tran
);
822 scf_transaction_reset(tran
);
823 if (rv
== 0 && scf_pg_update(sstate
.ss_pg
) == -1)
829 status
= DLADM_STATUS_OK
;
834 scf_transaction_destroy_children(tran
);
835 scf_transaction_destroy(tran
);
838 if (status
!= DLADM_STATUS_OK
&& new_pg
)
839 (void) scf_pg_delete(sstate
.ss_pg
);
841 drop_composed(&sstate
);
844 * If we created an instance and then failed, then remove the instance
847 if (status
!= DLADM_STATUS_OK
&& new_instance
)
848 (void) scf_instance_delete(sstate
.ss_inst
);
850 shut_down_scf(&sstate
);
852 if (status
== DLADM_STATUS_OK
)
853 status
= enable_instance(TRILL_SVC_NAME
, instance
);
859 * Create a new bridge or modify an existing one. Update the SMF configuration
862 * Input timer values are in IEEE scaled (* 256) format.
865 dladm_bridge_configure(dladm_handle_t handle
, const char *name
,
866 const UID_STP_CFG_T
*cfg
, dladm_bridge_prot_t brprot
, uint32_t flags
)
868 dladm_status_t status
;
870 scf_transaction_t
*tran
= NULL
;
871 boolean_t new_instance
= B_FALSE
;
872 boolean_t new_pg
= B_FALSE
;
873 datalink_id_t linkid
= DATALINK_INVALID_LINKID
;
874 char linkname
[MAXLINKNAMELEN
];
877 if (!dladm_valid_bridgename(name
))
878 return (DLADM_STATUS_FAILED
);
880 if (flags
& DLADM_OPT_CREATE
) {
882 * This check is here in case the user has installed and then
883 * removed the package. SMF should remove the manifest, but
884 * currently does not.
886 if (access("/usr/lib/bridged", F_OK
) != 0)
887 return (DLADM_STATUS_OPTMISSING
);
889 (void) snprintf(linkname
, sizeof (linkname
), "%s0", name
);
890 status
= dladm_create_datalink_id(handle
, linkname
,
891 DATALINK_CLASS_BRIDGE
, DL_ETHER
,
892 flags
& (DLADM_OPT_ACTIVE
| DLADM_OPT_PERSIST
), &linkid
);
893 if (status
!= DLADM_STATUS_OK
)
896 if ((flags
& DLADM_OPT_PERSIST
) &&
897 (status
= dladm_bridge_persist_conf(handle
, linkname
,
898 linkid
) != DLADM_STATUS_OK
))
902 if (brprot
== DLADM_BRIDGE_PROT_TRILL
)
903 status
= enable_trill(name
);
905 status
= disable_trill(name
, flags
);
906 if (status
!= DLADM_STATUS_OK
)
909 if ((status
= exact_instance(BRIDGE_SVC_NAME
, &sstate
)) !=
913 /* set up for a series of scf calls */
914 status
= DLADM_STATUS_FAILED
;
916 if (scf_service_get_instance(sstate
.ss_svc
, name
, sstate
.ss_inst
) ==
918 if (flags
& DLADM_OPT_CREATE
) {
919 status
= DLADM_STATUS_EXIST
;
923 if (!(flags
& DLADM_OPT_CREATE
)) {
924 status
= DLADM_STATUS_NOTFOUND
;
927 if (scf_service_add_instance(sstate
.ss_svc
, name
,
928 sstate
.ss_inst
) != 0)
930 new_instance
= B_TRUE
;
933 if ((tran
= scf_transaction_create(sstate
.ss_handle
)) == NULL
)
936 if (cfg
->field_mask
& BR_CFG_ALL
) {
937 if ((sstate
.ss_pg
= scf_pg_create(sstate
.ss_handle
)) == NULL
)
939 if (scf_instance_add_pg(sstate
.ss_inst
, "config",
940 SCF_GROUP_APPLICATION
, 0, sstate
.ss_pg
) == 0) {
942 } else if (scf_instance_get_pg(sstate
.ss_inst
, "config",
943 sstate
.ss_pg
) != 0) {
947 if (scf_transaction_start(tran
, sstate
.ss_pg
) != 0)
950 if ((cfg
->field_mask
& BR_CFG_PRIO
) &&
951 !set_count_property(sstate
.ss_handle
, tran
,
952 "priority", cfg
->bridge_priority
))
954 if ((cfg
->field_mask
& BR_CFG_AGE
) &&
955 !set_count_property(sstate
.ss_handle
, tran
,
956 "max-age", cfg
->max_age
* IEEE_TIMER_SCALE
))
958 if ((cfg
->field_mask
& BR_CFG_HELLO
) &&
959 !set_count_property(sstate
.ss_handle
, tran
,
960 "hello-time", cfg
->hello_time
* IEEE_TIMER_SCALE
))
962 if ((cfg
->field_mask
& BR_CFG_DELAY
) &&
963 !set_count_property(sstate
.ss_handle
, tran
,
965 cfg
->forward_delay
* IEEE_TIMER_SCALE
))
967 if ((cfg
->field_mask
& BR_CFG_FORCE_VER
) &&
968 !set_count_property(sstate
.ss_handle
, tran
,
969 "force-protocol", cfg
->force_version
))
972 rv
= scf_transaction_commit(tran
);
973 scf_transaction_reset(tran
);
974 if (rv
== 0 && scf_pg_update(sstate
.ss_pg
) == -1)
982 * If we're modifying an existing and running bridge, then tell the
983 * daemon to update the requested values.
985 if ((flags
& DLADM_OPT_ACTIVE
) && !(flags
& DLADM_OPT_CREATE
))
986 status
= bridge_refresh(name
);
988 status
= DLADM_STATUS_OK
;
992 scf_transaction_destroy_children(tran
);
993 scf_transaction_destroy(tran
);
996 if (status
!= DLADM_STATUS_OK
&& new_pg
)
997 (void) scf_pg_delete(sstate
.ss_pg
);
999 drop_composed(&sstate
);
1002 * If we created an instance and then failed, then remove the instance
1005 if (status
!= DLADM_STATUS_OK
&& new_instance
)
1006 (void) scf_instance_delete(sstate
.ss_inst
);
1008 shut_down_scf(&sstate
);
1011 * Remove the bridge linkid if we've allocated one in this function but
1012 * we've failed to set up the SMF properties.
1015 if (status
!= DLADM_STATUS_OK
&& linkid
!= DATALINK_INVALID_LINKID
) {
1016 (void) dladm_remove_conf(handle
, linkid
);
1017 (void) dladm_destroy_datalink_id(handle
, linkid
, flags
);
1024 * Enable a newly-created bridge in SMF by creating "general/enabled" and
1025 * deleting any "general_ovr/enabled" (used for temporary services).
1028 dladm_bridge_enable(const char *name
)
1030 return (enable_instance(BRIDGE_SVC_NAME
, name
));
1034 * Set a link as a member of a bridge, or remove bridge membership. If the
1035 * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running.
1036 * In all other cases, we must tell the daemon to add or delete the link in
1037 * order to stay in sync.
1040 dladm_bridge_setlink(dladm_handle_t handle
, datalink_id_t linkid
,
1043 dladm_status_t status
;
1045 char oldbridge
[MAXLINKNAMELEN
];
1046 boolean_t has_oldbridge
;
1047 boolean_t changed
= B_FALSE
;
1049 if (*bridge
!= '\0' && !dladm_valid_bridgename(bridge
))
1050 return (DLADM_STATUS_FAILED
);
1052 status
= dladm_open_conf(handle
, linkid
, &conf
);
1053 if (status
!= DLADM_STATUS_OK
)
1056 has_oldbridge
= B_FALSE
;
1057 status
= dladm_get_conf_field(handle
, conf
, FBRIDGE
, oldbridge
,
1058 sizeof (oldbridge
));
1059 if (status
== DLADM_STATUS_OK
) {
1061 * Don't allow a link to be reassigned directly from one bridge
1062 * to another. It must be removed first.
1064 if (*oldbridge
!= '\0' && *bridge
!= '\0') {
1065 status
= DLADM_STATUS_EXIST
;
1068 has_oldbridge
= B_TRUE
;
1069 } else if (status
!= DLADM_STATUS_NOTFOUND
) {
1073 if (*bridge
!= '\0') {
1074 status
= dladm_set_conf_field(handle
, conf
, FBRIDGE
,
1075 DLADM_TYPE_STR
, bridge
);
1077 } else if (has_oldbridge
) {
1078 status
= dladm_unset_conf_field(handle
, conf
, FBRIDGE
);
1081 status
= DLADM_STATUS_OK
;
1084 if (status
== DLADM_STATUS_OK
)
1085 status
= dladm_write_conf(handle
, conf
);
1088 dladm_destroy_conf(handle
, conf
);
1089 if (changed
&& status
== DLADM_STATUS_OK
) {
1090 if (bridge
[0] == '\0')
1092 status
= bridge_refresh(bridge
);
1098 * Get the name of the bridge of which the given linkid is a member.
1101 dladm_bridge_getlink(dladm_handle_t handle
, datalink_id_t linkid
, char *bridge
,
1104 dladm_status_t status
;
1107 if ((status
= dladm_getsnap_conf(handle
, linkid
, &conf
)) !=
1112 status
= dladm_get_conf_field(handle
, conf
, FBRIDGE
, bridge
, bridgelen
);
1113 if (status
== DLADM_STATUS_OK
&& *bridge
== '\0')
1114 status
= DLADM_STATUS_NOTFOUND
;
1116 dladm_destroy_conf(handle
, conf
);
1121 dladm_bridge_refresh(dladm_handle_t handle
, datalink_id_t linkid
)
1123 char bridge
[MAXLINKNAMELEN
];
1124 dladm_status_t status
;
1126 status
= dladm_bridge_getlink(handle
, linkid
, bridge
, sizeof (bridge
));
1127 if (status
== DLADM_STATUS_NOTFOUND
)
1128 return (DLADM_STATUS_OK
);
1129 if (status
== DLADM_STATUS_OK
)
1130 status
= bridge_refresh(bridge
);
1134 typedef struct bridge_held_arg_s
{
1135 const char *bha_bridge
;
1136 boolean_t bha_isheld
;
1137 } bridge_held_arg_t
;
1140 i_dladm_bridge_is_held(dladm_handle_t handle
, datalink_id_t linkid
, void *arg
)
1142 dladm_status_t status
= DLADM_STATUS_FAILED
;
1144 char bridge
[MAXLINKNAMELEN
];
1145 bridge_held_arg_t
*bha
= arg
;
1147 if ((status
= dladm_getsnap_conf(handle
, linkid
, &conf
)) !=
1149 return (DLADM_WALK_CONTINUE
);
1150 status
= dladm_get_conf_field(handle
, conf
, FBRIDGE
, bridge
,
1152 if (status
== DLADM_STATUS_OK
&& strcmp(bha
->bha_bridge
, bridge
) == 0) {
1153 bha
->bha_isheld
= B_TRUE
;
1154 dladm_destroy_conf(handle
, conf
);
1155 return (DLADM_WALK_TERMINATE
);
1157 dladm_destroy_conf(handle
, conf
);
1158 return (DLADM_WALK_CONTINUE
);
1163 * Delete a previously created bridge.
1166 dladm_bridge_delete(dladm_handle_t handle
, const char *bridge
, uint32_t flags
)
1168 datalink_id_t linkid
;
1169 datalink_class_t
class;
1170 dladm_status_t status
;
1171 char linkname
[MAXLINKNAMELEN
];
1173 if (!dladm_valid_bridgename(bridge
))
1174 return (DLADM_STATUS_LINKINVAL
);
1176 /* Get the datalink ID for this bridge */
1177 (void) snprintf(linkname
, sizeof (linkname
), "%s0", bridge
);
1178 if (dladm_name2info(handle
, linkname
, &linkid
, NULL
, NULL
, NULL
) !=
1180 linkid
= DATALINK_INVALID_LINKID
;
1181 else if (dladm_datalink_id2info(handle
, linkid
, NULL
, &class, NULL
,
1182 NULL
, 0) != DLADM_STATUS_OK
)
1183 linkid
= DATALINK_INVALID_LINKID
;
1184 else if (class != DATALINK_CLASS_BRIDGE
)
1185 return (DLADM_STATUS_BADARG
);
1187 if ((flags
& DLADM_OPT_ACTIVE
) && linkid
== DATALINK_INVALID_LINKID
)
1188 return (DLADM_STATUS_BADARG
);
1190 if (flags
& DLADM_OPT_PERSIST
) {
1191 bridge_held_arg_t arg
;
1193 arg
.bha_bridge
= bridge
;
1194 arg
.bha_isheld
= B_FALSE
;
1197 * See whether there are any persistent links using this
1198 * bridge. If so, we fail the operation.
1200 (void) dladm_walk_datalink_id(i_dladm_bridge_is_held
, handle
,
1201 &arg
, DATALINK_CLASS_PHYS
| DATALINK_CLASS_AGGR
|
1202 DATALINK_CLASS_ETHERSTUB
| DATALINK_CLASS_SIMNET
,
1203 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
1205 return (DLADM_STATUS_LINKBUSY
);
1208 if ((status
= disable_trill(bridge
, flags
)) != DLADM_STATUS_OK
)
1211 /* Disable or remove the SMF instance */
1212 status
= shut_down_instance(BRIDGE_SVC_NAME
, bridge
, flags
);
1213 if (status
!= DLADM_STATUS_OK
)
1216 if (flags
& DLADM_OPT_ACTIVE
) {
1218 * Delete ACTIVE linkprop now that daemon is gone.
1220 (void) dladm_set_linkprop(handle
, linkid
, NULL
, NULL
, 0,
1222 (void) dladm_destroy_datalink_id(handle
, linkid
,
1226 if (flags
& DLADM_OPT_PERSIST
) {
1227 (void) dladm_remove_conf(handle
, linkid
);
1228 (void) dladm_destroy_datalink_id(handle
, linkid
,
1237 /* Check if given name is valid for bridges */
1239 dladm_valid_bridgename(const char *bridge
)
1241 size_t len
= strnlen(bridge
, MAXLINKNAMELEN
);
1244 if (len
== MAXLINKNAMELEN
)
1248 * The bridge name cannot start or end with a digit.
1250 if (isdigit(bridge
[0]) || isdigit(bridge
[len
- 1]))
1254 * The legal characters within a bridge name are:
1255 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_').
1257 for (cp
= bridge
; *cp
!= '\0'; cp
++) {
1258 if (!isalnum(*cp
) && *cp
!= '_')
1266 * Convert a bridge-related observability node name back into the name of the
1267 * bridge. Returns B_FALSE without making changes if the input name is not in
1271 dladm_observe_to_bridge(char *link
)
1275 llen
= strnlen(link
, MAXLINKNAMELEN
);
1276 if (llen
< 2 || link
[llen
- 1] != '0' || isdigit(link
[llen
- 2]))
1278 link
[llen
- 1] = '\0';
1283 * Get bridge property values from the running daemon and return them in a
1287 dladm_bridge_run_properties(const char *instname
, UID_STP_CFG_T
*smcfg
,
1288 dladm_bridge_prot_t
*brprotp
)
1290 dladm_status_t status
;
1291 bridge_door_cfg_t bdcf
;
1292 bridge_door_cfg_t
*bdcfp
= &bdcf
;
1293 size_t buflen
= sizeof (bdcf
);
1295 status
= bridge_door_call(instname
, bdcBridgeGetConfig
,
1296 DATALINK_INVALID_LINKID
, (void **)&bdcfp
, 0, &buflen
, B_FALSE
);
1297 if (status
== DLADM_STATUS_OK
) {
1298 *smcfg
= bdcfp
->bdcf_cfg
;
1299 *brprotp
= bdcfp
->bdcf_prot
;
1301 smcfg
->field_mask
= 0;
1302 *brprotp
= DLADM_BRIDGE_PROT_STP
;
1308 * Get bridge state from the running daemon and return in structure borrowed
1312 dladm_bridge_state(const char *instname
, UID_STP_STATE_T
*statep
)
1314 size_t buflen
= sizeof (*statep
);
1316 return (bridge_door_call(instname
, bdcBridgeGetState
,
1317 DATALINK_INVALID_LINKID
, (void **)&statep
, 0, &buflen
, B_FALSE
));
1320 /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */
1322 dladm_bridge_get_portlist(const char *instname
, uint_t
*nports
)
1324 size_t buflen
= sizeof (int) + MAXPORTS
* sizeof (datalink_id_t
);
1327 if ((rbuf
= malloc(buflen
)) == NULL
)
1329 if (bridge_door_call(instname
, bdcBridgeGetPorts
,
1330 DATALINK_INVALID_LINKID
, (void **)&rbuf
, 0, &buflen
, B_TRUE
) !=
1336 * Returns an array of datalink_id_t values for all the ports
1337 * part of the bridge instance. First entry in the array is the
1341 return ((datalink_id_t
*)(rbuf
+ 1));
1346 dladm_bridge_free_portlist(datalink_id_t
*dlp
)
1348 free((int *)dlp
- 1);
1351 /* Retrieve Bridge port configuration values */
1353 dladm_bridge_get_port_cfg(dladm_handle_t handle
, datalink_id_t linkid
,
1354 int field
, int *valuep
)
1356 UID_STP_PORT_CFG_T portcfg
;
1357 dladm_status_t status
;
1359 status
= port_door_call(handle
, linkid
, bdcPortGetConfig
, &portcfg
,
1360 0, sizeof (portcfg
));
1361 if (status
!= DLADM_STATUS_OK
)
1366 *valuep
= portcfg
.admin_port_path_cost
;
1369 *valuep
= portcfg
.port_priority
;
1372 *valuep
= portcfg
.admin_point2point
;
1375 *valuep
= portcfg
.admin_edge
;
1377 case PT_CFG_NON_STP
:
1378 *valuep
= !portcfg
.admin_non_stp
;
1381 *valuep
= (portcfg
.field_mask
& PT_CFG_MCHECK
) ? 1 : 0;
1387 /* Retreive Bridge port status (disabled, bad SDU etc.) */
1389 dladm_bridge_link_state(dladm_handle_t handle
, datalink_id_t linkid
,
1390 UID_STP_PORT_STATE_T
*spsp
)
1392 return (port_door_call(handle
, linkid
, bdcPortGetState
, spsp
, 0,
1396 /* Retrieve Bridge forwarding status of the given link */
1398 dladm_bridge_get_forwarding(dladm_handle_t handle
, datalink_id_t linkid
,
1402 dladm_status_t status
;
1404 status
= port_door_call(handle
, linkid
, bdcPortGetForwarding
, twoints
,
1405 0, sizeof (twoints
));
1406 if (status
== DLADM_STATUS_OK
)
1407 *valuep
= twoints
[0];
1411 /* Retrieve Bridge forwarding table entries */
1413 dladm_bridge_get_fwdtable(dladm_handle_t handle
, const char *bridge
,
1416 bridge_listfwd_t
*blf
= NULL
, *newblf
, blfread
;
1417 uint_t nblf
= 0, maxblf
= 0;
1418 static uint8_t zero_addr
[ETHERADDRL
];
1421 (void) memset(&blfread
, 0, sizeof (blfread
));
1422 (void) snprintf(blfread
.blf_name
, sizeof (blfread
.blf_name
),
1425 if (nblf
>= maxblf
) {
1426 maxblf
= maxblf
== 0 ? 64 : (maxblf
<< 1);
1427 newblf
= realloc(blf
, maxblf
* sizeof (*blf
));
1428 if (newblf
== NULL
) {
1435 rc
= ioctl(dladm_dld_fd(handle
), BRIDGE_IOC_LISTFWD
, &blfread
);
1441 if (memcmp(blfread
.blf_dest
, zero_addr
, ETHERADDRL
) == 0)
1443 blf
[nblf
++] = blfread
;
1451 dladm_bridge_free_fwdtable(bridge_listfwd_t
*blf
)
1456 /* Retrieve list of TRILL nicknames from the TRILL module */
1458 dladm_bridge_get_trillnick(const char *bridge
, uint_t
*nnick
)
1461 char brcopy
[MAXLINKNAMELEN
];
1462 trill_listnick_t
*tln
= NULL
, *newtln
, tlnread
;
1463 uint_t ntln
= 0, maxtln
= 0;
1465 if ((fd
= socket(PF_TRILL
, SOCK_DGRAM
, 0)) == -1)
1467 (void) strlcpy(brcopy
, bridge
, sizeof (brcopy
));
1468 if (ioctl(fd
, TRILL_GETBRIDGE
, &brcopy
) < 0) {
1472 (void) memset(&tlnread
, 0, sizeof (tlnread
));
1474 if (ntln
>= maxtln
) {
1475 maxtln
= maxtln
== 0 ? 64 : (maxtln
<< 1);
1476 newtln
= realloc(tln
, maxtln
* sizeof (*tln
));
1477 if (newtln
== NULL
) {
1484 if (ioctl(fd
, TRILL_LISTNICK
, &tlnread
) == -1) {
1489 if (tlnread
.tln_nick
== 0)
1491 tln
[ntln
++] = tlnread
;
1500 dladm_bridge_free_trillnick(trill_listnick_t
*tln
)
1505 /* Retrieve any stored TRILL nickname from TRILL SMF service */
1507 dladm_bridge_get_nick(const char *bridge
)
1511 uint16_t nickname
= RBRIDGE_NICKNAME_NONE
;
1513 if (bind_instance(TRILL_SVC_NAME
, bridge
, &sstate
) != 0)
1516 if (get_composed_properties("config", B_TRUE
, &sstate
) == 0 &&
1517 get_count("nickname", &sstate
, &value
) == 0)
1519 shut_down_scf(&sstate
);
1523 /* Stores TRILL nickname in SMF configuraiton for the TRILL service */
1525 dladm_bridge_set_nick(const char *bridge
, uint16_t nick
)
1528 scf_transaction_t
*tran
= NULL
;
1529 boolean_t new_pg
= B_FALSE
;
1533 if (exact_instance(TRILL_SVC_NAME
, &sstate
) != DLADM_STATUS_OK
)
1536 if (scf_service_get_instance(sstate
.ss_svc
, bridge
, sstate
.ss_inst
) !=
1539 if ((tran
= scf_transaction_create(sstate
.ss_handle
)) == NULL
)
1541 if ((sstate
.ss_pg
= scf_pg_create(sstate
.ss_handle
)) == NULL
)
1543 if (scf_instance_add_pg(sstate
.ss_inst
, "config",
1544 SCF_GROUP_APPLICATION
, 0, sstate
.ss_pg
) == 0) {
1546 } else if (scf_instance_get_pg(sstate
.ss_inst
, "config",
1547 sstate
.ss_pg
) != 0) {
1551 if (scf_transaction_start(tran
, sstate
.ss_pg
) != 0)
1553 if (!set_count_property(sstate
.ss_handle
, tran
, "nickname",
1556 rv
= scf_transaction_commit(tran
);
1557 scf_transaction_reset(tran
);
1558 if (rv
== 0 && scf_pg_update(sstate
.ss_pg
) == -1)
1564 scf_transaction_destroy_children(tran
);
1565 scf_transaction_destroy(tran
);
1568 if (rv
!= 1 && new_pg
)
1569 (void) scf_pg_delete(sstate
.ss_pg
);
1571 drop_composed(&sstate
);
1572 shut_down_scf(&sstate
);
1573 if (rv
== 1 && (fmri
= alloc_fmri(TRILL_SVC_NAME
, bridge
)) != NULL
) {
1574 (void) smf_refresh_instance(fmri
);