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 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <ctype.h>
32 #include <stropts.h>
33 #include <errno.h>
34 #include <libintl.h>
35 #include <locale.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/socket.h>
40 #include <sys/sockio.h>
41 #include <inet/ip.h>
42 #include <inet/nd.h>
43 #include <net/if.h>
44 #include <libscf.h>
45 #include <libscf_priv.h>
46 #include <libuutil.h>
47
48 /*
49 * This program moves routing management under SMF. We do this by giving
50 * routeadm options that allow interaction with SMF services. These include:
51 * - setting the routing services routeadm will enable
52 * # routeadm -s routing-svcs="fmri [fmri...]"
53 * where each fmri is an SMF routing service.
54 * - changing properties of routing services
55 * # routeadm -m fmri key=value [key=value...]
56 * - listing routing daemon properties
57 * # routeadm -l fmri
58 * where all properties in the "routing" property group are listed.
59 *
60 * By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
61 * can also support running of routing daemons with no SMF service under SMF.
62 * Specifying a routing daemon with no SMF counterpart results in the
63 * daemon, it`s arguments and stop command being set in the appropriate instance
64 * to be picked up by start/stop methods.
65 *
66 * Internally, routeadm keeps track of routing services by setting the
67 * "current-routing-svc" property to "true" in the services it manages.
68 * So for example, running
69 * # routeadm -s routing-svcs="route:default ripng:default"
70 * sets this variable in each instance specified. If the user specifies a
71 * non-SMF routing daemon via
72 * # routeadm -s ipv4-routing-daemon=/usr/sbin/mydaemon
73 * the variable will be set for the legacy-routing:ipv4 instance.
74 *
75 * In order to ensure that the SMF versions of routing daemons are used
76 * where possible, routeadm will check the daemons specified in
77 * ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
78 * SMF counterpart. If so, rather than running the legacy service
79 * we move configuration, specifically the associated daemon arguments
80 * to the SMF counterpart. From there, when the daemon is enabled, it
81 * will pick up the daemon arguments setting, transfer the argument string
82 * to the appropriate properties and run the service.
83 *
84 * To support the semantics of routeadm -e (enable at next boot) through SMF,
85 * we make use of temporary state changes, which last only until reboot.
86 * For example, if a service is disabled, and it is to be enabled via
87 * routeadm -e, we simply change the disable to a temporary disable,
88 * and set the persistent enabled value to true. This ensures the daemon
89 * will run at next boot, but not now. The reverse is true for disabling
90 * enabled instances (and if the daemon is enabled when we issue the enable,
91 * we do nothing since it is already in the desired state).
92 *
93 * Since the code is quite involved, we provide a guide to the more complex
94 * actions taken in response to user commands.
95 *
96 * routeadm -e[d] ipv4[6]-routing[forwarding]
97 *
98 * In this case, the goal is to prepare the configured routing daemons
99 * (specified through routeadm -s routing-svcs="...") or forwarding
100 * services to switch on (-e) or of (-d) at next boot.
101 *
102 * Since this operation must be applied to multiple services in the
103 * routing daemon case (as opposed to the single ipv4[6]-forwarding
104 * service), we make use of the scf_walk_fmri() function, which
105 * applies a callback function to all matching functions. In the case
106 * of the routing daemons, we pass in a NULL signifying that all
107 * instances should be walked (we then weed out the relevant routing
108 * services through presence of the routeadm/protocol property). In
109 * the case of enable, a routing service is enabled IFF it has the
110 * previously-mentioned property - with an appropriate value (i.e. ipv4
111 * for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
112 * property set to true (this is set by other operations such as
113 * routeadm -s routing-svcs="..."). Then, smf_enable_instance() or
114 * smf_disable_instance() is called, setting the temporary state to
115 * the current state of the service. This then allows setting of
116 * general/enabled value to next-boot value. In the case of disabling
117 * ipv4[6]-routing, all valid ipv4[6] routing daemons are prepared
118 * for next-boot disable, not just those specified via routing-svcs (this
119 * means that if the user enables routing daemons with "svcadm enable",
120 * disabling global routing does really switch off all routing daemons).
121 *
122 * This is implemented through the ra_get_set_opt_common_cb() function,
123 * called by the ra_set_persistent_opt_cb() function. The same
124 * function can be used for both routing and forwarding options, in the
125 * latter case we simply provide the specific FMRI of the forwarding
126 * service in question (ipv4-forwarding or ipv6-forwarding), and dispense
127 * with the eligibility tests we need to weed out the routing services
128 * from the rest.
129 *
130 * Before we initiate the "enable" however, we must check routing daemons
131 * specified via the legacy variables (ipv4-routing-daemon etc).
132 * If they map to SMF routing services, we wish to transfer their
133 * configuration to the corresponding services and use them instead of
134 * the legacy services. To do this, we need to match the daemon program
135 * against the routeadm/daemon property of each routing daemon (we use
136 * scf_walk_fmri() and the routeadm/protocol property again to identify
137 * daemons). If a match is found, the daemon arguments are transferred
138 * to the appropriate service`s daemon-args property, to be picked up
139 * by it`s start method and converted into appropriate property values.
140 * This is accomplished by ra_check_legacy_daemons(), and the callback
141 * operation is carried out by ra_upgrade_legacy_daemons_cb(). If the
142 * daemon was not upgraded, we need to mark the legacy-routing:ipv4[6]
143 * instance to be enabled (by routeadm -e), since it now must run the
144 * un-upgradeable legacy daemon.
145 *
146 * routeadm -l fmri
147 *
148 * Lists all properties and values in the routing property group associated
149 * with instance fmri. We simply walk through the composed property
150 * group, displaying all values. See ra_list_props_cb().
151 *
152 * routeadm -m fmri key=value ...
153 *
154 * Modify property values in the routing property group. If the same
155 * key is used more than once, multiple property values are set for that
156 * property. Properties must exist in the composed property group, but
157 * will only ever be set at the instance level to prevent multiple
158 * instances inheriting the property in error. See ra_modify_props_cb().
159 *
160 * routeadm -s var=value
161 *
162 * In all cases bar the routing-svcs variable, this simply involves
163 * setting the appropriate SMF property value for the variable. The
164 * routing-svcs case is more complex, since we would like operations
165 * like the following to have intuitive effects:
166 * # routeadm -s routing-svcs=route -e ipv4-routing -u
167 * # routeadm -s routing-svcs=rdisc -u
168 * i.e., in the end, rdisc is the only routing service running. To
169 * accomplish this switchover, we need to disable the old routing-svcs
170 * and enable the new, marking the latter with the curr-routing-svc
171 * property so that routeadm -e will pick them up. This is carried
172 * out by the ra_update_routing_svcs() function.
173 *
174 * routeadm -R alt_root ...
175 *
176 * Used to support use of routeadm in Custom Jumpstart scripts, this
177 * option causes all subsequent commands to be appended to the
178 * /var/svc/profile/upgrade file, which is run on the subsequent boot.
179 * This is done because the SMF repository is not available to make
180 * the modifications to property values required in routeadm operations.
181 *
182 * routeadm -u
183 *
184 * Update applies the "next boot" state to the current system. Here
185 * we simply take the persistent state (general/enabled value) and
186 * make it the current state through smf_enable_instance() or
187 * smf_disable_instance() as appropriate (these calls, without the
188 * temporary flag set, delete the general_ovr/enabled property).
189 */
190
191 #define RA_OPT_IPV4_ROUTING "ipv4-routing"
192 #define RA_OPT_IPV6_ROUTING "ipv6-routing"
193 #define RA_OPT_IPV4_FORWARDING "ipv4-forwarding"
194 #define RA_OPT_IPV6_FORWARDING "ipv6-forwarding"
195
196 #define IS_ROUTING_OPT(opt) (strcmp(opt, RA_OPT_IPV4_ROUTING) == 0 || \
197 strcmp(opt, RA_OPT_IPV6_ROUTING) == 0)
198
199 #define RA_VAR_IPV4_ROUTING_DAEMON "ipv4-routing-daemon"
200 #define RA_VAR_IPV4_ROUTING_DAEMON_ARGS "ipv4-routing-daemon-args"
201 #define RA_VAR_IPV4_ROUTING_STOP_CMD "ipv4-routing-stop-cmd"
202 #define RA_VAR_IPV6_ROUTING_DAEMON "ipv6-routing-daemon"
203 #define RA_VAR_IPV6_ROUTING_DAEMON_ARGS "ipv6-routing-daemon-args"
204 #define RA_VAR_IPV6_ROUTING_STOP_CMD "ipv6-routing-stop-cmd"
205 #define RA_VAR_ROUTING_SVCS "routing-svcs"
206
207
208 #define RA_INSTANCE_ALL NULL
209 #define RA_INSTANCE_ROUTING_SETUP "svc:/network/routing-setup:default"
210 #define RA_INSTANCE_IPV4_FORWARDING "svc:/network/ipv4-forwarding:default"
211 #define RA_INSTANCE_IPV6_FORWARDING "svc:/network/ipv6-forwarding:default"
212 #define RA_INSTANCE_LEGACY_ROUTING_IPV4 \
213 "svc:/network/routing/legacy-routing:ipv4"
214 #define RA_INSTANCE_LEGACY_ROUTING_IPV6 \
215 "svc:/network/routing/legacy-routing:ipv6"
216 #define RA_INSTANCE_NDP "svc:/network/routing/ndp:default"
217
218 #define RA_PG_ROUTEADM "routeadm"
219 #define RA_PROP_CURR_ROUTING_SVC "current-routing-svc"
220 #define RA_PROP_ROUTING_SVCS "routing-svcs"
221 #define RA_PROP_DEFAULT_ROUTING_SVCS "default-routing-svcs"
222 #define RA_PROP_PROTO "protocol"
223 #define RA_PROP_DAEMON "daemon"
224 #define RA_PROP_DEFAULT_DAEMON "default-daemon"
225 #define RA_PROP_DAEMON_ARGS "daemon-args"
226 #define RA_PROP_DEFAULT_DAEMON_ARGS "default-daemon-args"
227 #define RA_PROP_DAEMON_STOP_CMD "daemon-stop-cmd"
228 #define RA_PROP_DEFAULT_STOP_CMD "default-daemon"
229 #define RA_PROP_LEGACY_DAEMON "legacy-daemon"
230 #define RA_PROP_DEFAULT_IPV4_ROUTING "default-ipv4-routing"
231 #define RA_PROP_DEFAULT_IPV6_ROUTING "default-ipv6-routing"
232 #define RA_PROP_DEFAULT_IPV4_FORWARDING "default-ipv4-forwarding"
233 #define RA_PROP_DEFAULT_IPV6_FORWARDING "default-ipv6-forwarding"
234 #define RA_PROP_IPV4_ROUTING_SET "ipv4-routing-set"
235 #define RA_PROP_IPV6_ROUTING_SET "ipv6-routing-set"
236 #define RA_PROP_ROUTING_CONF_READ "routing-conf-read"
237
238 #define RA_PG_ROUTING "routing"
239
240 #define RA_PROPVAL_BOOLEAN_TRUE "true"
241 #define RA_PROPVAL_BOOLEAN_FALSE "false"
242 #define RA_PROPVAL_PROTO_IPV4 "ipv4"
243 #define RA_PROPVAL_PROTO_IPV6 "ipv6"
244
245 #define RA_SVC_FLAG_NONE 0x0
246 #define RA_SVC_FLAG_IPV4_ROUTING 0x1
247 #define RA_SVC_FLAG_IPV6_ROUTING 0x2
248
249 #define RA_SMF_UPGRADE_FILE "/var/svc/profile/upgrade"
250 #define RA_SMF_UPGRADE_MSG " # added by routeadm(8)"
251 #define RA_CONF_FILE "/etc/inet/routing.conf"
252 #define RA_CONF_FILE_OLD "/etc/inet/routing.conf.old"
253 #define RA_MAX_CONF_LINE 256
254
255 /*
256 * Option value. Each option requires an FMRI identifying which services
257 * to run the get_current/persistent scf_walk_fmri() function with, and
258 * associated flags (to ensure that in the case that multiple services
259 * match, we select the correct ones). In addition, we specify the FMRI
260 * and property used to set default option value. The opt_enabled field
261 * is used to hold retrieved state from get_*_opt_() callbacks and to specify
262 * desired state for set_*_opt() operations.
263 */
264
265 typedef struct raopt {
266 const char *opt_name;
267 const char *opt_fmri;
268 int opt_flags;
269 boolean_t opt_enabled;
270 const char *opt_default_fmri;
271 const char *opt_default_prop;
272 boolean_t opt_default_enabled;
273 } raopt_t;
274
275
276 raopt_t ra_opts[] = {
277 { RA_OPT_IPV4_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV4_ROUTING,
278 B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV4_ROUTING,
279 B_FALSE },
280 { RA_OPT_IPV6_ROUTING, RA_INSTANCE_ALL, RA_SVC_FLAG_IPV6_ROUTING,
281 B_FALSE, RA_INSTANCE_ROUTING_SETUP, RA_PROP_DEFAULT_IPV6_ROUTING,
282 B_FALSE },
283 { RA_OPT_IPV4_FORWARDING, RA_INSTANCE_IPV4_FORWARDING, RA_SVC_FLAG_NONE,
284 B_FALSE, RA_INSTANCE_IPV4_FORWARDING, RA_PROP_DEFAULT_IPV4_FORWARDING,
285 B_FALSE },
286 { RA_OPT_IPV6_FORWARDING, RA_INSTANCE_IPV6_FORWARDING, RA_SVC_FLAG_NONE,
287 B_FALSE, RA_INSTANCE_IPV6_FORWARDING, RA_PROP_DEFAULT_IPV6_FORWARDING,
288 B_FALSE },
289 { NULL, NULL, RA_SVC_FLAG_NONE, B_FALSE, NULL, NULL, B_FALSE }
290 };
291
292 typedef enum option_values {
293 OPT_INVALID, OPT_ENABLED, OPT_DISABLED, OPT_DEFAULT, OPT_UNKNOWN
294 } oval_t;
295
296 typedef struct ra_var {
297 const char *var_name;
298 const char *var_fmri;
299 const char *var_prop;
300 char *var_value;
301 const char *var_default_fmri;
302 const char *var_default_prop;
303 char *var_default_value;
304 } ravar_t;
305
306 ravar_t ra_vars[] = {
307 { RA_VAR_IPV4_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV4,
308 RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
309 RA_PROP_DEFAULT_DAEMON, NULL},
310 { RA_VAR_IPV4_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV4,
311 RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
312 RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
313 { RA_VAR_IPV4_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV4,
314 RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV4,
315 RA_PROP_DEFAULT_STOP_CMD, NULL },
316 { RA_VAR_IPV6_ROUTING_DAEMON, RA_INSTANCE_LEGACY_ROUTING_IPV6,
317 RA_PROP_DAEMON, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
318 RA_PROP_DEFAULT_DAEMON, NULL },
319 { RA_VAR_IPV6_ROUTING_DAEMON_ARGS, RA_INSTANCE_LEGACY_ROUTING_IPV6,
320 RA_PROP_DAEMON_ARGS, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
321 RA_PROP_DEFAULT_DAEMON_ARGS, NULL },
322 { RA_VAR_IPV6_ROUTING_STOP_CMD, RA_INSTANCE_LEGACY_ROUTING_IPV6,
323 RA_PROP_DAEMON_STOP_CMD, NULL, RA_INSTANCE_LEGACY_ROUTING_IPV6,
324 RA_PROP_DEFAULT_STOP_CMD, NULL },
325 { RA_VAR_ROUTING_SVCS, RA_INSTANCE_ROUTING_SETUP,
326 RA_PROP_ROUTING_SVCS, NULL, RA_INSTANCE_ROUTING_SETUP,
327 RA_PROP_DEFAULT_ROUTING_SVCS, NULL },
328 { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
329 };
330
331 char *v_opt[] = {
332 #define IPV4_ROUTING_DAEMON 0
333 RA_VAR_IPV4_ROUTING_DAEMON,
334 #define IPV4_ROUTING_DAEMON_ARGS 1
335 RA_VAR_IPV4_ROUTING_DAEMON_ARGS,
336 #define IPV4_ROUTING_STOP_CMD 2
337 RA_VAR_IPV4_ROUTING_STOP_CMD,
338 #define IPV6_ROUTING_DAEMON 3
339 RA_VAR_IPV6_ROUTING_DAEMON,
340 #define IPV6_ROUTING_DAEMON_ARGS 4
341 RA_VAR_IPV6_ROUTING_DAEMON_ARGS,
342 #define IPV6_ROUTING_STOP_CMD 5
343 RA_VAR_IPV6_ROUTING_STOP_CMD,
344 #define ROUTING_SVCS 6
345 RA_VAR_ROUTING_SVCS,
346 NULL
347 };
348
349 #define IS_IPV4_VAR(varname) (strncmp(varname, "ipv4", 4) == 0)
350 #define IS_IPV6_VAR(varname) (strncmp(varname, "ipv6", 4) == 0)
351 #define VAR_PROTO_MATCH(varname, proto) (strncmp(varname, proto, 4) == 0)
352 #define IPV4_VARS_UNSET \
353 (strtok(ra_vars[IPV4_ROUTING_DAEMON].var_value, " \t") == NULL && \
354 strtok(ra_vars[IPV4_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
355 strtok(ra_vars[IPV4_ROUTING_STOP_CMD].var_value, " \t") == NULL)
356
357 #define IPV6_VARS_UNSET \
358 (strtok(ra_vars[IPV6_ROUTING_DAEMON].var_value, " \t") == NULL && \
359 strtok(ra_vars[IPV6_ROUTING_DAEMON_ARGS].var_value, " \t") == NULL && \
360 strtok(ra_vars[IPV6_ROUTING_STOP_CMD].var_value, " \t") == NULL)
361
362 /*
363 * Structure used in modify operations to tie property name and multiple values
364 * together.
365 */
366 typedef struct ra_prop {
367 char *prop_name;
368 char **prop_values;
369 int prop_numvalues;
370 } ra_prop_t;
371
372 typedef int (*ra_smf_cb_t)(void *, scf_walkinfo_t *);
373
374 /* Used to store program name */
375 static const char *myname;
376
377 static void usage(void);
378
379 static int ra_check_legacy_daemons(void);
380 static int ra_upgrade_legacy_daemons(void);
381 static int ra_upgrade_cmd(char, int, char **);
382 static int ra_update(void);
383 static int ra_update_routing_svcs(char *);
384 static int ra_report(boolean_t, const char *);
385 static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
386 static int ra_upgrade_from_legacy_conf(void);
387 static int ra_numv6intfs(void);
388 static int ra_parseconf(void);
389 static int ra_parseopt(char *, int, raopt_t *);
390 static int ra_parsevar(char *, ravar_t *);
391 static oval_t ra_str2oval(const char *);
392 static raopt_t *ra_str2opt(const char *);
393 static void ra_resetopts(void);
394 static ravar_t *ra_str2var(const char *);
395 static void ra_resetvars(const char *);
396 static char *ra_intloptname(const char *);
397
398 /* Callback for upgrade of legacy daemons */
399 static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
400
401 /* Callbacks used to set/retieve routing options */
402 static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
403 static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
404 static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
405 static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
406 static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
407 static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
408 static int ra_get_set_opt_common_cb(raopt_t *, scf_walkinfo_t *, boolean_t,
409 boolean_t);
410 static int ra_routing_opt_set_cb(void *, scf_walkinfo_t *);
411 static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t *);
412 static int ra_routing_opt_set_unset_cb(raopt_t *, scf_walkinfo_t *, boolean_t);
413
414 /* Callbacks used to set/retrieve routing variables */
415 static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
416 static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
417 static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
418 static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
419
420 /* Callbacks used to list/set daemon properties and list daemons and states. */
421 static int ra_list_props_cb(void *, scf_walkinfo_t *);
422 static int ra_modify_props_cb(void *, scf_walkinfo_t *);
423 static int ra_print_state_cb(void *, scf_walkinfo_t *);
424
425 /* Utility functions for SMF operations */
426 static int ra_get_pg(scf_handle_t *, scf_instance_t *, const char *,
427 boolean_t, boolean_t, scf_propertygroup_t **);
428 static int ra_get_boolean_prop(scf_handle_t *, scf_instance_t *,
429 const char *, const char *, boolean_t, boolean_t, boolean_t *);
430 static int ra_get_single_prop_as_string(scf_handle_t *, scf_instance_t *,
431 const char *, const char *, boolean_t, boolean_t, scf_type_t *, char **);
432 static int ra_get_prop_as_string(scf_handle_t *, scf_instance_t *,
433 const char *, const char *, boolean_t, boolean_t, scf_type_t *, int *,
434 char ***);
435 static void ra_free_prop_values(int, char **);
436 static int ra_set_boolean_prop(scf_handle_t *, scf_instance_t *,
437 const char *, const char *, boolean_t, boolean_t);
438 static int ra_set_prop_from_string(scf_handle_t *, scf_instance_t *,
439 const char *, const char *, scf_type_t, boolean_t, int,
440 const char **);
441
442 static void
usage(void)443 usage(void)
444 {
445 (void) fprintf(stderr, gettext(
446 "usage: %1$s [-p] [-R <root-dir>]\n"
447 " %1$s [-e <option>] [-d <option>] [-r <option>]\n"
448 " [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
449 " [-s <var>=<val>] [-R <root-dir>]\n"
450 " %1$s -u\n\n"
451 " <option> is one of:\n"
452 " ipv4-forwarding\n"
453 " ipv4-routing\n"
454 " ipv6-forwarding\n"
455 " ipv6-routing\n\n"
456 " <var> is one of:\n"
457 " ipv4-routing-daemon\n"
458 " ipv4-routing-daemon-args\n"
459 " ipv4-routing-stop-cmd\n"
460 " ipv6-routing-daemon\n"
461 " ipv6-routing-daemon-args\n"
462 " ipv6-routing-stop-cmd\n"
463 " routing-svcs\n"), myname);
464 }
465
466 int
main(int argc,char * argv[])467 main(int argc, char *argv[])
468 {
469 int opt, opt_index, numargs, status = 0;
470 int numvalues, i;
471 ssize_t keylen;
472 boolean_t modify = B_FALSE, report = B_TRUE, update = B_FALSE;
473 boolean_t booting = B_FALSE, alt_root_set = B_FALSE;
474 boolean_t parseable = B_FALSE;
475 char *key, *nk, *keyend, *val, **vals, *options, *fmri;
476 char *parseopt = NULL;
477 raopt_t *raopt;
478 ravar_t *ravar;
479 ra_prop_t raprop;
480
481 myname = argv[0];
482
483 (void) setlocale(LC_ALL, "");
484
485 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
486 #define TEXT_DOMAIN "SYS_TEST"
487 #endif
488
489 (void) textdomain(TEXT_DOMAIN);
490
491 /*
492 * Before processing any options, we parse /etc/inet/routing.conf
493 * (if present) and transfer values to SMF.
494 */
495 if (ra_upgrade_from_legacy_conf() == -1)
496 exit(EXIT_FAILURE);
497 while ((opt = getopt(argc, argv, ":bd:e:l:m:p:R:r:s:u")) != EOF) {
498 switch (opt) {
499 case 'b':
500 /*
501 * Project-private option that tells us enable/disable
502 * operations should not set ipv4(6)-routing-set
503 * property. Used in routing-setup service method
504 * to change default routing state, and, if
505 * no explicit enable/disable operations have been
506 * carried out, change current ipv4 routing state.
507 */
508 booting = B_TRUE;
509 break;
510 case 'd':
511 case 'e':
512 case 'r':
513 if (alt_root_set) {
514 if (ra_upgrade_cmd(opt, 1, &optarg) != 0)
515 exit(EXIT_FAILURE);
516 modify = B_TRUE;
517 break;
518 }
519 if ((raopt = ra_str2opt(optarg)) != NULL) {
520 /* Set current value appropriately */
521 switch (opt) {
522 case 'd':
523 raopt->opt_enabled = B_FALSE;
524 break;
525 case 'e':
526 /*
527 * Check legacy daemons, mark
528 * routing-svcs.
529 */
530 if (IS_ROUTING_OPT(optarg) &&
531 ra_check_legacy_daemons() == -1)
532 exit(EXIT_FAILURE);
533 raopt->opt_enabled = B_TRUE;
534 break;
535 case 'r':
536 /*
537 * This callback sets opt_enabled to
538 * the default value.
539 */
540 ra_resetopts();
541 if (ra_smf_cb(ra_get_default_opt_cb,
542 raopt->opt_default_fmri, raopt)
543 == -1)
544 exit(EXIT_FAILURE);
545 if (raopt->opt_enabled &&
546 IS_ROUTING_OPT(optarg) &&
547 ra_check_legacy_daemons() == -1)
548 exit(EXIT_FAILURE);
549 /* set value to default */
550 raopt->opt_enabled =
551 raopt->opt_default_enabled;
552 break;
553 }
554 if (ra_smf_cb(ra_set_persistent_opt_cb,
555 raopt->opt_fmri, raopt) == -1)
556 exit(EXIT_FAILURE);
557 /*
558 * ipv4(6)-routing explicitly enabled/disabled,
559 * need to set ipv4(6)-routing-set property
560 * for routing-setup service. Once this
561 * is set, routing-setup will not override
562 * administrator action and will not enable
563 * ipv4-routing in the case that no default
564 * route can be determined. If ipv4(6)-routing
565 * is reverted to its default value, set
566 * ipv4(6)-routing-set back to false.
567 */
568 if (!booting && (raopt->opt_flags &
569 (RA_SVC_FLAG_IPV4_ROUTING |
570 RA_SVC_FLAG_IPV6_ROUTING))) {
571 if (ra_smf_cb(opt == 'r' ?
572 ra_routing_opt_unset_cb :
573 ra_routing_opt_set_cb,
574 raopt->opt_default_fmri, raopt)
575 == -1)
576 exit(EXIT_FAILURE);
577 }
578 } else if ((ravar = ra_str2var(optarg)) != NULL) {
579 if (opt != 'r') {
580 usage();
581 exit(EXIT_FAILURE);
582 }
583 /* set current value to default */
584 ra_resetopts();
585 if (ra_smf_cb(ra_get_default_var_cb,
586 ravar->var_default_fmri, ravar) == -1)
587 exit(EXIT_FAILURE);
588 /* Need special case for routing-svcs var */
589 if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
590 == 0) {
591 if (ra_update_routing_svcs(
592 ravar->var_default_value) == -1)
593 exit(EXIT_FAILURE);
594 } else if (ra_smf_cb(ra_set_persistent_var_cb,
595 ravar->var_fmri, ravar) == -1)
596 exit(EXIT_FAILURE);
597 } else {
598 (void) fprintf(stderr, gettext(
599 "%1$s: invalid option: %2$s\n"), myname,
600 optarg);
601 usage();
602 exit(EXIT_FAILURE);
603 }
604 modify = B_TRUE;
605 break;
606 case 'l':
607 if (ra_smf_cb(ra_list_props_cb, optarg, NULL) == -1)
608 exit(EXIT_FAILURE);
609 report = B_FALSE;
610 break;
611 case 'm':
612 fmri = optarg;
613 modify = B_TRUE;
614 /*
615 * Argument list of key=value pairs, we need to
616 * collate all matching keys to set multiple values.
617 */
618 numargs = 1;
619 i = optind;
620 for (numargs = 1; argv[i] != NULL && argv[i][0] != '-';
621 numargs++)
622 i++;
623 if (numargs == 1) {
624 (void) fprintf(stderr, gettext(
625 "%s: key=value required for "
626 "property change\n"), myname);
627 usage();
628 exit(EXIT_FAILURE);
629 }
630 if (alt_root_set) {
631 if (ra_upgrade_cmd(opt, numargs,
632 &argv[optind - 1]) == -1)
633 exit(EXIT_FAILURE);
634 optind += numargs - 1;
635 break;
636 }
637 /*
638 * Collect all key=value pairs which use same key
639 * so we can add multiple property values.
640 */
641 for (key = argv[optind]; key != NULL && key[0] != '-';
642 key = argv[++optind]) {
643 if (key[0] == '\0')
644 continue;
645 vals = malloc(sizeof (char *));
646 if ((vals[0] = strchr(key, '=')) == NULL) {
647 (void) fprintf(stderr, gettext(
648 "%s: Malformed name=value "
649 "pair %s\n"), myname, key);
650 exit(EXIT_FAILURE);
651 }
652 numvalues = 1;
653 *(vals[0]) = '\0';
654 (vals[0])++;
655 i = optind + 1;
656 for (nk = argv[i];
657 nk != NULL && nk[0] != '-';
658 nk = argv[++i]) {
659 if (nk[0] == '\0')
660 continue;
661 if ((keyend = strchr(nk, '='))
662 == NULL) {
663 (void) fprintf(stderr, gettext(
664 "%s: Malformed name=value "
665 " pair %s\n"), myname, nk);
666 exit(EXIT_FAILURE);
667 }
668 if ((keylen = keyend - nk) !=
669 strlen(key))
670 continue;
671 if (strncmp(key, nk, keylen) == 0) {
672 vals = realloc(vals, ++numvalues
673 * sizeof (char *));
674 vals[numvalues - 1] = ++keyend;
675 nk[0] = '\0';
676 optind++;
677 }
678 }
679 raprop.prop_name = key;
680 raprop.prop_values = vals;
681 raprop.prop_numvalues = numvalues;
682 if (ra_smf_cb(ra_modify_props_cb, fmri,
683 &raprop) == -1)
684 exit(EXIT_FAILURE);
685 }
686 break;
687 case 'p':
688 parseable = B_TRUE;
689 parseopt = optarg;
690 break;
691 case 'R':
692 if (chroot(optarg) == -1) {
693 (void) fprintf(stderr, gettext(
694 "%1$s: failed to chroot to %2$s: %3$s\n"),
695 myname, optarg, strerror(errno));
696 exit(EXIT_FAILURE);
697 }
698 alt_root_set = B_TRUE;
699 report = B_FALSE;
700 break;
701 case 's':
702 if (alt_root_set) {
703 if (ra_upgrade_cmd(opt, 1, &optarg) == -1)
704 exit(EXIT_FAILURE);
705 modify = B_TRUE;
706 break;
707 }
708 options = optarg;
709 while (*options != '\0') {
710 opt_index = getsubopt(&options, v_opt, &val);
711 if (val == NULL) {
712 usage();
713 exit(EXIT_FAILURE);
714 }
715 if (opt_index == -1) {
716 (void) fprintf(stderr, gettext(
717 "%1$s: invalid variable: %2$s\n"),
718 myname, optarg);
719 usage();
720 exit(EXIT_FAILURE);
721 }
722 ravar = &ra_vars[opt_index];
723 /* Need special case for routing-svcs var */
724 if (strcmp(ravar->var_name, RA_VAR_ROUTING_SVCS)
725 == 0) {
726 if (ra_update_routing_svcs(val) == -1)
727 return (-1);
728 } else {
729 ravar->var_value = strdup(val);
730 if (ra_smf_cb(ra_set_persistent_var_cb,
731 ravar->var_fmri, ravar) == -1)
732 exit(EXIT_FAILURE);
733 }
734 }
735 modify = B_TRUE;
736 break;
737 case 'u':
738 update = B_TRUE;
739 break;
740 case ':':
741 /* if not 'p', usage failure */
742 if (strcmp(argv[optind - 1], "-p") != 0) {
743 (void) fprintf(stderr, gettext(
744 "%s: option requires an argument -%s\n"),
745 myname, argv[optind - 1]);
746 usage();
747 exit(EXIT_FAILURE);
748 }
749 parseable = B_TRUE;
750 break;
751 case '?':
752 usage();
753 exit(EXIT_FAILURE);
754 }
755 }
756
757 if (argc > optind) {
758 /* There shouldn't be any extra args. */
759 usage();
760 exit(EXIT_FAILURE);
761 }
762
763 if (parseable && (update || modify)) {
764 (void) fprintf(stderr, gettext("%s: the -p option cannot be "
765 "used with any of -demrsu\n"), myname);
766 usage();
767 exit(EXIT_FAILURE);
768 }
769
770 if (update && ! alt_root_set)
771 status = ra_update();
772
773 if (report && !modify && !update)
774 status = ra_report(parseable, parseopt);
775
776 return (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
777 }
778
779 /*
780 * Upgrade legacy daemons, mark to-be-enabled routing services.
781 */
782 static int
ra_check_legacy_daemons(void)783 ra_check_legacy_daemons(void)
784 {
785 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
786 ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
787 ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
788 char *fmri, *nextfmri;
789 boolean_t mark = B_FALSE;
790
791 if (ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
792 routing_svcs) == -1)
793 return (-1);
794
795 /* First unmark all services */
796 if (ra_smf_cb(ra_mark_routing_svcs_cb, NULL, &mark) == -1)
797 return (-1);
798
799 mark = B_TRUE;
800 if (routing_svcs->var_value != NULL) {
801 /*
802 * For routing-svcs variable, mark each named
803 * service as a current-routing-svc.
804 */
805 if ((fmri = strdup(routing_svcs->var_value)) == NULL) {
806 (void) fprintf(stderr, gettext(
807 "%s: out of memory\n"), myname);
808 return (-1);
809 }
810 /* Now, mark each service named in routing-svcs. */
811 for (nextfmri = strtok(fmri, " \t");
812 nextfmri != NULL;
813 nextfmri = strtok(NULL, " \t")) {
814 if (ra_smf_cb(ra_mark_routing_svcs_cb, nextfmri,
815 &mark) == -1) {
816 free(fmri);
817 return (-1);
818 }
819 }
820 free(fmri);
821 }
822
823 /*
824 * Now check if legacy variables (if specified) map to SMF routing
825 * daemons. If so, transfer associated daemon arguments.
826 */
827 if (ra_upgrade_legacy_daemons() == -1)
828 return (-1);
829
830 ra_resetvars(NULL);
831 /*
832 * At this point, if the legacy services still have ipv4/ipv6
833 * routing daemons specified, we know they weren`t upgraded, so
834 * we mark them also.
835 */
836 if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
837 ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1)
838 return (-1);
839
840 if (v4d->var_value != NULL && strtok(v4d->var_value, " \t") != NULL &&
841 ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV4,
842 &mark) == -1)
843 return (-1);
844 if (v6d->var_value != NULL && strtok(v6d->var_value, " \t") != NULL &&
845 ra_smf_cb(ra_mark_routing_svcs_cb, RA_INSTANCE_LEGACY_ROUTING_IPV6,
846 &mark) == -1)
847 return (-1);
848
849 return (0);
850 }
851
852 /*
853 * Retrieve legacy daemon variables, and check if any SMF routing daemons
854 * run the daemons specified. If so, the legacy configuration (arguments
855 * to the daemon) is transferred to the routeadm/daemon-args property
856 * of the corresponding instance. From there, the instance picks up the
857 * value and will transfer the daemon arguments to individiual properties
858 * when enabled.
859 */
860 static int
ra_upgrade_legacy_daemons(void)861 ra_upgrade_legacy_daemons(void)
862 {
863 ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
864 ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
865 ravar_t *v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
866 ravar_t *v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
867 ravar_t *v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
868 ravar_t *v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
869
870 if (ra_smf_cb(ra_get_persistent_var_cb, v4d->var_fmri, v4d) == -1 ||
871 ra_smf_cb(ra_get_persistent_var_cb, v6d->var_fmri, v6d) == -1 ||
872 ra_smf_cb(ra_get_persistent_var_cb, v4args->var_fmri, v4args)
873 == -1 ||
874 ra_smf_cb(ra_get_persistent_var_cb, v6args->var_fmri, v6args)
875 == -1 ||
876 ra_smf_cb(ra_get_persistent_var_cb, v4stop->var_fmri, v4stop)
877 == -1 ||
878 ra_smf_cb(ra_get_persistent_var_cb, v6stop->var_fmri, v6stop)
879 == -1)
880 return (-1);
881
882 return (ra_smf_cb(ra_upgrade_legacy_daemons_cb, NULL, NULL));
883 }
884
885 /*
886 * Determine if service runs the same daemon as that which is specified
887 * in ipv4-routing-daemon or ipv6-routing-daemon. If so, the associated
888 * daemon arguments are transferred to the service.
889 */
890
891 /* ARGSUSED0 */
892 static int
ra_upgrade_legacy_daemons_cb(void * data,scf_walkinfo_t * wip)893 ra_upgrade_legacy_daemons_cb(void *data, scf_walkinfo_t *wip)
894 {
895 const char *inst_fmri = wip->fmri;
896 scf_instance_t *inst = wip->inst;
897 scf_handle_t *h = scf_instance_handle(inst);
898 char *daemon, *l_daemon = NULL;
899 ravar_t *v4d = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON);
900 ravar_t *v6d = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON);
901 ravar_t *v4args = ra_str2var(RA_VAR_IPV4_ROUTING_DAEMON_ARGS);
902 ravar_t *v6args = ra_str2var(RA_VAR_IPV6_ROUTING_DAEMON_ARGS);
903 ravar_t *v4stop = ra_str2var(RA_VAR_IPV4_ROUTING_STOP_CMD);
904 ravar_t *v6stop = ra_str2var(RA_VAR_IPV6_ROUTING_STOP_CMD);
905 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
906 boolean_t mark, marked;
907 char *new_routing_svcs;
908
909 /*
910 * Ensure instance is a routing service, and not one of the
911 * legacy instances - if it is, the daemon property is already
912 * set to the legacy daemon.
913 */
914 if (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
915 RA_PROP_DAEMON, B_TRUE, B_FALSE, NULL, &daemon) == -1 ||
916 strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV4, inst_fmri) == 0 ||
917 strcmp(RA_INSTANCE_LEGACY_ROUTING_IPV6, inst_fmri) == 0)
918 return (0);
919
920 /* A legacy daemon may be defined */
921 (void) ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
922 RA_PROP_LEGACY_DAEMON, B_TRUE, B_FALSE, NULL, &l_daemon);
923
924 /*
925 * If we match daemon/legacy_daemon with ipv4-routing-daemon or
926 * ipv6-routing-daemon values, transfer daemon-args value
927 * to the matching service.
928 */
929 if (v4d->var_value != NULL && (strcmp(v4d->var_value, daemon) == 0 ||
930 (l_daemon != NULL && strcmp(v4d->var_value, l_daemon) == 0))) {
931 (void) printf(gettext("%s: migrating daemon configuration "
932 "for %s to %s\n"), myname, l_daemon != NULL ?
933 l_daemon : daemon, inst_fmri);
934 /* Transfer daemon-args value, clear legacy v4 values */
935 if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
936 RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
937 (const char **)&(v4args->var_value)) == -1)
938 return (-1);
939 ra_resetvars(RA_PROPVAL_PROTO_IPV4);
940 if (ra_smf_cb(ra_set_persistent_var_cb,
941 RA_INSTANCE_LEGACY_ROUTING_IPV4, v4d) == -1 ||
942 ra_smf_cb(ra_set_persistent_var_cb,
943 RA_INSTANCE_LEGACY_ROUTING_IPV4, v4args) == -1 ||
944 ra_smf_cb(ra_set_persistent_var_cb,
945 RA_INSTANCE_LEGACY_ROUTING_IPV4, v4stop) == -1)
946 return (-1);
947 } else if (v6d->var_value != NULL && (strcmp(v6d->var_value, daemon)
948 == 0 ||
949 (l_daemon != NULL && strcmp(v6d->var_value, l_daemon) == 0))) {
950 (void) printf(gettext("%s: migrating daemon configuration "
951 "for %s to %s\n"), myname, l_daemon != NULL ?
952 l_daemon : daemon, inst_fmri);
953 /* Transfer daemon-args value, clear legacy v6 values */
954 if (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
955 RA_PROP_DAEMON_ARGS, SCF_TYPE_ASTRING, B_TRUE, 1,
956 (const char **)&(v6args->var_value)) == -1)
957 return (-1);
958 ra_resetvars(RA_PROPVAL_PROTO_IPV6);
959 if (ra_smf_cb(ra_set_persistent_var_cb,
960 RA_INSTANCE_LEGACY_ROUTING_IPV6, v6d) == -1 ||
961 ra_smf_cb(ra_set_persistent_var_cb,
962 RA_INSTANCE_LEGACY_ROUTING_IPV6, v6args) == -1 ||
963 ra_smf_cb(ra_set_persistent_var_cb,
964 RA_INSTANCE_LEGACY_ROUTING_IPV6, v6stop) == -1)
965 return (-1);
966 } else
967 return (0);
968
969 /*
970 * If service is unmarked at this point, add it to routing-svcs and
971 * mark it.
972 */
973 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
974 RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE, &marked) == -1 ||
975 marked == B_FALSE) {
976 mark = B_TRUE;
977 if (ra_smf_cb(ra_mark_routing_svcs_cb, inst_fmri, &mark)
978 == -1 ||
979 ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
980 routing_svcs) == -1)
981 return (-1);
982 if ((new_routing_svcs =
983 malloc(strlen(routing_svcs->var_value) +
984 strlen(inst_fmri) + 2)) == NULL) {
985 (void) fprintf(stderr, gettext(
986 "%s: out of memory"), myname);
987 return (-1);
988 }
989 if (strlen(routing_svcs->var_value) == 0)
990 (void) snprintf(new_routing_svcs,
991 strlen(inst_fmri) + 1, "%s", inst_fmri);
992 else
993 (void) snprintf(new_routing_svcs,
994 strlen(routing_svcs->var_value) +
995 strlen(inst_fmri) + 2, "%s %s",
996 routing_svcs->var_value, inst_fmri);
997 free(routing_svcs->var_value);
998 routing_svcs->var_value = new_routing_svcs;
999 (void) smf_refresh_instance(inst_fmri);
1000 return (ra_smf_cb(ra_set_persistent_var_cb,
1001 routing_svcs->var_fmri, routing_svcs));
1002 }
1003 (void) smf_refresh_instance(inst_fmri);
1004 return (0);
1005 }
1006
1007 /*
1008 * If we are upgrading, append operation to <alt_root>/var/svc/profile/upgrade.
1009 */
1010 static int
ra_upgrade_cmd(char opt,int argc,char ** argv)1011 ra_upgrade_cmd(char opt, int argc, char **argv)
1012 {
1013 FILE *fp;
1014 int i;
1015
1016 if ((fp = fopen(RA_SMF_UPGRADE_FILE, "a+")) == NULL) {
1017 (void) fprintf(stderr, gettext(
1018 "%1$s: failed to open %2$s: %3$s\n"),
1019 myname, RA_SMF_UPGRADE_FILE, strerror(errno));
1020 return (-1);
1021 }
1022 (void) fprintf(fp, "/sbin/routeadm -%c ", opt);
1023 if (argv != NULL) {
1024 for (i = 0; i < argc; i++)
1025 (void) fprintf(fp, "%s ", argv[i]);
1026 }
1027 (void) fprintf(fp, "%s\n", RA_SMF_UPGRADE_MSG);
1028 (void) fclose(fp);
1029 return (0);
1030 }
1031
1032 /*
1033 * Set current state to "next boot" state, i.e. if general/enabled
1034 * value is overlaid by a general_ovr/enabled value, set the current state
1035 * to the value of the latter. Doing this applies "next boot" changes to
1036 * the current setup. If any IPv6 interfaces are present, also start in.ndpd.
1037 */
1038 static int
ra_update(void)1039 ra_update(void)
1040 {
1041 int i;
1042
1043 if (ra_check_legacy_daemons() == -1)
1044 return (-1);
1045 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1046 if (ra_smf_cb(ra_set_current_opt_cb, ra_opts[i].opt_fmri,
1047 &ra_opts[i]) == -1) {
1048 return (-1);
1049 }
1050 }
1051 /*
1052 * If in.ndpd isn't already running, then we start it here, regardless
1053 * of global IPv6 routing status (provided there are IPv6 interfaces
1054 * present).
1055 */
1056 if (ra_numv6intfs() > 0)
1057 return (smf_enable_instance(RA_INSTANCE_NDP, SMF_TEMPORARY));
1058 return (0);
1059 }
1060
1061 /*
1062 * Here we catch the special case where ipv4/ipv6 routing was enabled,
1063 * and the user updates the routing-svcs list. The problem is that
1064 * the enabled state is the result of services on the old routing-svcs list
1065 * being enabled, and we want to support users doing something like this:
1066 *
1067 * # routeadm -s routing-svcs=route -e ipv4-routing -u
1068 *
1069 * followed by
1070 *
1071 * # routeadm -s routing-svcs=rdisc -u
1072 *
1073 * To do this, we need to:
1074 * - cache the old ipv4-routing/ipv6-routing values.
1075 * - persistently disable the old routing-svcs list.
1076 * - if ipv4-routing was enabled, mark and persistently enable all the new
1077 * v4 routing-svcs
1078 * - if ipv6-routing was enabled, mark and persistently enable all the new
1079 * v6 routing-svcs.
1080 * This will result in the next "-u" switching on the new routing-svcs, and
1081 * switching off the old ones, as the user would expect.
1082 */
1083 static int
ra_update_routing_svcs(char * routing_svcs_new)1084 ra_update_routing_svcs(char *routing_svcs_new)
1085 {
1086 raopt_t *v4opt = ra_str2opt(RA_OPT_IPV4_ROUTING);
1087 raopt_t *v6opt = ra_str2opt(RA_OPT_IPV6_ROUTING);
1088 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
1089 char *routing_svcs_old, *fmri;
1090 boolean_t v4_old, v6_old, mark = B_FALSE;
1091
1092 ra_resetopts();
1093 if (ra_smf_cb(ra_get_persistent_opt_cb, v4opt->opt_fmri, v4opt) == -1 ||
1094 ra_smf_cb(ra_get_persistent_opt_cb, v6opt->opt_fmri, v6opt) == -1 ||
1095 ra_smf_cb(ra_get_persistent_var_cb, routing_svcs->var_fmri,
1096 routing_svcs) == -1)
1097 return (-1);
1098 v4_old = v4opt->opt_enabled;
1099 v6_old = v6opt->opt_enabled;
1100 routing_svcs_old = routing_svcs->var_value;
1101 routing_svcs->var_value = routing_svcs_new;
1102
1103 if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
1104 routing_svcs) == -1) {
1105 free(routing_svcs_old);
1106 return (-1);
1107 }
1108
1109 if (!v4_old && !v6_old) {
1110 /* We don`t need to do anything, since services were disabled */
1111 free(routing_svcs_old);
1112 return (0);
1113 }
1114 v4opt->opt_enabled = B_FALSE;
1115 v6opt->opt_enabled = B_FALSE;
1116
1117 /* Persistently disable each old v4/v6 "routing-svc" */
1118 for (fmri = strtok(routing_svcs_old, " \t"); fmri != NULL;
1119 fmri = strtok(NULL, " \t")) {
1120 if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1) {
1121 free(routing_svcs_old);
1122 return (-1);
1123 }
1124 if (v4_old &&
1125 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1) {
1126 free(routing_svcs_old);
1127 return (-1);
1128 }
1129 if (v6_old &&
1130 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1) {
1131 free(routing_svcs_old);
1132 return (-1);
1133 }
1134 }
1135 free(routing_svcs_old);
1136 v4opt->opt_enabled = v4_old;
1137 v6opt->opt_enabled = v6_old;
1138
1139 /* Persistently enable each new v4/v6 "routing-svc" */
1140 mark = B_TRUE;
1141 for (fmri = strtok(routing_svcs_new, " \t"); fmri != NULL;
1142 fmri = strtok(NULL, " \t")) {
1143 if (ra_smf_cb(ra_mark_routing_svcs_cb, fmri, &mark) == -1)
1144 return (-1);
1145 if (v4_old &&
1146 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v4opt) == -1)
1147 return (-1);
1148 if (v6_old &&
1149 ra_smf_cb(ra_set_persistent_opt_cb, fmri, v6opt) == -1)
1150 return (-1);
1151 }
1152 return (0);
1153 }
1154
1155 /*
1156 * Display status, in parseable form if required. If param is
1157 * specified, only the named option/variable is displayed (this option is
1158 * for parseable display only).
1159 */
1160 static int
ra_report(boolean_t parseable,const char * param)1161 ra_report(boolean_t parseable, const char *param)
1162 {
1163 int i;
1164 char *c_state, *d_state, *p_state, *p_var, *d_var;
1165 char *enabled = "enabled";
1166 char *disabled = "disabled";
1167 boolean_t param_found = B_FALSE;
1168
1169 if (!parseable) {
1170 (void) printf(gettext(
1171 " Configuration Current "
1172 "Current\n"
1173 " Option Configuration "
1174 "System State\n"
1175 "---------------------------------------------------"
1176 "------------\n"));
1177 }
1178 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
1179 if (param != NULL) {
1180 if (strcmp(ra_opts[i].opt_name, param) == 0)
1181 param_found = B_TRUE;
1182 else
1183 continue;
1184 }
1185 if (ra_smf_cb(ra_get_current_opt_cb,
1186 ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1187 return (-1);
1188 c_state = ra_opts[i].opt_enabled ? enabled : disabled;
1189 ra_resetopts();
1190 if (ra_smf_cb(ra_get_persistent_opt_cb,
1191 ra_opts[i].opt_fmri, &ra_opts[i]) == -1)
1192 return (-1);
1193 p_state = ra_opts[i].opt_enabled ? enabled : disabled;
1194 ra_resetopts();
1195 if (ra_smf_cb(ra_get_default_opt_cb,
1196 ra_opts[i].opt_default_fmri, &ra_opts[i]) == -1)
1197 return (-1);
1198 d_state = ra_opts[i].opt_default_enabled ? enabled : disabled;
1199 ra_resetopts();
1200 if (parseable) {
1201 if (param == NULL)
1202 (void) printf("%s ", ra_opts[i].opt_name);
1203 (void) printf("persistent=%s default=%s "
1204 "current=%s\n", p_state, d_state, c_state);
1205 } else {
1206 (void) printf(gettext("%1$27s %2$-21s%3$s\n"),
1207 ra_intloptname(ra_opts[i].opt_name),
1208 p_state, c_state);
1209 }
1210 }
1211 if (!parseable)
1212 (void) printf("\n");
1213
1214 ra_resetvars(NULL);
1215
1216 /* Gather persistent/default variable values */
1217 for (i = 0; ra_vars[i].var_name != NULL; i++) {
1218 if (ra_smf_cb(ra_get_persistent_var_cb,
1219 ra_vars[i].var_fmri, &ra_vars[i]) == -1 ||
1220 ra_smf_cb(ra_get_default_var_cb,
1221 ra_vars[i].var_default_fmri, &ra_vars[i]) == -1)
1222 return (-1);
1223
1224 }
1225 for (i = 0; ra_vars[i].var_name != NULL; i++) {
1226 if (param != NULL) {
1227 if (strcmp(ra_vars[i].var_name, param) == 0)
1228 param_found = B_TRUE;
1229 else
1230 continue;
1231 }
1232 p_var = ra_vars[i].var_value == NULL ? "":
1233 ra_vars[i].var_value;
1234 d_var = ra_vars[i].var_default_value == NULL ?
1235 "": ra_vars[i].var_default_value;
1236 if (parseable) {
1237 if (param == NULL)
1238 (void) printf("%s ", ra_vars[i].var_name);
1239 (void) printf("persistent=\"%s\" "
1240 "default=\"%s\" \n", p_var, d_var);
1241 } else {
1242 /* If daemon variables are not set, do not display. */
1243 if ((IS_IPV4_VAR(ra_vars[i].var_name) &&
1244 IPV4_VARS_UNSET) ||
1245 (IS_IPV6_VAR(ra_vars[i].var_name) &&
1246 IPV6_VARS_UNSET))
1247 continue;
1248 (void) printf(gettext("%1$27s \"%2$s\"\n"),
1249 ra_intloptname(ra_vars[i].var_name), p_var);
1250 }
1251 }
1252
1253 if (param != NULL && !param_found) {
1254 (void) fprintf(stderr, gettext(
1255 "%s: no such option/variable %s\n"), myname, param);
1256 return (-1);
1257 }
1258 if (parseable)
1259 return (0);
1260 (void) printf(gettext("\nRouting daemons:\n"));
1261 (void) printf("\n %s %s\n", "STATE", "FMRI");
1262 if (ra_smf_cb(ra_print_state_cb, NULL, NULL) == -1)
1263 return (-1);
1264 return (0);
1265 }
1266
1267 /*
1268 * Call scf_walk_fmri() with appropriate function, fmri, and data.
1269 * A NULL fmri causes scf_walk_fmri() to run on all instances. We make
1270 * use of this many times in applying changes to the routing services.
1271 */
1272 static int
ra_smf_cb(ra_smf_cb_t cbfunc,const char * fmri,void * data)1273 ra_smf_cb(ra_smf_cb_t cbfunc, const char *fmri, void *data)
1274 {
1275 scf_handle_t *h;
1276 int exit_status = 0;
1277
1278 if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
1279 scf_handle_bind(h) == -1) {
1280 (void) fprintf(stderr, gettext(
1281 "%s: cannot connect to SMF repository\n"), myname);
1282 return (-1);
1283 }
1284 return (scf_walk_fmri(h, fmri == NULL ? 0 : 1,
1285 fmri == NULL ? NULL : (char **)&fmri, 0,
1286 cbfunc, data, &exit_status, uu_die));
1287 }
1288
1289 /*
1290 * Applies persistent configuration settings to current setup.
1291 */
1292 static int
ra_set_current_opt_cb(void * data,scf_walkinfo_t * wip)1293 ra_set_current_opt_cb(void *data, scf_walkinfo_t *wip)
1294 {
1295 return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_FALSE));
1296 }
1297
1298 /*
1299 * Sets persistent value for option, to be applied on next boot
1300 * or by "routeadm -u".
1301 */
1302 static int
ra_set_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1303 ra_set_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1304 {
1305 return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_FALSE));
1306 }
1307
1308 static int
ra_get_current_opt_cb(void * data,scf_walkinfo_t * wip)1309 ra_get_current_opt_cb(void *data, scf_walkinfo_t *wip)
1310 {
1311 return (ra_get_set_opt_common_cb(data, wip, B_FALSE, B_TRUE));
1312 }
1313
1314 static int
ra_get_persistent_opt_cb(void * data,scf_walkinfo_t * wip)1315 ra_get_persistent_opt_cb(void *data, scf_walkinfo_t *wip)
1316 {
1317 return (ra_get_set_opt_common_cb(data, wip, B_TRUE, B_TRUE));
1318 }
1319
1320 static int
ra_routing_opt_set_cb(void * data,scf_walkinfo_t * wip)1321 ra_routing_opt_set_cb(void *data, scf_walkinfo_t *wip)
1322 {
1323 return (ra_routing_opt_set_unset_cb(data, wip, B_TRUE));
1324 }
1325
1326 static int
ra_routing_opt_unset_cb(void * data,scf_walkinfo_t * wip)1327 ra_routing_opt_unset_cb(void *data, scf_walkinfo_t *wip)
1328 {
1329 return (ra_routing_opt_set_unset_cb(data, wip, B_FALSE));
1330 }
1331
1332 /*
1333 * Notify network/routing-setup service that administrator has explicitly
1334 * set/reset ipv4(6)-routing value. If no explicit setting of this value is
1335 * done, ipv4-routing can be enabled in the situation when no default route can
1336 * be determined.
1337 */
1338 static int
ra_routing_opt_set_unset_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t set)1339 ra_routing_opt_set_unset_cb(raopt_t *raopt, scf_walkinfo_t *wip, boolean_t set)
1340 {
1341 scf_instance_t *inst = wip->inst;
1342 scf_handle_t *h = scf_instance_handle(inst);
1343
1344 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1345 raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING ?
1346 RA_PROP_IPV4_ROUTING_SET : RA_PROP_IPV6_ROUTING_SET,
1347 B_FALSE, set));
1348 }
1349
1350 /*
1351 * Shared function that either sets or determines persistent or current
1352 * state. Setting persistent state (for next boot) involves setting
1353 * the general_ovr/enabled value to the current service state, and
1354 * the general/enabled value to the desired (next-boot) state.
1355 * Setting current state involves removing the temporary state
1356 * setting so the persistent state has effect.
1357 *
1358 * Persistent state is reported as being enabled if any of the
1359 * candidate services have a general/enabled value set to true,
1360 * while current state is reported as being enabled if any of the
1361 * candidate services has a general_ovr/enabled or general/enabled
1362 * value set to true.
1363 */
1364 static int
ra_get_set_opt_common_cb(raopt_t * raopt,scf_walkinfo_t * wip,boolean_t persistent,boolean_t get)1365 ra_get_set_opt_common_cb(raopt_t *raopt, scf_walkinfo_t *wip,
1366 boolean_t persistent, boolean_t get)
1367 {
1368 const char *inst_fmri = wip->fmri;
1369 scf_instance_t *inst = wip->inst;
1370 scf_handle_t *h = scf_instance_handle(inst);
1371 scf_propertygroup_t *routeadm_pg;
1372 boolean_t persistent_state_enabled;
1373 boolean_t temporary_state_enabled;
1374 boolean_t current_state_enabled;
1375 boolean_t curr_svc = B_TRUE;
1376 boolean_t found_proto;
1377 char **protolist = NULL;
1378 int i, ret, numvalues = 0;
1379
1380 /*
1381 * Ensure we are dealing with a routeadm-managed service. If
1382 * the FMRI used for walking instances is NULL, it is reasonable
1383 * that a service not have a routeadm property group as we will
1384 * check all services in this case.
1385 */
1386 if (ra_get_pg(h, inst, RA_PG_ROUTEADM, B_TRUE, raopt->opt_fmri != NULL,
1387 &routeadm_pg) == -1) {
1388 /* Not a routing service, not an error. */
1389 if (scf_error() == SCF_ERROR_NOT_FOUND &&
1390 raopt->opt_fmri == NULL)
1391 return (0);
1392 return (-1);
1393 }
1394 scf_pg_destroy(routeadm_pg);
1395
1396 /* Services with no "protocol" property are not routing daemons */
1397 if (raopt->opt_fmri == NULL && ra_get_prop_as_string(h, inst,
1398 RA_PG_ROUTEADM, RA_PROP_PROTO, B_TRUE, B_FALSE, NULL, &numvalues,
1399 &protolist) == -1) {
1400 if (scf_error() == SCF_ERROR_NOT_FOUND)
1401 return (0);
1402 return (-1);
1403 }
1404
1405 /*
1406 * Skip invalid services based on flag settings. Flags are used when
1407 * we run callback functions on all instances to identify
1408 * the correct instances to operate on.
1409 */
1410 if (raopt->opt_flags & RA_SVC_FLAG_IPV4_ROUTING) {
1411 found_proto = B_FALSE;
1412 if (protolist != NULL) {
1413 /* Check if protolist contains "ipv4" */
1414 for (i = 0; i < numvalues; i++) {
1415 if (protolist[i] != NULL && strcmp(
1416 protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
1417 found_proto = B_TRUE;
1418 }
1419 }
1420 /* If not an ipv4 routing service, skip. */
1421 if (protolist == NULL || !found_proto) {
1422 ra_free_prop_values(numvalues, protolist);
1423 return (0);
1424 }
1425 }
1426 if (raopt->opt_flags & RA_SVC_FLAG_IPV6_ROUTING) {
1427 found_proto = B_FALSE;
1428 if (protolist != NULL) {
1429 /* Check if protolist contains "ipv6" */
1430 for (i = 0; i < numvalues; i++) {
1431 if (protolist[i] != NULL && strcmp(
1432 protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
1433 found_proto = B_TRUE;
1434 }
1435 }
1436 /* If not an ipv6 routing service, skip. */
1437 if (protolist == NULL || !found_proto) {
1438 ra_free_prop_values(numvalues, protolist);
1439 return (0);
1440 }
1441 /*
1442 * If no IPv6 interfaces are configured, do not apply
1443 * the "enable" state change to this IPv6 routing service.
1444 */
1445 if (raopt->opt_enabled && ra_numv6intfs() < 1)
1446 return (0);
1447 }
1448 ra_free_prop_values(numvalues, protolist);
1449
1450 /* If enabling routing services, select only current routing services */
1451 if (raopt->opt_fmri == NULL && !get && raopt->opt_enabled) {
1452 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1453 RA_PROP_CURR_ROUTING_SVC, B_FALSE, B_FALSE,
1454 &curr_svc) == -1)
1455 return (0);
1456 else if (!curr_svc && persistent) {
1457 /*
1458 * We apply "current" routing changes to all routing
1459 * daemons, whether current or not, so bail if
1460 * we are trying to make a persistent update to a
1461 * non-"routing-svc".
1462 */
1463 return (0);
1464 }
1465 }
1466 if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL, SCF_PROPERTY_ENABLED,
1467 B_FALSE, B_TRUE, &persistent_state_enabled) == -1)
1468 return (-1);
1469
1470 current_state_enabled = persistent_state_enabled;
1471
1472 if (ra_get_boolean_prop(h, inst, SCF_PG_GENERAL_OVR,
1473 SCF_PROPERTY_ENABLED, B_FALSE, B_FALSE, &temporary_state_enabled)
1474 == 0)
1475 current_state_enabled = temporary_state_enabled;
1476
1477 if (get) {
1478 /*
1479 * Persistent state is enabled if any services are
1480 * persistently enabled, i.e. general/enabled == true).
1481 * current state is enabled if any services
1482 * services are currently enabled, i.e. if defined,
1483 * general_ovr/enabled == true, if not, general/enabled == true.
1484 */
1485 if (persistent)
1486 raopt->opt_enabled = raopt->opt_enabled ||
1487 persistent_state_enabled;
1488 else
1489 raopt->opt_enabled = raopt->opt_enabled ||
1490 current_state_enabled;
1491 } else {
1492 if (persistent) {
1493 /*
1494 * For peristent state changes, from -e/-d,
1495 * we set the general_ovr/enabled value to the
1496 * current state (to ensure it is preserved),
1497 * while setting the general/enabled value to
1498 * the desired value. This has the effect of
1499 * the desired value coming into effect on next boot.
1500 */
1501 ret = current_state_enabled ?
1502 smf_enable_instance(inst_fmri, SMF_TEMPORARY) :
1503 smf_disable_instance(inst_fmri, SMF_TEMPORARY);
1504 if (ret != 0) {
1505 (void) fprintf(stderr, gettext(
1506 "%s: unexpected libscf error: %s\n"),
1507 myname, scf_strerror(scf_error()));
1508 return (-1);
1509 }
1510 /*
1511 * Refresh here so general_ovr/enabled state overrides
1512 * general/enabled state.
1513 */
1514 (void) smf_refresh_instance(inst_fmri);
1515 /*
1516 * Now we can safely set the general/enabled value
1517 * to the value we require on next boot (or
1518 * "routeadm -u").
1519 */
1520 ret = ra_set_boolean_prop(h, inst, SCF_PG_GENERAL,
1521 SCF_PROPERTY_ENABLED, B_FALSE, raopt->opt_enabled);
1522 if (ret != 0)
1523 return (-1);
1524 /*
1525 * Refresh here so general/enabled value is set.
1526 */
1527 (void) smf_refresh_instance(inst_fmri);
1528 if (raopt->opt_fmri != NULL)
1529 return (0);
1530 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
1531 } else {
1532 /*
1533 * Refresh here to get latest property values prior
1534 * to starting daemon.
1535 */
1536 (void) smf_refresh_instance(inst_fmri);
1537 /*
1538 * For current changes (result of -u), we
1539 * enable/disable depending on persistent value
1540 * stored in general/enabled. Here we disable
1541 * old routing-svcs (identified by a current-routing-svc
1542 * value of false) also.
1543 */
1544 ret = persistent_state_enabled && curr_svc ?
1545 smf_enable_instance(inst_fmri, 0) :
1546 smf_disable_instance(inst_fmri, 0);
1547 if (ret != 0) {
1548 (void) fprintf(stderr, gettext(
1549 "%s: unexpected libscf error: %s\n"),
1550 myname, scf_strerror(scf_error()));
1551 return (-1);
1552 }
1553 if (current_state_enabled && persistent_state_enabled) {
1554 /*
1555 * Instance was already enabled, so we restart
1556 * to get latest property values. This covers
1557 * the case where users update properties
1558 * via routeadm -m, and issue an update. The
1559 * daemon should be running with the latest
1560 * property values.
1561 */
1562 (void) smf_restart_instance(inst_fmri);
1563 }
1564 }
1565 }
1566 return (0);
1567 }
1568
1569 static int
ra_set_default_opt_cb(void * data,scf_walkinfo_t * wip)1570 ra_set_default_opt_cb(void *data, scf_walkinfo_t *wip)
1571 {
1572 scf_instance_t *inst = wip->inst;
1573 scf_handle_t *h = scf_instance_handle(inst);
1574 raopt_t *raopt = data;
1575
1576 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1577 raopt->opt_default_prop, B_FALSE, raopt->opt_default_enabled));
1578 }
1579
1580 static int
ra_get_default_opt_cb(void * data,scf_walkinfo_t * wip)1581 ra_get_default_opt_cb(void *data, scf_walkinfo_t *wip)
1582 {
1583 scf_instance_t *inst = wip->inst;
1584 scf_handle_t *h = scf_instance_handle(inst);
1585 raopt_t *raopt = data;
1586
1587 return (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1588 raopt->opt_default_prop, B_TRUE, B_TRUE,
1589 &(raopt->opt_default_enabled)));
1590 }
1591
1592 /*
1593 * Callbacks to set/retrieve persistent/default routing variable values.
1594 * The set functions use the value stored in the var_value/var_default_value
1595 * field of the associated ra_var_t, while the retrieval functions store
1596 * the value retrieved in that field.
1597 */
1598 static int
ra_get_persistent_var_cb(void * data,scf_walkinfo_t * wip)1599 ra_get_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1600 {
1601 scf_instance_t *inst = wip->inst;
1602 scf_handle_t *h = scf_instance_handle(inst);
1603 ravar_t *ravar = data;
1604
1605 return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1606 ravar->var_prop, B_TRUE, B_TRUE, NULL, &ravar->var_value));
1607 }
1608
1609 static int
ra_set_persistent_var_cb(void * data,scf_walkinfo_t * wip)1610 ra_set_persistent_var_cb(void *data, scf_walkinfo_t *wip)
1611 {
1612 scf_instance_t *inst = wip->inst;
1613 scf_handle_t *h = scf_instance_handle(inst);
1614 ravar_t *ravar = data;
1615
1616 return (ra_set_prop_from_string(h, inst, RA_PG_ROUTEADM,
1617 ravar->var_prop, SCF_TYPE_INVALID, B_FALSE, 1,
1618 (const char **)&ravar->var_value));
1619 }
1620
1621 static int
ra_get_default_var_cb(void * data,scf_walkinfo_t * wip)1622 ra_get_default_var_cb(void *data, scf_walkinfo_t *wip)
1623 {
1624 scf_instance_t *inst = wip->inst;
1625 scf_handle_t *h = scf_instance_handle(inst);
1626 ravar_t *ravar = data;
1627
1628 return (ra_get_single_prop_as_string(h, inst, RA_PG_ROUTEADM,
1629 ravar->var_default_prop, B_TRUE, B_TRUE, NULL,
1630 &ravar->var_default_value));
1631 }
1632
1633 /*
1634 * Depending on the value of the boolean_t * passed in, this callback
1635 * either marks the relevant service(s) as current-routing-svcs (or unmarking)
1636 * by setting that property to true or false. When routing services
1637 * are to be enabled, the a current-routing-svc value of true flags the
1638 * service as one to be enabled.
1639 */
1640 static int
ra_mark_routing_svcs_cb(void * data,scf_walkinfo_t * wip)1641 ra_mark_routing_svcs_cb(void *data, scf_walkinfo_t *wip)
1642 {
1643 scf_instance_t *inst = wip->inst;
1644 scf_handle_t *h = scf_instance_handle(inst);
1645 boolean_t *mark = data;
1646 boolean_t marked;
1647 int numvalues = 0;
1648 char **protolist = NULL;
1649
1650 /* Check we are dealing with a routing daemon service */
1651 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1652 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1653 return (0);
1654 ra_free_prop_values(numvalues, protolist);
1655 if (*mark)
1656 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1657 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_TRUE));
1658 /* Unmark service. */
1659 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
1660 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE, &marked) == 0 && marked)
1661 return (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
1662 RA_PROP_CURR_ROUTING_SVC, B_TRUE, B_FALSE));
1663 return (0);
1664 }
1665
1666 /*
1667 * List property values for all properties in the "routing" property
1668 * group of the routing service instance.
1669 */
1670
1671 /* ARGSUSED0 */
1672 static int
ra_list_props_cb(void * data,scf_walkinfo_t * wip)1673 ra_list_props_cb(void *data, scf_walkinfo_t *wip)
1674 {
1675 const char *inst_fmri = wip->fmri;
1676 scf_instance_t *inst = wip->inst;
1677 scf_handle_t *h = scf_instance_handle(inst);
1678 scf_iter_t *propiter, *valiter;
1679 scf_propertygroup_t *pg;
1680 scf_property_t *prop;
1681 scf_value_t *val;
1682 char **protolist = NULL, *pnamebuf, *valbuf;
1683 ssize_t pnamelen, vallen;
1684 int numvalues = 0;
1685 int propiterret, valiterret, retval = 0;
1686
1687 /* Services with no "protocol" property are not routing daemons */
1688 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1689 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1690 if (scf_error() == SCF_ERROR_NOT_FOUND)
1691 (void) fprintf(stderr,
1692 gettext("%s: %s is not a routing daemon service\n"),
1693 myname, inst_fmri);
1694 else
1695 (void) fprintf(stderr,
1696 gettext("%s: unexpected libscf error: %s\n"),
1697 myname, scf_strerror(scf_error()));
1698 ra_free_prop_values(numvalues, protolist);
1699 return (-1);
1700 }
1701 ra_free_prop_values(numvalues, protolist);
1702
1703 if (ra_get_pg(h, inst, RA_PG_ROUTING, B_TRUE, B_FALSE, &pg) == -1) {
1704 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1705 (void) printf("%s: no %s property group for %s\n",
1706 myname, RA_PG_ROUTING, inst_fmri);
1707 return (0);
1708 }
1709 (void) fprintf(stderr,
1710 gettext("%s: unexpected libscf error: %s\n"),
1711 myname, scf_strerror(scf_error()));
1712 return (-1);
1713 }
1714
1715 (void) printf("%s:\n", inst_fmri);
1716
1717 /* Create an iterator to walk through all properties */
1718 if ((propiter = scf_iter_create(h)) == NULL ||
1719 (prop = scf_property_create(h)) == NULL ||
1720 scf_iter_pg_properties(propiter, pg) != 0) {
1721 (void) fprintf(stderr, gettext
1722 ("%s: could not iterate through properties for %s: %s\n"),
1723 myname, inst_fmri, scf_strerror(scf_error()));
1724 }
1725 while ((propiterret = scf_iter_next_property(propiter, prop)) == 1) {
1726 if ((pnamelen = scf_property_get_name(prop, NULL, 0) + 1)
1727 == 0) {
1728 (void) fprintf(stderr, gettext("%s: could not retrieve "
1729 "property name for instance %s: %s\n"), myname,
1730 inst_fmri, scf_strerror(scf_error()));
1731 retval = -1;
1732 break;
1733 }
1734 if ((pnamebuf = malloc(pnamelen)) == NULL) {
1735 (void) fprintf(stderr,
1736 gettext("%s: out of memory\n"), myname);
1737 retval = -1;
1738 break;
1739 }
1740 (void) scf_property_get_name(prop, pnamebuf,
1741 pnamelen);
1742 (void) printf("\t%s = ", pnamebuf);
1743 if ((valiter = scf_iter_create(h)) == NULL ||
1744 (val = scf_value_create(h)) == NULL ||
1745 scf_iter_property_values(valiter, prop)
1746 != 0) {
1747 (void) fprintf(stderr, gettext
1748 ("%s: could not iterate through "
1749 "properties for %s: %s\n"), myname, inst_fmri,
1750 scf_strerror(scf_error()));
1751 scf_value_destroy(val);
1752 scf_iter_destroy(valiter);
1753 free(pnamebuf);
1754 retval = -1;
1755 break;
1756 }
1757 while ((valiterret = scf_iter_next_value(valiter, val)) == 1) {
1758 if ((vallen = scf_value_get_as_string
1759 (val, NULL, 0) + 1) == 0) {
1760 (void) fprintf(stderr, gettext
1761 ("%s: could not retrieve "
1762 "property value for instance %s, "
1763 "property %s: %s\n"), myname, inst_fmri,
1764 pnamebuf, scf_strerror(scf_error()));
1765 retval = -1;
1766 } else if ((valbuf = malloc(vallen)) == NULL) {
1767 (void) fprintf(stderr,
1768 gettext("%s: out of memory\n"), myname);
1769 retval = -1;
1770 }
1771 if (retval == -1) {
1772 scf_iter_destroy(valiter);
1773 scf_value_destroy(val);
1774 free(pnamebuf);
1775 goto out;
1776 }
1777 (void) scf_value_get_as_string(val, valbuf, vallen);
1778 (void) printf("%s ", valbuf);
1779 free(valbuf);
1780 }
1781 (void) printf("\n");
1782 scf_iter_destroy(valiter);
1783 scf_value_destroy(val);
1784 free(pnamebuf);
1785 if (valiterret == -1) {
1786 (void) fprintf(stderr,
1787 gettext("%s: could not iterate through"
1788 "properties for %s: %s\n"), myname, inst_fmri,
1789 scf_strerror(scf_error()));
1790 retval = -1;
1791 break;
1792 }
1793 }
1794 out:
1795 scf_iter_destroy(propiter);
1796 scf_property_destroy(prop);
1797 scf_pg_destroy(pg);
1798 if (propiterret == -1)
1799 (void) fprintf(stderr, gettext
1800 ("%s: could not iterate through properties for %s: %s\n"),
1801 myname, inst_fmri, scf_strerror(scf_error()));
1802 return (retval);
1803 }
1804
1805 /*
1806 * Modify property with name stored in passed-in ra_prop_t to have
1807 * the assocatied values. Only works for existing properties in
1808 * the "routing" property group for routing daemon services, so all
1809 * routing daemons should place configurable options in that group.
1810 */
1811 static int
ra_modify_props_cb(void * data,scf_walkinfo_t * wip)1812 ra_modify_props_cb(void *data, scf_walkinfo_t *wip)
1813 {
1814 const char *inst_fmri = wip->fmri;
1815 scf_instance_t *inst = wip->inst;
1816 scf_handle_t *h = scf_instance_handle(inst);
1817 ra_prop_t *raprop = data;
1818 int numvalues = 0;
1819 char **protolist = NULL;
1820
1821 /* Services with no "protocol" property are not routing daemons */
1822 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1823 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1) {
1824 if (scf_error() == SCF_ERROR_NOT_FOUND)
1825 (void) fprintf(stderr,
1826 gettext("%s: %s is not a routing daemon service\n"),
1827 myname, inst_fmri);
1828 else
1829 (void) fprintf(stderr,
1830 gettext("%s: unexpected libscf error: %s\n"),
1831 myname, scf_strerror(scf_error()));
1832 ra_free_prop_values(numvalues, protolist);
1833 return (-1);
1834 }
1835 ra_free_prop_values(numvalues, protolist);
1836
1837 if (ra_set_prop_from_string(h, inst, RA_PG_ROUTING, raprop->prop_name,
1838 SCF_TYPE_INVALID, B_FALSE, raprop->prop_numvalues,
1839 (const char **)raprop->prop_values) == -1)
1840 return (-1);
1841
1842 (void) smf_refresh_instance(inst_fmri);
1843 return (0);
1844 }
1845
1846 /*
1847 * Display FMRI, state for each routing daemon service.
1848 */
1849
1850 /* ARGSUSED0 */
1851 static int
ra_print_state_cb(void * data,scf_walkinfo_t * wip)1852 ra_print_state_cb(void *data, scf_walkinfo_t *wip)
1853 {
1854 const char *inst_fmri = wip->fmri;
1855 scf_instance_t *inst = wip->inst;
1856 scf_handle_t *h = scf_instance_handle(inst);
1857 char *inst_state, **protolist = NULL;
1858 int numvalues = 0;
1859
1860 /* Ensure service is a routing daemon */
1861 if (ra_get_prop_as_string(h, inst, RA_PG_ROUTEADM, RA_PROP_PROTO,
1862 B_TRUE, B_FALSE, NULL, &numvalues, &protolist) == -1)
1863 return (0);
1864 ra_free_prop_values(numvalues, protolist);
1865
1866 if ((inst_state = smf_get_state(inst_fmri)) == NULL) {
1867 (void) fprintf(stderr,
1868 gettext("%s: could not retrieve state for %s: %s\n"),
1869 myname, inst_fmri, scf_strerror(scf_error()));
1870 return (-1);
1871 }
1872 (void) printf("%27s %2s\n", inst_state, inst_fmri);
1873 free(inst_state);
1874
1875 return (0);
1876 }
1877
1878 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)1879 ra_get_pg(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
1880 boolean_t composed, boolean_t required, scf_propertygroup_t **pg)
1881 {
1882 /* Retrieve (possibly composed) property group for instance */
1883 if ((*pg = scf_pg_create(h)) == NULL || (composed &&
1884 scf_instance_get_pg_composed(inst, NULL, pgname, *pg) != 0) ||
1885 (!composed && scf_instance_get_pg(inst, pgname, *pg) != 0)) {
1886 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1887 if (required)
1888 (void) fprintf(stderr, gettext(
1889 "%s: no such property group %s\n"),
1890 myname, pgname);
1891 return (-1);
1892 }
1893 if (required)
1894 (void) fprintf(stderr, gettext(
1895 "%s: unexpected libscf error: %s\n"), myname,
1896 scf_strerror(scf_error()));
1897 return (-1);
1898 }
1899 return (0);
1900 }
1901
1902 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)1903 ra_get_boolean_prop(scf_handle_t *h, scf_instance_t *inst,
1904 const char *pgname, const char *propname, boolean_t composed,
1905 boolean_t required, boolean_t *val)
1906 {
1907 char *valstr;
1908
1909 if (ra_get_single_prop_as_string(h, inst, pgname, propname,
1910 composed, required, NULL, &valstr) != 0)
1911 return (-1);
1912 *val = strcmp(valstr, RA_PROPVAL_BOOLEAN_TRUE) == 0;
1913 free(valstr);
1914 return (0);
1915 }
1916
1917 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)1918 ra_get_single_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1919 const char *pgname, const char *propname, boolean_t composed,
1920 boolean_t required, scf_type_t *type, char **value)
1921 {
1922 char **values;
1923 int numvalues = 1;
1924
1925 if (ra_get_prop_as_string(h, inst, pgname, propname, composed, required,
1926 type, &numvalues, &values) == -1)
1927 return (-1);
1928 *value = values[0];
1929 free(values);
1930 return (0);
1931 }
1932
1933 /*
1934 * Retrieve property named in propname, possibly using the composed
1935 * property group view (union of instance and service-level properties,
1936 * where instance-level properties override service-level values).
1937 */
1938 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)1939 ra_get_prop_as_string(scf_handle_t *h, scf_instance_t *inst,
1940 const char *pgname, const char *propname, boolean_t composed,
1941 boolean_t required, scf_type_t *type, int *numvalues, char ***values)
1942 {
1943 scf_propertygroup_t *pg = NULL;
1944 scf_property_t *prop = NULL;
1945 scf_iter_t *valiter = NULL;
1946 scf_value_t *val = NULL;
1947 ssize_t vallen = 0;
1948 int valiterret, i, numvalues_retrieved, ret = 0;
1949
1950 if (ra_get_pg(h, inst, pgname, composed, required, &pg) == -1)
1951 return (-1);
1952
1953 *values = NULL;
1954 /*
1955 * Retrieve values. All values routeadm needs to retrieve
1956 * (bar those gathered by routeadm -l), are known to be single-valued.
1957 */
1958 if ((prop = scf_property_create(h)) == NULL)
1959 goto error;
1960 if (scf_pg_get_property(pg, propname, prop) != 0) {
1961 *numvalues = 0;
1962 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1963 if (required)
1964 (void) fprintf(stderr, gettext(
1965 "%s: property %s/%s not found\n"),
1966 myname, pgname, propname);
1967 ret = -1;
1968 goto out;
1969 }
1970 goto error;
1971 }
1972 if ((val = scf_value_create(h)) == NULL &&
1973 scf_property_get_value(prop, val) != 0 ||
1974 (valiter = scf_iter_create(h)) == NULL ||
1975 scf_iter_property_values(valiter, prop) != 0)
1976 goto error;
1977 /* retrieve each value */
1978 for (numvalues_retrieved = 0;
1979 (valiterret = scf_iter_next_value(valiter, val)) == 1;
1980 numvalues_retrieved++) {
1981 if ((vallen = scf_value_get_as_string
1982 (val, NULL, 0) + 1) == 0)
1983 goto error;
1984 if ((*values = realloc(*values,
1985 sizeof (*values) + sizeof (char *))) == NULL ||
1986 ((*values)[numvalues_retrieved] = malloc(vallen)) == NULL) {
1987 (void) fprintf(stderr, gettext(
1988 "%s: out of memory\n"), myname);
1989 ret = -1;
1990 goto out;
1991 }
1992 (void) scf_value_get_as_string(val,
1993 (*values)[numvalues_retrieved], vallen);
1994 }
1995 if (valiterret == -1)
1996 goto error;
1997 /*
1998 * if *numvalues != 0, it holds expected number of values. If a
1999 * different number are found, it is an error.
2000 */
2001 if (*numvalues != 0 && *numvalues != numvalues_retrieved) {
2002 (void) fprintf(stderr, gettext(
2003 "%s: got %d values for property %s/%s, expected %d\n"),
2004 myname, numvalues_retrieved, pgname, propname, *numvalues);
2005 ret = -1;
2006 goto out;
2007 }
2008 *numvalues = numvalues_retrieved;
2009
2010 /* Retrieve property type if required. */
2011 if (type != NULL)
2012 (void) scf_property_type(prop, type);
2013
2014 goto out;
2015 error:
2016 if (scf_error() == SCF_ERROR_NOT_FOUND) {
2017 (void) fprintf(stderr, gettext(
2018 "%s: property %s not found"), myname, propname);
2019 } else {
2020 (void) fprintf(stderr, gettext(
2021 "%s: unexpected libscf error: %s, "), myname);
2022 }
2023 for (i = 0; i < numvalues_retrieved; i++)
2024 free((*values)[i]);
2025 if (*values != NULL)
2026 free(*values);
2027
2028 ret = -1;
2029 out:
2030 if (val != NULL)
2031 scf_value_destroy(val);
2032 if (valiter != NULL)
2033 scf_iter_destroy(valiter);
2034 if (prop != NULL)
2035 scf_property_destroy(prop);
2036 if (pg != NULL)
2037 scf_pg_destroy(pg);
2038 return (ret);
2039 }
2040
2041 static void
ra_free_prop_values(int numvalues,char ** values)2042 ra_free_prop_values(int numvalues, char **values)
2043 {
2044 int i;
2045 if (values != NULL) {
2046 for (i = 0; i < numvalues; i++)
2047 free(values[i]);
2048 free(values);
2049 }
2050 }
2051
2052 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)2053 ra_set_boolean_prop(scf_handle_t *h, scf_instance_t *inst, const char *pgname,
2054 const char *prop, boolean_t create, boolean_t propval)
2055 {
2056 const char *val = propval ? RA_PROPVAL_BOOLEAN_TRUE :
2057 RA_PROPVAL_BOOLEAN_FALSE;
2058
2059 return (ra_set_prop_from_string(h, inst, pgname, prop, SCF_TYPE_BOOLEAN,
2060 create, 1, &val));
2061 }
2062
2063 /*
2064 * Set the property named in propname to the values passed in in the propvals
2065 * array. Only create a new property if "create" is true.
2066 */
2067 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)2068 ra_set_prop_from_string(scf_handle_t *h, scf_instance_t *inst,
2069 const char *pgname, const char *propname, scf_type_t proptype,
2070 boolean_t create, int numpropvals, const char **propvals)
2071 {
2072 scf_propertygroup_t *instpg = NULL, *cpg = NULL;
2073 scf_type_t oldproptype, newproptype = proptype;
2074 scf_property_t *prop = NULL;
2075 scf_value_t **values = NULL;
2076 scf_transaction_t *tx = NULL;
2077 scf_transaction_entry_t *ent = NULL;
2078 boolean_t new = B_FALSE;
2079 int i, retval, numvalues = 0, ret = 0;
2080 char *pgtype = NULL, **ovalues;
2081 ssize_t typelen;
2082
2083 /* Firstly, does property exist? If not, and create is false, bail */
2084 if (ra_get_prop_as_string(h, inst, pgname, propname, B_TRUE,
2085 B_FALSE, &oldproptype, &numvalues, &ovalues) == -1) {
2086 if (scf_error() != SCF_ERROR_NOT_FOUND)
2087 goto error;
2088 if (!create) {
2089 (void) fprintf(stderr, gettext(
2090 "%s: no such property %s/%s\n"), myname, pgname,
2091 propname);
2092 return (-1);
2093 }
2094 } else
2095 ra_free_prop_values(numvalues, ovalues);
2096
2097 /* Use old property type */
2098 if (proptype == SCF_TYPE_INVALID)
2099 newproptype = oldproptype;
2100
2101 /*
2102 * Does property group exist at instance level? If not, we need to
2103 * create it, since the composed view of the property group did
2104 * contain the property. We never modify properties at the service
2105 * level, as it`s possible that multiple instances will inherit those
2106 * settings.
2107 */
2108 if (ra_get_pg(h, inst, pgname, B_FALSE, B_FALSE, &instpg) == -1) {
2109 if (scf_error() != SCF_ERROR_NOT_FOUND)
2110 goto error;
2111 /* Ensure pg exists at service level, get composed pg */
2112 if (ra_get_pg(h, inst, pgname, B_TRUE, B_FALSE, &cpg) == -1)
2113 goto error;
2114
2115 /* Create instance-level property group */
2116 if ((typelen = scf_pg_get_type(cpg, NULL, 0) + 1) == 0)
2117 goto error;
2118 if ((pgtype = malloc(typelen)) == NULL) {
2119 (void) fprintf(stderr, gettext(
2120 "%s: out of memory\n"), myname);
2121 goto error;
2122 }
2123 (void) scf_pg_get_type(cpg, pgtype, typelen);
2124 if ((instpg = scf_pg_create(h)) == NULL ||
2125 scf_instance_add_pg(inst, pgname, pgtype, 0, instpg)
2126 == -1) {
2127 (void) fprintf(stderr, gettext(
2128 "%s: could not create property group %s\n"),
2129 myname, pgname);
2130 goto error;
2131 }
2132 }
2133 if ((prop = scf_property_create(h)) == NULL)
2134 goto error;
2135 if ((values = calloc(numpropvals, sizeof (scf_value_t *))) == NULL) {
2136 (void) fprintf(stderr, gettext("%s: out of memory"), myname);
2137 goto error;
2138 }
2139 if (scf_pg_get_property(instpg, propname, prop) != 0) {
2140 /* New property? */
2141 if (scf_error() == SCF_ERROR_NOT_FOUND)
2142 new = B_TRUE;
2143 else
2144 goto error;
2145 }
2146 if ((tx = scf_transaction_create(h)) == NULL ||
2147 (ent = scf_entry_create(h)) == NULL)
2148 goto error;
2149 retry:
2150 if (scf_transaction_start(tx, instpg) == -1)
2151 goto error;
2152 if (new) {
2153 if (scf_transaction_property_new(tx, ent, propname,
2154 newproptype) == -1)
2155 goto error;
2156 } else if (scf_transaction_property_change(tx, ent, propname,
2157 newproptype) == -1)
2158 goto error;
2159 for (i = 0; i < numpropvals; i++) {
2160 if ((values[i] = scf_value_create(h)) == NULL ||
2161 scf_value_set_from_string(values[i], newproptype,
2162 propvals[i] == NULL ? "": propvals[i]) == -1 ||
2163 scf_entry_add_value(ent, values[i]) != 0)
2164 goto error;
2165 }
2166 retval = scf_transaction_commit(tx);
2167 if (retval == 0) {
2168 scf_transaction_reset(tx);
2169 if (scf_pg_update(instpg) == -1)
2170 goto error;
2171 goto retry;
2172 }
2173 if (retval == -1)
2174 goto error;
2175 goto out;
2176 error:
2177 switch (scf_error()) {
2178 case SCF_ERROR_INVALID_ARGUMENT:
2179 (void) fprintf(stderr, gettext(
2180 "%s: invalid value for property %s/%s\n"), myname,
2181 pgname, propname);
2182 break;
2183 case SCF_ERROR_NOT_FOUND:
2184 (void) fprintf(stderr, gettext(
2185 "%s: no such property %s/%s\n"), myname,
2186 pgname, propname);
2187 break;
2188 default:
2189 (void) fprintf(stderr, gettext(
2190 "%s: unexpected libscf error: %s\n"), myname,
2191 scf_strerror(scf_error()));
2192 break;
2193 }
2194 ret = -1;
2195 out:
2196 if (tx != NULL)
2197 scf_transaction_destroy(tx);
2198 if (ent != NULL)
2199 scf_entry_destroy(ent);
2200 if (values != NULL) {
2201 for (i = 0; i < numpropvals; i++) {
2202 if (values[i] != NULL)
2203 scf_value_destroy(values[i]);
2204 }
2205 free(values);
2206 }
2207 if (prop != NULL)
2208 scf_property_destroy(prop);
2209 if (cpg != NULL)
2210 scf_pg_destroy(cpg);
2211 if (instpg != NULL)
2212 scf_pg_destroy(instpg);
2213 if (pgtype != NULL)
2214 free(pgtype);
2215 return (ret);
2216 }
2217
2218 /*
2219 * This function gathers configuration from the legacy /etc/inet/routing.conf,
2220 * if any, and sets the appropriate variable values accordingly. Once
2221 * these are set, the legacy daemons are checked to see if they have
2222 * SMF counterparts (ra_check_legacy_daemons()). If they do, the
2223 * configuration is upgraded. Finally, the legacy option settings are
2224 * applied, enabling/disabling the routing/forwarding services as
2225 * appropriate.
2226 */
2227 static int
ra_upgrade_from_legacy_conf(void)2228 ra_upgrade_from_legacy_conf(void)
2229 {
2230 scf_handle_t *h = NULL;
2231 scf_instance_t *inst = NULL;
2232 int ret = 0, i, r;
2233 boolean_t old_conf_read;
2234 ravar_t *routing_svcs = ra_str2var(RA_VAR_ROUTING_SVCS);
2235
2236 /*
2237 * First, determine if we have already upgraded - if "routing-conf-read"
2238 * is true, we bail. The use of a boolean property indicating if
2239 * routing.conf has been read and applied might seem a lot more
2240 * work than simply copying routing.conf aside, but leaving the
2241 * file in place allows users to downgrade and have their old
2242 * routing configuration still in place.
2243 */
2244 if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
2245 scf_handle_bind(h) == -1) {
2246 (void) fprintf(stderr, gettext(
2247 "%s: cannot connect to SMF repository\n"), myname);
2248 ret = -1;
2249 goto out;
2250 }
2251 if ((inst = scf_instance_create(h)) == NULL ||
2252 scf_handle_decode_fmri(h, RA_INSTANCE_ROUTING_SETUP,
2253 NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2254 (void) fprintf(stderr, gettext(
2255 "%s: unexpected libscf error: %s\n"), myname,
2256 scf_strerror(scf_error()));
2257 ret = -1;
2258 goto out;
2259 }
2260 if (ra_get_boolean_prop(h, inst, RA_PG_ROUTEADM,
2261 RA_PROP_ROUTING_CONF_READ, B_TRUE, B_TRUE, &old_conf_read) == -1) {
2262 ret = -1;
2263 goto out;
2264 }
2265
2266 if (old_conf_read)
2267 goto out;
2268
2269 /*
2270 * Now set "routing-conf-read" to true so we don`t reimport legacy
2271 * configuration again.
2272 */
2273 if (ra_set_boolean_prop(h, inst, RA_PG_ROUTEADM,
2274 RA_PROP_ROUTING_CONF_READ, B_FALSE, B_TRUE) == -1)
2275 return (-1);
2276 (void) smf_refresh_instance(RA_INSTANCE_ROUTING_SETUP);
2277
2278 ra_resetvars(NULL);
2279
2280 /* First, gather values from routing.conf */
2281 if ((r = ra_parseconf()) == -1) {
2282 ret = -1;
2283 goto out;
2284 }
2285 /* No routing.conf file found */
2286 if (r == 0)
2287 goto out;
2288 /*
2289 * Now, set the options/variables gathered. We set variables first,
2290 * as we cannot enable routing before we determine the daemons
2291 * to enable.
2292 */
2293
2294 for (i = 0; ra_vars[i].var_name != NULL; i++) {
2295 /* Skip routing-svcs var, not featured in legacy config */
2296 if (strcmp(ra_vars[i].var_name, RA_VAR_ROUTING_SVCS) == 0)
2297 continue;
2298 if (ra_smf_cb(ra_set_persistent_var_cb, ra_vars[i].var_fmri,
2299 &(ra_vars[i])) == -1) {
2300 ret = -1;
2301 goto out;
2302 }
2303 }
2304 /* Clear routing-svcs value */
2305 if (ra_smf_cb(ra_set_persistent_var_cb, routing_svcs->var_fmri,
2306 routing_svcs) == -1) {
2307 ret = -1;
2308 goto out;
2309 }
2310
2311 if (ra_check_legacy_daemons() == -1) {
2312 ret = -1;
2313 goto out;
2314 }
2315
2316 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2317 if (ra_smf_cb(ra_set_persistent_opt_cb, ra_opts[i].opt_fmri,
2318 &(ra_opts[i])) == -1 ||
2319 ra_smf_cb(ra_set_default_opt_cb,
2320 ra_opts[i].opt_default_fmri, &(ra_opts[i])) == -1) {
2321 ret = -1;
2322 break;
2323 }
2324 }
2325 out:
2326 if (inst != NULL)
2327 scf_instance_destroy(inst);
2328 if (h != NULL)
2329 scf_handle_destroy(h);
2330
2331 return (ret);
2332 }
2333
2334 /*
2335 *
2336 * Return the number of IPv6 addresses configured. This answers the
2337 * generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
2338 * is configured, and we also only enable IPv6 routing daemons if IPv6 is
2339 * enabled.
2340 */
2341 static int
ra_numv6intfs(void)2342 ra_numv6intfs(void)
2343 {
2344 static int num = -1;
2345 int ipsock;
2346 struct lifnum lifn;
2347
2348 if (num != -1)
2349 return (num);
2350
2351 if ((ipsock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
2352 (void) fprintf(stderr,
2353 gettext("%1$s: unable to open %2$s: %3$s\n"),
2354 myname, IP_DEV_NAME, strerror(errno));
2355 return (0);
2356 }
2357 lifn.lifn_family = AF_INET6;
2358 lifn.lifn_flags = 0;
2359
2360 if (ioctl(ipsock, SIOCGLIFNUM, &lifn) == -1) {
2361 (void) close(ipsock);
2362 return (0);
2363 }
2364 (void) close(ipsock);
2365
2366 return (num = lifn.lifn_count);
2367 }
2368
2369 /*
2370 * Parse the configuration file and fill the ra_opts array with opt_value
2371 * and opt_default_value values, and the ra_vars array with var_value and
2372 * var_default_value values. Then copy aside routing.conf so it will not
2373 * be read by future invokations of routeadm.
2374 */
2375 static int
ra_parseconf(void)2376 ra_parseconf(void)
2377 {
2378 FILE *fp;
2379 uint_t lineno;
2380 char line[RA_MAX_CONF_LINE];
2381 char *cp, *confstr;
2382 raopt_t *raopt;
2383 ravar_t *ravar;
2384
2385 if ((fp = fopen(RA_CONF_FILE, "r")) == NULL) {
2386 /*
2387 * There's no config file, so we simply return as there
2388 * is no work to do.
2389 */
2390 return (0);
2391 }
2392
2393 for (lineno = 1; fgets(line, sizeof (line), fp) != NULL; lineno++) {
2394 if (line[strlen(line) - 1] == '\n')
2395 line[strlen(line) - 1] = '\0';
2396
2397 cp = line;
2398
2399 /* Skip leading whitespace */
2400 while (isspace(*cp))
2401 cp++;
2402
2403 /* Skip comment lines and empty lines */
2404 if (*cp == '#' || *cp == '\0')
2405 continue;
2406
2407 /*
2408 * Anything else must be of the form:
2409 * <option> <value> <default_value>
2410 */
2411 if ((confstr = strtok(cp, " ")) == NULL) {
2412 (void) fprintf(stderr,
2413 gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
2414 myname, RA_CONF_FILE, lineno);
2415 continue;
2416 }
2417
2418 if ((raopt = ra_str2opt(confstr)) != NULL) {
2419 if (ra_parseopt(confstr, lineno, raopt) != 0) {
2420 (void) fclose(fp);
2421 return (-1);
2422 }
2423 } else if ((ravar = ra_str2var(confstr)) != NULL) {
2424 if (ra_parsevar(confstr, ravar) != 0) {
2425 (void) fclose(fp);
2426 return (-1);
2427 }
2428 } else {
2429 (void) fprintf(stderr,
2430 gettext("%1$s: %2$s: invalid option name on "
2431 "line %3$d\n"),
2432 myname, RA_CONF_FILE, lineno);
2433 continue;
2434 }
2435 }
2436
2437 (void) fclose(fp);
2438
2439 return (1);
2440 }
2441
2442 static int
ra_parseopt(char * confstr,int lineno,raopt_t * raopt)2443 ra_parseopt(char *confstr, int lineno, raopt_t *raopt)
2444 {
2445 oval_t oval, d_oval;
2446
2447 if ((confstr = strtok(NULL, " ")) == NULL) {
2448 (void) fprintf(stderr,
2449 gettext("%1$s: %2$s: missing value on line %3$d\n"),
2450 myname, RA_CONF_FILE, lineno);
2451 return (0);
2452 }
2453 if ((oval = ra_str2oval(confstr)) == OPT_INVALID) {
2454 (void) fprintf(stderr,
2455 gettext("%1$s: %2$s: invalid option "
2456 "value on line %3$d\n"),
2457 myname, RA_CONF_FILE, lineno);
2458 return (0);
2459 }
2460 if (oval != OPT_DEFAULT)
2461 raopt->opt_enabled = oval == OPT_ENABLED;
2462
2463 if ((confstr = strtok(NULL, " ")) == NULL) {
2464 (void) fprintf(stderr,
2465 gettext("%1$s: %2$s: missing revert "
2466 "value on line %3$d\n"),
2467 myname, RA_CONF_FILE, lineno);
2468 return (0);
2469 }
2470 if ((d_oval = ra_str2oval(confstr)) == OPT_INVALID) {
2471 (void) fprintf(stderr,
2472 gettext("%1$s: %2$s: invalid revert "
2473 "value on line %3$d\n"),
2474 myname, RA_CONF_FILE, lineno, confstr);
2475 return (0);
2476 }
2477 raopt->opt_default_enabled = d_oval == OPT_ENABLED;
2478 if (oval == OPT_DEFAULT)
2479 raopt->opt_enabled = d_oval == OPT_ENABLED;
2480
2481 /*
2482 * Set ipv4(6)-routing-set property as appropriate on upgrading
2483 * routing.conf. If option was default, set this value to false,
2484 * as this indicates the administrator has not explicitly enabled
2485 * or disabled ipv4(6)-routing. The ipv4-routing-set value is used
2486 * in the routing-setup service, and if it is false, ipv4-routing
2487 * is enabled in the case where no default route can be determined.
2488 */
2489 if (raopt->opt_flags & (RA_SVC_FLAG_IPV4_ROUTING |
2490 RA_SVC_FLAG_IPV6_ROUTING)) {
2491 if (ra_smf_cb(oval == OPT_DEFAULT ? ra_routing_opt_unset_cb :
2492 ra_routing_opt_set_cb, raopt->opt_default_fmri, raopt)
2493 == -1)
2494 return (-1);
2495 }
2496 return (0);
2497 }
2498
2499 static int
ra_parsevar(char * confstr,ravar_t * ravar)2500 ra_parsevar(char *confstr, ravar_t *ravar)
2501 {
2502 confstr = strtok(NULL, "=");
2503 if (confstr == NULL) {
2504 /*
2505 * This isn't an error condition, it simply means that the
2506 * variable has no value.
2507 */
2508 ravar->var_value = NULL;
2509 return (0);
2510 }
2511
2512 if ((ravar->var_value = strdup(confstr)) == NULL) {
2513 (void) fprintf(stderr, gettext("%s: "
2514 "unable to allocate memory\n"), myname);
2515 return (-1);
2516 }
2517 return (0);
2518 }
2519
2520 /* Convert a string to an option value. */
2521 static oval_t
ra_str2oval(const char * valstr)2522 ra_str2oval(const char *valstr)
2523 {
2524 if (strcmp(valstr, "enabled") == 0)
2525 return (OPT_ENABLED);
2526 else if (strcmp(valstr, "disabled") == 0)
2527 return (OPT_DISABLED);
2528 else if (strcmp(valstr, "default") == 0)
2529 return (OPT_DEFAULT);
2530 return (OPT_INVALID);
2531 }
2532
2533 static raopt_t *
ra_str2opt(const char * optnamestr)2534 ra_str2opt(const char *optnamestr)
2535 {
2536 int i;
2537
2538 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2539 if (strcmp(optnamestr, ra_opts[i].opt_name) == 0)
2540 break;
2541 }
2542 if (ra_opts[i].opt_name == NULL)
2543 return (NULL);
2544 return (&ra_opts[i]);
2545 }
2546
2547 /*
2548 * Reset all option values previously gathered to B_FALSE.
2549 */
2550 static void
ra_resetopts(void)2551 ra_resetopts(void)
2552 {
2553 int i;
2554
2555 for (i = 0; ra_opts[i].opt_name != NULL; i++) {
2556 ra_opts[i].opt_enabled = B_FALSE;
2557 ra_opts[i].opt_default_enabled = B_FALSE;
2558 }
2559 }
2560
2561 static ravar_t *
ra_str2var(const char * varnamestr)2562 ra_str2var(const char *varnamestr)
2563 {
2564 int i;
2565 for (i = 0; ra_vars[i].var_name != NULL; i++) {
2566 if (strcmp(varnamestr, ra_vars[i].var_name) == 0)
2567 break;
2568 }
2569 if (ra_vars[i].var_name == NULL)
2570 return (NULL);
2571 return (&ra_vars[i]);
2572 }
2573
2574 /*
2575 * Reset variable values previously gathered to NULL.
2576 */
2577 static void
ra_resetvars(const char * proto)2578 ra_resetvars(const char *proto)
2579 {
2580 int i;
2581 for (i = 0; ra_vars[i].var_name != NULL; i++) {
2582 if (proto != NULL &&
2583 !VAR_PROTO_MATCH(ra_vars[i].var_name, proto))
2584 continue;
2585 if (ra_vars[i].var_value != NULL)
2586 free(ra_vars[i].var_value);
2587 ra_vars[i].var_value = NULL;
2588 if (ra_vars[i].var_default_value != NULL)
2589 free(ra_vars[i].var_default_value);
2590 ra_vars[i].var_default_value = NULL;
2591 }
2592 }
2593
2594 /*
2595 * Given an option name, this function provides an internationalized, human
2596 * readable version of the option name.
2597 */
2598 static char *
ra_intloptname(const char * optname)2599 ra_intloptname(const char *optname)
2600 {
2601 if (strcmp(optname, RA_OPT_IPV4_FORWARDING) == 0)
2602 return (gettext("IPv4 forwarding"));
2603 else if (strcmp(optname, RA_OPT_IPV4_ROUTING) == 0)
2604 return (gettext("IPv4 routing"));
2605 else if (strcmp(optname, RA_OPT_IPV6_FORWARDING) == 0)
2606 return (gettext("IPv6 forwarding"));
2607 else if (strcmp(optname, RA_OPT_IPV6_ROUTING) == 0)
2608 return (gettext("IPv6 routing"));
2609 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON) == 0)
2610 return (gettext("IPv4 routing daemon"));
2611 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_DAEMON_ARGS) == 0)
2612 return (gettext("IPv4 routing daemon args"));
2613 else if (strcmp(optname, RA_VAR_IPV4_ROUTING_STOP_CMD) == 0)
2614 return (gettext("IPv4 routing daemon stop"));
2615 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON) == 0)
2616 return (gettext("IPv6 routing daemon"));
2617 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_DAEMON_ARGS) == 0)
2618 return (gettext("IPv6 routing daemon args"));
2619 else if (strcmp(optname, RA_VAR_IPV6_ROUTING_STOP_CMD) == 0)
2620 return (gettext("IPv6 routing daemon stop"));
2621 else if (strcmp(optname, RA_VAR_ROUTING_SVCS) == 0)
2622 return (gettext("Routing services"));
2623 /*
2624 * If we get here, there's a bug and someone should trip over this
2625 * NULL pointer.
2626 */
2627 return (NULL);
2628 }
2629