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