/*
* 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
*/
/*
*/
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <libdladm.h>
#include <libdllink.h>
#include <libinetutil.h>
#include <libipadm.h>
#include <libnetcfg.h>
#include <libgen.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <libnwam.h>
#include "libnwam_impl.h"
#include <libnwam_priv.h>
/*
* Functions to support creating, modifying, destroying, querying the
* state of and changing the state of NCP (Network Configuration Profiles)
* and the NCUs (Network Configuration Units) that are contained in those
* NCP objects. An NCP is simply a container for a set of NCUs which represent
* the datalink and interface configuration preferences for the system.
* An NCP can consist a set of prioritized link NCUs, e.g. wired links preferred
* of both. Interface NCUs inherit activation from their underlying links,
* so if wired is preferred over wireless and a cable is plugged in,
* the wired link NCU will be active, as will the IP interface NCU above it.
*/
/*
* The NCP and NCU property table is used to mapping property types to
* property name strings, their associated value types etc. The table is used
* for validation purposes, and for commit()ing and read()ing NCPs and NCUs.
*/
"specifies the NCP management type - valid values are "
"\'fixed\' and \'reactive\'",
};
sizeof (*ncp_prop_table_entries))
"specifies the NCU type - valid values are \'datalink\' and \'ip\'",
"specifies the NCU class - valid values are \'phys\' and \'ip\'",
"specifies the parent NCP name",
"specifies the NCU activation mode - valid values are:\n"
"\'prioritized\' and \'manual\'",
"specifies if manual NCU is to be enabled",
"specifies the priority grouping of NCUs - lower values are "
"prioritized, negative values are invalid",
"specifies the mode of prioritization - valid values are:\n"
"\'exclusive\', \'shared\' and \'all\'",
"specifies MAC address of form aa:bb:cc:dd:ee:ff for the link",
"specifies modules to autopush on link, separated by '.'",
"specifies MTU for link",
"specifies IP versions for IP NCU - valid values are:\n"
"\'ipv4\' and \'ipv6\'",
"specifies IPv4 address source(s) - valid values are:\n"
"\'dhcp\' and \'static\'",
"specifies static IPv4 host address(es)",
"specifies per-interface default IPv4 route",
"specifies IPv6 address source(s) - valid values are:\n"
"\'dhcp\', \'autoconf\' and \'static\'.\n"
"\'dhcp\' and \'autoconf\' are mandatory values.",
"specifies static IPv6 host address(es)",
"specifies per-interface default IPv6 route",
};
sizeof (*ncu_prop_table_entries))
typedef struct ncp_dr_arg_s {
const char *ncu_name;
} ncp_dr_arg_t;
{
}
/*
* Returns the configuration filename for the given NCU type.
*/
static nwam_error_t
{
return (NWAM_INVALID_ARG);
return (NWAM_NO_MEMORY);
return (NWAM_SUCCESS);
}
/*
* Creates IPv4 and IPv6 loopback addresses. Creating a loopback address also
* creates the interface entry.
*/
static nwam_error_t
{
return (NWAM_ERROR_IPADM);
/* IPv4 loopback address first */
!= IPADM_SUCCESS ||
!= IPADM_SUCCESS ||
goto done;
/* and then IPv6 loopback address */
!= IPADM_SUCCESS ||
!= IPADM_SUCCESS ||
goto done;
done:
if (status != IPADM_SUCCESS)
return (NWAM_ERROR_IPADM);
else
return (NWAM_SUCCESS);
}
{
/* Create empty container for NCUs */
ncphp)) != NWAM_SUCCESS)
return (err);
/* default management-type is reactive */
!= NWAM_SUCCESS ||
goto rtn;
/* Implicitly, create loopback addresses for this NCP */
goto rtn;
rtn:
if (err != NWAM_SUCCESS) {
}
return (err);
}
{
}
static nwam_error_t
{
char *parentname;
&parentval)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
*parentnamep = NULL;
return (err);
}
return (NWAM_SUCCESS);
}
/*
* Make a copy of the NCU with the following changes:
* - change "link:name" to "name" in the handle
* - map libnwam properties to libdladm properties
* The caller is reponsible free()ing the returned handle.
*
* The NCU returned by this function is written out to persistent store with
* reverse of what nwam_make_ncu_from_dlmgmt() does.
*/
static nwam_error_t
{
return (err);
/* copying checks for the existence of the new NCU, use temp name */
return (err);
}
/* change "link:name" to "name" */
return (NWAM_SUCCESS);
}
/*
*/
static nwam_error_t
{
char *ncufile;
/*
* understands and commit that NCU.
*/
return (err);
!= NWAM_SUCCESS) {
return (err);
}
return (err);
}
static int
{
/* new NCU name (and typedname) is the same as the old name */
&newncuh)) != NWAM_SUCCESS)
goto fail;
/* Duplicate the old NCU's data */
goto fail;
/* Update the parent property for the new NCU */
!= NWAM_SUCCESS)
goto fail;
if (err != NWAM_SUCCESS)
goto fail;
!= NWAM_SUCCESS)
goto fail;
/*
* Save the new NCU, Don't use nwam_ncu_commit() as it will prevent
* advanced NCUs from being committed. These NCUs should be allowed
* to be copied here as we are copying the entire NCP. However, for
* interface NCUs, use nwam_ncu_commit() as it requires multiple
* libipadm function calls to write out one NCU.
*/
if (type == NWAM_NCU_TYPE_INTERFACE)
else
fail:
return (err);
}
{
int cb_ret;
/* NCPs of "fixed" type cannot be copied */
return (err);
if (fixed)
return (NWAM_ENTITY_FIXED);
/* copy the data */
!= NWAM_SUCCESS)
return (err);
/* Create loopback addresses in the new NCP, they are not walked */
goto fail;
/* copy the NCUs */
if (err != NWAM_SUCCESS)
goto fail;
fail:
if (err != NWAM_SUCCESS) {
/* remove the NCP even if some NCUs have already been copied */
(void) nwam_ncp_destroy(*newncphp, 0);
if (err == NWAM_WALK_HALTED)
return (cb_ret);
else
return (err);
}
return (NWAM_SUCCESS);
}
/*
* Convert type to flag
*/
static uint64_t
{
switch (type) {
case NWAM_NCU_TYPE_LINK:
return (NWAM_FLAG_NCU_TYPE_LINK);
case NWAM_NCU_TYPE_INTERFACE:
return (NWAM_FLAG_NCU_TYPE_INTERFACE);
case NWAM_NCU_TYPE_ANY:
return (NWAM_FLAG_NCU_TYPE_ALL);
default:
return (0);
}
}
/*
* Are ncu type and class compatible?
*/
static boolean_t
{
switch (type) {
case NWAM_NCU_TYPE_LINK:
switch (class) {
case DATALINK_CLASS_PHYS:
case DATALINK_CLASS_AGGR:
case DATALINK_CLASS_ETHERSTUB:
case DATALINK_CLASS_VLAN:
case DATALINK_CLASS_VNIC:
case DATALINK_CLASS_IPTUN:
case DATALINK_CLASS_SIMNET:
case DATALINK_CLASS_BRIDGE:
case DATALINK_CLASS_PART:
return (B_TRUE);
}
break;
case NWAM_NCU_TYPE_INTERFACE:
switch (class) {
case IPADMIF_CLASS_IP:
case IPADMIF_CLASS_IPMP:
case IPADMIF_CLASS_LOOPBACK:
case IPADMIF_CLASS_VNI:
return (B_TRUE);
}
break;
case NWAM_NCU_TYPE_ANY:
return (class == 0);
}
return (B_FALSE);
}
/*
* Convert the given type and class to a class flag
*/
{
return (0);
switch (type) {
case NWAM_NCU_TYPE_LINK:
switch (class) {
case DATALINK_CLASS_PHYS:
return (NWAM_FLAG_NCU_CLASS_PHYS);
case DATALINK_CLASS_AGGR:
return (NWAM_FLAG_NCU_CLASS_AGGR);
case DATALINK_CLASS_ETHERSTUB:
return (NWAM_FLAG_NCU_CLASS_ETHERSTUB);
case DATALINK_CLASS_VLAN:
return (NWAM_FLAG_NCU_CLASS_VLAN);
case DATALINK_CLASS_VNIC:
return (NWAM_FLAG_NCU_CLASS_VNIC);
case DATALINK_CLASS_IPTUN:
return (NWAM_FLAG_NCU_CLASS_IPTUN);
case DATALINK_CLASS_SIMNET:
return (NWAM_FLAG_NCU_CLASS_SIMNET);
case DATALINK_CLASS_BRIDGE:
return (NWAM_FLAG_NCU_CLASS_BRIDGE);
case DATALINK_CLASS_PART:
return (NWAM_FLAG_NCU_CLASS_PART);
default:
return (NWAM_FLAG_NCU_CLASS_ALL_LINK);
}
case NWAM_NCU_TYPE_INTERFACE:
switch (class) {
case IPADMIF_CLASS_IP:
return (NWAM_FLAG_NCU_CLASS_IP);
case IPADMIF_CLASS_IPMP:
return (NWAM_FLAG_NCU_CLASS_IPMP);
case IPADMIF_CLASS_LOOPBACK:
return (NWAM_FLAG_NCU_CLASS_LOOPBACK);
case IPADMIF_CLASS_VNI:
return (NWAM_FLAG_NCU_CLASS_VNI);
default:
return (NWAM_FLAG_NCU_CLASS_ALL_INTERFACE);
}
}
return (0);
}
const char *
{
const char *s;
switch (type) {
case NWAM_NCU_TYPE_LINK:
case NWAM_NCU_TYPE_INTERFACE:
s = ipadm_class2str(class);
break;
default:
s = "unknown";
}
return (buf);
}
/*
* Make ncp active, deactivating any other active ncp.
*/
{
char *name;
if (err == NWAM_ERROR_NWAMD_BIND) {
/*
* nwamd is not running, set netcfg/active_ncp property so
* when nwamd is next started, this NCP will be used.
*/
return (err);
}
return (err);
}
/* ARGSUSED2 */
static int
{
!= NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
{
return (err);
ncp_selectcb));
}
/* Checks if NCP is read-only. Only NWAM_NCP_NAME_AUTOMATIC is read-only. */
{
char *name;
return (err);
return (NWAM_SUCCESS);
}
{
}
/* Checks if NCU is writable depending on its parent */
{
return (err);
return (err);
}
{
return (err);
return (NWAM_ENTITY_READ_ONLY);
return (err);
}
/* Returns true if the NCP is active */
static boolean_t
{
/*
* Determine which NCP is active via the netcfg/active_ncp property
* value. This allows us to determine which NCP is active even
* if nwamd is not running.
*/
return (B_FALSE);
return (ret);
}
{
return (err);
return (NWAM_ENTITY_NOT_DESTROYABLE);
if (nwam_ncp_is_active(ncph))
return (NWAM_ENTITY_IN_USE);
/* determine the datalink and ipadm configuration filenames */
&linkfile)) != NWAM_SUCCESS ||
&ipadmfile)) != NWAM_SUCCESS)
goto done;
!= NWAM_SUCCESS)
goto done;
/*
* Remove the associated static route, datalink and ipadm
* configuration files now that the NCP entry in libnwam has been
* removed.
*/
done:
return (err);
}
{
void *olddata;
!= NWAM_SUCCESS ||
return (err);
return (NWAM_ENTITY_READ_ONLY);
/*
* Duplicate data, remove property and validate. If validation
* fails, revert to data duplicated prior to remove.
*/
!= NWAM_SUCCESS)
return (err);
goto fail;
goto fail;
return (NWAM_SUCCESS);
fail:
return (err);
}
{
!= NWAM_SUCCESS ||
return (err);
return (NWAM_ENTITY_READ_ONLY);
}
{
}
int *retp)
{
}
/* Given a property, return expected property data type */
{
}
{
}
{
}
{
}
{
&fixedval);
if (err == NWAM_ENTITY_NOT_FOUND)
return (NWAM_SUCCESS);
else if (err != NWAM_SUCCESS)
return (err);
if (err == NWAM_SUCCESS)
return (err);
}
/*
* Makes a libnwam-readable link NCU from one read in by nwam_read() by making
* the following changes:
* - change "name" to "link:name" in the handle
* - map libdladm properties to libnwam properties
*/
static nwam_error_t
{
char *typedname;
return (err);
/* change "name" to "link:name" */
/*
* Non-physical links will have a 'class' property value. If a link
* does not have the the "class" property, then it must be a physical
* link, which has its class property stored in the global
* datalink.conf file.
*/
if (err != NWAM_SUCCESS) {
val);
}
/* If the "type" property does not exist, add it */
if (err != NWAM_SUCCESS) {
val);
}
/* If the "parent" property does not exist, add it */
}
return (NWAM_SUCCESS);
}
/*
* Makes a libnwam-readable interface NCU from one read in by nwam_read() by
* makeing the following changes:
* - only deal with the interface line from ipadm-<profile>.conf, which has
* "_family" property)
* - change "name" to "interface:name"
* - retrieve the address objects for this interface
* - add the info from the address object to the NCU.
*/
static nwam_error_t
{
char **strvals;
/*
* Look for the "_family" property to determine that this is the
* interface line.
*/
&vals)) != NWAM_SUCCESS)
return (err);
/* change "name" to "interface:name" */
&typedname)) != NWAM_SUCCESS)
goto done;
goto done;
/*
* The properties type, class, parent, enabled, ip{v4,v6}-default-route
* are already present. Convert the "_family" values to "ip-version"
* and remove it.
*/
!= NWAM_SUCCESS)
goto done;
goto done;
}
for (i = 0; i < num; i++)
!= NWAM_SUCCESS ||
vals)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
goto done;
}
/* If the "type" property doesn't exist, add it */
!= NWAM_SUCCESS) {
vals);
}
/* rename the "_class" property name to "class" */
== NWAM_SUCCESS) {
vals);
}
/* If the "parent" property does not exist, add it */
}
/* If the "enabled" property does not exist, add it as B_TRUE */
!= NWAM_SUCCESS) {
}
/* Retrieve all the address objects for this profile */
if (ipstat != IPADM_SUCCESS) {
if (ipstat == IPADM_NOSUCH_IF)
goto done;
}
/* determine what addresses are configured */
/* create comma-separated addresses, also count them */
nv4++;
"/%d,",
} else {
",");
}
} else {
/* skip linklocal addresses */
/*LINTED*/
continue;
nv6++;
"/%d,",
} else {
",");
}
}
}
}
/* create appropriate values for "ipv4-addrsrc" property */
num = 2;
uintvals[0] = NWAM_ADDRSRC_DHCP;
}
num = 1;
} else {
goto skip_v4;
}
goto done;
}
!= NWAM_SUCCESS ||
goto done;
}
/* create appropriate values for "ipv4-addr" property */
if (nv4 > 0) {
goto done;
}
addrs[i] = p;
!= NWAM_SUCCESS ||
goto done;
}
}
/* create appropriate values for "ipv6-addrsrc" property */
num = 3;
uintvals[0] = NWAM_ADDRSRC_DHCP;
}
} else if (v6_dhcp) {
num = 2;
uintvals[0] = NWAM_ADDRSRC_DHCP;
}
} else if (nv6 != 0) {
/* If nv6 is not 0, then there is at least one static address */
num = 1;
uintvals[0] = NWAM_ADDRSRC_STATIC;
} else {
goto skip_v6;
}
goto done;
}
!= NWAM_SUCCESS ||
goto done;
}
/* create appropriate values for "ipv6-addr" property */
if (nv6 > 0) {
goto done;
addrs[i] = p;
if (err == NWAM_SUCCESS) {
}
}
done:
if (ipstat != IPADM_SUCCESS)
return (err);
}
/*
* Returns the NCP name from the given datalink or ipadm configuration filename.
*/
char *
{
return (NULL);
strlen(NWAM_DATALINK_CONF_FILE_PRE)) == 0)
strlen(NWAM_IPADM_CONF_FILE_PRE)) == 0)
else
return (NULL);
return (NULL);
/* replace the "." from ".conf" with NULL, if it exists */
*cp = '\0';
return (ncp);
}
{
strlen(NWAM_DATALINK_CONF_FILE_PRE)) == 0)
return (NWAM_NCU_TYPE_LINK);
strlen(NWAM_IPADM_CONF_FILE_PRE)) == 0)
return (NWAM_NCU_TYPE_INTERFACE);
else
return (NWAM_NCU_TYPE_UNKNOWN);
}
/*
* Returns B_TRUE if nwam should not be touching the given link. This is the
* case only for the Automatic NCP and links with the "allow-autoconf"
* datalink property unset (set to 0, default value is 1).
*/
static boolean_t
{
/* Only skip in Automatic NCP */
if (!NWAM_NCP_AUTOMATIC(ncpname))
return (B_FALSE);
return (B_FALSE);
!= DLADM_STATUS_OK)
goto fail;
goto fail;
fail:
return (B_FALSE);
}
static int
{
char *ncpname;
!= NWAM_SUCCESS)
return (err);
/* Ignore IP Tunnels links, check the "class" property in the nvlist */
return (NWAM_INVALID_ARG);
/* retrieve the parent NCP name from the dbname */
/*
* For Automatic NCPs, if the allow-autoconf property is set for the
* link of this NCU, then it should not be walked.
*/
return (NWAM_INVALID_ARG);
}
/*
* convert the dlmgmt properties to ones libnwam consumers understand,
* and extract the class for filter matching
*/
if (err != NWAM_SUCCESS) {
return (err);
}
if (matchflags & walkfilter) {
return (NWAM_SUCCESS);
}
return (NWAM_INVALID_ARG);
}
static int
{
char *ncpname;
!= NWAM_SUCCESS)
return (err);
/*
* Skip NCUs for the loopback interface. Here, the NCU handle
* contains the untyped interface name.
*/
goto fail;
}
/* retrieve the parent NCP name from the dbname */
/*
* Skip IP configuration created over IP Tunnels.
*/
return (NWAM_INVALID_ARG);
}
return (NWAM_INVALID_ARG);
}
/*
* For Automatic NCPs, if the allow-autoconf property is set for the
* link of this NCU, then it should not be walked.
*/
return (NWAM_INVALID_ARG);
}
if (err != NWAM_SUCCESS)
goto fail;
&classval)) != NWAM_SUCCESS ||
goto fail;
}
if (matchflags & walkfilter) {
return (NWAM_SUCCESS);
}
fail:
return (err);
}
{
char *ncufile;
!= NWAM_SUCCESS)
return (err);
/* walk link NCUs */
&ncufile)) != NWAM_SUCCESS)
return (err);
return (err);
err = NWAM_SUCCESS;
}
/* and then interface NCUs */
if (flags & (NWAM_FLAG_NCU_TYPE_INTERFACE |
return (err);
if (err == NWAM_ENTITY_NOT_FOUND)
err = NWAM_SUCCESS;
}
return (err);
}
void
{
}
/* Name to validate may be internal name. If so, convert it before validating */
static boolean_t
{
char *n;
ret = dladm_valid_linkname(n);
free(n);
} else {
}
return (ret);
}
{
if (!valid_ncu_name(name))
return (NWAM_INVALID_ARG);
return (err);
return (NWAM_ENTITY_READ_ONLY);
/* NCUs cannot be created in a 'fixed' NCP */
return (err);
return (NWAM_ENTITY_FIXED);
/* check if an advanced NCU class is being created */
return (NWAM_ENTITY_ADVANCED);
return (NWAM_ENTITY_EXISTS);
}
if (!valid_ncu_name(name) ||
return (NWAM_INVALID_ARG);
!= NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
/* Create handle */
if (err != NWAM_SUCCESS)
return (err);
/* The new NCU is initialized with the appropriate type and class */
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
goto finish;
}
typeval)) != NWAM_SUCCESS ||
classval)) != NWAM_SUCCESS ||
goto finish;
}
/* Set default NCU properties */
/* ip-version is ipv4,ipv6 */
!= NWAM_SUCCESS)
goto finish;
/* activation-mode is manual */
&actval)) != NWAM_SUCCESS)
goto finish;
}
if (err != NWAM_SUCCESS) {
}
return (err);
}
{
/* NCUs for the 'fixed' NCP cannot be read */
return (err);
return (NWAM_ENTITY_FIXED);
if (type == NWAM_NCU_TYPE_ANY) {
/*
* If we get to this point, we have discovered that no
* NCU type is discernable from name or type arguments.
* Either exactly one NCU called name must exist of either
* type, or the operation should fail.
*/
} else {
if (err_ip == NWAM_SUCCESS) {
} else {
}
err = NWAM_SUCCESS;
}
return (err);
}
!= NWAM_SUCCESS)
return (err);
/* Input name (bge0) may be a typedname (link:bge0) */
return (err);
} else if (err == NWAM_SUCCESS) {
/*
* If a typedname was given, make sure it is the same as the
* requested type.
*/
return (NWAM_ENTITY_NOT_FOUND);
}
}
if (err != NWAM_SUCCESS)
return (err);
/* convert the handle to one that libnwam understands */
if (type == NWAM_NCU_TYPE_LINK)
else
if (err != NWAM_SUCCESS) {
}
return (err);
}
{
int err = 0;
else
return (nwam_errno_to_nwam_error(err));
}
{
return (NWAM_SUCCESS);
}
{
}
/*
* Generate the link:name or interface:name from the given name and type.
*/
char **typednamep)
{
char *prefixstr;
switch (type) {
case NWAM_NCU_TYPE_INTERFACE:
break;
case NWAM_NCU_TYPE_LINK:
break;
default:
return (NWAM_INVALID_ARG);
}
return (NWAM_NO_MEMORY);
/* Name may be already qualified by type */
} else {
}
return (NWAM_SUCCESS);
}
/*
* Retrieve the NCU name and type from the given link:name or interface:name.
*/
char **namep)
{
char *prefixstr;
strlen(NWAM_NCU_LINK_NAME_PRE)) == 0) {
strlen(NWAM_NCU_INTERFACE_NAME_PRE)) == 0) {
} else {
return (NWAM_INVALID_ARG);
}
return (NWAM_NO_MEMORY);
return (NWAM_SUCCESS);
}
void
{
}
{
&typeval) != NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
return (NWAM_INVALID_ARG);
}
return (NWAM_ENTITY_ADVANCED);
!= NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
return (err);
}
{
void *olddata;
return (err);
return (NWAM_ENTITY_READ_ONLY);
return (NWAM_ENTITY_ADVANCED);
/*
* Duplicate data, remove property and validate. If validation
* fails, revert to data duplicated prior to remove.
*/
!= NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
return (err);
}
return (NWAM_SUCCESS);
}
{
return (err);
return (NWAM_ENTITY_READ_ONLY);
return (NWAM_ENTITY_ADVANCED);
/*
* If "parent" property doesn't exist, NWAM_INVALID_ARG
* is returned. Allow the setting to continue.
*/
return (err);
}
/*
* Do not allow the MTU to be changed on the active NCP since libdladm
* returns "link busy" when trying to change the MTU.
*/
return (NWAM_ENTITY_IN_USE);
}
/* Need to ensure property, type and value are valid */
!= NWAM_SUCCESS)
return (err);
}
{
}
int (*cb)(const char *, nwam_value_t, void *),
{
}
{
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
if (parentname != NULL)
return (err);
}
return (NWAM_SUCCESS);
}
/*
* etc using given ifname and family. The num is used to generate translate 1
* to 'a', ..., 26 to 'z', 27 to 'aa', ... for the aobjnames.
*/
static int
{
return (-1);
cp[0] = '\0';
return (0);
}
/*
* Write out an interface NCU. The interface and addresses are written out
* separately by libipadm. Work through the NCU properties and call
* appropriate libipadm functions.
*/
/* ARGSUSED */
static nwam_error_t
{
char *fnstr;
int nverr = 0;
char **strvals;
/* the following is used to generate 'a', 'b', etc for v4a, v4b, etc */
"ipadm_open");
return (NWAM_ERROR_IPADM);
}
goto done;
/*
* We will call multiple libipadm commands to write this NCU. Backup
* the existing NCU file so that it can be restored if there is any
* failure.
*/
&ncufile)) != NWAM_SUCCESS)
goto done;
!= NETCFG_SUCCESS ||
goto done;
} else {
}
/*
* Because multiple entries have to be made to the configuration file,
* remove existing configuration for this interface.
*/
if (ipstat == IPADM_OBJ_NOTFOUND)
else if (ipstat != IPADM_SUCCESS) {
fnstr = "ipadm_delete_ip";
goto done;
}
/*
* Check "ip-version" and call ipadm_create_ip() to create the
* interface entries.
*/
&vals)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS)
goto done;
!= IPADM_SUCCESS) {
fnstr = "ipadm_create_ip";
goto done;
}
/*
* Read back the just created "_ifname" entry so that we can add other
* non-address related properties to it. Read the relevant property
* from the NCU data and add to the nvlist to write out.
*/
!= NETCFG_SUCCESS ||
goto done;
/* type */
&vals)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
num)) != 0)
goto done;
/* parent */
&vals)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
goto done;
/* enabled */
&vals)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
goto done;
/* ipv4-default-route */
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v4_route;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
goto done;
/* ipv6-default-route */
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v6_route;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
goto done;
/* write out the "_ifname" line */
goto done;
/* add v4 addresses */
&vals);
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v4_dhcp;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS)
goto done;
/* DHCP address, if any */
for (i = 0; i < num; i++) {
if (uintvals[i] != NWAM_ADDRSRC_DHCP)
continue;
fnstr = "generating v4 dhcp aobjname";
goto done;
}
&addr)) != IPADM_SUCCESS) {
fnstr = "ipadm_create_addrobj dhcp";
goto done;
}
if (ipstat != IPADM_SUCCESS) {
fnstr = "ipadm_create_addr dhcp";
goto done;
}
}
/* static addresses, if any */
&vals);
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v4_static;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS)
goto done;
for (i = 0; i < num; i++) {
fnstr = "generating v4 static aobjname";
goto done;
}
&addr)) != IPADM_SUCCESS) {
fnstr = "ipadm_create_addrobj static";
goto done;
}
!= IPADM_SUCCESS) {
fnstr = "ipadm_set_addr";
goto done;
}
if (ipstat != IPADM_SUCCESS) {
fnstr = "ipadm_create_addr static";
goto done;
}
}
/* add v6 addresses */
&vals);
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v6_dhcp;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS)
goto done;
/* DHCP address, if any */
for (i = 0; i < num; i++) {
if (uintvals[i] == NWAM_ADDRSRC_DHCP)
else if (uintvals[i] == NWAM_ADDRSRC_AUTOCONF)
}
fnstr = "generating v6 addrconf aobjname";
goto done;
}
fnstr = "ipadm_create_addrobj addrconf";
goto done;
}
if (!stateful)
if (!stateless)
if (ipstat != IPADM_SUCCESS) {
fnstr = "ipadm_create_addr addrconf";
goto done;
}
}
/* static addresses, if any */
&vals);
if (err == NWAM_ENTITY_NOT_FOUND)
goto skip_v6_static;
if (err != NWAM_SUCCESS ||
!= NWAM_SUCCESS)
goto done;
for (i = 0; i < num; i++) {
fnstr = "generating v6 static aobjname";
goto done;
}
&addr)) != IPADM_SUCCESS) {
fnstr = "ipadm_create_addrobj v6 static";
goto done;
}
!= IPADM_SUCCESS) {
fnstr = "ipadm_set_addr v6";
goto done;
}
if (ipstat != IPADM_SUCCESS) {
fnstr = "ipadm_create_addr v6 static";
goto done;
}
}
/* if all is well, then err must be NWAM_SUCCESS from retrieving vals */
done:
if (err == NWAM_ENTITY_NOT_FOUND)
err = NWAM_SUCCESS;
if (ipstat != IPADM_SUCCESS) {
}
if (nerr != NETCFG_SUCCESS)
if (nverr != 0)
if (err != NWAM_SUCCESS) {
if (backed_up)
(void) netcfg_restore_db(&backup_idl);
} else {
if (backed_up)
(void) netcfg_destroy_backup_db(&backup_idl);
}
/*
* Since this commit of interface NCU avoids nwam_commit(), send
* message to nwamd about this commit.
*/
return (err);
}
{
return (err);
return (NWAM_ENTITY_READ_ONLY);
return (NWAM_ENTITY_ADVANCED);
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
return (err);
}
if (type == NWAM_NCU_TYPE_LINK)
else if (type == NWAM_NCU_TYPE_INTERFACE)
else
return (err);
}
/* Get the NCU type */
{
!= NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
/* Get the NCU class */
{
&classval)) != NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
/*
* Determine if the NCU has manual activation-mode or not.
*/
{
&actval)) != NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
else
return (NWAM_SUCCESS);
}
/* Determine if NCU is enabled or not */
static nwam_error_t
{
&enabledval)) != NWAM_SUCCESS)
return (err);
return (err);
}
/*
* Make ncu active; fails if the NCU's parent NCP is not active.
*/
{
/*
* Don't allow NCUs of Automatic NCP or advanced NCUs to be enabled.
* nwam_ncu_get_read_only() checks the parent NCP name and NCUs of the
* Automatic NCP are considered read only.
*/
return (err);
return (NWAM_ENTITY_NOT_MANUAL);
/* Link NCUs with manual activation-mode or IP NCUs can be enabled */
return (err);
if (type == NWAM_NCU_TYPE_LINK) {
return (err);
if (!manual)
return (NWAM_ENTITY_NOT_MANUAL);
}
/* Make sure NCU is not enabled */
!= NWAM_SUCCESS)
return (err);
if (enabled) {
return (NWAM_ENTITY_ENABLED);
}
return (err);
}
/*
* Disable ncu; fails if the NCU's parent NCP is not active, or if the
* NCU is not currently active.
*/
{
/*
* Don't allow NCUs of Automatic NCP or advanced NCUs to be disabled.
* nwam_ncu_get_read_only() checks the parent NCP name and NCUs of the
* Automatic NCP are considered read only.
*/
return (err);
return (NWAM_ENTITY_NOT_MANUAL);
/* Link NCUs with manual activation-mode or IP NCUs can be disabled */
return (err);
if (type == NWAM_NCU_TYPE_LINK) {
return (err);
if (!manual)
return (NWAM_ENTITY_NOT_MANUAL);
}
/* Make sure NCU is enabled */
!= NWAM_SUCCESS)
return (err);
if (!enabled) {
return (NWAM_ENTITY_DISABLED);
}
return (err);
}
{
/* Make sure NCU is enabled */
!= NWAM_SUCCESS)
return (err);
if (!enabled) {
return (NWAM_ENTITY_DISABLED);
}
return (err);
}
{
/* Make sure NCU is enabled */
!= NWAM_SUCCESS)
return (err);
if (!enabled) {
return (NWAM_ENTITY_DISABLED);
}
return (err);
}
{
return (err);
return (NWAM_ENTITY_NOT_DESTROYABLE);
return (NWAM_ENTITY_ADVANCED);
!= NWAM_SUCCESS)
return (err);
/*
* Make a copy of the NCU that maps to dlmgmt and then use that NCU to
* remove the target NCU.
*/
if (type == NWAM_NCU_TYPE_LINK) {
!= NWAM_SUCCESS) {
return (err);
}
if (err != NWAM_SUCCESS) {
return (err);
}
/*
* If NWAM_FLAG_DO_NOT_FREE is specified, then copyncuh has
* not been freed by nwam_destroy(). Free it here instead,
* ncuh is not freed. However, if the flag is not specified,
* copyncuh has been freed. ncuh must also be freed. On
* failure from nwam_destroy(), copyncuh must be freed.
*/
if (err == NWAM_SUCCESS) {
if (flags & NWAM_FLAG_DO_NOT_FREE)
else
} else {
}
} else {
char *ifname;
goto done;
if (ipstat != IPADM_SUCCESS) {
goto done;
}
if (ipstat == IPADM_SUCCESS)
err = NWAM_SUCCESS;
else
/*
* Since this destroy of interface NCU avoid nwam_destroy(),
* send message to nwamd about this destroy.
*/
/* If NWAM_FLAG_DO_NOT_FREE is not specified, free ncuh */
}
done:
return (err);
}
{
descriptionp));
}
/* Get expected property data type */
{
}
{
return (NWAM_SUCCESS);
}
{
}
/*
* Ensure that the properties in the ncu, determined by that ncu's
* type and class, belong there.
*/
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID);
return (NWAM_ENTITY_INVALID);
}
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID);
return (NWAM_ENTITY_INVALID);
}
return (NWAM_INVALID_ARG);
return (NWAM_SUCCESS);
} else {
return (NWAM_ENTITY_INVALID_MEMBER);
}
}
{
}
/* Validate property's ncu membership and type, number and range of values */
{
/* First, determine if this property is valid for this ncu */
!= NWAM_SUCCESS)
return (err);
}
/* Property-specific value validation functions follow */
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
return (NWAM_ENTITY_INVALID_VALUE);
}
static nwam_error_t
{
char *ncp;
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
switch (activation_mode) {
return (NWAM_SUCCESS);
}
return (NWAM_ENTITY_INVALID_VALUE);
}
/* ARGSUSED0 */
static nwam_error_t
{
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (versions[i] != IPV4_VERSION &&
versions[i] != IPV6_VERSION)
return (NWAM_ENTITY_INVALID_VALUE);
}
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
addrsrc[i] != NWAM_ADDRSRC_STATIC)
return (NWAM_ENTITY_INVALID_VALUE);
}
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
addrsrc[i] != NWAM_ADDRSRC_STATIC &&
addrsrc[i] != NWAM_ADDRSRC_AUTOCONF)
return (NWAM_ENTITY_INVALID_VALUE);
if (addrsrc[i] == NWAM_ADDRSRC_DHCP)
dhcp_found = B_TRUE;
if (addrsrc[i] == NWAM_ADDRSRC_AUTOCONF)
}
/*
* DHCP and AUTOCONF need to be specified as v6 address sources
* since there is no way to switch them off in NWAM at present.
*/
if (dhcp_found && autoconf_found)
return (NWAM_SUCCESS);
else
return (NWAM_ENTITY_INVALID_VALUE);
}
/* ARGSUSED0 */
static nwam_error_t
{
return (NWAM_SUCCESS);
}
{
}
{
}
/*
* Given the ncu type and ncu class, return the list of properties that needs
* to be set. Note this list is a complete property list that includes both
* the required ones and the optional ones. Caller needs to free prop_list.
*/
{
}
{
}
{
char *ncpname;
return (err);
if (!nwam_ncp_is_active(ncph)) {
return (NWAM_ENTITY_INVALID);
}
!= NWAM_SUCCESS)
return (err);
return (err);
}
{
return (nwam_request_active_priority_group(priorityp));
}
{
return (err);
else
return (NWAM_SUCCESS);
}
/*
* This function is used by dlmgmtd and ipmgmtd to send an action to nwamd
* anytime a link or interface is added or removed. This will allow nwamd to
* read in the NCU created by dladm and ipadm. If any of the underlying PHYS
* NCUs specified in "over" (delimited by ":") do not exist and we are adding
* NCU, they are implicitly created.
*/
void
{
/* If it is the Automatic NCP and allow-autoconf is unset, do nothing */
return;
/* convert "name" to link:name or interface:name */
return;
/* and send the given action to nwamd */
goto done;
/* get the parent NCP handle */
goto done;
/* "over" are delimited by ":", the default for "portnames" in aggrs */
goto done;
/*
* Generate the typed name and create the NCU. If it already
* exists, create will fail doing nothing.
*/
&typedover) == NWAM_SUCCESS) {
(void) nwam_ncu_commit(ncuh, 0);
}
}
}
done:
}
/*
* NCP walker to identify active NCP and desired NCU, [on|off]lining it.
* If NCP is not fixed and is active, and link NCU exists and is not
* disabled, either online or offline the NCU and terminate the walk.
* Otherwise, continue walking NCPs. Notify caller if fixed NCP is active
* as legacy DR handling for the fixed case must be used.
*/
static int
{
int i;
/* Ignore offline NCPs */
return (0);
/* If fixed NCP is active, let caller know. */
return (-1);
}
!= NWAM_SUCCESS)
return (0);
return (1);
}
switch (err) {
case NWAM_SUCCESS:
if (!arg->ncu_online) {
/* Wait for NCU to transition offline */
for (i = 0; i < NCU_DR_RETRIES; i++) {
== NWAM_SUCCESS &&
break;
(void) sleep(NCU_DR_SLEEP);
}
}
return (1);
case NWAM_ENTITY_DISABLED:
return (1);
default:
/* Terminate walk indicating error */
return (-1);
}
}
{
int ret = 0;
switch (ret) {
case 1:
return (NWAM_SUCCESS);
case 0:
return (NWAM_ENTITY_NOT_FOUND);
default:
}
}
{
int ret = 0;
switch (ret) {
case 1:
return (NWAM_SUCCESS);
case 0:
return (NWAM_ENTITY_NOT_FOUND);
default:
}
}