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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 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 * 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