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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
39 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
47 #include <libscf_priv.h>
51 * This program moves routing management under SMF. We do this by giving
52 * routeadm options that allow interaction with SMF services. These include:
53 * - setting the routing services routeadm will enable
54 * # routeadm -s routing-svcs="fmri [fmri...]"
55 * where each fmri is an SMF routing service.
56 * - changing properties of routing services
57 * # routeadm -m fmri key=value [key=value...]
58 * - listing routing daemon properties
60 * where all properties in the "routing" property group are listed.
62 * By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
63 * can also support running of routing daemons with no SMF service under SMF.
64 * Specifying a routing daemon with no SMF counterpart results in the
65 * daemon, it`s arguments and stop command being set in the appropriate instance
66 * to be picked up by start/stop methods.
68 * Internally, routeadm keeps track of routing services by setting the
69 * "current-routing-svc" property to "true" in the services it manages.
70 * So for example, running
71 * # routeadm -s routing-svcs="route:default ripng:default"
72 * sets this variable in each instance specified. If the user specifies a
73 * non-SMF routing daemon via
74 * # routeadm -s ipv4-routing-daemon=/usr/sbin/mydaemon
75 * the variable will be set for the legacy-routing:ipv4 instance.
77 * In order to ensure that the SMF versions of routing daemons are used
78 * where possible, routeadm will check the daemons specified in
79 * ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
80 * SMF counterpart. If so, rather than running the legacy service
81 * we move configuration, specifically the associated daemon arguments
82 * to the SMF counterpart. From there, when the daemon is enabled, it
83 * will pick up the daemon arguments setting, transfer the argument string
84 * to the appropriate properties and run the service.
86 * To support the semantics of routeadm -e (enable at next boot) through SMF,
87 * we make use of temporary state changes, which last only until reboot.
88 * For example, if a service is disabled, and it is to be enabled via
89 * routeadm -e, we simply change the disable to a temporary disable,
90 * and set the persistent enabled value to true. This ensures the daemon
91 * will run at next boot, but not now. The reverse is true for disabling
92 * enabled instances (and if the daemon is enabled when we issue the enable,
93 * we do nothing since it is already in the desired state).
95 * Since the code is quite involved, we provide a guide to the more complex
96 * actions taken in response to user commands.
98 * routeadm -e[d] ipv4[6]-routing[forwarding]
100 * In this case, the goal is to prepare the configured routing daemons
101 * (specified through routeadm -s routing-svcs="...") or forwarding
102 * services to switch on (-e) or of (-d) at next boot.
104 * Since this operation must be applied to multiple services in the
105 * routing daemon case (as opposed to the single ipv4[6]-forwarding
106 * service), we make use of the scf_walk_fmri() function, which
107 * applies a callback function to all matching functions. In the case
108 * of the routing daemons, we pass in a NULL signifying that all
109 * instances should be walked (we then weed out the relevant routing
110 * services through presence of the routeadm/protocol property). In
111 * the case of enable, a routing service is enabled IFF it has the
112 * previously-mentioned property - with an appropriate value (i.e. ipv4
113 * for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
114 * property set to true (this is set by other operations such as
115 * routeadm -s routing-svcs="..."). Then, smf_enable_instance() or
116 * smf_disable_instance() is called, setting the temporary state to
117 * the current state of the service. This then allows setting of
118 * general/enabled value to next-boot value. In the case of disabling
119 * ipv4[6]-routing, all valid ipv4[6] routing daemons are prepared
120 * for next-boot disable, not just those specified via routing-svcs (this
121 * means that if the user enables routing daemons with "svcadm enable",
122 * disabling global routing does really switch off all routing daemons).
124 * This is implemented through the ra_get_set_opt_common_cb() function,
125 * called by the ra_set_persistent_opt_cb() function. The same
126 * function can be used for both routing and forwarding options, in the
127 * latter case we simply provide the specific FMRI of the forwarding
128 * service in question (ipv4-forwarding or ipv6-forwarding), and dispense
129 * with the eligibility tests we need to weed out the routing services
132 * Before we initiate the "enable" however, we must check routing daemons
133 * specified via the legacy variables (ipv4-routing-daemon etc).
134 * If they map to SMF routing services, we wish to transfer their
135 * configuration to the corresponding services and use them instead of
136 * the legacy services. To do this, we need to match the daemon program
137 * against the routeadm/daemon property of each routing daemon (we use
138 * scf_walk_fmri() and the routeadm/protocol property again to identify
139 * daemons). If a match is found, the daemon arguments are transferred
140 * to the appropriate service`s daemon-args property, to be picked up
141 * by it`s start method and converted into appropriate property values.
142 * This is accomplished by ra_check_legacy_daemons(), and the callback
143 * operation is carried out by ra_upgrade_legacy_daemons_cb(). If the
144 * daemon was not upgraded, we need to mark the legacy-routing:ipv4[6]
145 * instance to be enabled (by routeadm -e), since it now must run the
146 * un-upgradeable legacy daemon.
150 * Lists all properties and values in the routing property group associated
151 * with instance fmri. We simply walk through the composed property
152 * group, displaying all values. See ra_list_props_cb().
154 * routeadm -m fmri key=value ...
156 * Modify property values in the routing property group. If the same
157 * key is used more than once, multiple property values are set for that
158 * property. Properties must exist in the composed property group, but
159 * will only ever be set at the instance level to prevent multiple
160 * instances inheriting the property in error. See ra_modify_props_cb().
162 * routeadm -s var=value
164 * In all cases bar the routing-svcs variable, this simply involves
165 * setting the appropriate SMF property value for the variable. The
166 * routing-svcs case is more complex, since we would like operations
167 * like the following to have intuitive effects:
168 * # routeadm -s routing-svcs=route -e ipv4-routing -u
169 * # routeadm -s routing-svcs=rdisc -u
170 * i.e., in the end, rdisc is the only routing service running. To
171 * accomplish this switchover, we need to disable the old routing-svcs
172 * and enable the new, marking the latter with the curr-routing-svc
173 * property so that routeadm -e will pick them up. This is carried
174 * out by the ra_update_routing_svcs() function.
176 * routeadm -R alt_root ...
178 * Used to support use of routeadm in Custom Jumpstart scripts, this
179 * option causes all subsequent commands to be appended to the
180 * /var/svc/profile/upgrade file, which is run on the subsequent boot.
181 * This is done because the SMF repository is not available to make
182 * the modifications to property values required in routeadm operations.
186 * Update applies the "next boot" state to the current system. Here
187 * we simply take the persistent state (general/enabled value) and
188 * make it the current state through smf_enable_instance() or
189 * smf_disable_instance() as appropriate (these calls, without the
190 * temporary flag set, delete the general_ovr/enabled property).
193 #define RA_OPT_IPV4_ROUTING "ipv4-routing"
194 #define RA_OPT_IPV6_ROUTING "ipv6-routing"
195 #define RA_OPT_IPV4_FORWARDING "ipv4-forwarding"
196 #define RA_OPT_IPV6_FORWARDING "ipv6-forwarding"
198 #define IS_ROUTING_OPT(opt) (strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
199 strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
201 #define RA_VAR_IPV4_ROUTING_DAEMON "ipv4-routing-daemon"
202 #define RA_VAR_IPV4_ROUTING_DAEMON_ARGS "ipv4-routing-daemon-args"
203 #define RA_VAR_IPV4_ROUTING_STOP_CMD "ipv4-routing-stop-cmd"
204 #define RA_VAR_IPV6_ROUTING_DAEMON "ipv6-routing-daemon"
205 #define RA_VAR_IPV6_ROUTING_DAEMON_ARGS "ipv6-routing-daemon-args"
206 #define RA_VAR_IPV6_ROUTING_STOP_CMD "ipv6-routing-stop-cmd"
207 #define RA_VAR_ROUTING_SVCS "routing-svcs"
210 #define RA_INSTANCE_ALL NULL
211 #define RA_INSTANCE_ROUTING_SETUP "svc:/network/routing-setup:default"
212 #define RA_INSTANCE_IPV4_FORWARDING "svc:/network/ipv4-forwarding:default"
213 #define RA_INSTANCE_IPV6_FORWARDING "svc:/network/ipv6-forwarding:default"
214 #define RA_INSTANCE_LEGACY_ROUTING_IPV4 \
215 "svc:/network/routing/legacy-routing:ipv4"
216 #define RA_INSTANCE_LEGACY_ROUTING_IPV6 \
217 "svc:/network/routing/legacy-routing:ipv6"
218 #define RA_INSTANCE_NDP "svc:/network/routing/ndp:default"
220 #define RA_PG_ROUTEADM "routeadm"
221 #define RA_PROP_CURR_ROUTING_SVC "current-routing-svc"
222 #define RA_PROP_ROUTING_SVCS "routing-svcs"
223 #define RA_PROP_DEFAULT_ROUTING_SVCS "default-routing-svcs"
224 #define RA_PROP_PROTO "protocol"
225 #define RA_PROP_DAEMON "daemon"
226 #define RA_PROP_DEFAULT_DAEMON "default-daemon"
227 #define RA_PROP_DAEMON_ARGS "daemon-args"
228 #define RA_PROP_DEFAULT_DAEMON_ARGS "default-daemon-args"
229 #define RA_PROP_DAEMON_STOP_CMD "daemon-stop-cmd"
230 #define RA_PROP_DEFAULT_STOP_CMD "default-daemon"
231 #define RA_PROP_LEGACY_DAEMON "legacy-daemon"
232 #define RA_PROP_DEFAULT_IPV4_ROUTING "default-ipv4-routing"
233 #define RA_PROP_DEFAULT_IPV6_ROUTING "default-ipv6-routing"
234 #define RA_PROP_DEFAULT_IPV4_FORWARDING "default-ipv4-forwarding"
235 #define RA_PROP_DEFAULT_IPV6_FORWARDING "default-ipv6-forwarding"
236 #define RA_PROP_IPV4_ROUTING_SET "ipv4-routing-set"
237 #define RA_PROP_IPV6_ROUTING_SET "ipv6-routing-set"
238 #define RA_PROP_ROUTING_CONF_READ "routing-conf-read"
240 #define RA_PG_ROUTING "routing"
242 #define RA_PROPVAL_BOOLEAN_TRUE "true"
243 #define RA_PROPVAL_BOOLEAN_FALSE "false"
244 #define RA_PROPVAL_PROTO_IPV4 "ipv4"
245 #define RA_PROPVAL_PROTO_IPV6 "ipv6"
247 #define RA_SVC_FLAG_NONE 0x0
248 #define RA_SVC_FLAG_IPV4_ROUTING 0x1
249 #define RA_SVC_FLAG_IPV6_ROUTING 0x2
251 #define RA_SMF_UPGRADE_FILE "/var/svc/profile/upgrade"
252 #define RA_SMF_UPGRADE_MSG " # added by routeadm(1M)"
253 #define RA_CONF_FILE "/etc/inet/routing.conf"
254 #define RA_CONF_FILE_OLD "/etc/inet/routing.conf.old"
255 #define RA_MAX_CONF_LINE 256
258 * Option value. Each option requires an FMRI identifying which services
259 * to run the get_current/persistent scf_walk_fmri() function with, and
260 * associated flags (to ensure that in the case that multiple services
261 * match, we select the correct ones). In addition, we specify the FMRI
262 * and property used to set default option value. The opt_enabled field
263 * is used to hold retrieved state from get_*_opt_() callbacks and to specify
264 * desired state for set_*_opt() operations.
267 typedef struct raopt
{
268 const char *opt_name
;
269 const char *opt_fmri
;
271 boolean_t opt_enabled
;
272 const char *opt_default_fmri
;
273 const char *opt_default_prop
;
274 boolean_t opt_default_enabled
;
278 raopt_t ra_opts
[] = {
279 { RA_OPT_IPV4_ROUTING
, RA_INSTANCE_ALL
, RA_SVC_FLAG_IPV4_ROUTING
,
280 B_FALSE
, RA_INSTANCE_ROUTING_SETUP
, RA_PROP_DEFAULT_IPV4_ROUTING
,
282 { RA_OPT_IPV6_ROUTING
, RA_INSTANCE_ALL
, RA_SVC_FLAG_IPV6_ROUTING
,
283 B_FALSE
, RA_INSTANCE_ROUTING_SETUP
, RA_PROP_DEFAULT_IPV6_ROUTING
,
285 { RA_OPT_IPV4_FORWARDING
, RA_INSTANCE_IPV4_FORWARDING
, RA_SVC_FLAG_NONE
,
286 B_FALSE
, RA_INSTANCE_IPV4_FORWARDING
, RA_PROP_DEFAULT_IPV4_FORWARDING
,
288 { RA_OPT_IPV6_FORWARDING
, RA_INSTANCE_IPV6_FORWARDING
, RA_SVC_FLAG_NONE
,
289 B_FALSE
, RA_INSTANCE_IPV6_FORWARDING
, RA_PROP_DEFAULT_IPV6_FORWARDING
,
291 { NULL
, NULL
, RA_SVC_FLAG_NONE
, B_FALSE
, NULL
, NULL
, B_FALSE
}
294 typedef enum option_values
{
295 OPT_INVALID
, OPT_ENABLED
, OPT_DISABLED
, OPT_DEFAULT
, OPT_UNKNOWN
298 typedef struct ra_var
{
299 const char *var_name
;
300 const char *var_fmri
;
301 const char *var_prop
;
303 const char *var_default_fmri
;
304 const char *var_default_prop
;
305 char *var_default_value
;
308 ravar_t ra_vars
[] = {
309 { RA_VAR_IPV4_ROUTING_DAEMON
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
310 RA_PROP_DAEMON
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
311 RA_PROP_DEFAULT_DAEMON
, NULL
},
312 { RA_VAR_IPV4_ROUTING_DAEMON_ARGS
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
313 RA_PROP_DAEMON_ARGS
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
314 RA_PROP_DEFAULT_DAEMON_ARGS
, NULL
},
315 { RA_VAR_IPV4_ROUTING_STOP_CMD
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
316 RA_PROP_DAEMON_STOP_CMD
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
317 RA_PROP_DEFAULT_STOP_CMD
, NULL
},
318 { RA_VAR_IPV6_ROUTING_DAEMON
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
319 RA_PROP_DAEMON
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
320 RA_PROP_DEFAULT_DAEMON
, NULL
},
321 { RA_VAR_IPV6_ROUTING_DAEMON_ARGS
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
322 RA_PROP_DAEMON_ARGS
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
323 RA_PROP_DEFAULT_DAEMON_ARGS
, NULL
},
324 { RA_VAR_IPV6_ROUTING_STOP_CMD
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
325 RA_PROP_DAEMON_STOP_CMD
, NULL
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
326 RA_PROP_DEFAULT_STOP_CMD
, NULL
},
327 { RA_VAR_ROUTING_SVCS
, RA_INSTANCE_ROUTING_SETUP
,
328 RA_PROP_ROUTING_SVCS
, NULL
, RA_INSTANCE_ROUTING_SETUP
,
329 RA_PROP_DEFAULT_ROUTING_SVCS
, NULL
},
330 { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
}
334 #define IPV4_ROUTING_DAEMON 0
335 RA_VAR_IPV4_ROUTING_DAEMON
,
336 #define IPV4_ROUTING_DAEMON_ARGS 1
337 RA_VAR_IPV4_ROUTING_DAEMON_ARGS
,
338 #define IPV4_ROUTING_STOP_CMD 2
339 RA_VAR_IPV4_ROUTING_STOP_CMD
,
340 #define IPV6_ROUTING_DAEMON 3
341 RA_VAR_IPV6_ROUTING_DAEMON
,
342 #define IPV6_ROUTING_DAEMON_ARGS 4
343 RA_VAR_IPV6_ROUTING_DAEMON_ARGS
,
344 #define IPV6_ROUTING_STOP_CMD 5
345 RA_VAR_IPV6_ROUTING_STOP_CMD
,
346 #define ROUTING_SVCS 6
351 #define IS_IPV4_VAR(varname) (strncmp(varname, "ipv4", 4) == 0)
352 #define IS_IPV6_VAR(varname) (strncmp(varname, "ipv6", 4) == 0)
353 #define VAR_PROTO_MATCH(varname, proto) (strncmp(varname, proto, 4) == 0)
354 #define IPV4_VARS_UNSET \
355 (strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
356 strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
357 strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
359 #define IPV6_VARS_UNSET \
360 (strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
361 strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
362 strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
365 * Structure used in modify operations to tie property name and multiple values
368 typedef struct ra_prop
{
374 typedef int (*ra_smf_cb_t
)(void *, scf_walkinfo_t
*);
376 /* Used to store program name */
377 static const char *myname
;
379 static void usage(void);
381 static int ra_check_legacy_daemons(void);
382 static int ra_upgrade_legacy_daemons(void);
383 static int ra_upgrade_cmd(char, int, char **);
384 static int ra_update(void);
385 static int ra_update_routing_svcs(char *);
386 static int ra_report(boolean_t
, const char *);
387 static int ra_smf_cb(ra_smf_cb_t
, const char *, void *);
388 static int ra_upgrade_from_legacy_conf(void);
389 static int ra_numv6intfs(void);
390 static int ra_parseconf(void);
391 static int ra_parseopt(char *, int, raopt_t
*);
392 static int ra_parsevar(char *, ravar_t
*);
393 static oval_t
ra_str2oval(const char *);
394 static raopt_t
*ra_str2opt(const char *);
395 static void ra_resetopts(void);
396 static ravar_t
*ra_str2var(const char *);
397 static void ra_resetvars(const char *);
398 static char *ra_intloptname(const char *);
400 /* Callback for upgrade of legacy daemons */
401 static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t
*);
403 /* Callbacks used to set/retieve routing options */
404 static int ra_set_current_opt_cb(void *, scf_walkinfo_t
*);
405 static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t
*);
406 static int ra_set_default_opt_cb(void *, scf_walkinfo_t
*);
407 static int ra_get_current_opt_cb(void *, scf_walkinfo_t
*);
408 static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t
*);
409 static int ra_get_default_opt_cb(void *, scf_walkinfo_t
*);
410 static int ra_get_set_opt_common_cb(raopt_t
*, scf_walkinfo_t
*, boolean_t
,
412 static int ra_routing_opt_set_cb(void *, scf_walkinfo_t
*);
413 static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t
*);
414 static int ra_routing_opt_set_unset_cb(raopt_t
*, scf_walkinfo_t
*, boolean_t
);
416 /* Callbacks used to set/retrieve routing variables */
417 static int ra_set_persistent_var_cb(void *, scf_walkinfo_t
*);
418 static int ra_get_persistent_var_cb(void *, scf_walkinfo_t
*);
419 static int ra_get_default_var_cb(void *, scf_walkinfo_t
*);
420 static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t
*);
422 /* Callbacks used to list/set daemon properties and list daemons and states. */
423 static int ra_list_props_cb(void *, scf_walkinfo_t
*);
424 static int ra_modify_props_cb(void *, scf_walkinfo_t
*);
425 static int ra_print_state_cb(void *, scf_walkinfo_t
*);
427 /* Utility functions for SMF operations */
428 static int ra_get_pg(scf_handle_t
*, scf_instance_t
*, const char *,
429 boolean_t
, boolean_t
, scf_propertygroup_t
**);
430 static int ra_get_boolean_prop(scf_handle_t
*, scf_instance_t
*,
431 const char *, const char *, boolean_t
, boolean_t
, boolean_t
*);
432 static int ra_get_single_prop_as_string(scf_handle_t
*, scf_instance_t
*,
433 const char *, const char *, boolean_t
, boolean_t
, scf_type_t
*, char **);
434 static int ra_get_prop_as_string(scf_handle_t
*, scf_instance_t
*,
435 const char *, const char *, boolean_t
, boolean_t
, scf_type_t
*, int *,
437 static void ra_free_prop_values(int, char **);
438 static int ra_set_boolean_prop(scf_handle_t
*, scf_instance_t
*,
439 const char *, const char *, boolean_t
, boolean_t
);
440 static int ra_set_prop_from_string(scf_handle_t
*, scf_instance_t
*,
441 const char *, const char *, scf_type_t
, boolean_t
, int,
447 (void) fprintf(stderr
, gettext(
448 "usage: %1$s [-p] [-R <root-dir>]\n"
449 " %1$s [-e <option>] [-d <option>] [-r <option>]\n"
450 " [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
451 " [-s <var>=<val>] [-R <root-dir>]\n"
453 " <option> is one of:\n"
458 " <var> is one of:\n"
459 " ipv4-routing-daemon\n"
460 " ipv4-routing-daemon-args\n"
461 " ipv4-routing-stop-cmd\n"
462 " ipv6-routing-daemon\n"
463 " ipv6-routing-daemon-args\n"
464 " ipv6-routing-stop-cmd\n"
465 " routing-svcs\n"), myname
);
469 main(int argc
, char *argv
[])
471 int opt
, opt_index
, numargs
, status
= 0;
474 boolean_t modify
= B_FALSE
, report
= B_TRUE
, update
= B_FALSE
;
475 boolean_t booting
= B_FALSE
, alt_root_set
= B_FALSE
;
476 boolean_t parseable
= B_FALSE
;
477 char *key
, *nk
, *keyend
, *val
, **vals
, *options
, *fmri
;
478 char *parseopt
= NULL
;
485 (void) setlocale(LC_ALL
, "");
487 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
488 #define TEXT_DOMAIN "SYS_TEST"
491 (void) textdomain(TEXT_DOMAIN
);
494 * Before processing any options, we parse /etc/inet/routing.conf
495 * (if present) and transfer values to SMF.
497 if (ra_upgrade_from_legacy_conf() == -1)
499 while ((opt
= getopt(argc
, argv
, ":bd:e:l:m:p:R:r:s:u")) != EOF
) {
503 * Project-private option that tells us enable/disable
504 * operations should not set ipv4(6)-routing-set
505 * property. Used in routing-setup service method
506 * to change default routing state, and, if
507 * no explicit enable/disable operations have been
508 * carried out, change current ipv4 routing state.
516 if (ra_upgrade_cmd(opt
, 1, &optarg
) != 0)
521 if ((raopt
= ra_str2opt(optarg
)) != NULL
) {
522 /* Set current value appropriately */
525 raopt
->opt_enabled
= B_FALSE
;
529 * Check legacy daemons, mark
532 if (IS_ROUTING_OPT(optarg
) &&
533 ra_check_legacy_daemons() == -1)
535 raopt
->opt_enabled
= B_TRUE
;
539 * This callback sets opt_enabled to
543 if (ra_smf_cb(ra_get_default_opt_cb
,
544 raopt
->opt_default_fmri
, raopt
)
547 if (raopt
->opt_enabled
&&
548 IS_ROUTING_OPT(optarg
) &&
549 ra_check_legacy_daemons() == -1)
551 /* set value to default */
553 raopt
->opt_default_enabled
;
556 if (ra_smf_cb(ra_set_persistent_opt_cb
,
557 raopt
->opt_fmri
, raopt
) == -1)
560 * ipv4(6)-routing explicitly enabled/disabled,
561 * need to set ipv4(6)-routing-set property
562 * for routing-setup service. Once this
563 * is set, routing-setup will not override
564 * administrator action and will not enable
565 * ipv4-routing in the case that no default
566 * route can be determined. If ipv4(6)-routing
567 * is reverted to its default value, set
568 * ipv4(6)-routing-set back to false.
570 if (!booting
&& (raopt
->opt_flags
&
571 (RA_SVC_FLAG_IPV4_ROUTING
|
572 RA_SVC_FLAG_IPV6_ROUTING
))) {
573 if (ra_smf_cb(opt
== 'r' ?
574 ra_routing_opt_unset_cb
:
575 ra_routing_opt_set_cb
,
576 raopt
->opt_default_fmri
, raopt
)
580 } else if ((ravar
= ra_str2var(optarg
)) != NULL
) {
585 /* set current value to default */
587 if (ra_smf_cb(ra_get_default_var_cb
,
588 ravar
->var_default_fmri
, ravar
) == -1)
590 /* Need special case for routing-svcs var */
591 if (strcmp(ravar
->var_name
, RA_VAR_ROUTING_SVCS
)
593 if (ra_update_routing_svcs(
594 ravar
->var_default_value
) == -1)
596 } else if (ra_smf_cb(ra_set_persistent_var_cb
,
597 ravar
->var_fmri
, ravar
) == -1)
600 (void) fprintf(stderr
, gettext(
601 "%1$s: invalid option: %2$s\n"), myname
,
609 if (ra_smf_cb(ra_list_props_cb
, optarg
, NULL
) == -1)
617 * Argument list of key=value pairs, we need to
618 * collate all matching keys to set multiple values.
622 for (numargs
= 1; argv
[i
] != NULL
&& argv
[i
][0] != '-';
626 (void) fprintf(stderr
, gettext(
627 "%s: key=value required for "
628 "property change\n"), myname
);
633 if (ra_upgrade_cmd(opt
, numargs
,
634 &argv
[optind
- 1]) == -1)
636 optind
+= numargs
- 1;
640 * Collect all key=value pairs which use same key
641 * so we can add multiple property values.
643 for (key
= argv
[optind
]; key
!= NULL
&& key
[0] != '-';
644 key
= argv
[++optind
]) {
647 vals
= malloc(sizeof (char *));
648 if ((vals
[0] = strchr(key
, '=')) == NULL
) {
649 (void) fprintf(stderr
, gettext(
650 "%s: Malformed name=value "
651 "pair %s\n"), myname
, key
);
659 nk
!= NULL
&& nk
[0] != '-';
663 if ((keyend
= strchr(nk
, '='))
665 (void) fprintf(stderr
, gettext(
666 "%s: Malformed name=value "
667 " pair %s\n"), myname
, nk
);
670 if ((keylen
= keyend
- nk
) !=
673 if (strncmp(key
, nk
, keylen
) == 0) {
674 vals
= realloc(vals
, ++numvalues
676 vals
[numvalues
- 1] = ++keyend
;
681 raprop
.prop_name
= key
;
682 raprop
.prop_values
= vals
;
683 raprop
.prop_numvalues
= numvalues
;
684 if (ra_smf_cb(ra_modify_props_cb
, fmri
,
694 if (chroot(optarg
) == -1) {
695 (void) fprintf(stderr
, gettext(
696 "%1$s: failed to chroot to %2$s: %3$s\n"),
697 myname
, optarg
, strerror(errno
));
700 alt_root_set
= B_TRUE
;
705 if (ra_upgrade_cmd(opt
, 1, &optarg
) == -1)
711 while (*options
!= '\0') {
712 opt_index
= getsubopt(&options
, v_opt
, &val
);
717 if (opt_index
== -1) {
718 (void) fprintf(stderr
, gettext(
719 "%1$s: invalid variable: %2$s\n"),
724 ravar
= &ra_vars
[opt_index
];
725 /* Need special case for routing-svcs var */
726 if (strcmp(ravar
->var_name
, RA_VAR_ROUTING_SVCS
)
728 if (ra_update_routing_svcs(val
) == -1)
731 ravar
->var_value
= strdup(val
);
732 if (ra_smf_cb(ra_set_persistent_var_cb
,
733 ravar
->var_fmri
, ravar
) == -1)
743 /* if not 'p', usage failure */
744 if (strcmp(argv
[optind
- 1], "-p") != 0) {
745 (void) fprintf(stderr
, gettext(
746 "%s: option requires an argument -%s\n"),
747 myname
, argv
[optind
- 1]);
760 /* There shouldn't be any extra args. */
765 if (parseable
&& (update
|| modify
)) {
766 (void) fprintf(stderr
, gettext("%s: the -p option cannot be "
767 "used with any of -demrsu\n"), myname
);
772 if (update
&& ! alt_root_set
)
773 status
= ra_update();
775 if (report
&& !modify
&& !update
)
776 status
= ra_report(parseable
, parseopt
);
778 return (status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
782 * Upgrade legacy daemons, mark to-be-enabled routing services.
785 ra_check_legacy_daemons(void)
787 ravar_t
*routing_svcs
= ra_str2var(RA_VAR_ROUTING_SVCS
);
788 ravar_t
*v4d
= ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON
);
789 ravar_t
*v6d
= ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON
);
790 char *fmri
, *nextfmri
;
791 boolean_t mark
= B_FALSE
;
793 if (ra_smf_cb(ra_get_persistent_var_cb
, routing_svcs
->var_fmri
,
797 /* First unmark all services */
798 if (ra_smf_cb(ra_mark_routing_svcs_cb
, NULL
, &mark
) == -1)
802 if (routing_svcs
->var_value
!= NULL
) {
804 * For routing-svcs variable, mark each named
805 * service as a current-routing-svc.
807 if ((fmri
= strdup(routing_svcs
->var_value
)) == NULL
) {
808 (void) fprintf(stderr
, gettext(
809 "%s: out of memory\n"), myname
);
812 /* Now, mark each service named in routing-svcs. */
813 for (nextfmri
= strtok(fmri
, " \t");
815 nextfmri
= strtok(NULL
, " \t")) {
816 if (ra_smf_cb(ra_mark_routing_svcs_cb
, nextfmri
,
826 * Now check if legacy variables (if specified) map to SMF routing
827 * daemons. If so, transfer associated daemon arguments.
829 if (ra_upgrade_legacy_daemons() == -1)
834 * At this point, if the legacy services still have ipv4/ipv6
835 * routing daemons specified, we know they weren`t upgraded, so
838 if (ra_smf_cb(ra_get_persistent_var_cb
, v4d
->var_fmri
, v4d
) == -1 ||
839 ra_smf_cb(ra_get_persistent_var_cb
, v6d
->var_fmri
, v6d
) == -1)
842 if (v4d
->var_value
!= NULL
&& strtok(v4d
->var_value
, " \t") != NULL
&&
843 ra_smf_cb(ra_mark_routing_svcs_cb
, RA_INSTANCE_LEGACY_ROUTING_IPV4
,
846 if (v6d
->var_value
!= NULL
&& strtok(v6d
->var_value
, " \t") != NULL
&&
847 ra_smf_cb(ra_mark_routing_svcs_cb
, RA_INSTANCE_LEGACY_ROUTING_IPV6
,
855 * Retrieve legacy daemon variables, and check if any SMF routing daemons
856 * run the daemons specified. If so, the legacy configuration (arguments
857 * to the daemon) is transferred to the routeadm/daemon-args property
858 * of the corresponding instance. From there, the instance picks up the
859 * value and will transfer the daemon arguments to individiual properties
863 ra_upgrade_legacy_daemons(void)
865 ravar_t
*v4d
= ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON
);
866 ravar_t
*v6d
= ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON
);
867 ravar_t
*v4args
= ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS
);
868 ravar_t
*v6args
= ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS
);
869 ravar_t
*v4stop
= ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD
);
870 ravar_t
*v6stop
= ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD
);
872 if (ra_smf_cb(ra_get_persistent_var_cb
, v4d
->var_fmri
, v4d
) == -1 ||
873 ra_smf_cb(ra_get_persistent_var_cb
, v6d
->var_fmri
, v6d
) == -1 ||
874 ra_smf_cb(ra_get_persistent_var_cb
, v4args
->var_fmri
, v4args
)
876 ra_smf_cb(ra_get_persistent_var_cb
, v6args
->var_fmri
, v6args
)
878 ra_smf_cb(ra_get_persistent_var_cb
, v4stop
->var_fmri
, v4stop
)
880 ra_smf_cb(ra_get_persistent_var_cb
, v6stop
->var_fmri
, v6stop
)
884 return (ra_smf_cb(ra_upgrade_legacy_daemons_cb
, NULL
, NULL
));
888 * Determine if service runs the same daemon as that which is specified
889 * in ipv4-routing-daemon or ipv6-routing-daemon. If so, the associated
890 * daemon arguments are transferred to the service.
895 ra_upgrade_legacy_daemons_cb(void *data
, scf_walkinfo_t
*wip
)
897 const char *inst_fmri
= wip
->fmri
;
898 scf_instance_t
*inst
= wip
->inst
;
899 scf_handle_t
*h
= scf_instance_handle(inst
);
900 char *daemon
, *l_daemon
= NULL
;
901 ravar_t
*v4d
= ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON
);
902 ravar_t
*v6d
= ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON
);
903 ravar_t
*v4args
= ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS
);
904 ravar_t
*v6args
= ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS
);
905 ravar_t
*v4stop
= ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD
);
906 ravar_t
*v6stop
= ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD
);
907 ravar_t
*routing_svcs
= ra_str2var(RA_VAR_ROUTING_SVCS
);
908 boolean_t mark
, marked
;
909 char *new_routing_svcs
;
912 * Ensure instance is a routing service, and not one of the
913 * legacy instances - if it is, the daemon property is already
914 * set to the legacy daemon.
916 if (ra_get_single_prop_as_string(h
, inst
, RA_PG_ROUTEADM
,
917 RA_PROP_DAEMON
, B_TRUE
, B_FALSE
, NULL
, &daemon
) == -1 ||
918 strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4
, inst_fmri
) == 0 ||
919 strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6
, inst_fmri
) == 0)
922 /* A legacy daemon may be defined */
923 (void) ra_get_single_prop_as_string(h
, inst
, RA_PG_ROUTEADM
,
924 RA_PROP_LEGACY_DAEMON
, B_TRUE
, B_FALSE
, NULL
, &l_daemon
);
927 * If we match daemon/legacy_daemon with ipv4-routing-daemon or
928 * ipv6-routing-daemon values, transfer daemon-args value
929 * to the matching service.
931 if (v4d
->var_value
!= NULL
&& (strcmp(v4d
->var_value
, daemon
) == 0 ||
932 (l_daemon
!= NULL
&& strcmp(v4d
->var_value
, l_daemon
) == 0))) {
933 (void) printf(gettext("%s: migrating daemon configuration "
934 "for %s to %s\n"), myname
, l_daemon
!= NULL
?
935 l_daemon
: daemon
, inst_fmri
);
936 /* Transfer daemon-args value, clear legacy v4 values */
937 if (ra_set_prop_from_string(h
, inst
, RA_PG_ROUTEADM
,
938 RA_PROP_DAEMON_ARGS
, SCF_TYPE_ASTRING
, B_TRUE
, 1,
939 (const char **)&(v4args
->var_value
)) == -1)
941 ra_resetvars(RA_PROPVAL_PROTO_IPV4
);
942 if (ra_smf_cb(ra_set_persistent_var_cb
,
943 RA_INSTANCE_LEGACY_ROUTING_IPV4
, v4d
) == -1 ||
944 ra_smf_cb(ra_set_persistent_var_cb
,
945 RA_INSTANCE_LEGACY_ROUTING_IPV4
, v4args
) == -1 ||
946 ra_smf_cb(ra_set_persistent_var_cb
,
947 RA_INSTANCE_LEGACY_ROUTING_IPV4
, v4stop
) == -1)
949 } else if (v6d
->var_value
!= NULL
&& (strcmp(v6d
->var_value
, daemon
)
951 (l_daemon
!= NULL
&& strcmp(v6d
->var_value
, l_daemon
) == 0))) {
952 (void) printf(gettext("%s: migrating daemon configuration "
953 "for %s to %s\n"), myname
, l_daemon
!= NULL
?
954 l_daemon
: daemon
, inst_fmri
);
955 /* Transfer daemon-args value, clear legacy v6 values */
956 if (ra_set_prop_from_string(h
, inst
, RA_PG_ROUTEADM
,
957 RA_PROP_DAEMON_ARGS
, SCF_TYPE_ASTRING
, B_TRUE
, 1,
958 (const char **)&(v6args
->var_value
)) == -1)
960 ra_resetvars(RA_PROPVAL_PROTO_IPV6
);
961 if (ra_smf_cb(ra_set_persistent_var_cb
,
962 RA_INSTANCE_LEGACY_ROUTING_IPV6
, v6d
) == -1 ||
963 ra_smf_cb(ra_set_persistent_var_cb
,
964 RA_INSTANCE_LEGACY_ROUTING_IPV6
, v6args
) == -1 ||
965 ra_smf_cb(ra_set_persistent_var_cb
,
966 RA_INSTANCE_LEGACY_ROUTING_IPV6
, v6stop
) == -1)
972 * If service is unmarked at this point, add it to routing-svcs and
975 if (ra_get_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
976 RA_PROP_CURR_ROUTING_SVC
, B_FALSE
, B_FALSE
, &marked
) == -1 ||
979 if (ra_smf_cb(ra_mark_routing_svcs_cb
, inst_fmri
, &mark
)
981 ra_smf_cb(ra_get_persistent_var_cb
, routing_svcs
->var_fmri
,
984 if ((new_routing_svcs
=
985 malloc(strlen(routing_svcs
->var_value
) +
986 strlen(inst_fmri
) + 2)) == NULL
) {
987 (void) fprintf(stderr
, gettext(
988 "%s: out of memory"), myname
);
991 if (strlen(routing_svcs
->var_value
) == 0)
992 (void) snprintf(new_routing_svcs
,
993 strlen(inst_fmri
) + 1, "%s", inst_fmri
);
995 (void) snprintf(new_routing_svcs
,
996 strlen(routing_svcs
->var_value
) +
997 strlen(inst_fmri
) + 2, "%s %s",
998 routing_svcs
->var_value
, inst_fmri
);
999 free(routing_svcs
->var_value
);
1000 routing_svcs
->var_value
= new_routing_svcs
;
1001 (void) smf_refresh_instance(inst_fmri
);
1002 return (ra_smf_cb(ra_set_persistent_var_cb
,
1003 routing_svcs
->var_fmri
, routing_svcs
));
1005 (void) smf_refresh_instance(inst_fmri
);
1010 * If we are upgrading, append operation to <alt_root>/var/svc/profile/upgrade.
1013 ra_upgrade_cmd(char opt
, int argc
, char **argv
)
1018 if ((fp
= fopen(RA_SMF_UPGRADE_FILE
, "a+")) == NULL
) {
1019 (void) fprintf(stderr
, gettext(
1020 "%1$s: failed to open %2$s: %3$s\n"),
1021 myname
, RA_SMF_UPGRADE_FILE
, strerror(errno
));
1024 (void) fprintf(fp
, "/sbin/routeadm -%c ", opt
);
1026 for (i
= 0; i
< argc
; i
++)
1027 (void) fprintf(fp
, "%s ", argv
[i
]);
1029 (void) fprintf(fp
, "%s\n", RA_SMF_UPGRADE_MSG
);
1035 * Set current state to "next boot" state, i.e. if general/enabled
1036 * value is overlaid by a general_ovr/enabled value, set the current state
1037 * to the value of the latter. Doing this applies "next boot" changes to
1038 * the current setup. If any IPv6 interfaces are present, also start in.ndpd.
1045 if (ra_check_legacy_daemons() == -1)
1047 for (i
= 0; ra_opts
[i
].opt_name
!= NULL
; i
++) {
1048 if (ra_smf_cb(ra_set_current_opt_cb
, ra_opts
[i
].opt_fmri
,
1049 &ra_opts
[i
]) == -1) {
1054 * If in.ndpd isn't already running, then we start it here, regardless
1055 * of global IPv6 routing status (provided there are IPv6 interfaces
1058 if (ra_numv6intfs() > 0)
1059 return (smf_enable_instance(RA_INSTANCE_NDP
, SMF_TEMPORARY
));
1064 * Here we catch the special case where ipv4/ipv6 routing was enabled,
1065 * and the user updates the routing-svcs list. The problem is that
1066 * the enabled state is the result of services on the old routing-svcs list
1067 * being enabled, and we want to support users doing something like this:
1069 * # routeadm -s routing-svcs=route -e ipv4-routing -u
1073 * # routeadm -s routing-svcs=rdisc -u
1075 * To do this, we need to:
1076 * - cache the old ipv4-routing/ipv6-routing values.
1077 * - persistently disable the old routing-svcs list.
1078 * - if ipv4-routing was enabled, mark and persistently enable all the new
1080 * - if ipv6-routing was enabled, mark and persistently enable all the new
1082 * This will result in the next "-u" switching on the new routing-svcs, and
1083 * switching off the old ones, as the user would expect.
1086 ra_update_routing_svcs(char *routing_svcs_new
)
1088 raopt_t
*v4opt
= ra_str2opt(RA_OPT_IPV4_ROUTING
);
1089 raopt_t
*v6opt
= ra_str2opt(RA_OPT_IPV6_ROUTING
);
1090 ravar_t
*routing_svcs
= ra_str2var(RA_VAR_ROUTING_SVCS
);
1091 char *routing_svcs_old
, *fmri
;
1092 boolean_t v4_old
, v6_old
, mark
= B_FALSE
;
1095 if (ra_smf_cb(ra_get_persistent_opt_cb
, v4opt
->opt_fmri
, v4opt
) == -1 ||
1096 ra_smf_cb(ra_get_persistent_opt_cb
, v6opt
->opt_fmri
, v6opt
) == -1 ||
1097 ra_smf_cb(ra_get_persistent_var_cb
, routing_svcs
->var_fmri
,
1098 routing_svcs
) == -1)
1100 v4_old
= v4opt
->opt_enabled
;
1101 v6_old
= v6opt
->opt_enabled
;
1102 routing_svcs_old
= routing_svcs
->var_value
;
1103 routing_svcs
->var_value
= routing_svcs_new
;
1105 if (ra_smf_cb(ra_set_persistent_var_cb
, routing_svcs
->var_fmri
,
1106 routing_svcs
) == -1) {
1107 free(routing_svcs_old
);
1111 if (!v4_old
&& !v6_old
) {
1112 /* We don`t need to do anything, since services were disabled */
1113 free(routing_svcs_old
);
1116 v4opt
->opt_enabled
= B_FALSE
;
1117 v6opt
->opt_enabled
= B_FALSE
;
1119 /* Persistently disable each old v4/v6 "routing-svc" */
1120 for (fmri
= strtok(routing_svcs_old
, " \t"); fmri
!= NULL
;
1121 fmri
= strtok(NULL
, " \t")) {
1122 if (ra_smf_cb(ra_mark_routing_svcs_cb
, fmri
, &mark
) == -1) {
1123 free(routing_svcs_old
);
1127 ra_smf_cb(ra_set_persistent_opt_cb
, fmri
, v4opt
) == -1) {
1128 free(routing_svcs_old
);
1132 ra_smf_cb(ra_set_persistent_opt_cb
, fmri
, v6opt
) == -1) {
1133 free(routing_svcs_old
);
1137 free(routing_svcs_old
);
1138 v4opt
->opt_enabled
= v4_old
;
1139 v6opt
->opt_enabled
= v6_old
;
1141 /* Persistently enable each new v4/v6 "routing-svc" */
1143 for (fmri
= strtok(routing_svcs_new
, " \t"); fmri
!= NULL
;
1144 fmri
= strtok(NULL
, " \t")) {
1145 if (ra_smf_cb(ra_mark_routing_svcs_cb
, fmri
, &mark
) == -1)
1148 ra_smf_cb(ra_set_persistent_opt_cb
, fmri
, v4opt
) == -1)
1151 ra_smf_cb(ra_set_persistent_opt_cb
, fmri
, v6opt
) == -1)
1158 * Display status, in parseable form if required. If param is
1159 * specified, only the named option/variable is displayed (this option is
1160 * for parseable display only).
1163 ra_report(boolean_t parseable
, const char *param
)
1166 char *c_state
, *d_state
, *p_state
, *p_var
, *d_var
;
1167 char *enabled
= "enabled";
1168 char *disabled
= "disabled";
1169 boolean_t param_found
= B_FALSE
;
1172 (void) printf(gettext(
1173 " Configuration Current "
1175 " Option Configuration "
1177 "---------------------------------------------------"
1180 for (i
= 0; ra_opts
[i
].opt_name
!= NULL
; i
++) {
1181 if (param
!= NULL
) {
1182 if (strcmp(ra_opts
[i
].opt_name
, param
) == 0)
1183 param_found
= B_TRUE
;
1187 if (ra_smf_cb(ra_get_current_opt_cb
,
1188 ra_opts
[i
].opt_fmri
, &ra_opts
[i
]) == -1)
1190 c_state
= ra_opts
[i
].opt_enabled
? enabled
: disabled
;
1192 if (ra_smf_cb(ra_get_persistent_opt_cb
,
1193 ra_opts
[i
].opt_fmri
, &ra_opts
[i
]) == -1)
1195 p_state
= ra_opts
[i
].opt_enabled
? enabled
: disabled
;
1197 if (ra_smf_cb(ra_get_default_opt_cb
,
1198 ra_opts
[i
].opt_default_fmri
, &ra_opts
[i
]) == -1)
1200 d_state
= ra_opts
[i
].opt_default_enabled
? enabled
: disabled
;
1204 (void) printf("%s ", ra_opts
[i
].opt_name
);
1205 (void) printf("persistent=%s default=%s "
1206 "current=%s\n", p_state
, d_state
, c_state
);
1208 (void) printf(gettext("%1$27s %2$-21s%3$s\n"),
1209 ra_intloptname(ra_opts
[i
].opt_name
),
1214 (void) printf("\n");
1218 /* Gather persistent/default variable values */
1219 for (i
= 0; ra_vars
[i
].var_name
!= NULL
; i
++) {
1220 if (ra_smf_cb(ra_get_persistent_var_cb
,
1221 ra_vars
[i
].var_fmri
, &ra_vars
[i
]) == -1 ||
1222 ra_smf_cb(ra_get_default_var_cb
,
1223 ra_vars
[i
].var_default_fmri
, &ra_vars
[i
]) == -1)
1227 for (i
= 0; ra_vars
[i
].var_name
!= NULL
; i
++) {
1228 if (param
!= NULL
) {
1229 if (strcmp(ra_vars
[i
].var_name
, param
) == 0)
1230 param_found
= B_TRUE
;
1234 p_var
= ra_vars
[i
].var_value
== NULL
? "":
1235 ra_vars
[i
].var_value
;
1236 d_var
= ra_vars
[i
].var_default_value
== NULL
?
1237 "": ra_vars
[i
].var_default_value
;
1240 (void) printf("%s ", ra_vars
[i
].var_name
);
1241 (void) printf("persistent=\"%s\" "
1242 "default=\"%s\" \n", p_var
, d_var
);
1244 /* If daemon variables are not set, do not display. */
1245 if ((IS_IPV4_VAR(ra_vars
[i
].var_name
) &&
1247 (IS_IPV6_VAR(ra_vars
[i
].var_name
) &&
1250 (void) printf(gettext("%1$27s \"%2$s\"\n"),
1251 ra_intloptname(ra_vars
[i
].var_name
), p_var
);
1255 if (param
!= NULL
&& !param_found
) {
1256 (void) fprintf(stderr
, gettext(
1257 "%s: no such option/variable %s\n"), myname
, param
);
1262 (void) printf(gettext("\nRouting daemons:\n"));
1263 (void) printf("\n %s %s\n", "STATE", "FMRI");
1264 if (ra_smf_cb(ra_print_state_cb
, NULL
, NULL
) == -1)
1270 * Call scf_walk_fmri() with appropriate function, fmri, and data.
1271 * A NULL fmri causes scf_walk_fmri() to run on all instances. We make
1272 * use of this many times in applying changes to the routing services.
1275 ra_smf_cb(ra_smf_cb_t cbfunc
, const char *fmri
, void *data
)
1278 int exit_status
= 0;
1280 if ((h
= scf_handle_create(SCF_VERSION
)) == NULL
||
1281 scf_handle_bind(h
) == -1) {
1282 (void) fprintf(stderr
, gettext(
1283 "%s: cannot connect to SMF repository\n"), myname
);
1286 return (scf_walk_fmri(h
, fmri
== NULL
? 0 : 1,
1287 fmri
== NULL
? NULL
: (char **)&fmri
, 0,
1288 cbfunc
, data
, &exit_status
, uu_die
));
1292 * Applies persistent configuration settings to current setup.
1295 ra_set_current_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1297 return (ra_get_set_opt_common_cb(data
, wip
, B_FALSE
, B_FALSE
));
1301 * Sets persistent value for option, to be applied on next boot
1302 * or by "routeadm -u".
1305 ra_set_persistent_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1307 return (ra_get_set_opt_common_cb(data
, wip
, B_TRUE
, B_FALSE
));
1311 ra_get_current_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1313 return (ra_get_set_opt_common_cb(data
, wip
, B_FALSE
, B_TRUE
));
1317 ra_get_persistent_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1319 return (ra_get_set_opt_common_cb(data
, wip
, B_TRUE
, B_TRUE
));
1323 ra_routing_opt_set_cb(void *data
, scf_walkinfo_t
*wip
)
1325 return (ra_routing_opt_set_unset_cb(data
, wip
, B_TRUE
));
1329 ra_routing_opt_unset_cb(void *data
, scf_walkinfo_t
*wip
)
1331 return (ra_routing_opt_set_unset_cb(data
, wip
, B_FALSE
));
1335 * Notify network/routing-setup service that administrator has explicitly
1336 * set/reset ipv4(6)-routing value. If no explicit setting of this value is
1337 * done, ipv4-routing can be enabled in the situation when no default route can
1341 ra_routing_opt_set_unset_cb(raopt_t
*raopt
, scf_walkinfo_t
*wip
, boolean_t set
)
1343 scf_instance_t
*inst
= wip
->inst
;
1344 scf_handle_t
*h
= scf_instance_handle(inst
);
1346 return (ra_set_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1347 raopt
->opt_flags
& RA_SVC_FLAG_IPV4_ROUTING
?
1348 RA_PROP_IPV4_ROUTING_SET
: RA_PROP_IPV6_ROUTING_SET
,
1353 * Shared function that either sets or determines persistent or current
1354 * state. Setting persistent state (for next boot) involves setting
1355 * the general_ovr/enabled value to the current service state, and
1356 * the general/enabled value to the desired (next-boot) state.
1357 * Setting current state involves removing the temporary state
1358 * setting so the persistent state has effect.
1360 * Persistent state is reported as being enabled if any of the
1361 * candidate services have a general/enabled value set to true,
1362 * while current state is reported as being enabled if any of the
1363 * candidate services has a general_ovr/enabled or general/enabled
1364 * value set to true.
1367 ra_get_set_opt_common_cb(raopt_t
*raopt
, scf_walkinfo_t
*wip
,
1368 boolean_t persistent
, boolean_t get
)
1370 const char *inst_fmri
= wip
->fmri
;
1371 scf_instance_t
*inst
= wip
->inst
;
1372 scf_handle_t
*h
= scf_instance_handle(inst
);
1373 scf_propertygroup_t
*routeadm_pg
;
1374 boolean_t persistent_state_enabled
;
1375 boolean_t temporary_state_enabled
;
1376 boolean_t current_state_enabled
;
1377 boolean_t curr_svc
= B_TRUE
;
1378 boolean_t found_proto
;
1379 char **protolist
= NULL
;
1380 int i
, ret
, numvalues
= 0;
1383 * Ensure we are dealing with a routeadm-managed service. If
1384 * the FMRI used for walking instances is NULL, it is reasonable
1385 * that a service not have a routeadm property group as we will
1386 * check all services in this case.
1388 if (ra_get_pg(h
, inst
, RA_PG_ROUTEADM
, B_TRUE
, raopt
->opt_fmri
!= NULL
,
1389 &routeadm_pg
) == -1) {
1390 /* Not a routing service, not an error. */
1391 if (scf_error() == SCF_ERROR_NOT_FOUND
&&
1392 raopt
->opt_fmri
== NULL
)
1396 scf_pg_destroy(routeadm_pg
);
1398 /* Services with no "protocol" property are not routing daemons */
1399 if (raopt
->opt_fmri
== NULL
&& ra_get_prop_as_string(h
, inst
,
1400 RA_PG_ROUTEADM
, RA_PROP_PROTO
, B_TRUE
, B_FALSE
, NULL
, &numvalues
,
1401 &protolist
) == -1) {
1402 if (scf_error() == SCF_ERROR_NOT_FOUND
)
1408 * Skip invalid services based on flag settings. Flags are used when
1409 * we run callback functions on all instances to identify
1410 * the correct instances to operate on.
1412 if (raopt
->opt_flags
& RA_SVC_FLAG_IPV4_ROUTING
) {
1413 found_proto
= B_FALSE
;
1414 if (protolist
!= NULL
) {
1415 /* Check if protolist contains "ipv4" */
1416 for (i
= 0; i
< numvalues
; i
++) {
1417 if (protolist
[i
] != NULL
&& strcmp(
1418 protolist
[i
], RA_PROPVAL_PROTO_IPV4
) == 0)
1419 found_proto
= B_TRUE
;
1422 /* If not an ipv4 routing service, skip. */
1423 if (protolist
== NULL
|| !found_proto
) {
1424 ra_free_prop_values(numvalues
, protolist
);
1428 if (raopt
->opt_flags
& RA_SVC_FLAG_IPV6_ROUTING
) {
1429 found_proto
= B_FALSE
;
1430 if (protolist
!= NULL
) {
1431 /* Check if protolist contains "ipv6" */
1432 for (i
= 0; i
< numvalues
; i
++) {
1433 if (protolist
[i
] != NULL
&& strcmp(
1434 protolist
[i
], RA_PROPVAL_PROTO_IPV6
) == 0)
1435 found_proto
= B_TRUE
;
1438 /* If not an ipv6 routing service, skip. */
1439 if (protolist
== NULL
|| !found_proto
) {
1440 ra_free_prop_values(numvalues
, protolist
);
1444 * If no IPv6 interfaces are configured, do not apply
1445 * the "enable" state change to this IPv6 routing service.
1447 if (raopt
->opt_enabled
&& ra_numv6intfs() < 1)
1450 ra_free_prop_values(numvalues
, protolist
);
1452 /* If enabling routing services, select only current routing services */
1453 if (raopt
->opt_fmri
== NULL
&& !get
&& raopt
->opt_enabled
) {
1454 if (ra_get_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1455 RA_PROP_CURR_ROUTING_SVC
, B_FALSE
, B_FALSE
,
1458 else if (!curr_svc
&& persistent
) {
1460 * We apply "current" routing changes to all routing
1461 * daemons, whether current or not, so bail if
1462 * we are trying to make a persistent update to a
1463 * non-"routing-svc".
1468 if (ra_get_boolean_prop(h
, inst
, SCF_PG_GENERAL
, SCF_PROPERTY_ENABLED
,
1469 B_FALSE
, B_TRUE
, &persistent_state_enabled
) == -1)
1472 current_state_enabled
= persistent_state_enabled
;
1474 if (ra_get_boolean_prop(h
, inst
, SCF_PG_GENERAL_OVR
,
1475 SCF_PROPERTY_ENABLED
, B_FALSE
, B_FALSE
, &temporary_state_enabled
)
1477 current_state_enabled
= temporary_state_enabled
;
1481 * Persistent state is enabled if any services are
1482 * persistently enabled, i.e. general/enabled == true).
1483 * current state is enabled if any services
1484 * services are currently enabled, i.e. if defined,
1485 * general_ovr/enabled == true, if not, general/enabled == true.
1488 raopt
->opt_enabled
= raopt
->opt_enabled
||
1489 persistent_state_enabled
;
1491 raopt
->opt_enabled
= raopt
->opt_enabled
||
1492 current_state_enabled
;
1496 * For peristent state changes, from -e/-d,
1497 * we set the general_ovr/enabled value to the
1498 * current state (to ensure it is preserved),
1499 * while setting the general/enabled value to
1500 * the desired value. This has the effect of
1501 * the desired value coming into effect on next boot.
1503 ret
= current_state_enabled
?
1504 smf_enable_instance(inst_fmri
, SMF_TEMPORARY
) :
1505 smf_disable_instance(inst_fmri
, SMF_TEMPORARY
);
1507 (void) fprintf(stderr
, gettext(
1508 "%s: unexpected libscf error: %s\n"),
1509 myname
, scf_strerror(scf_error()));
1513 * Refresh here so general_ovr/enabled state overrides
1514 * general/enabled state.
1516 (void) smf_refresh_instance(inst_fmri
);
1518 * Now we can safely set the general/enabled value
1519 * to the value we require on next boot (or
1522 ret
= ra_set_boolean_prop(h
, inst
, SCF_PG_GENERAL
,
1523 SCF_PROPERTY_ENABLED
, B_FALSE
, raopt
->opt_enabled
);
1527 * Refresh here so general/enabled value is set.
1529 (void) smf_refresh_instance(inst_fmri
);
1530 if (raopt
->opt_fmri
!= NULL
)
1532 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP
);
1535 * Refresh here to get latest property values prior
1536 * to starting daemon.
1538 (void) smf_refresh_instance(inst_fmri
);
1540 * For current changes (result of -u), we
1541 * enable/disable depending on persistent value
1542 * stored in general/enabled. Here we disable
1543 * old routing-svcs (identified by a current-routing-svc
1544 * value of false) also.
1546 ret
= persistent_state_enabled
&& curr_svc
?
1547 smf_enable_instance(inst_fmri
, 0) :
1548 smf_disable_instance(inst_fmri
, 0);
1550 (void) fprintf(stderr
, gettext(
1551 "%s: unexpected libscf error: %s\n"),
1552 myname
, scf_strerror(scf_error()));
1555 if (current_state_enabled
&& persistent_state_enabled
) {
1557 * Instance was already enabled, so we restart
1558 * to get latest property values. This covers
1559 * the case where users update properties
1560 * via routeadm -m, and issue an update. The
1561 * daemon should be running with the latest
1564 (void) smf_restart_instance(inst_fmri
);
1572 ra_set_default_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1574 scf_instance_t
*inst
= wip
->inst
;
1575 scf_handle_t
*h
= scf_instance_handle(inst
);
1576 raopt_t
*raopt
= data
;
1578 return (ra_set_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1579 raopt
->opt_default_prop
, B_FALSE
, raopt
->opt_default_enabled
));
1583 ra_get_default_opt_cb(void *data
, scf_walkinfo_t
*wip
)
1585 scf_instance_t
*inst
= wip
->inst
;
1586 scf_handle_t
*h
= scf_instance_handle(inst
);
1587 raopt_t
*raopt
= data
;
1589 return (ra_get_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1590 raopt
->opt_default_prop
, B_TRUE
, B_TRUE
,
1591 &(raopt
->opt_default_enabled
)));
1595 * Callbacks to set/retrieve persistent/default routing variable values.
1596 * The set functions use the value stored in the var_value/var_default_value
1597 * field of the associated ra_var_t, while the retrieval functions store
1598 * the value retrieved in that field.
1601 ra_get_persistent_var_cb(void *data
, scf_walkinfo_t
*wip
)
1603 scf_instance_t
*inst
= wip
->inst
;
1604 scf_handle_t
*h
= scf_instance_handle(inst
);
1605 ravar_t
*ravar
= data
;
1607 return (ra_get_single_prop_as_string(h
, inst
, RA_PG_ROUTEADM
,
1608 ravar
->var_prop
, B_TRUE
, B_TRUE
, NULL
, &ravar
->var_value
));
1612 ra_set_persistent_var_cb(void *data
, scf_walkinfo_t
*wip
)
1614 scf_instance_t
*inst
= wip
->inst
;
1615 scf_handle_t
*h
= scf_instance_handle(inst
);
1616 ravar_t
*ravar
= data
;
1618 return (ra_set_prop_from_string(h
, inst
, RA_PG_ROUTEADM
,
1619 ravar
->var_prop
, SCF_TYPE_INVALID
, B_FALSE
, 1,
1620 (const char **)&ravar
->var_value
));
1624 ra_get_default_var_cb(void *data
, scf_walkinfo_t
*wip
)
1626 scf_instance_t
*inst
= wip
->inst
;
1627 scf_handle_t
*h
= scf_instance_handle(inst
);
1628 ravar_t
*ravar
= data
;
1630 return (ra_get_single_prop_as_string(h
, inst
, RA_PG_ROUTEADM
,
1631 ravar
->var_default_prop
, B_TRUE
, B_TRUE
, NULL
,
1632 &ravar
->var_default_value
));
1636 * Depending on the value of the boolean_t * passed in, this callback
1637 * either marks the relevant service(s) as current-routing-svcs (or unmarking)
1638 * by setting that property to true or false. When routing services
1639 * are to be enabled, the a current-routing-svc value of true flags the
1640 * service as one to be enabled.
1643 ra_mark_routing_svcs_cb(void *data
, scf_walkinfo_t
*wip
)
1645 scf_instance_t
*inst
= wip
->inst
;
1646 scf_handle_t
*h
= scf_instance_handle(inst
);
1647 boolean_t
*mark
= data
;
1650 char **protolist
= NULL
;
1652 /* Check we are dealing with a routing daemon service */
1653 if (ra_get_prop_as_string(h
, inst
, RA_PG_ROUTEADM
, RA_PROP_PROTO
,
1654 B_TRUE
, B_FALSE
, NULL
, &numvalues
, &protolist
) == -1)
1656 ra_free_prop_values(numvalues
, protolist
);
1658 return (ra_set_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1659 RA_PROP_CURR_ROUTING_SVC
, B_TRUE
, B_TRUE
));
1660 /* Unmark service. */
1661 if (ra_get_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1662 RA_PROP_CURR_ROUTING_SVC
, B_TRUE
, B_FALSE
, &marked
) == 0 && marked
)
1663 return (ra_set_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
1664 RA_PROP_CURR_ROUTING_SVC
, B_TRUE
, B_FALSE
));
1669 * List property values for all properties in the "routing" property
1670 * group of the routing service instance.
1675 ra_list_props_cb(void *data
, scf_walkinfo_t
*wip
)
1677 const char *inst_fmri
= wip
->fmri
;
1678 scf_instance_t
*inst
= wip
->inst
;
1679 scf_handle_t
*h
= scf_instance_handle(inst
);
1680 scf_iter_t
*propiter
, *valiter
;
1681 scf_propertygroup_t
*pg
;
1682 scf_property_t
*prop
;
1684 char **protolist
= NULL
, *pnamebuf
, *valbuf
;
1685 ssize_t pnamelen
, vallen
;
1687 int propiterret
, valiterret
, retval
= 0;
1689 /* Services with no "protocol" property are not routing daemons */
1690 if (ra_get_prop_as_string(h
, inst
, RA_PG_ROUTEADM
, RA_PROP_PROTO
,
1691 B_TRUE
, B_FALSE
, NULL
, &numvalues
, &protolist
) == -1) {
1692 if (scf_error() == SCF_ERROR_NOT_FOUND
)
1693 (void) fprintf(stderr
,
1694 gettext("%s: %s is not a routing daemon service\n"),
1697 (void) fprintf(stderr
,
1698 gettext("%s: unexpected libscf error: %s\n"),
1699 myname
, scf_strerror(scf_error()));
1700 ra_free_prop_values(numvalues
, protolist
);
1703 ra_free_prop_values(numvalues
, protolist
);
1705 if (ra_get_pg(h
, inst
, RA_PG_ROUTING
, B_TRUE
, B_FALSE
, &pg
) == -1) {
1706 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
1707 (void) printf("%s: no %s property group for %s\n",
1708 myname
, RA_PG_ROUTING
, inst_fmri
);
1711 (void) fprintf(stderr
,
1712 gettext("%s: unexpected libscf error: %s\n"),
1713 myname
, scf_strerror(scf_error()));
1717 (void) printf("%s:\n", inst_fmri
);
1719 /* Create an iterator to walk through all properties */
1720 if ((propiter
= scf_iter_create(h
)) == NULL
||
1721 (prop
= scf_property_create(h
)) == NULL
||
1722 scf_iter_pg_properties(propiter
, pg
) != 0) {
1723 (void) fprintf(stderr
, gettext
1724 ("%s: could not iterate through properties for %s: %s\n"),
1725 myname
, inst_fmri
, scf_strerror(scf_error()));
1727 while ((propiterret
= scf_iter_next_property(propiter
, prop
)) == 1) {
1728 if ((pnamelen
= scf_property_get_name(prop
, NULL
, 0) + 1)
1730 (void) fprintf(stderr
, gettext("%s: could not retrieve "
1731 "property name for instance %s: %s\n"), myname
,
1732 inst_fmri
, scf_strerror(scf_error()));
1736 if ((pnamebuf
= malloc(pnamelen
)) == NULL
) {
1737 (void) fprintf(stderr
,
1738 gettext("%s: out of memory\n"), myname
);
1742 (void) scf_property_get_name(prop
, pnamebuf
,
1744 (void) printf("\t%s = ", pnamebuf
);
1745 if ((valiter
= scf_iter_create(h
)) == NULL
||
1746 (val
= scf_value_create(h
)) == NULL
||
1747 scf_iter_property_values(valiter
, prop
)
1749 (void) fprintf(stderr
, gettext
1750 ("%s: could not iterate through "
1751 "properties for %s: %s\n"), myname
, inst_fmri
,
1752 scf_strerror(scf_error()));
1753 scf_value_destroy(val
);
1754 scf_iter_destroy(valiter
);
1759 while ((valiterret
= scf_iter_next_value(valiter
, val
)) == 1) {
1760 if ((vallen
= scf_value_get_as_string
1761 (val
, NULL
, 0) + 1) == 0) {
1762 (void) fprintf(stderr
, gettext
1763 ("%s: could not retrieve "
1764 "property value for instance %s, "
1765 "property %s: %s\n"), myname
, inst_fmri
,
1766 pnamebuf
, scf_strerror(scf_error()));
1768 } else if ((valbuf
= malloc(vallen
)) == NULL
) {
1769 (void) fprintf(stderr
,
1770 gettext("%s: out of memory\n"), myname
);
1774 scf_iter_destroy(valiter
);
1775 scf_value_destroy(val
);
1779 (void) scf_value_get_as_string(val
, valbuf
, vallen
);
1780 (void) printf("%s ", valbuf
);
1783 (void) printf("\n");
1784 scf_iter_destroy(valiter
);
1785 scf_value_destroy(val
);
1787 if (valiterret
== -1) {
1788 (void) fprintf(stderr
,
1789 gettext("%s: could not iterate through"
1790 "properties for %s: %s\n"), myname
, inst_fmri
,
1791 scf_strerror(scf_error()));
1797 scf_iter_destroy(propiter
);
1798 scf_property_destroy(prop
);
1800 if (propiterret
== -1)
1801 (void) fprintf(stderr
, gettext
1802 ("%s: could not iterate through properties for %s: %s\n"),
1803 myname
, inst_fmri
, scf_strerror(scf_error()));
1808 * Modify property with name stored in passed-in ra_prop_t to have
1809 * the assocatied values. Only works for existing properties in
1810 * the "routing" property group for routing daemon services, so all
1811 * routing daemons should place configurable options in that group.
1814 ra_modify_props_cb(void *data
, scf_walkinfo_t
*wip
)
1816 const char *inst_fmri
= wip
->fmri
;
1817 scf_instance_t
*inst
= wip
->inst
;
1818 scf_handle_t
*h
= scf_instance_handle(inst
);
1819 ra_prop_t
*raprop
= data
;
1821 char **protolist
= NULL
;
1823 /* Services with no "protocol" property are not routing daemons */
1824 if (ra_get_prop_as_string(h
, inst
, RA_PG_ROUTEADM
, RA_PROP_PROTO
,
1825 B_TRUE
, B_FALSE
, NULL
, &numvalues
, &protolist
) == -1) {
1826 if (scf_error() == SCF_ERROR_NOT_FOUND
)
1827 (void) fprintf(stderr
,
1828 gettext("%s: %s is not a routing daemon service\n"),
1831 (void) fprintf(stderr
,
1832 gettext("%s: unexpected libscf error: %s\n"),
1833 myname
, scf_strerror(scf_error()));
1834 ra_free_prop_values(numvalues
, protolist
);
1837 ra_free_prop_values(numvalues
, protolist
);
1839 if (ra_set_prop_from_string(h
, inst
, RA_PG_ROUTING
, raprop
->prop_name
,
1840 SCF_TYPE_INVALID
, B_FALSE
, raprop
->prop_numvalues
,
1841 (const char **)raprop
->prop_values
) == -1)
1844 (void) smf_refresh_instance(inst_fmri
);
1849 * Display FMRI, state for each routing daemon service.
1854 ra_print_state_cb(void *data
, scf_walkinfo_t
*wip
)
1856 const char *inst_fmri
= wip
->fmri
;
1857 scf_instance_t
*inst
= wip
->inst
;
1858 scf_handle_t
*h
= scf_instance_handle(inst
);
1859 char *inst_state
, **protolist
= NULL
;
1862 /* Ensure service is a routing daemon */
1863 if (ra_get_prop_as_string(h
, inst
, RA_PG_ROUTEADM
, RA_PROP_PROTO
,
1864 B_TRUE
, B_FALSE
, NULL
, &numvalues
, &protolist
) == -1)
1866 ra_free_prop_values(numvalues
, protolist
);
1868 if ((inst_state
= smf_get_state(inst_fmri
)) == NULL
) {
1869 (void) fprintf(stderr
,
1870 gettext("%s: could not retrieve state for %s: %s\n"),
1871 myname
, inst_fmri
, scf_strerror(scf_error()));
1874 (void) printf("%27s %2s\n", inst_state
, inst_fmri
);
1881 ra_get_pg(scf_handle_t
*h
, scf_instance_t
*inst
, const char *pgname
,
1882 boolean_t composed
, boolean_t required
, scf_propertygroup_t
**pg
)
1884 /* Retrieve (possibly composed) property group for instance */
1885 if ((*pg
= scf_pg_create(h
)) == NULL
|| (composed
&&
1886 scf_instance_get_pg_composed(inst
, NULL
, pgname
, *pg
) != 0) ||
1887 (!composed
&& scf_instance_get_pg(inst
, pgname
, *pg
) != 0)) {
1888 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
1890 (void) fprintf(stderr
, gettext(
1891 "%s: no such property group %s\n"),
1896 (void) fprintf(stderr
, gettext(
1897 "%s: unexpected libscf error: %s\n"), myname
,
1898 scf_strerror(scf_error()));
1905 ra_get_boolean_prop(scf_handle_t
*h
, scf_instance_t
*inst
,
1906 const char *pgname
, const char *propname
, boolean_t composed
,
1907 boolean_t required
, boolean_t
*val
)
1911 if (ra_get_single_prop_as_string(h
, inst
, pgname
, propname
,
1912 composed
, required
, NULL
, &valstr
) != 0)
1914 *val
= strcmp(valstr
, RA_PROPVAL_BOOLEAN_TRUE
) == 0;
1920 ra_get_single_prop_as_string(scf_handle_t
*h
, scf_instance_t
*inst
,
1921 const char *pgname
, const char *propname
, boolean_t composed
,
1922 boolean_t required
, scf_type_t
*type
, char **value
)
1927 if (ra_get_prop_as_string(h
, inst
, pgname
, propname
, composed
, required
,
1928 type
, &numvalues
, &values
) == -1)
1936 * Retrieve property named in propname, possibly using the composed
1937 * property group view (union of instance and service-level properties,
1938 * where instance-level properties override service-level values).
1941 ra_get_prop_as_string(scf_handle_t
*h
, scf_instance_t
*inst
,
1942 const char *pgname
, const char *propname
, boolean_t composed
,
1943 boolean_t required
, scf_type_t
*type
, int *numvalues
, char ***values
)
1945 scf_propertygroup_t
*pg
= NULL
;
1946 scf_property_t
*prop
= NULL
;
1947 scf_iter_t
*valiter
= NULL
;
1948 scf_value_t
*val
= NULL
;
1950 int valiterret
, i
, numvalues_retrieved
, ret
= 0;
1952 if (ra_get_pg(h
, inst
, pgname
, composed
, required
, &pg
) == -1)
1957 * Retrieve values. All values routeadm needs to retrieve
1958 * (bar those gathered by routeadm -l), are known to be single-valued.
1960 if ((prop
= scf_property_create(h
)) == NULL
)
1962 if (scf_pg_get_property(pg
, propname
, prop
) != 0) {
1964 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
1966 (void) fprintf(stderr
, gettext(
1967 "%s: property %s/%s not found\n"),
1968 myname
, pgname
, propname
);
1974 if ((val
= scf_value_create(h
)) == NULL
&&
1975 scf_property_get_value(prop
, val
) != 0 ||
1976 (valiter
= scf_iter_create(h
)) == NULL
||
1977 scf_iter_property_values(valiter
, prop
) != 0)
1979 /* retrieve each value */
1980 for (numvalues_retrieved
= 0;
1981 (valiterret
= scf_iter_next_value(valiter
, val
)) == 1;
1982 numvalues_retrieved
++) {
1983 if ((vallen
= scf_value_get_as_string
1984 (val
, NULL
, 0) + 1) == 0)
1986 if ((*values
= realloc(*values
,
1987 sizeof (*values
) + sizeof (char *))) == NULL
||
1988 ((*values
)[numvalues_retrieved
] = malloc(vallen
)) == NULL
) {
1989 (void) fprintf(stderr
, gettext(
1990 "%s: out of memory\n"), myname
);
1994 (void) scf_value_get_as_string(val
,
1995 (*values
)[numvalues_retrieved
], vallen
);
1997 if (valiterret
== -1)
2000 * if *numvalues != 0, it holds expected number of values. If a
2001 * different number are found, it is an error.
2003 if (*numvalues
!= 0 && *numvalues
!= numvalues_retrieved
) {
2004 (void) fprintf(stderr
, gettext(
2005 "%s: got %d values for property %s/%s, expected %d\n"),
2006 myname
, numvalues_retrieved
, pgname
, propname
, *numvalues
);
2010 *numvalues
= numvalues_retrieved
;
2012 /* Retrieve property type if required. */
2014 (void) scf_property_type(prop
, type
);
2018 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
2019 (void) fprintf(stderr
, gettext(
2020 "%s: property %s not found"), myname
, propname
);
2022 (void) fprintf(stderr
, gettext(
2023 "%s: unexpected libscf error: %s, "), myname
);
2025 for (i
= 0; i
< numvalues_retrieved
; i
++)
2027 if (*values
!= NULL
)
2033 scf_value_destroy(val
);
2034 if (valiter
!= NULL
)
2035 scf_iter_destroy(valiter
);
2037 scf_property_destroy(prop
);
2044 ra_free_prop_values(int numvalues
, char **values
)
2047 if (values
!= NULL
) {
2048 for (i
= 0; i
< numvalues
; i
++)
2055 ra_set_boolean_prop(scf_handle_t
*h
, scf_instance_t
*inst
, const char *pgname
,
2056 const char *prop
, boolean_t create
, boolean_t propval
)
2058 const char *val
= propval
? RA_PROPVAL_BOOLEAN_TRUE
:
2059 RA_PROPVAL_BOOLEAN_FALSE
;
2061 return (ra_set_prop_from_string(h
, inst
, pgname
, prop
, SCF_TYPE_BOOLEAN
,
2066 * Set the property named in propname to the values passed in in the propvals
2067 * array. Only create a new property if "create" is true.
2070 ra_set_prop_from_string(scf_handle_t
*h
, scf_instance_t
*inst
,
2071 const char *pgname
, const char *propname
, scf_type_t proptype
,
2072 boolean_t create
, int numpropvals
, const char **propvals
)
2074 scf_propertygroup_t
*instpg
= NULL
, *cpg
= NULL
;
2075 scf_type_t oldproptype
, newproptype
= proptype
;
2076 scf_property_t
*prop
= NULL
;
2077 scf_value_t
**values
= NULL
;
2078 scf_transaction_t
*tx
= NULL
;
2079 scf_transaction_entry_t
*ent
= NULL
;
2080 boolean_t
new = B_FALSE
;
2081 int i
, retval
, numvalues
= 0, ret
= 0;
2082 char *pgtype
= NULL
, **ovalues
;
2085 /* Firstly, does property exist? If not, and create is false, bail */
2086 if (ra_get_prop_as_string(h
, inst
, pgname
, propname
, B_TRUE
,
2087 B_FALSE
, &oldproptype
, &numvalues
, &ovalues
) == -1) {
2088 if (scf_error() != SCF_ERROR_NOT_FOUND
)
2091 (void) fprintf(stderr
, gettext(
2092 "%s: no such property %s/%s\n"), myname
, pgname
,
2097 ra_free_prop_values(numvalues
, ovalues
);
2099 /* Use old property type */
2100 if (proptype
== SCF_TYPE_INVALID
)
2101 newproptype
= oldproptype
;
2104 * Does property group exist at instance level? If not, we need to
2105 * create it, since the composed view of the property group did
2106 * contain the property. We never modify properties at the service
2107 * level, as it`s possible that multiple instances will inherit those
2110 if (ra_get_pg(h
, inst
, pgname
, B_FALSE
, B_FALSE
, &instpg
) == -1) {
2111 if (scf_error() != SCF_ERROR_NOT_FOUND
)
2113 /* Ensure pg exists at service level, get composed pg */
2114 if (ra_get_pg(h
, inst
, pgname
, B_TRUE
, B_FALSE
, &cpg
) == -1)
2117 /* Create instance-level property group */
2118 if ((typelen
= scf_pg_get_type(cpg
, NULL
, 0) + 1) == 0)
2120 if ((pgtype
= malloc(typelen
)) == NULL
) {
2121 (void) fprintf(stderr
, gettext(
2122 "%s: out of memory\n"), myname
);
2125 (void) scf_pg_get_type(cpg
, pgtype
, typelen
);
2126 if ((instpg
= scf_pg_create(h
)) == NULL
||
2127 scf_instance_add_pg(inst
, pgname
, pgtype
, 0, instpg
)
2129 (void) fprintf(stderr
, gettext(
2130 "%s: could not create property group %s\n"),
2135 if ((prop
= scf_property_create(h
)) == NULL
)
2137 if ((values
= calloc(numpropvals
, sizeof (scf_value_t
*))) == NULL
) {
2138 (void) fprintf(stderr
, gettext("%s: out of memory"), myname
);
2141 if (scf_pg_get_property(instpg
, propname
, prop
) != 0) {
2143 if (scf_error() == SCF_ERROR_NOT_FOUND
)
2148 if ((tx
= scf_transaction_create(h
)) == NULL
||
2149 (ent
= scf_entry_create(h
)) == NULL
)
2152 if (scf_transaction_start(tx
, instpg
) == -1)
2155 if (scf_transaction_property_new(tx
, ent
, propname
,
2158 } else if (scf_transaction_property_change(tx
, ent
, propname
,
2161 for (i
= 0; i
< numpropvals
; i
++) {
2162 if ((values
[i
] = scf_value_create(h
)) == NULL
||
2163 scf_value_set_from_string(values
[i
], newproptype
,
2164 propvals
[i
] == NULL
? "": propvals
[i
]) == -1 ||
2165 scf_entry_add_value(ent
, values
[i
]) != 0)
2168 retval
= scf_transaction_commit(tx
);
2170 scf_transaction_reset(tx
);
2171 if (scf_pg_update(instpg
) == -1)
2179 switch (scf_error()) {
2180 case SCF_ERROR_INVALID_ARGUMENT
:
2181 (void) fprintf(stderr
, gettext(
2182 "%s: invalid value for property %s/%s\n"), myname
,
2185 case SCF_ERROR_NOT_FOUND
:
2186 (void) fprintf(stderr
, gettext(
2187 "%s: no such property %s/%s\n"), myname
,
2191 (void) fprintf(stderr
, gettext(
2192 "%s: unexpected libscf error: %s\n"), myname
,
2193 scf_strerror(scf_error()));
2199 scf_transaction_destroy(tx
);
2201 scf_entry_destroy(ent
);
2202 if (values
!= NULL
) {
2203 for (i
= 0; i
< numpropvals
; i
++) {
2204 if (values
[i
] != NULL
)
2205 scf_value_destroy(values
[i
]);
2210 scf_property_destroy(prop
);
2212 scf_pg_destroy(cpg
);
2214 scf_pg_destroy(instpg
);
2221 * This function gathers configuration from the legacy /etc/inet/routing.conf,
2222 * if any, and sets the appropriate variable values accordingly. Once
2223 * these are set, the legacy daemons are checked to see if they have
2224 * SMF counterparts (ra_check_legacy_daemons()). If they do, the
2225 * configuration is upgraded. Finally, the legacy option settings are
2226 * applied, enabling/disabling the routing/forwarding services as
2230 ra_upgrade_from_legacy_conf(void)
2232 scf_handle_t
*h
= NULL
;
2233 scf_instance_t
*inst
= NULL
;
2235 boolean_t old_conf_read
;
2236 ravar_t
*routing_svcs
= ra_str2var(RA_VAR_ROUTING_SVCS
);
2239 * First, determine if we have already upgraded - if "routing-conf-read"
2240 * is true, we bail. The use of a boolean property indicating if
2241 * routing.conf has been read and applied might seem a lot more
2242 * work than simply copying routing.conf aside, but leaving the
2243 * file in place allows users to downgrade and have their old
2244 * routing configuration still in place.
2246 if ((h
= scf_handle_create(SCF_VERSION
)) == NULL
||
2247 scf_handle_bind(h
) == -1) {
2248 (void) fprintf(stderr
, gettext(
2249 "%s: cannot connect to SMF repository\n"), myname
);
2253 if ((inst
= scf_instance_create(h
)) == NULL
||
2254 scf_handle_decode_fmri(h
, RA_INSTANCE_ROUTING_SETUP
,
2255 NULL
, NULL
, inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) == -1) {
2256 (void) fprintf(stderr
, gettext(
2257 "%s: unexpected libscf error: %s\n"), myname
,
2258 scf_strerror(scf_error()));
2262 if (ra_get_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
2263 RA_PROP_ROUTING_CONF_READ
, B_TRUE
, B_TRUE
, &old_conf_read
) == -1) {
2272 * Now set "routing-conf-read" to true so we don`t reimport legacy
2273 * configuration again.
2275 if (ra_set_boolean_prop(h
, inst
, RA_PG_ROUTEADM
,
2276 RA_PROP_ROUTING_CONF_READ
, B_FALSE
, B_TRUE
) == -1)
2278 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP
);
2282 /* First, gather values from routing.conf */
2283 if ((r
= ra_parseconf()) == -1) {
2287 /* No routing.conf file found */
2291 * Now, set the options/variables gathered. We set variables first,
2292 * as we cannot enable routing before we determine the daemons
2296 for (i
= 0; ra_vars
[i
].var_name
!= NULL
; i
++) {
2297 /* Skip routing-svcs var, not featured in legacy config */
2298 if (strcmp(ra_vars
[i
].var_name
, RA_VAR_ROUTING_SVCS
) == 0)
2300 if (ra_smf_cb(ra_set_persistent_var_cb
, ra_vars
[i
].var_fmri
,
2301 &(ra_vars
[i
])) == -1) {
2306 /* Clear routing-svcs value */
2307 if (ra_smf_cb(ra_set_persistent_var_cb
, routing_svcs
->var_fmri
,
2308 routing_svcs
) == -1) {
2313 if (ra_check_legacy_daemons() == -1) {
2318 for (i
= 0; ra_opts
[i
].opt_name
!= NULL
; i
++) {
2319 if (ra_smf_cb(ra_set_persistent_opt_cb
, ra_opts
[i
].opt_fmri
,
2320 &(ra_opts
[i
])) == -1 ||
2321 ra_smf_cb(ra_set_default_opt_cb
,
2322 ra_opts
[i
].opt_default_fmri
, &(ra_opts
[i
])) == -1) {
2329 scf_instance_destroy(inst
);
2331 scf_handle_destroy(h
);
2338 * Return the number of IPv6 addresses configured. This answers the
2339 * generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
2340 * is configured, and we also only enable IPv6 routing daemons if IPv6 is
2346 static int num
= -1;
2353 if ((ipsock
= socket(PF_INET6
, SOCK_DGRAM
, 0)) == -1) {
2354 (void) fprintf(stderr
,
2355 gettext("%1$s: unable to open %2$s: %3$s\n"),
2356 myname
, IP_DEV_NAME
, strerror(errno
));
2359 lifn
.lifn_family
= AF_INET6
;
2360 lifn
.lifn_flags
= 0;
2362 if (ioctl(ipsock
, SIOCGLIFNUM
, &lifn
) == -1) {
2363 (void) close(ipsock
);
2366 (void) close(ipsock
);
2368 return (num
= lifn
.lifn_count
);
2372 * Parse the configuration file and fill the ra_opts array with opt_value
2373 * and opt_default_value values, and the ra_vars array with var_value and
2374 * var_default_value values. Then copy aside routing.conf so it will not
2375 * be read by future invokations of routeadm.
2382 char line
[RA_MAX_CONF_LINE
];
2387 if ((fp
= fopen(RA_CONF_FILE
, "r")) == NULL
) {
2389 * There's no config file, so we simply return as there
2395 for (lineno
= 1; fgets(line
, sizeof (line
), fp
) != NULL
; lineno
++) {
2396 if (line
[strlen(line
) - 1] == '\n')
2397 line
[strlen(line
) - 1] = '\0';
2401 /* Skip leading whitespace */
2402 while (isspace(*cp
))
2405 /* Skip comment lines and empty lines */
2406 if (*cp
== '#' || *cp
== '\0')
2410 * Anything else must be of the form:
2411 * <option> <value> <default_value>
2413 if ((confstr
= strtok(cp
, " ")) == NULL
) {
2414 (void) fprintf(stderr
,
2415 gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
2416 myname
, RA_CONF_FILE
, lineno
);
2420 if ((raopt
= ra_str2opt(confstr
)) != NULL
) {
2421 if (ra_parseopt(confstr
, lineno
, raopt
) != 0) {
2425 } else if ((ravar
= ra_str2var(confstr
)) != NULL
) {
2426 if (ra_parsevar(confstr
, ravar
) != 0) {
2431 (void) fprintf(stderr
,
2432 gettext("%1$s: %2$s: invalid option name on "
2434 myname
, RA_CONF_FILE
, lineno
);
2445 ra_parseopt(char *confstr
, int lineno
, raopt_t
*raopt
)
2447 oval_t oval
, d_oval
;
2449 if ((confstr
= strtok(NULL
, " ")) == NULL
) {
2450 (void) fprintf(stderr
,
2451 gettext("%1$s: %2$s: missing value on line %3$d\n"),
2452 myname
, RA_CONF_FILE
, lineno
);
2455 if ((oval
= ra_str2oval(confstr
)) == OPT_INVALID
) {
2456 (void) fprintf(stderr
,
2457 gettext("%1$s: %2$s: invalid option "
2458 "value on line %3$d\n"),
2459 myname
, RA_CONF_FILE
, lineno
);
2462 if (oval
!= OPT_DEFAULT
)
2463 raopt
->opt_enabled
= oval
== OPT_ENABLED
;
2465 if ((confstr
= strtok(NULL
, " ")) == NULL
) {
2466 (void) fprintf(stderr
,
2467 gettext("%1$s: %2$s: missing revert "
2468 "value on line %3$d\n"),
2469 myname
, RA_CONF_FILE
, lineno
);
2472 if ((d_oval
= ra_str2oval(confstr
)) == OPT_INVALID
) {
2473 (void) fprintf(stderr
,
2474 gettext("%1$s: %2$s: invalid revert "
2475 "value on line %3$d\n"),
2476 myname
, RA_CONF_FILE
, lineno
, confstr
);
2479 raopt
->opt_default_enabled
= d_oval
== OPT_ENABLED
;
2480 if (oval
== OPT_DEFAULT
)
2481 raopt
->opt_enabled
= d_oval
== OPT_ENABLED
;
2484 * Set ipv4(6)-routing-set property as appropriate on upgrading
2485 * routing.conf. If option was default, set this value to false,
2486 * as this indicates the administrator has not explicitly enabled
2487 * or disabled ipv4(6)-routing. The ipv4-routing-set value is used
2488 * in the routing-setup service, and if it is false, ipv4-routing
2489 * is enabled in the case where no default route can be determined.
2491 if (raopt
->opt_flags
& (RA_SVC_FLAG_IPV4_ROUTING
|
2492 RA_SVC_FLAG_IPV6_ROUTING
)) {
2493 if (ra_smf_cb(oval
== OPT_DEFAULT
? ra_routing_opt_unset_cb
:
2494 ra_routing_opt_set_cb
, raopt
->opt_default_fmri
, raopt
)
2502 ra_parsevar(char *confstr
, ravar_t
*ravar
)
2504 confstr
= strtok(NULL
, "=");
2505 if (confstr
== NULL
) {
2507 * This isn't an error condition, it simply means that the
2508 * variable has no value.
2510 ravar
->var_value
= NULL
;
2514 if ((ravar
->var_value
= strdup(confstr
)) == NULL
) {
2515 (void) fprintf(stderr
, gettext("%s: "
2516 "unable to allocate memory\n"), myname
);
2522 /* Convert a string to an option value. */
2524 ra_str2oval(const char *valstr
)
2526 if (strcmp(valstr
, "enabled") == 0)
2527 return (OPT_ENABLED
);
2528 else if (strcmp(valstr
, "disabled") == 0)
2529 return (OPT_DISABLED
);
2530 else if (strcmp(valstr
, "default") == 0)
2531 return (OPT_DEFAULT
);
2532 return (OPT_INVALID
);
2536 ra_str2opt(const char *optnamestr
)
2540 for (i
= 0; ra_opts
[i
].opt_name
!= NULL
; i
++) {
2541 if (strcmp(optnamestr
, ra_opts
[i
].opt_name
) == 0)
2544 if (ra_opts
[i
].opt_name
== NULL
)
2546 return (&ra_opts
[i
]);
2550 * Reset all option values previously gathered to B_FALSE.
2557 for (i
= 0; ra_opts
[i
].opt_name
!= NULL
; i
++) {
2558 ra_opts
[i
].opt_enabled
= B_FALSE
;
2559 ra_opts
[i
].opt_default_enabled
= B_FALSE
;
2564 ra_str2var(const char *varnamestr
)
2567 for (i
= 0; ra_vars
[i
].var_name
!= NULL
; i
++) {
2568 if (strcmp(varnamestr
, ra_vars
[i
].var_name
) == 0)
2571 if (ra_vars
[i
].var_name
== NULL
)
2573 return (&ra_vars
[i
]);
2577 * Reset variable values previously gathered to NULL.
2580 ra_resetvars(const char *proto
)
2583 for (i
= 0; ra_vars
[i
].var_name
!= NULL
; i
++) {
2584 if (proto
!= NULL
&&
2585 !VAR_PROTO_MATCH(ra_vars
[i
].var_name
, proto
))
2587 if (ra_vars
[i
].var_value
!= NULL
)
2588 free(ra_vars
[i
].var_value
);
2589 ra_vars
[i
].var_value
= NULL
;
2590 if (ra_vars
[i
].var_default_value
!= NULL
)
2591 free(ra_vars
[i
].var_default_value
);
2592 ra_vars
[i
].var_default_value
= NULL
;
2597 * Given an option name, this function provides an internationalized, human
2598 * readable version of the option name.
2601 ra_intloptname(const char *optname
)
2603 if (strcmp(optname
, RA_OPT_IPV4_FORWARDING
) == 0)
2604 return (gettext("IPv4 forwarding"));
2605 else if (strcmp(optname
, RA_OPT_IPV4_ROUTING
) == 0)
2606 return (gettext("IPv4 routing"));
2607 else if (strcmp(optname
, RA_OPT_IPV6_FORWARDING
) == 0)
2608 return (gettext("IPv6 forwarding"));
2609 else if (strcmp(optname
, RA_OPT_IPV6_ROUTING
) == 0)
2610 return (gettext("IPv6 routing"));
2611 else if (strcmp(optname
, RA_VAR_IPV4_ROUTING_DAEMON
) == 0)
2612 return (gettext("IPv4 routing daemon"));
2613 else if (strcmp(optname
, RA_VAR_IPV4_ROUTING_DAEMON_ARGS
) == 0)
2614 return (gettext("IPv4 routing daemon args"));
2615 else if (strcmp(optname
, RA_VAR_IPV4_ROUTING_STOP_CMD
) == 0)
2616 return (gettext("IPv4 routing daemon stop"));
2617 else if (strcmp(optname
, RA_VAR_IPV6_ROUTING_DAEMON
) == 0)
2618 return (gettext("IPv6 routing daemon"));
2619 else if (strcmp(optname
, RA_VAR_IPV6_ROUTING_DAEMON_ARGS
) == 0)
2620 return (gettext("IPv6 routing daemon args"));
2621 else if (strcmp(optname
, RA_VAR_IPV6_ROUTING_STOP_CMD
) == 0)
2622 return (gettext("IPv6 routing daemon stop"));
2623 else if (strcmp(optname
, RA_VAR_ROUTING_SVCS
) == 0)
2624 return (gettext("Routing services"));
2626 * If we get here, there's a bug and someone should trip over this