1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <limits.h>
33 #include <ctype.h>
34 #include <stropts.h>
35 #include <errno.h>
36 #include <libintl.h>
37 #include <locale.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <inet/ip.h>
44 #include <inet/nd.h>
45 #include <net/if.h>
46 #include <libscf.h>
47 #include <libscf_priv.h>
48 #include <libuutil.h>
49
50 /*
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
59 * # routeadm -l fmri
60 * where all properties in the "routing" property group are listed.
61 *
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.
67 *
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.
76 *
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.
85 *
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).
94 *
95 * Since the code is quite involved, we provide a guide to the more complex
96 * actions taken in response to user commands.
97 *
98 * routeadm -e[d] ipv4[6]-routing[forwarding]
99 *
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.
103 *
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).
123 *
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
130 * from the rest.
131 *
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.
147 *
148 * routeadm -l fmri
149 *
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().
153 *
154 * routeadm -m fmri key=value ...
155 *
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().
161 *
162 * routeadm -s var=value
163 *
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.
175 *
176 * routeadm -R alt_root ...
177 *
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.
183 *
184 * routeadm -u
185 *
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).
191 */
192
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"
197
198 #define IS_ROUTING_OPT(opt) (strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
199 strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
200
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"
208
209
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"
219
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"
239
240 #define RA_PG_ROUTING "routing"
241
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"
246
247 #define RA_SVC_FLAG_NONE 0x0
248 #define RA_SVC_FLAG_IPV4_ROUTING 0x1
249 #define RA_SVC_FLAG_IPV6_ROUTING 0x2
250
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
256
257 /*
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.
265 */
266
267 typedef struct raopt {
268 const char *opt_name;
269 const char *opt_fmri;
270 int opt_flags;
271 boolean_t opt_enabled;
272 const char *opt_default_fmri;
273 const char *opt_default_prop;
274 boolean_t opt_default_enabled;
275 } raopt_t;
276
277
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,
281 B_FALSE },
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,
284 B_FALSE },
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,
287 B_FALSE },
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,
290 B_FALSE },
291 { NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
292 };
293
294 typedef enum option_values {
295 OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
296 } oval_t;
297
298 typedef struct ra_var {
299 const char *var_name;
300 const char *var_fmri;
301 const char *var_prop;
302 char *var_value;
303 const char *var_default_fmri;
304 const char *var_default_prop;
305 char *var_default_value;
306 } ravar_t;
307
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 }
331 };
332
333 char *v_opt[] = {
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
347 RA_VAR_ROUTING_SVCS,
348 NULL
349 };
350
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)
358
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)
363
364 /*
365 * Structure used in modify operations to tie property name and multiple values
366 * together.
367 */
368 typedef struct ra_prop {
369 char *prop_name;
370 char **prop_values;
371 int prop_numvalues;
372 } ra_prop_t;
373
374 typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
375
376 /* Used to store program name */
377 static const char *myname;
378
379 static void usage(void);
380
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 *);
399
400 /* Callback for upgrade of legacy daemons */
401 static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
402
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,
411 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);
415
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 *);
421
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 *);
426
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 *,
436 char ***);
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,
442 const char **);
443
444 static void
usage(void)445 usage(void)
446 {
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"
452 " %1$s -u\n\n"
453 " <option> is one of:\n"
454 " ipv4-forwarding\n"
455 " ipv4-routing\n"
456 " ipv6-forwarding\n"
457 " ipv6-routing\n\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);
466 }
467
468 int
main(int argc,char * argv[])469 main(int argc, char *argv[])
470 {
471 int opt, opt_index, numargs, status = 0;
472 int numvalues, i;
473 ssize_t keylen;
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;
479 raopt_t *raopt;
480 ravar_t *ravar;
481 ra_prop_t raprop;
482
483 myname = argv[0];
484
485 (void) setlocale(LC_ALL, "");
486
487 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
488 #define TEXT_DOMAIN "SYS_TEST"
489 #endif
490
491 (void) textdomain(TEXT_DOMAIN);
492
493 /*
494 * Before processing any options, we parse /etc/inet/routing.conf
495 * (if present) and transfer values to SMF.
496 */
497 if (ra_upgrade_from_legacy_conf() == -1)
498 exit(EXIT_FAILURE);
499 while ((opt = getopt(argc, argv, ":bd:e:l:m:p:R:r:s:u")) != EOF) {
500 switch (opt) {
501 case 'b':
502 /*
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.
509 */
510 booting = B_TRUE;
511 break;
512 case 'd':
513 case 'e':
514 case 'r':
515 if (alt_root_set) {
516 if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
517 exit(EXIT_FAILURE);
518 modify = B_TRUE;
519 break;
520 }
521 if ((raopt = ra_str2opt(optarg)) != NULL) {
522 /* Set current value appropriately */
523 switch (opt) {
524 case 'd':
525 raopt->opt_enabled = B_FALSE;
526 break;
527 case 'e':
528 /*
529 * Check legacy daemons, mark
530 * routing-svcs.
531 */
532 if (IS_ROUTING_OPT(optarg) &&
533 ra_check_legacy_daemons() == -1)
534 exit(EXIT_FAILURE);
535 raopt->opt_enabled = B_TRUE;
536 break;
537 case 'r':
538 /*
539 * This callback sets opt_enabled to
540 * the default value.
541 */
542 ra_resetopts();
543 if (ra_smf_cb(ra_get_default_opt_cb,
544 raopt->opt_default_fmri, raopt)
545 == -1)
546 exit(EXIT_FAILURE);
547 if (raopt->opt_enabled &&
548 IS_ROUTING_OPT(optarg) &&
549 ra_check_legacy_daemons() == -1)
550 exit(EXIT_FAILURE);
551 /* set value to default */
552 raopt->opt_enabled =
553 raopt->opt_default_enabled;
554 break;
555 }
556 if (ra_smf_cb(ra_set_persistent_opt_cb,
557 raopt->opt_fmri, raopt) == -1)
558 exit(EXIT_FAILURE);
559 /*
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.
569 */
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)
577 == -1)
578 exit(EXIT_FAILURE);
579 }
580 } else if ((ravar = ra_str2var(optarg)) != NULL) {
581 if (opt != 'r') {
582 usage();
583 exit(EXIT_FAILURE);
584 }
585 /* set current value to default */
586 ra_resetopts();
587 if (ra_smf_cb(ra_get_default_var_cb,
588 ravar->var_default_fmri, ravar) == -1)
589 exit(EXIT_FAILURE);
590 /* Need special case for routing-svcs var */
591 if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
592 == 0) {
593 if (ra_update_routing_svcs(
594 ravar->var_default_value) == -1)
595 exit(EXIT_FAILURE);
596 } else if (ra_smf_cb(ra_set_persistent_var_cb,
597 ravar->var_fmri, ravar) == -1)
598 exit(EXIT_FAILURE);
599 } else {
600 (void) fprintf(stderr, gettext(
601 "%1$s: invalid option: %2$s\n"), myname,
602 optarg);
603 usage();
604 exit(EXIT_FAILURE);
605 }
606 modify = B_TRUE;
607 break;
608 case 'l':
609 if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
610 exit(EXIT_FAILURE);
611 report = B_FALSE;
612 break;
613 case 'm':
614 fmri = optarg;
615 modify = B_TRUE;
616 /*
617 * Argument list of key=value pairs, we need to
618 * collate all matching keys to set multiple values.
619 */
620 numargs = 1;
621 i = optind;
622 for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
623 numargs++)
624 i++;
625 if (numargs == 1) {
626 (void) fprintf(stderr, gettext(
627 "%s: key=value required for "
628 "property change\n"), myname);
629 usage();
630 exit(EXIT_FAILURE);
631 }
632 if (alt_root_set) {
633 if (ra_upgrade_cmd(opt, numargs,
634 &argv[optind - 1]) == -1)
635 exit(EXIT_FAILURE);
636 optind += numargs - 1;
637 break;
638 }
639 /*
640 * Collect all key=value pairs which use same key
641 * so we can add multiple property values.
642 */
643 for (key = argv[optind]; key != NULL && key[0] != '-';
644 key = argv[++optind]) {
645 if (key[0] == '\0')
646 continue;
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);
652 exit(EXIT_FAILURE);
653 }
654 numvalues = 1;
655 *(vals[0]) = '\0';
656 (vals[0])++;
657 i = optind + 1;
658 for (nk = argv[i];
659 nk != NULL && nk[0] != '-';
660 nk = argv[++i]) {
661 if (nk[0] == '\0')
662 continue;
663 if ((keyend = strchr(nk, '='))
664 == NULL) {
665 (void) fprintf(stderr, gettext(
666 "%s: Malformed name=value "
667 " pair %s\n"), myname, nk);
668 exit(EXIT_FAILURE);
669 }
670 if ((keylen = keyend - nk) !=
671 strlen(key))
672 continue;
673 if (strncmp(key, nk, keylen) == 0) {
674 vals = realloc(vals, ++numvalues
675 * sizeof (char *));
676 vals[numvalues - 1] = ++keyend;
677 nk[0] = '\0';
678 optind++;
679 }
680 }
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,
685 &raprop) == -1)
686 exit(EXIT_FAILURE);
687 }
688 break;
689 case 'p':
690 parseable = B_TRUE;
691 parseopt = optarg;
692 break;
693 case 'R':
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));
698 exit(EXIT_FAILURE);
699 }
700 alt_root_set = B_TRUE;
701 report = B_FALSE;
702 break;
703 case 's':
704 if (alt_root_set) {
705 if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
706 exit(EXIT_FAILURE);
707 modify = B_TRUE;
708 break;
709 }
710 options = optarg;
711 while (*options != '\0') {
712 opt_index = getsubopt(&options, v_opt, &val);
713 if (val == NULL) {
714 usage();
715 exit(EXIT_FAILURE);
716 }
717 if (opt_index == -1) {
718 (void) fprintf(stderr, gettext(
719 "%1$s: invalid variable: %2$s\n"),
720 myname, optarg);
721 usage();
722 exit(EXIT_FAILURE);
723 }
724 ravar = &ra_vars[opt_index];
725 /* Need special case for routing-svcs var */
726 if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
727 == 0) {
728 if (ra_update_routing_svcs(val) == -1)
729 return (-1);
730 } else {
731 ravar->var_value = strdup(val);
732 if (ra_smf_cb(ra_set_persistent_var_cb,
733 ravar->var_fmri, ravar) == -1)
734 exit(EXIT_FAILURE);
735 }
736 }
737 modify = B_TRUE;
738 break;
739 case 'u':
740 update = B_TRUE;
741 break;
742 case ':':
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]);
748 usage();
749 exit(EXIT_FAILURE);
750 }
751 parseable = B_TRUE;
752 break;
753 case '?':
754 usage();
755 exit(EXIT_FAILURE);
756 }
757 }
758
759 if (argc > optind) {
760 /* There shouldn't be any extra args. */
761 usage();
762 exit(EXIT_FAILURE);
763 }
764
765 if (parseable && (update || modify)) {
766 (void) fprintf(stderr, gettext("%s: the -p option cannot be "
767 "used with any of -demrsu\n"), myname);
768 usage();
769 exit(EXIT_FAILURE);
770 }
771
772 if (update && ! alt_root_set)
773 status = ra_update();
774
775 if (report && !modify && !update)
776 status = ra_report(parseable, parseopt);
777
778 return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
779 }
780
781 /*
782 * Upgrade legacy daemons, mark to-be-enabled routing services.
783 */
784 static int
ra_check_legacy_daemons(void)785 ra_check_legacy_daemons(void)
786 {
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;
792
793 if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
794 routing_svcs) == -1)
795 return (-1);
796
797 /* First unmark all services */
798 if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
799 return (-1);
800
801 mark = B_TRUE;
802 if (routing_svcs->var_value != NULL) {
803 /*
804 * For routing-svcs variable, mark each named
805 * service as a current-routing-svc.
806 */
807 if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
808 (void) fprintf(stderr, gettext(
809 "%s: out of memory\n"), myname);
810 return (-1);
811 }
812 /* Now, mark each service named in routing-svcs. */
813 for (nextfmri = strtok(fmri, " \t");
814 nextfmri != NULL;
815 nextfmri = strtok(NULL, " \t")) {
816 if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
817 &mark) == -1) {
818 free(fmri);
819 return (-1);
820 }
821 }
822 free(fmri);
823 }
824
825 /*
826 * Now check if legacy variables (if specified) map to SMF routing
827 * daemons. If so, transfer associated daemon arguments.
828 */
829 if (ra_upgrade_legacy_daemons() == -1)
830 return (-1);
831
832 ra_resetvars(NULL);
833 /*
834 * At this point, if the legacy services still have ipv4/ipv6
835 * routing daemons specified, we know they weren`t upgraded, so
836 * we mark them also.
837 */
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)
840 return (-1);
841
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,
844 &mark) == -1)
845 return (-1);
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,
848 &mark) == -1)
849 return (-1);
850
851 return (0);
852 }
853
854 /*
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
860 * when enabled.
861 */
862 static int
ra_upgrade_legacy_daemons(void)863 ra_upgrade_legacy_daemons(void)
864 {
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);
871
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)
875 == -1 ||
876 ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
877 == -1 ||
878 ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
879 == -1 ||
880 ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
881 == -1)
882 return (-1);
883
884 return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
885 }
886
887 /*
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.
891 */
892
893 /* ARGSUSED0 */
894 static int
ra_upgrade_legacy_daemons_cb(void * data,scf_walkinfo_t * wip)895 ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
896 {
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;
910
911 /*
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.
915 */
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)
920 return (0);
921
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);
925
926 /*
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.
930 */
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)
940 return (-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)
948 return (-1);
949 } else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
950 == 0 ||
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)
959 return (-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)
967 return (-1);
968 } else
969 return (0);
970
971 /*
972 * If service is unmarked at this point, add it to routing-svcs and
973 * mark it.
974 */
975 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
976 RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
977 marked == B_FALSE) {
978 mark = B_TRUE;
979 if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
980 == -1 ||
981 ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
982 routing_svcs) == -1)
983 return (-1);
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);
989 return (-1);
990 }
991 if (strlen(routing_svcs->var_value) == 0)
992 (void) snprintf(new_routing_svcs,
993 strlen(inst_fmri) + 1, "%s", inst_fmri);
994 else
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));
1004 }
1005 (void) smf_refresh_instance(inst_fmri);
1006 return (0);
1007 }
1008
1009 /*
1010 * If we are upgrading, append operation to <alt_root>/var/svc/profile/upgrade.
1011 */
1012 static int
ra_upgrade_cmd(char opt,int argc,char ** argv)1013 ra_upgrade_cmd(char opt, int argc, char **argv)
1014 {
1015 FILE *fp;
1016 int i;
1017
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));
1022 return (-1);
1023 }
1024 (void) fprintf(fp, "/sbin/routeadm -%c ", opt);
1025 if (argv != NULL) {
1026 for (i = 0; i < argc; i++)
1027 (void) fprintf(fp, "%s ", argv[i]);
1028 }
1029 (void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
1030 (void) fclose(fp);
1031 return (0);
1032 }
1033
1034 /*
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.
1039 */
1040 static int
ra_update(void)1041 ra_update(void)
1042 {
1043 int i;
1044
1045 if (ra_check_legacy_daemons() == -1)
1046 return (-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) {
1050 return (-1);
1051 }
1052 }
1053 /*
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
1056 * present).
1057 */
1058 if (ra_numv6intfs() > 0)
1059 return (smf_enable_instance(RA_INSTANCE_NDP, SMF_TEMPORARY));
1060 return (0);
1061 }
1062
1063 /*
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:
1068 *
1069 * # routeadm -s routing-svcs=route -e ipv4-routing -u
1070 *
1071 * followed by
1072 *
1073 * # routeadm -s routing-svcs=rdisc -u
1074 *
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
1079 * v4 routing-svcs
1080 * - if ipv6-routing was enabled, mark and persistently enable all the new
1081 * v6 routing-svcs.
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.
1084 */
1085 static int
ra_update_routing_svcs(char * routing_svcs_new)1086 ra_update_routing_svcs(char *routing_svcs_new)
1087 {
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;
1093
1094 ra_resetopts();
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)
1099 return (-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;
1104
1105 if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
1106 routing_svcs) == -1) {
1107 free(routing_svcs_old);
1108 return (-1);
1109 }
1110
1111 if (!v4_old && !v6_old) {
1112 /* We don`t need to do anything, since services were disabled */
1113 free(routing_svcs_old);
1114 return (0);
1115 }
1116 v4opt->opt_enabled = B_FALSE;
1117 v6opt->opt_enabled = B_FALSE;
1118
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);
1124 return (-1);
1125 }
1126 if (v4_old &&
1127 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
1128 free(routing_svcs_old);
1129 return (-1);
1130 }
1131 if (v6_old &&
1132 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
1133 free(routing_svcs_old);
1134 return (-1);
1135 }
1136 }
1137 free(routing_svcs_old);
1138 v4opt->opt_enabled = v4_old;
1139 v6opt->opt_enabled = v6_old;
1140
1141 /* Persistently enable each new v4/v6 "routing-svc" */
1142 mark = B_TRUE;
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)
1146 return (-1);
1147 if (v4_old &&
1148 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
1149 return (-1);
1150 if (v6_old &&
1151 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
1152 return (-1);
1153 }
1154 return (0);
1155 }
1156
1157 /*
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).
1161 */
1162 static int
ra_report(boolean_t parseable,const char * param)1163 ra_report(boolean_t parseable, const char *param)
1164 {
1165 int i;
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;
1170
1171 if (!parseable) {
1172 (void) printf(gettext(
1173 " Configuration Current "
1174 "Current\n"
1175 " Option Configuration "
1176 "System State\n"
1177 "---------------------------------------------------"
1178 "------------\n"));
1179 }
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;
1184 else
1185 continue;
1186 }
1187 if (ra_smf_cb(ra_get_current_opt_cb,
1188 ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1189 return (-1);
1190 c_state = ra_opts[i].opt_enabled ? enabled : disabled;
1191 ra_resetopts();
1192 if (ra_smf_cb(ra_get_persistent_opt_cb,
1193 ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1194 return (-1);
1195 p_state = ra_opts[i].opt_enabled ? enabled : disabled;
1196 ra_resetopts();
1197 if (ra_smf_cb(ra_get_default_opt_cb,
1198 ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
1199 return (-1);
1200 d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
1201 ra_resetopts();
1202 if (parseable) {
1203 if (param == NULL)
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);
1207 } else {
1208 (void) printf(gettext("%1$27s %2$-21s%3$s\n"),
1209 ra_intloptname(ra_opts[i].opt_name),
1210 p_state, c_state);
1211 }
1212 }
1213 if (!parseable)
1214 (void) printf("\n");
1215
1216 ra_resetvars(NULL);
1217
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)
1224 return (-1);
1225
1226 }
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;
1231 else
1232 continue;
1233 }
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;
1238 if (parseable) {
1239 if (param == NULL)
1240 (void) printf("%s ", ra_vars[i].var_name);
1241 (void) printf("persistent=\"%s\" "
1242 "default=\"%s\" \n", p_var, d_var);
1243 } else {
1244 /* If daemon variables are not set, do not display. */
1245 if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
1246 IPV4_VARS_UNSET) ||
1247 (IS_IPV6_VAR(ra_vars[i].var_name) &&
1248 IPV6_VARS_UNSET))
1249 continue;
1250 (void) printf(gettext("%1$27s \"%2$s\"\n"),
1251 ra_intloptname(ra_vars[i].var_name), p_var);
1252 }
1253 }
1254
1255 if (param != NULL && !param_found) {
1256 (void) fprintf(stderr, gettext(
1257 "%s: no such option/variable %s\n"), myname, param);
1258 return (-1);
1259 }
1260 if (parseable)
1261 return (0);
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)
1265 return (-1);
1266 return (0);
1267 }
1268
1269 /*
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.
1273 */
1274 static int
ra_smf_cb(ra_smf_cb_t cbfunc,const char * fmri,void * data)1275 ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
1276 {
1277 scf_handle_t *h;
1278 int exit_status = 0;
1279
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);
1284 return (-1);
1285 }
1286 return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
1287 fmri == NULL ? NULL : (char **)&fmri, 0,
1288 cbfunc, data, &exit_status, uu_die));
1289 }
1290
1291 /*
1292 * Applies persistent configuration settings to current setup.
1293 */
1294 static int
ra_set_current_opt_cb(void * data,scf_walkinfo_t * wip)1295 ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
1296 {
1297 return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
1298 }
1299
1300 /*
1301 * Sets persistent value for option, to be applied on next boot
1302 * or by "routeadm -u".
1303 */
1304 static int
ra_set_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1305 ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1306 {
1307 return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
1308 }
1309
1310 static int
ra_get_current_opt_cb(void * data,scf_walkinfo_t * wip)1311 ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
1312 {
1313 return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
1314 }
1315
1316 static int
ra_get_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1317 ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1318 {
1319 return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
1320 }
1321
1322 static int
ra_routing_opt_set_cb(void * data,scf_walkinfo_t * wip)1323 ra_routing_opt_set_cb(void *data, scf_walkinfo_t *wip)
1324 {
1325 return (ra_routing_opt_set_unset_cb(data, wip, B_TRUE));
1326 }
1327
1328 static int
ra_routing_opt_unset_cb(void * data,scf_walkinfo_t * wip)1329 ra_routing_opt_unset_cb(void *data, scf_walkinfo_t *wip)
1330 {
1331 return (ra_routing_opt_set_unset_cb(data, wip, B_FALSE));
1332 }
1333
1334 /*
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
1338 * be determined.
1339 */
1340 static int
ra_routing_opt_set_unset_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t set)1341 ra_routing_opt_set_unset_cb(raopt_t *raopt, scf_walkinfo_t *wip, boolean_t set)
1342 {
1343 scf_instance_t *inst = wip->inst;
1344 scf_handle_t *h = scf_instance_handle(inst);
1345
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,
1349 B_FALSE, set));
1350 }
1351
1352 /*
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.
1359 *
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.
1365 */
1366 static int
ra_get_set_opt_common_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t persistent,boolean_t get)1367 ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
1368 boolean_t persistent, boolean_t get)
1369 {
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;
1381
1382 /*
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.
1387 */
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)
1393 return (0);
1394 return (-1);
1395 }
1396 scf_pg_destroy(routeadm_pg);
1397
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)
1403 return (0);
1404 return (-1);
1405 }
1406
1407 /*
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.
1411 */
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;
1420 }
1421 }
1422 /* If not an ipv4 routing service, skip. */
1423 if (protolist == NULL || !found_proto) {
1424 ra_free_prop_values(numvalues, protolist);
1425 return (0);
1426 }
1427 }
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;
1436 }
1437 }
1438 /* If not an ipv6 routing service, skip. */
1439 if (protolist == NULL || !found_proto) {
1440 ra_free_prop_values(numvalues, protolist);
1441 return (0);
1442 }
1443 /*
1444 * If no IPv6 interfaces are configured, do not apply
1445 * the "enable" state change to this IPv6 routing service.
1446 */
1447 if (raopt->opt_enabled && ra_numv6intfs() < 1)
1448 return (0);
1449 }
1450 ra_free_prop_values(numvalues, protolist);
1451
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,
1456 &curr_svc) == -1)
1457 return (0);
1458 else if (!curr_svc && persistent) {
1459 /*
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".
1464 */
1465 return (0);
1466 }
1467 }
1468 if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
1469 B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
1470 return (-1);
1471
1472 current_state_enabled = persistent_state_enabled;
1473
1474 if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
1475 SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
1476 == 0)
1477 current_state_enabled = temporary_state_enabled;
1478
1479 if (get) {
1480 /*
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.
1486 */
1487 if (persistent)
1488 raopt->opt_enabled = raopt->opt_enabled ||
1489 persistent_state_enabled;
1490 else
1491 raopt->opt_enabled = raopt->opt_enabled ||
1492 current_state_enabled;
1493 } else {
1494 if (persistent) {
1495 /*
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.
1502 */
1503 ret = current_state_enabled ?
1504 smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
1505 smf_disable_instance(inst_fmri, SMF_TEMPORARY);
1506 if (ret != 0) {
1507 (void) fprintf(stderr, gettext(
1508 "%s: unexpected libscf error: %s\n"),
1509 myname, scf_strerror(scf_error()));
1510 return (-1);
1511 }
1512 /*
1513 * Refresh here so general_ovr/enabled state overrides
1514 * general/enabled state.
1515 */
1516 (void) smf_refresh_instance(inst_fmri);
1517 /*
1518 * Now we can safely set the general/enabled value
1519 * to the value we require on next boot (or
1520 * "routeadm -u").
1521 */
1522 ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
1523 SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
1524 if (ret != 0)
1525 return (-1);
1526 /*
1527 * Refresh here so general/enabled value is set.
1528 */
1529 (void) smf_refresh_instance(inst_fmri);
1530 if (raopt->opt_fmri != NULL)
1531 return (0);
1532 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
1533 } else {
1534 /*
1535 * Refresh here to get latest property values prior
1536 * to starting daemon.
1537 */
1538 (void) smf_refresh_instance(inst_fmri);
1539 /*
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.
1545 */
1546 ret = persistent_state_enabled && curr_svc ?
1547 smf_enable_instance(inst_fmri, 0) :
1548 smf_disable_instance(inst_fmri, 0);
1549 if (ret != 0) {
1550 (void) fprintf(stderr, gettext(
1551 "%s: unexpected libscf error: %s\n"),
1552 myname, scf_strerror(scf_error()));
1553 return (-1);
1554 }
1555 if (current_state_enabled && persistent_state_enabled) {
1556 /*
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
1562 * property values.
1563 */
1564 (void) smf_restart_instance(inst_fmri);
1565 }
1566 }
1567 }
1568 return (0);
1569 }
1570
1571 static int
ra_set_default_opt_cb(void * data,scf_walkinfo_t * wip)1572 ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
1573 {
1574 scf_instance_t *inst = wip->inst;
1575 scf_handle_t *h = scf_instance_handle(inst);
1576 raopt_t *raopt = data;
1577
1578 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1579 raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
1580 }
1581
1582 static int
ra_get_default_opt_cb(void * data,scf_walkinfo_t * wip)1583 ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
1584 {
1585 scf_instance_t *inst = wip->inst;
1586 scf_handle_t *h = scf_instance_handle(inst);
1587 raopt_t *raopt = data;
1588
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)));
1592 }
1593
1594 /*
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.
1599 */
1600 static int
ra_get_persistent_var_cb(void * data,scf_walkinfo_t * wip)1601 ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1602 {
1603 scf_instance_t *inst = wip->inst;
1604 scf_handle_t *h = scf_instance_handle(inst);
1605 ravar_t *ravar = data;
1606
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));
1609 }
1610
1611 static int
ra_set_persistent_var_cb(void * data,scf_walkinfo_t * wip)1612 ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1613 {
1614 scf_instance_t *inst = wip->inst;
1615 scf_handle_t *h = scf_instance_handle(inst);
1616 ravar_t *ravar = data;
1617
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));
1621 }
1622
1623 static int
ra_get_default_var_cb(void * data,scf_walkinfo_t * wip)1624 ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
1625 {
1626 scf_instance_t *inst = wip->inst;
1627 scf_handle_t *h = scf_instance_handle(inst);
1628 ravar_t *ravar = data;
1629
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));
1633 }
1634
1635 /*
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.
1641 */
1642 static int
ra_mark_routing_svcs_cb(void * data,scf_walkinfo_t * wip)1643 ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
1644 {
1645 scf_instance_t *inst = wip->inst;
1646 scf_handle_t *h = scf_instance_handle(inst);
1647 boolean_t *mark = data;
1648 boolean_t marked;
1649 int numvalues = 0;
1650 char **protolist = NULL;
1651
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)
1655 return (0);
1656 ra_free_prop_values(numvalues, protolist);
1657 if (*mark)
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));
1665 return (0);
1666 }
1667
1668 /*
1669 * List property values for all properties in the "routing" property
1670 * group of the routing service instance.
1671 */
1672
1673 /* ARGSUSED0 */
1674 static int
ra_list_props_cb(void * data,scf_walkinfo_t * wip)1675 ra_list_props_cb(void *data, scf_walkinfo_t *wip)
1676 {
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;
1683 scf_value_t *val;
1684 char **protolist = NULL, *pnamebuf, *valbuf;
1685 ssize_t pnamelen, vallen;
1686 int numvalues = 0;
1687 int propiterret, valiterret, retval = 0;
1688
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"),
1695 myname, inst_fmri);
1696 else
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);
1701 return (-1);
1702 }
1703 ra_free_prop_values(numvalues, protolist);
1704
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);
1709 return (0);
1710 }
1711 (void) fprintf(stderr,
1712 gettext("%s: unexpected libscf error: %s\n"),
1713 myname, scf_strerror(scf_error()));
1714 return (-1);
1715 }
1716
1717 (void) printf("%s:\n", inst_fmri);
1718
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()));
1726 }
1727 while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
1728 if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
1729 == 0) {
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()));
1733 retval = -1;
1734 break;
1735 }
1736 if ((pnamebuf = malloc(pnamelen)) == NULL) {
1737 (void) fprintf(stderr,
1738 gettext("%s: out of memory\n"), myname);
1739 retval = -1;
1740 break;
1741 }
1742 (void) scf_property_get_name(prop, pnamebuf,
1743 pnamelen);
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)
1748 != 0) {
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);
1755 free(pnamebuf);
1756 retval = -1;
1757 break;
1758 }
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()));
1767 retval = -1;
1768 } else if ((valbuf = malloc(vallen)) == NULL) {
1769 (void) fprintf(stderr,
1770 gettext("%s: out of memory\n"), myname);
1771 retval = -1;
1772 }
1773 if (retval == -1) {
1774 scf_iter_destroy(valiter);
1775 scf_value_destroy(val);
1776 free(pnamebuf);
1777 goto out;
1778 }
1779 (void) scf_value_get_as_string(val, valbuf, vallen);
1780 (void) printf("%s ", valbuf);
1781 free(valbuf);
1782 }
1783 (void) printf("\n");
1784 scf_iter_destroy(valiter);
1785 scf_value_destroy(val);
1786 free(pnamebuf);
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()));
1792 retval = -1;
1793 break;
1794 }
1795 }
1796 out:
1797 scf_iter_destroy(propiter);
1798 scf_property_destroy(prop);
1799 scf_pg_destroy(pg);
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()));
1804 return (retval);
1805 }
1806
1807 /*
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.
1812 */
1813 static int
ra_modify_props_cb(void * data,scf_walkinfo_t * wip)1814 ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
1815 {
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;
1820 int numvalues = 0;
1821 char **protolist = NULL;
1822
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"),
1829 myname, inst_fmri);
1830 else
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);
1835 return (-1);
1836 }
1837 ra_free_prop_values(numvalues, protolist);
1838
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)
1842 return (-1);
1843
1844 (void) smf_refresh_instance(inst_fmri);
1845 return (0);
1846 }
1847
1848 /*
1849 * Display FMRI, state for each routing daemon service.
1850 */
1851
1852 /* ARGSUSED0 */
1853 static int
ra_print_state_cb(void * data,scf_walkinfo_t * wip)1854 ra_print_state_cb(void *data, scf_walkinfo_t *wip)
1855 {
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;
1860 int numvalues = 0;
1861
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)
1865 return (0);
1866 ra_free_prop_values(numvalues, protolist);
1867
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()));
1872 return (-1);
1873 }
1874 (void) printf("%27s %2s\n", inst_state, inst_fmri);
1875 free(inst_state);
1876
1877 return (0);
1878 }
1879
1880 static int
ra_get_pg(scf_handle_t * h,scf_instance_t * inst,const char * pgname,boolean_t composed,boolean_t required,scf_propertygroup_t ** pg)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)
1883 {
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) {
1889 if (required)
1890 (void) fprintf(stderr, gettext(
1891 "%s: no such property group %s\n"),
1892 myname, pgname);
1893 return (-1);
1894 }
1895 if (required)
1896 (void) fprintf(stderr, gettext(
1897 "%s: unexpected libscf error: %s\n"), myname,
1898 scf_strerror(scf_error()));
1899 return (-1);
1900 }
1901 return (0);
1902 }
1903
1904 static int
ra_get_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,boolean_t * val)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)
1908 {
1909 char *valstr;
1910
1911 if (ra_get_single_prop_as_string(h, inst, pgname, propname,
1912 composed, required, NULL, &valstr) != 0)
1913 return (-1);
1914 *val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
1915 free(valstr);
1916 return (0);
1917 }
1918
1919 static int
ra_get_single_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,char ** value)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)
1923 {
1924 char **values;
1925 int numvalues = 1;
1926
1927 if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
1928 type, &numvalues, &values) == -1)
1929 return (-1);
1930 *value = values[0];
1931 free(values);
1932 return (0);
1933 }
1934
1935 /*
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).
1939 */
1940 static int
ra_get_prop_as_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,boolean_t composed,boolean_t required,scf_type_t * type,int * numvalues,char *** 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)
1944 {
1945 scf_propertygroup_t *pg = NULL;
1946 scf_property_t *prop = NULL;
1947 scf_iter_t *valiter = NULL;
1948 scf_value_t *val = NULL;
1949 ssize_t vallen = 0;
1950 int valiterret, i, numvalues_retrieved, ret = 0;
1951
1952 if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
1953 return (-1);
1954
1955 *values = NULL;
1956 /*
1957 * Retrieve values. All values routeadm needs to retrieve
1958 * (bar those gathered by routeadm -l), are known to be single-valued.
1959 */
1960 if ((prop = scf_property_create(h)) == NULL)
1961 goto error;
1962 if (scf_pg_get_property(pg, propname, prop) != 0) {
1963 *numvalues = 0;
1964 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1965 if (required)
1966 (void) fprintf(stderr, gettext(
1967 "%s: property %s/%s not found\n"),
1968 myname, pgname, propname);
1969 ret = -1;
1970 goto out;
1971 }
1972 goto error;
1973 }
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)
1978 goto error;
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)
1985 goto error;
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);
1991 ret = -1;
1992 goto out;
1993 }
1994 (void) scf_value_get_as_string(val,
1995 (*values)[numvalues_retrieved], vallen);
1996 }
1997 if (valiterret == -1)
1998 goto error;
1999 /*
2000 * if *numvalues != 0, it holds expected number of values. If a
2001 * different number are found, it is an error.
2002 */
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);
2007 ret = -1;
2008 goto out;
2009 }
2010 *numvalues = numvalues_retrieved;
2011
2012 /* Retrieve property type if required. */
2013 if (type != NULL)
2014 (void) scf_property_type(prop, type);
2015
2016 goto out;
2017 error:
2018 if (scf_error() == SCF_ERROR_NOT_FOUND) {
2019 (void) fprintf(stderr, gettext(
2020 "%s: property %s not found"), myname, propname);
2021 } else {
2022 (void) fprintf(stderr, gettext(
2023 "%s: unexpected libscf error: %s, "), myname);
2024 }
2025 for (i = 0; i < numvalues_retrieved; i++)
2026 free((*values)[i]);
2027 if (*values != NULL)
2028 free(*values);
2029
2030 ret = -1;
2031 out:
2032 if (val != NULL)
2033 scf_value_destroy(val);
2034 if (valiter != NULL)
2035 scf_iter_destroy(valiter);
2036 if (prop != NULL)
2037 scf_property_destroy(prop);
2038 if (pg != NULL)
2039 scf_pg_destroy(pg);
2040 return (ret);
2041 }
2042
2043 static void
ra_free_prop_values(int numvalues,char ** values)2044 ra_free_prop_values(int numvalues, char **values)
2045 {
2046 int i;
2047 if (values != NULL) {
2048 for (i = 0; i < numvalues; i++)
2049 free(values[i]);
2050 free(values);
2051 }
2052 }
2053
2054 static int
ra_set_boolean_prop(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * prop,boolean_t create,boolean_t propval)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)
2057 {
2058 const char *val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
2059 RA_PROPVAL_BOOLEAN_FALSE;
2060
2061 return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
2062 create, 1, &val));
2063 }
2064
2065 /*
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.
2068 */
2069 static int
ra_set_prop_from_string(scf_handle_t * h,scf_instance_t * inst,const char * pgname,const char * propname,scf_type_t proptype,boolean_t create,int numpropvals,const char ** propvals)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)
2073 {
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;
2083 ssize_t typelen;
2084
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)
2089 goto error;
2090 if (!create) {
2091 (void) fprintf(stderr, gettext(
2092 "%s: no such property %s/%s\n"), myname, pgname,
2093 propname);
2094 return (-1);
2095 }
2096 } else
2097 ra_free_prop_values(numvalues, ovalues);
2098
2099 /* Use old property type */
2100 if (proptype == SCF_TYPE_INVALID)
2101 newproptype = oldproptype;
2102
2103 /*
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
2108 * settings.
2109 */
2110 if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
2111 if (scf_error() != SCF_ERROR_NOT_FOUND)
2112 goto error;
2113 /* Ensure pg exists at service level, get composed pg */
2114 if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
2115 goto error;
2116
2117 /* Create instance-level property group */
2118 if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
2119 goto error;
2120 if ((pgtype = malloc(typelen)) == NULL) {
2121 (void) fprintf(stderr, gettext(
2122 "%s: out of memory\n"), myname);
2123 goto error;
2124 }
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)
2128 == -1) {
2129 (void) fprintf(stderr, gettext(
2130 "%s: could not create property group %s\n"),
2131 myname, pgname);
2132 goto error;
2133 }
2134 }
2135 if ((prop = scf_property_create(h)) == NULL)
2136 goto error;
2137 if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
2138 (void) fprintf(stderr, gettext("%s: out of memory"), myname);
2139 goto error;
2140 }
2141 if (scf_pg_get_property(instpg, propname, prop) != 0) {
2142 /* New property? */
2143 if (scf_error() == SCF_ERROR_NOT_FOUND)
2144 new = B_TRUE;
2145 else
2146 goto error;
2147 }
2148 if ((tx = scf_transaction_create(h)) == NULL ||
2149 (ent = scf_entry_create(h)) == NULL)
2150 goto error;
2151 retry:
2152 if (scf_transaction_start(tx, instpg) == -1)
2153 goto error;
2154 if (new) {
2155 if (scf_transaction_property_new(tx, ent, propname,
2156 newproptype) == -1)
2157 goto error;
2158 } else if (scf_transaction_property_change(tx, ent, propname,
2159 newproptype) == -1)
2160 goto error;
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)
2166 goto error;
2167 }
2168 retval = scf_transaction_commit(tx);
2169 if (retval == 0) {
2170 scf_transaction_reset(tx);
2171 if (scf_pg_update(instpg) == -1)
2172 goto error;
2173 goto retry;
2174 }
2175 if (retval == -1)
2176 goto error;
2177 goto out;
2178 error:
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,
2183 pgname, propname);
2184 break;
2185 case SCF_ERROR_NOT_FOUND:
2186 (void) fprintf(stderr, gettext(
2187 "%s: no such property %s/%s\n"), myname,
2188 pgname, propname);
2189 break;
2190 default:
2191 (void) fprintf(stderr, gettext(
2192 "%s: unexpected libscf error: %s\n"), myname,
2193 scf_strerror(scf_error()));
2194 break;
2195 }
2196 ret = -1;
2197 out:
2198 if (tx != NULL)
2199 scf_transaction_destroy(tx);
2200 if (ent != NULL)
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]);
2206 }
2207 free(values);
2208 }
2209 if (prop != NULL)
2210 scf_property_destroy(prop);
2211 if (cpg != NULL)
2212 scf_pg_destroy(cpg);
2213 if (instpg != NULL)
2214 scf_pg_destroy(instpg);
2215 if (pgtype != NULL)
2216 free(pgtype);
2217 return (ret);
2218 }
2219
2220 /*
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
2227 * appropriate.
2228 */
2229 static int
ra_upgrade_from_legacy_conf(void)2230 ra_upgrade_from_legacy_conf(void)
2231 {
2232 scf_handle_t *h = NULL;
2233 scf_instance_t *inst = NULL;
2234 int ret = 0, i, r;
2235 boolean_t old_conf_read;
2236 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
2237
2238 /*
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.
2245 */
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);
2250 ret = -1;
2251 goto out;
2252 }
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()));
2259 ret = -1;
2260 goto out;
2261 }
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) {
2264 ret = -1;
2265 goto out;
2266 }
2267
2268 if (old_conf_read)
2269 goto out;
2270
2271 /*
2272 * Now set "routing-conf-read" to true so we don`t reimport legacy
2273 * configuration again.
2274 */
2275 if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
2276 RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
2277 return (-1);
2278 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
2279
2280 ra_resetvars(NULL);
2281
2282 /* First, gather values from routing.conf */
2283 if ((r = ra_parseconf()) == -1) {
2284 ret = -1;
2285 goto out;
2286 }
2287 /* No routing.conf file found */
2288 if (r == 0)
2289 goto out;
2290 /*
2291 * Now, set the options/variables gathered. We set variables first,
2292 * as we cannot enable routing before we determine the daemons
2293 * to enable.
2294 */
2295
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)
2299 continue;
2300 if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
2301 &(ra_vars[i])) == -1) {
2302 ret = -1;
2303 goto out;
2304 }
2305 }
2306 /* Clear routing-svcs value */
2307 if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
2308 routing_svcs) == -1) {
2309 ret = -1;
2310 goto out;
2311 }
2312
2313 if (ra_check_legacy_daemons() == -1) {
2314 ret = -1;
2315 goto out;
2316 }
2317
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) {
2323 ret = -1;
2324 break;
2325 }
2326 }
2327 out:
2328 if (inst != NULL)
2329 scf_instance_destroy(inst);
2330 if (h != NULL)
2331 scf_handle_destroy(h);
2332
2333 return (ret);
2334 }
2335
2336 /*
2337 *
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
2341 * enabled.
2342 */
2343 static int
ra_numv6intfs(void)2344 ra_numv6intfs(void)
2345 {
2346 static int num = -1;
2347 int ipsock;
2348 struct lifnum lifn;
2349
2350 if (num != -1)
2351 return (num);
2352
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));
2357 return (0);
2358 }
2359 lifn.lifn_family = AF_INET6;
2360 lifn.lifn_flags = 0;
2361
2362 if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
2363 (void) close(ipsock);
2364 return (0);
2365 }
2366 (void) close(ipsock);
2367
2368 return (num = lifn.lifn_count);
2369 }
2370
2371 /*
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.
2376 */
2377 static int
ra_parseconf(void)2378 ra_parseconf(void)
2379 {
2380 FILE *fp;
2381 uint_t lineno;
2382 char line[RA_MAX_CONF_LINE];
2383 char *cp, *confstr;
2384 raopt_t *raopt;
2385 ravar_t *ravar;
2386
2387 if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
2388 /*
2389 * There's no config file, so we simply return as there
2390 * is no work to do.
2391 */
2392 return (0);
2393 }
2394
2395 for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
2396 if (line[strlen(line) - 1] == '\n')
2397 line[strlen(line) - 1] = '\0';
2398
2399 cp = line;
2400
2401 /* Skip leading whitespace */
2402 while (isspace(*cp))
2403 cp++;
2404
2405 /* Skip comment lines and empty lines */
2406 if (*cp == '#' || *cp == '\0')
2407 continue;
2408
2409 /*
2410 * Anything else must be of the form:
2411 * <option> <value> <default_value>
2412 */
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);
2417 continue;
2418 }
2419
2420 if ((raopt = ra_str2opt(confstr)) != NULL) {
2421 if (ra_parseopt(confstr, lineno, raopt) != 0) {
2422 (void) fclose(fp);
2423 return (-1);
2424 }
2425 } else if ((ravar = ra_str2var(confstr)) != NULL) {
2426 if (ra_parsevar(confstr, ravar) != 0) {
2427 (void) fclose(fp);
2428 return (-1);
2429 }
2430 } else {
2431 (void) fprintf(stderr,
2432 gettext("%1$s: %2$s: invalid option name on "
2433 "line %3$d\n"),
2434 myname, RA_CONF_FILE, lineno);
2435 continue;
2436 }
2437 }
2438
2439 (void) fclose(fp);
2440
2441 return (1);
2442 }
2443
2444 static int
ra_parseopt(char * confstr,int lineno,raopt_t * raopt)2445 ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
2446 {
2447 oval_t oval, d_oval;
2448
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);
2453 return (0);
2454 }
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);
2460 return (0);
2461 }
2462 if (oval != OPT_DEFAULT)
2463 raopt->opt_enabled = oval == OPT_ENABLED;
2464
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);
2470 return (0);
2471 }
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);
2477 return (0);
2478 }
2479 raopt->opt_default_enabled = d_oval == OPT_ENABLED;
2480 if (oval == OPT_DEFAULT)
2481 raopt->opt_enabled = d_oval == OPT_ENABLED;
2482
2483 /*
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.
2490 */
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)
2495 == -1)
2496 return (-1);
2497 }
2498 return (0);
2499 }
2500
2501 static int
ra_parsevar(char * confstr,ravar_t * ravar)2502 ra_parsevar(char *confstr, ravar_t *ravar)
2503 {
2504 confstr = strtok(NULL, "=");
2505 if (confstr == NULL) {
2506 /*
2507 * This isn't an error condition, it simply means that the
2508 * variable has no value.
2509 */
2510 ravar->var_value = NULL;
2511 return (0);
2512 }
2513
2514 if ((ravar->var_value = strdup(confstr)) == NULL) {
2515 (void) fprintf(stderr, gettext("%s: "
2516 "unable to allocate memory\n"), myname);
2517 return (-1);
2518 }
2519 return (0);
2520 }
2521
2522 /* Convert a string to an option value. */
2523 static oval_t
ra_str2oval(const char * valstr)2524 ra_str2oval(const char *valstr)
2525 {
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);
2533 }
2534
2535 static raopt_t *
ra_str2opt(const char * optnamestr)2536 ra_str2opt(const char *optnamestr)
2537 {
2538 int i;
2539
2540 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2541 if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
2542 break;
2543 }
2544 if (ra_opts[i].opt_name == NULL)
2545 return (NULL);
2546 return (&ra_opts[i]);
2547 }
2548
2549 /*
2550 * Reset all option values previously gathered to B_FALSE.
2551 */
2552 static void
ra_resetopts(void)2553 ra_resetopts(void)
2554 {
2555 int i;
2556
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;
2560 }
2561 }
2562
2563 static ravar_t *
ra_str2var(const char * varnamestr)2564 ra_str2var(const char *varnamestr)
2565 {
2566 int i;
2567 for (i = 0; ra_vars[i].var_name != NULL; i++) {
2568 if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
2569 break;
2570 }
2571 if (ra_vars[i].var_name == NULL)
2572 return (NULL);
2573 return (&ra_vars[i]);
2574 }
2575
2576 /*
2577 * Reset variable values previously gathered to NULL.
2578 */
2579 static void
ra_resetvars(const char * proto)2580 ra_resetvars(const char *proto)
2581 {
2582 int i;
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))
2586 continue;
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;
2593 }
2594 }
2595
2596 /*
2597 * Given an option name, this function provides an internationalized, human
2598 * readable version of the option name.
2599 */
2600 static char *
ra_intloptname(const char * optname)2601 ra_intloptname(const char *optname)
2602 {
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"));
2625 /*
2626 * If we get here, there's a bug and someone should trip over this
2627 * NULL pointer.
2628 */
2629 return (NULL);
2630 }
2631