/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <stropts.h>
#include <errno.h>
#include <libintl.h>
#include <locale.h>
#include <fcntl.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libuutil.h>
/*
* This program moves routing management under SMF. We do this by giving
* routeadm options that allow interaction with SMF services. These include:
* - setting the routing services routeadm will enable
* # routeadm -s routing-svcs="fmri [fmri...]"
* where each fmri is an SMF routing service.
* - changing properties of routing services
* # routeadm -m fmri key=value [key=value...]
* - listing routing daemon properties
* # routeadm -l fmri
* where all properties in the "routing" property group are listed.
*
* By providing legacy routing services (legacy-routing:ipv4 and ipv6), we
* can also support running of routing daemons with no SMF service under SMF.
* Specifying a routing daemon with no SMF counterpart results in the
* daemon, it`s arguments and stop command being set in the appropriate instance
*
* Internally, routeadm keeps track of routing services by setting the
* "current-routing-svc" property to "true" in the services it manages.
* So for example, running
* # routeadm -s routing-svcs="route:default ripng:default"
* sets this variable in each instance specified. If the user specifies a
* non-SMF routing daemon via
* the variable will be set for the legacy-routing:ipv4 instance.
*
* In order to ensure that the SMF versions of routing daemons are used
* where possible, routeadm will check the daemons specified in
* ipv4-routing-daemon/ipv6-routing-daemon to determine if there is an
* SMF counterpart. If so, rather than running the legacy service
* we move configuration, specifically the associated daemon arguments
* to the SMF counterpart. From there, when the daemon is enabled, it
* will pick up the daemon arguments setting, transfer the argument string
* to the appropriate properties and run the service.
*
* To support the semantics of routeadm -e (enable at next boot) through SMF,
* we make use of temporary state changes, which last only until reboot.
* For example, if a service is disabled, and it is to be enabled via
* routeadm -e, we simply change the disable to a temporary disable,
* and set the persistent enabled value to true. This ensures the daemon
* will run at next boot, but not now. The reverse is true for disabling
* enabled instances (and if the daemon is enabled when we issue the enable,
* we do nothing since it is already in the desired state).
*
* Since the code is quite involved, we provide a guide to the more complex
* actions taken in response to user commands.
*
* routeadm -e[d] ipv4[6]-routing[forwarding]
*
* In this case, the goal is to prepare the configured routing daemons
* (specified through routeadm -s routing-svcs="...") or forwarding
* services to switch on (-e) or of (-d) at next boot.
*
* Since this operation must be applied to multiple services in the
* routing daemon case (as opposed to the single ipv4[6]-forwarding
* service), we make use of the scf_walk_fmri() function, which
* applies a callback function to all matching functions. In the case
* of the routing daemons, we pass in a NULL signifying that all
* instances should be walked (we then weed out the relevant routing
* the case of enable, a routing service is enabled IFF it has the
* previously-mentioned property - with an appropriate value (i.e. ipv4
* for "routeadm -e ipv4-routing") - and it has routeadm/curr-routing-svc
* property set to true (this is set by other operations such as
* routeadm -s routing-svcs="..."). Then, smf_enable_instance() or
* smf_disable_instance() is called, setting the temporary state to
* the current state of the service. This then allows setting of
* ipv4[6]-routing, all valid ipv4[6] routing daemons are prepared
* for next-boot disable, not just those specified via routing-svcs (this
* means that if the user enables routing daemons with "svcadm enable",
* disabling global routing does really switch off all routing daemons).
*
* This is implemented through the ra_get_set_opt_common_cb() function,
* called by the ra_set_persistent_opt_cb() function. The same
* function can be used for both routing and forwarding options, in the
* latter case we simply provide the specific FMRI of the forwarding
* service in question (ipv4-forwarding or ipv6-forwarding), and dispense
* with the eligibility tests we need to weed out the routing services
* from the rest.
*
* Before we initiate the "enable" however, we must check routing daemons
* specified via the legacy variables (ipv4-routing-daemon etc).
* If they map to SMF routing services, we wish to transfer their
* configuration to the corresponding services and use them instead of
* the legacy services. To do this, we need to match the daemon program
* daemons). If a match is found, the daemon arguments are transferred
* to the appropriate service`s daemon-args property, to be picked up
* by it`s start method and converted into appropriate property values.
* This is accomplished by ra_check_legacy_daemons(), and the callback
* operation is carried out by ra_upgrade_legacy_daemons_cb(). If the
* daemon was not upgraded, we need to mark the legacy-routing:ipv4[6]
* instance to be enabled (by routeadm -e), since it now must run the
* un-upgradeable legacy daemon.
*
* routeadm -l fmri
*
* Lists all properties and values in the routing property group associated
* with instance fmri. We simply walk through the composed property
* group, displaying all values. See ra_list_props_cb().
*
* routeadm -m fmri key=value ...
*
* Modify property values in the routing property group. If the same
* key is used more than once, multiple property values are set for that
* property. Properties must exist in the composed property group, but
* will only ever be set at the instance level to prevent multiple
* instances inheriting the property in error. See ra_modify_props_cb().
*
* routeadm -s var=value
*
* In all cases bar the routing-svcs variable, this simply involves
* setting the appropriate SMF property value for the variable. The
* routing-svcs case is more complex, since we would like operations
* like the following to have intuitive effects:
* # routeadm -s routing-svcs=route -e ipv4-routing -u
* # routeadm -s routing-svcs=rdisc -u
* i.e., in the end, rdisc is the only routing service running. To
* accomplish this switchover, we need to disable the old routing-svcs
* and enable the new, marking the latter with the curr-routing-svc
* property so that routeadm -e will pick them up. This is carried
* out by the ra_update_routing_svcs() function.
*
* routeadm -R alt_root ...
*
* Used to support use of routeadm in Custom Jumpstart scripts, this
* option causes all subsequent commands to be appended to the
* This is done because the SMF repository is not available to make
* the modifications to property values required in routeadm operations.
*
* routeadm -u
*
* Update applies the "next boot" state to the current system. Here
* make it the current state through smf_enable_instance() or
* smf_disable_instance() as appropriate (these calls, without the
* temporary flag set, delete the general_ovr/enabled property).
*/
#define RA_INSTANCE_LEGACY_ROUTING_IPV4 \
"svc:/network/routing/legacy-routing:ipv4"
#define RA_INSTANCE_LEGACY_ROUTING_IPV6 \
"svc:/network/routing/legacy-routing:ipv6"
/*
* Option value. Each option requires an FMRI identifying which services
* to run the get_current/persistent scf_walk_fmri() function with, and
* associated flags (to ensure that in the case that multiple services
* match, we select the correct ones). In addition, we specify the FMRI
* and property used to set default option value. The opt_enabled field
* is used to hold retrieved state from get_*_opt_() callbacks and to specify
* desired state for set_*_opt() operations.
*/
typedef struct raopt {
const char *opt_name;
const char *opt_fmri;
int opt_flags;
const char *opt_default_fmri;
const char *opt_default_prop;
} raopt_t;
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
};
typedef enum option_values {
} oval_t;
typedef struct ra_var {
const char *var_name;
const char *var_fmri;
const char *var_prop;
char *var_value;
const char *var_default_fmri;
const char *var_default_prop;
char *var_default_value;
} ravar_t;
};
char *v_opt[] = {
#define IPV4_ROUTING_DAEMON 0
};
#define IPV4_VARS_UNSET \
#define IPV6_VARS_UNSET \
/*
* Structure used in modify operations to tie property name and multiple values
* together.
*/
typedef struct ra_prop {
char *prop_name;
char **prop_values;
int prop_numvalues;
} ra_prop_t;
/* Used to store program name */
static const char *myname;
static void usage(void);
static int ra_check_legacy_daemons(void);
static int ra_upgrade_legacy_daemons(void);
static int ra_upgrade_cmd(char, int, char **);
static int ra_update(void);
static int ra_update_routing_svcs(char *);
static int ra_smf_cb(ra_smf_cb_t, const char *, void *);
static int ra_upgrade_from_legacy_conf(void);
static int ra_numv6intfs(void);
static int ra_parseconf(void);
static int ra_parseopt(char *, int, raopt_t *);
static int ra_parsevar(char *, ravar_t *);
static oval_t ra_str2oval(const char *);
static raopt_t *ra_str2opt(const char *);
static void ra_resetopts(void);
static ravar_t *ra_str2var(const char *);
static void ra_resetvars(const char *);
static char *ra_intloptname(const char *);
/* Callback for upgrade of legacy daemons */
static int ra_upgrade_legacy_daemons_cb(void *, scf_walkinfo_t *);
static int ra_set_current_opt_cb(void *, scf_walkinfo_t *);
static int ra_set_persistent_opt_cb(void *, scf_walkinfo_t *);
static int ra_set_default_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_current_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_persistent_opt_cb(void *, scf_walkinfo_t *);
static int ra_get_default_opt_cb(void *, scf_walkinfo_t *);
static int ra_routing_opt_set_cb(void *, scf_walkinfo_t *);
static int ra_routing_opt_unset_cb(void *, scf_walkinfo_t *);
static int ra_set_persistent_var_cb(void *, scf_walkinfo_t *);
static int ra_get_persistent_var_cb(void *, scf_walkinfo_t *);
static int ra_get_default_var_cb(void *, scf_walkinfo_t *);
static int ra_mark_routing_svcs_cb(void *, scf_walkinfo_t *);
static int ra_list_props_cb(void *, scf_walkinfo_t *);
static int ra_modify_props_cb(void *, scf_walkinfo_t *);
static int ra_print_state_cb(void *, scf_walkinfo_t *);
/* Utility functions for SMF operations */
char ***);
static void ra_free_prop_values(int, char **);
const char *, const char *, scf_type_t, boolean_t, int,
const char **);
static void
usage(void)
{
"usage: %1$s [-p] [-R <root-dir>]\n"
" %1$s [-e <option>] [-d <option>] [-r <option>]\n"
" [-l <FMRI>] [-m <FMRI> key=value [...]]\n"
" [-s <var>=<val>] [-R <root-dir>]\n"
" %1$s -u\n\n"
" <option> is one of:\n"
" ipv4-forwarding\n"
" ipv4-routing\n"
" ipv6-forwarding\n"
" ipv6-routing\n\n"
" <var> is one of:\n"
" ipv4-routing-daemon\n"
" ipv4-routing-daemon-args\n"
" ipv4-routing-stop-cmd\n"
" ipv6-routing-daemon\n"
" ipv6-routing-daemon-args\n"
" ipv6-routing-stop-cmd\n"
" routing-svcs\n"), myname);
}
int
{
int numvalues, i;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Before processing any options, we parse /etc/inet/routing.conf
* (if present) and transfer values to SMF.
*/
if (ra_upgrade_from_legacy_conf() == -1)
switch (opt) {
case 'b':
/*
* operations should not set ipv4(6)-routing-set
* property. Used in routing-setup service method
* to change default routing state, and, if
* carried out, change current ipv4 routing state.
*/
break;
case 'd':
case 'e':
case 'r':
if (alt_root_set) {
break;
}
/* Set current value appropriately */
switch (opt) {
case 'd':
break;
case 'e':
/*
* Check legacy daemons, mark
* routing-svcs.
*/
if (IS_ROUTING_OPT(optarg) &&
ra_check_legacy_daemons() == -1)
break;
case 'r':
/*
* This callback sets opt_enabled to
* the default value.
*/
ra_resetopts();
== -1)
if (raopt->opt_enabled &&
IS_ROUTING_OPT(optarg) &&
ra_check_legacy_daemons() == -1)
/* set value to default */
raopt->opt_enabled =
break;
}
/*
* need to set ipv4(6)-routing-set property
* for routing-setup service. Once this
* is set, routing-setup will not override
* administrator action and will not enable
* ipv4-routing in the case that no default
* route can be determined. If ipv4(6)-routing
* is reverted to its default value, set
* ipv4(6)-routing-set back to false.
*/
== -1)
}
if (opt != 'r') {
usage();
}
/* set current value to default */
ra_resetopts();
/* Need special case for routing-svcs var */
== 0) {
} else if (ra_smf_cb(ra_set_persistent_var_cb,
} else {
"%1$s: invalid option: %2$s\n"), myname,
optarg);
usage();
}
break;
case 'l':
break;
case 'm':
/*
* Argument list of key=value pairs, we need to
* collate all matching keys to set multiple values.
*/
numargs = 1;
i = optind;
numargs++)
i++;
if (numargs == 1) {
"%s: key=value required for "
"property change\n"), myname);
usage();
}
if (alt_root_set) {
break;
}
/*
* Collect all key=value pairs which use same key
* so we can add multiple property values.
*/
if (key[0] == '\0')
continue;
"%s: Malformed name=value "
}
numvalues = 1;
*(vals[0]) = '\0';
(vals[0])++;
i = optind + 1;
if (nk[0] == '\0')
continue;
== NULL) {
"%s: Malformed name=value "
}
continue;
* sizeof (char *));
nk[0] = '\0';
optind++;
}
}
&raprop) == -1)
}
break;
case 'p':
break;
case 'R':
"%1$s: failed to chroot to %2$s: %3$s\n"),
}
break;
case 's':
if (alt_root_set) {
break;
}
while (*options != '\0') {
usage();
}
if (opt_index == -1) {
"%1$s: invalid variable: %2$s\n"),
usage();
}
/* Need special case for routing-svcs var */
== 0) {
return (-1);
} else {
}
}
break;
case 'u':
break;
case ':':
/* if not 'p', usage failure */
"%s: option requires an argument -%s\n"),
usage();
}
break;
case '?':
usage();
}
}
/* There shouldn't be any extra args. */
usage();
}
"used with any of -demrsu\n"), myname);
usage();
}
if (update && ! alt_root_set)
}
/*
* Upgrade legacy daemons, mark to-be-enabled routing services.
*/
static int
ra_check_legacy_daemons(void)
{
routing_svcs) == -1)
return (-1);
/* First unmark all services */
return (-1);
/*
* For routing-svcs variable, mark each named
* service as a current-routing-svc.
*/
"%s: out of memory\n"), myname);
return (-1);
}
/* Now, mark each service named in routing-svcs. */
&mark) == -1) {
return (-1);
}
}
}
/*
* Now check if legacy variables (if specified) map to SMF routing
* daemons. If so, transfer associated daemon arguments.
*/
if (ra_upgrade_legacy_daemons() == -1)
return (-1);
/*
* routing daemons specified, we know they weren`t upgraded, so
* we mark them also.
*/
return (-1);
&mark) == -1)
return (-1);
&mark) == -1)
return (-1);
return (0);
}
/*
* Retrieve legacy daemon variables, and check if any SMF routing daemons
* run the daemons specified. If so, the legacy configuration (arguments
* to the daemon) is transferred to the routeadm/daemon-args property
* of the corresponding instance. From there, the instance picks up the
* value and will transfer the daemon arguments to individiual properties
* when enabled.
*/
static int
{
== -1 ||
== -1 ||
== -1 ||
== -1)
return (-1);
}
/*
* Determine if service runs the same daemon as that which is specified
* in ipv4-routing-daemon or ipv6-routing-daemon. If so, the associated
* daemon arguments are transferred to the service.
*/
/* ARGSUSED0 */
static int
{
char *new_routing_svcs;
/*
* Ensure instance is a routing service, and not one of the
* legacy instances - if it is, the daemon property is already
* set to the legacy daemon.
*/
return (0);
/* A legacy daemon may be defined */
/*
* If we match daemon/legacy_daemon with ipv4-routing-daemon or
* ipv6-routing-daemon values, transfer daemon-args value
* to the matching service.
*/
/* Transfer daemon-args value, clear legacy v4 values */
return (-1);
return (-1);
== 0 ||
/* Transfer daemon-args value, clear legacy v6 values */
return (-1);
return (-1);
} else
return (0);
/*
* If service is unmarked at this point, add it to routing-svcs and
* mark it.
*/
== -1 ||
routing_svcs) == -1)
return (-1);
if ((new_routing_svcs =
"%s: out of memory"), myname);
return (-1);
}
(void) snprintf(new_routing_svcs,
else
(void) snprintf(new_routing_svcs,
(void) smf_refresh_instance(inst_fmri);
return (ra_smf_cb(ra_set_persistent_var_cb,
}
(void) smf_refresh_instance(inst_fmri);
return (0);
}
/*
*/
static int
{
int i;
"%1$s: failed to open %2$s: %3$s\n"),
return (-1);
}
for (i = 0; i < argc; i++)
}
return (0);
}
/*
* value is overlaid by a general_ovr/enabled value, set the current state
* to the value of the latter. Doing this applies "next boot" changes to
* the current setup. If any IPv6 interfaces are present, also start in.ndpd.
*/
static int
ra_update(void)
{
int i;
if (ra_check_legacy_daemons() == -1)
return (-1);
&ra_opts[i]) == -1) {
return (-1);
}
}
/*
* If in.ndpd isn't already running, then we start it here, regardless
* of global IPv6 routing status (provided there are IPv6 interfaces
* present).
*/
if (ra_numv6intfs() > 0)
return (0);
}
/*
* and the user updates the routing-svcs list. The problem is that
* the enabled state is the result of services on the old routing-svcs list
* being enabled, and we want to support users doing something like this:
*
* # routeadm -s routing-svcs=route -e ipv4-routing -u
*
* followed by
*
* # routeadm -s routing-svcs=rdisc -u
*
* To do this, we need to:
* - cache the old ipv4-routing/ipv6-routing values.
* - persistently disable the old routing-svcs list.
* - if ipv4-routing was enabled, mark and persistently enable all the new
* v4 routing-svcs
* - if ipv6-routing was enabled, mark and persistently enable all the new
* v6 routing-svcs.
* This will result in the next "-u" switching on the new routing-svcs, and
* switching off the old ones, as the user would expect.
*/
static int
{
ra_resetopts();
routing_svcs) == -1)
return (-1);
routing_svcs) == -1) {
return (-1);
}
/* We don`t need to do anything, since services were disabled */
return (0);
}
return (-1);
}
if (v4_old &&
return (-1);
}
if (v6_old &&
return (-1);
}
}
return (-1);
if (v4_old &&
return (-1);
if (v6_old &&
return (-1);
}
return (0);
}
/*
* Display status, in parseable form if required. If param is
* for parseable display only).
*/
static int
{
int i;
if (!parseable) {
" Configuration Current "
"Current\n"
" Option Configuration "
"System State\n"
"---------------------------------------------------"
"------------\n"));
}
else
continue;
}
return (-1);
ra_resetopts();
return (-1);
ra_resetopts();
return (-1);
ra_resetopts();
if (parseable) {
(void) printf("persistent=%s default=%s "
} else {
}
}
if (!parseable)
(void) printf("\n");
/* Gather persistent/default variable values */
return (-1);
}
else
continue;
}
if (parseable) {
(void) printf("persistent=\"%s\" "
} else {
/* If daemon variables are not set, do not display. */
IPV4_VARS_UNSET) ||
continue;
}
}
return (-1);
}
if (parseable)
return (0);
return (-1);
return (0);
}
/*
* Call scf_walk_fmri() with appropriate function, fmri, and data.
* A NULL fmri causes scf_walk_fmri() to run on all instances. We make
* use of this many times in applying changes to the routing services.
*/
static int
{
scf_handle_t *h;
int exit_status = 0;
scf_handle_bind(h) == -1) {
"%s: cannot connect to SMF repository\n"), myname);
return (-1);
}
}
/*
* Applies persistent configuration settings to current setup.
*/
static int
{
}
/*
* Sets persistent value for option, to be applied on next boot
* or by "routeadm -u".
*/
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
/*
* Notify network/routing-setup service that administrator has explicitly
* done, ipv4-routing can be enabled in the situation when no default route can
* be determined.
*/
static int
{
}
/*
* Shared function that either sets or determines persistent or current
* state. Setting persistent state (for next boot) involves setting
* the general_ovr/enabled value to the current service state, and
* Setting current state involves removing the temporary state
* setting so the persistent state has effect.
*
* Persistent state is reported as being enabled if any of the
* while current state is reported as being enabled if any of the
* candidate services has a general_ovr/enabled or general/enabled
* value set to true.
*/
static int
{
/*
* Ensure we are dealing with a routeadm-managed service. If
* the FMRI used for walking instances is NULL, it is reasonable
* that a service not have a routeadm property group as we will
* check all services in this case.
*/
&routeadm_pg) == -1) {
/* Not a routing service, not an error. */
if (scf_error() == SCF_ERROR_NOT_FOUND &&
return (0);
return (-1);
}
/* Services with no "protocol" property are not routing daemons */
&protolist) == -1) {
if (scf_error() == SCF_ERROR_NOT_FOUND)
return (0);
return (-1);
}
/*
* Skip invalid services based on flag settings. Flags are used when
* we run callback functions on all instances to identify
* the correct instances to operate on.
*/
/* Check if protolist contains "ipv4" */
for (i = 0; i < numvalues; i++) {
protolist[i], RA_PROPVAL_PROTO_IPV4) == 0)
}
}
/* If not an ipv4 routing service, skip. */
return (0);
}
}
/* Check if protolist contains "ipv6" */
for (i = 0; i < numvalues; i++) {
protolist[i], RA_PROPVAL_PROTO_IPV6) == 0)
}
}
/* If not an ipv6 routing service, skip. */
return (0);
}
/*
* If no IPv6 interfaces are configured, do not apply
* the "enable" state change to this IPv6 routing service.
*/
return (0);
}
/* If enabling routing services, select only current routing services */
&curr_svc) == -1)
return (0);
else if (!curr_svc && persistent) {
/*
* We apply "current" routing changes to all routing
* daemons, whether current or not, so bail if
* we are trying to make a persistent update to a
* non-"routing-svc".
*/
return (0);
}
}
return (-1);
== 0)
if (get) {
/*
* Persistent state is enabled if any services are
* current state is enabled if any services
* services are currently enabled, i.e. if defined,
* general_ovr/enabled == true, if not, general/enabled == true.
*/
if (persistent)
else
} else {
if (persistent) {
/*
* For peristent state changes, from -e/-d,
* we set the general_ovr/enabled value to the
* current state (to ensure it is preserved),
* the desired value. This has the effect of
* the desired value coming into effect on next boot.
*/
if (ret != 0) {
"%s: unexpected libscf error: %s\n"),
return (-1);
}
/*
* Refresh here so general_ovr/enabled state overrides
*/
(void) smf_refresh_instance(inst_fmri);
/*
* to the value we require on next boot (or
* "routeadm -u").
*/
if (ret != 0)
return (-1);
/*
*/
(void) smf_refresh_instance(inst_fmri);
return (0);
} else {
/*
* Refresh here to get latest property values prior
* to starting daemon.
*/
(void) smf_refresh_instance(inst_fmri);
/*
* For current changes (result of -u), we
* old routing-svcs (identified by a current-routing-svc
* value of false) also.
*/
smf_enable_instance(inst_fmri, 0) :
if (ret != 0) {
"%s: unexpected libscf error: %s\n"),
return (-1);
}
/*
* Instance was already enabled, so we restart
* to get latest property values. This covers
* the case where users update properties
* via routeadm -m, and issue an update. The
* daemon should be running with the latest
* property values.
*/
(void) smf_restart_instance(inst_fmri);
}
}
}
return (0);
}
static int
{
}
static int
{
&(raopt->opt_default_enabled)));
}
/*
* Callbacks to set/retrieve persistent/default routing variable values.
* The set functions use the value stored in the var_value/var_default_value
* field of the associated ra_var_t, while the retrieval functions store
* the value retrieved in that field.
*/
static int
{
}
static int
{
}
static int
{
&ravar->var_default_value));
}
/*
* Depending on the value of the boolean_t * passed in, this callback
* either marks the relevant service(s) as current-routing-svcs (or unmarking)
* by setting that property to true or false. When routing services
* are to be enabled, the a current-routing-svc value of true flags the
* service as one to be enabled.
*/
static int
{
int numvalues = 0;
/* Check we are dealing with a routing daemon service */
return (0);
if (*mark)
/* Unmark service. */
return (0);
}
/*
* List property values for all properties in the "routing" property
* group of the routing service instance.
*/
/* ARGSUSED0 */
static int
{
int numvalues = 0;
/* Services with no "protocol" property are not routing daemons */
if (scf_error() == SCF_ERROR_NOT_FOUND)
gettext("%s: %s is not a routing daemon service\n"),
else
gettext("%s: unexpected libscf error: %s\n"),
return (-1);
}
if (scf_error() == SCF_ERROR_NOT_FOUND) {
(void) printf("%s: no %s property group for %s\n",
return (0);
}
gettext("%s: unexpected libscf error: %s\n"),
return (-1);
}
/* Create an iterator to walk through all properties */
("%s: could not iterate through properties for %s: %s\n"),
}
== 0) {
"property name for instance %s: %s\n"), myname,
retval = -1;
break;
}
retval = -1;
break;
}
pnamelen);
!= 0) {
("%s: could not iterate through "
scf_strerror(scf_error()));
retval = -1;
break;
}
if ((vallen = scf_value_get_as_string
("%s: could not retrieve "
"property value for instance %s, "
retval = -1;
retval = -1;
}
if (retval == -1) {
goto out;
}
}
(void) printf("\n");
if (valiterret == -1) {
gettext("%s: could not iterate through"
scf_strerror(scf_error()));
retval = -1;
break;
}
}
out:
if (propiterret == -1)
("%s: could not iterate through properties for %s: %s\n"),
return (retval);
}
/*
* Modify property with name stored in passed-in ra_prop_t to have
* the assocatied values. Only works for existing properties in
* the "routing" property group for routing daemon services, so all
* routing daemons should place configurable options in that group.
*/
static int
{
int numvalues = 0;
/* Services with no "protocol" property are not routing daemons */
if (scf_error() == SCF_ERROR_NOT_FOUND)
gettext("%s: %s is not a routing daemon service\n"),
else
gettext("%s: unexpected libscf error: %s\n"),
return (-1);
}
return (-1);
(void) smf_refresh_instance(inst_fmri);
return (0);
}
/*
* Display FMRI, state for each routing daemon service.
*/
/* ARGSUSED0 */
static int
{
int numvalues = 0;
/* Ensure service is a routing daemon */
return (0);
gettext("%s: could not retrieve state for %s: %s\n"),
return (-1);
}
return (0);
}
static int
{
/* Retrieve (possibly composed) property group for instance */
if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (required)
"%s: no such property group %s\n"),
return (-1);
}
if (required)
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
return (-1);
}
return (0);
}
static int
{
char *valstr;
return (-1);
return (0);
}
static int
{
char **values;
return (-1);
return (0);
}
/*
* Retrieve property named in propname, possibly using the composed
* property group view (union of instance and service-level properties,
* where instance-level properties override service-level values).
*/
static int
{
return (-1);
/*
* Retrieve values. All values routeadm needs to retrieve
* (bar those gathered by routeadm -l), are known to be single-valued.
*/
goto error;
*numvalues = 0;
if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (required)
"%s: property %s/%s not found\n"),
ret = -1;
goto out;
}
goto error;
}
goto error;
/* retrieve each value */
for (numvalues_retrieved = 0;
numvalues_retrieved++) {
if ((vallen = scf_value_get_as_string
goto error;
"%s: out of memory\n"), myname);
ret = -1;
goto out;
}
(void) scf_value_get_as_string(val,
}
if (valiterret == -1)
goto error;
/*
* if *numvalues != 0, it holds expected number of values. If a
* different number are found, it is an error.
*/
"%s: got %d values for property %s/%s, expected %d\n"),
ret = -1;
goto out;
}
/* Retrieve property type if required. */
goto out;
if (scf_error() == SCF_ERROR_NOT_FOUND) {
} else {
"%s: unexpected libscf error: %s, "), myname);
}
for (i = 0; i < numvalues_retrieved; i++)
ret = -1;
out:
return (ret);
}
static void
{
int i;
for (i = 0; i < numvalues; i++)
}
}
static int
{
}
/*
* Set the property named in propname to the values passed in in the propvals
* array. Only create a new property if "create" is true.
*/
static int
{
/* Firstly, does property exist? If not, and create is false, bail */
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto error;
if (!create) {
propname);
return (-1);
}
} else
/* Use old property type */
if (proptype == SCF_TYPE_INVALID)
/*
* Does property group exist at instance level? If not, we need to
* create it, since the composed view of the property group did
* contain the property. We never modify properties at the service
* level, as it`s possible that multiple instances will inherit those
* settings.
*/
if (scf_error() != SCF_ERROR_NOT_FOUND)
goto error;
/* Ensure pg exists at service level, get composed pg */
goto error;
/* Create instance-level property group */
goto error;
"%s: out of memory\n"), myname);
goto error;
}
== -1) {
"%s: could not create property group %s\n"),
goto error;
}
}
goto error;
goto error;
}
/* New property? */
if (scf_error() == SCF_ERROR_NOT_FOUND)
else
goto error;
}
goto error;
goto error;
if (new) {
newproptype) == -1)
goto error;
newproptype) == -1)
goto error;
for (i = 0; i < numpropvals; i++) {
goto error;
}
if (retval == 0) {
goto error;
goto retry;
}
if (retval == -1)
goto error;
goto out;
switch (scf_error()) {
"%s: invalid value for property %s/%s\n"), myname,
break;
case SCF_ERROR_NOT_FOUND:
"%s: no such property %s/%s\n"), myname,
break;
default:
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
break;
}
ret = -1;
out:
for (i = 0; i < numpropvals; i++) {
scf_value_destroy(values[i]);
}
}
return (ret);
}
/*
* This function gathers configuration from the legacy /etc/inet/routing.conf,
* if any, and sets the appropriate variable values accordingly. Once
* these are set, the legacy daemons are checked to see if they have
* SMF counterparts (ra_check_legacy_daemons()). If they do, the
* configuration is upgraded. Finally, the legacy option settings are
* applied, enabling/disabling the routing/forwarding services as
* appropriate.
*/
static int
{
scf_handle_t *h = NULL;
int ret = 0, i, r;
/*
* First, determine if we have already upgraded - if "routing-conf-read"
* is true, we bail. The use of a boolean property indicating if
* routing.conf has been read and applied might seem a lot more
* work than simply copying routing.conf aside, but leaving the
* file in place allows users to downgrade and have their old
* routing configuration still in place.
*/
scf_handle_bind(h) == -1) {
"%s: cannot connect to SMF repository\n"), myname);
ret = -1;
goto out;
}
"%s: unexpected libscf error: %s\n"), myname,
scf_strerror(scf_error()));
ret = -1;
goto out;
}
ret = -1;
goto out;
}
if (old_conf_read)
goto out;
/*
* Now set "routing-conf-read" to true so we don`t reimport legacy
* configuration again.
*/
return (-1);
/* First, gather values from routing.conf */
if ((r = ra_parseconf()) == -1) {
ret = -1;
goto out;
}
/* No routing.conf file found */
if (r == 0)
goto out;
/*
* as we cannot enable routing before we determine the daemons
* to enable.
*/
/* Skip routing-svcs var, not featured in legacy config */
continue;
&(ra_vars[i])) == -1) {
ret = -1;
goto out;
}
}
/* Clear routing-svcs value */
routing_svcs) == -1) {
ret = -1;
goto out;
}
if (ra_check_legacy_daemons() == -1) {
ret = -1;
goto out;
}
&(ra_opts[i])) == -1 ||
ret = -1;
break;
}
}
out:
if (h != NULL)
return (ret);
}
/*
*
* Return the number of IPv6 addresses configured. This answers the
* generic question, "is IPv6 configured?". We only start in.ndpd if IPv6
* is configured, and we also only enable IPv6 routing daemons if IPv6 is
* enabled.
*/
static int
ra_numv6intfs(void)
{
int ipsock;
if (num != -1)
return (num);
gettext("%1$s: unable to open %2$s: %3$s\n"),
return (0);
}
lifn.lifn_flags = 0;
return (0);
}
}
/*
* Parse the configuration file and fill the ra_opts array with opt_value
* and opt_default_value values, and the ra_vars array with var_value and
* var_default_value values. Then copy aside routing.conf so it will not
* be read by future invokations of routeadm.
*/
static int
ra_parseconf(void)
{
/*
* There's no config file, so we simply return as there
* is no work to do.
*/
return (0);
}
/* Skip leading whitespace */
cp++;
/* Skip comment lines and empty lines */
continue;
/*
* Anything else must be of the form:
* <option> <value> <default_value>
*/
gettext("%1$s: %2$s: invalid entry on line %3$d\n"),
continue;
}
return (-1);
}
return (-1);
}
} else {
gettext("%1$s: %2$s: invalid option name on "
"line %3$d\n"),
continue;
}
}
return (1);
}
static int
{
gettext("%1$s: %2$s: missing value on line %3$d\n"),
return (0);
}
gettext("%1$s: %2$s: invalid option "
"value on line %3$d\n"),
return (0);
}
if (oval != OPT_DEFAULT)
gettext("%1$s: %2$s: missing revert "
"value on line %3$d\n"),
return (0);
}
gettext("%1$s: %2$s: invalid revert "
"value on line %3$d\n"),
return (0);
}
if (oval == OPT_DEFAULT)
/*
* Set ipv4(6)-routing-set property as appropriate on upgrading
* routing.conf. If option was default, set this value to false,
* as this indicates the administrator has not explicitly enabled
* or disabled ipv4(6)-routing. The ipv4-routing-set value is used
* in the routing-setup service, and if it is false, ipv4-routing
* is enabled in the case where no default route can be determined.
*/
== -1)
return (-1);
}
return (0);
}
static int
{
/*
* This isn't an error condition, it simply means that the
* variable has no value.
*/
return (0);
}
"unable to allocate memory\n"), myname);
return (-1);
}
return (0);
}
/* Convert a string to an option value. */
static oval_t
{
return (OPT_ENABLED);
return (OPT_DISABLED);
return (OPT_DEFAULT);
return (OPT_INVALID);
}
static raopt_t *
{
int i;
break;
}
return (NULL);
return (&ra_opts[i]);
}
/*
* Reset all option values previously gathered to B_FALSE.
*/
static void
ra_resetopts(void)
{
int i;
}
}
static ravar_t *
{
int i;
break;
}
return (NULL);
return (&ra_vars[i]);
}
/*
* Reset variable values previously gathered to NULL.
*/
static void
{
int i;
continue;
}
}
/*
* Given an option name, this function provides an internationalized, human
* readable version of the option name.
*/
static char *
{
return (gettext("IPv4 forwarding"));
return (gettext("IPv4 routing"));
return (gettext("IPv6 forwarding"));
return (gettext("IPv6 routing"));
return (gettext("IPv4 routing daemon"));
return (gettext("IPv4 routing daemon args"));
return (gettext("IPv4 routing daemon stop"));
return (gettext("IPv6 routing daemon"));
return (gettext("IPv6 routing daemon args"));
return (gettext("IPv6 routing daemon stop"));
return (gettext("Routing services"));
/*
* If we get here, there's a bug and someone should trip over this
* NULL pointer.
*/
return (NULL);
}