/*
* 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 <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <strings.h>
#include <dirent.h>
#include <stdlib.h>
#include <libdladm_impl.h>
#include <libdllink.h>
#include <libintl.h>
#include <libdlpi.h>
#include <libdllink.h>
#include <libinetutil.h>
#include <libnetcfg.h>
#include <zone.h>
typedef struct media_type_desc {
} media_type_t;
{ DL_ETHER, "Ethernet" },
{ DL_WIFI, "WiFi" },
{ DL_IB, "Infiniband" },
{ DL_IPV4, "IPv4Tunnel" },
{ DL_IPV6, "IPv6Tunnel" },
{ DL_6TO4, "6to4Tunnel" },
{ DL_TPB, "TokenBus" },
{ DL_TPR, "TokenRing" },
{ DL_METRO, "MetroNet" },
{ DL_HDLC, "HDLC" },
{ DL_CHAR, "SyncCharacter" },
{ DL_CTCA, "CTCA" },
{ DL_FDDI, "FDDI" },
{ DL_FC, "FiberChannel" },
{ DL_ATM, "ATM" },
{ DL_IPATM, "ATM(ClassicIP)" },
{ DL_X25, "X.25" },
{ DL_IPX25, "X.25(ClassicIP)" },
{ DL_ISDN, "ISDN" },
{ DL_HIPPI, "HIPPI" },
{ DL_100VG, "100BaseVGEthernet" },
{ DL_100VGTPR, "100BaseVGTokenRing" },
{ DL_ETH_CSMA, "IEEE802.3" },
{ DL_100BT, "100BaseT" },
{ DL_FRAME, "FrameRelay" },
{ DL_MPFRAME, "MPFrameRelay" },
{ DL_ASYNC, "AsyncCharacter" },
{ DL_IPNET, "IPNET" },
{ DL_OTHER, "Other" }
};
typedef struct {
char *lp_name;
{ MPT_MACNOSPOOF, "mac-nospoof" },
{ MPT_RESTRICTED, "restricted" },
{ MPT_IPNOSPOOF, "ip-nospoof" },
{ MPT_DHCPNOSPOOF, "dhcp-nospoof" }
};
{
int dld_fd;
return (DLADM_STATUS_BADARG);
return (dladm_errno2status(errno));
/*
* Don't open DLMGMT_DOOR now. dlmgmtd(1M) is not able to
* open the door when the dladm handle is opened because the
* door hasn't been created yet at that time. Thus, we must
* open it on-demand in dladm_door_fd(). Move the open()
* to dladm_door_fd() for all cases.
*/
return (DLADM_STATUS_NOMEM);
}
NETCFG_PROFILE_LEN) != NETCFG_SUCCESS) {
return (DLADM_STATUS_FAILED);
}
} else {
}
return (DLADM_STATUS_OK);
}
void
{
}
}
int
{
}
/*
* If DLMGMT_DOOR hasn't been opened in the handle yet, open it.
*/
{
int fd;
return (dladm_errno2status(errno));
}
return (DLADM_STATUS_OK);
}
const char *
{
const char *s;
switch (status) {
case DLADM_STATUS_OK:
s = "ok";
break;
case DLADM_STATUS_BADARG:
s = "invalid argument";
break;
case DLADM_STATUS_FAILED:
s = "operation failed";
break;
case DLADM_STATUS_TOOSMALL:
s = "buffer size too small";
break;
case DLADM_STATUS_NOTSUP:
s = "operation not supported";
break;
case DLADM_STATUS_NOTFOUND:
s = "object not found";
break;
case DLADM_STATUS_BADVAL:
s = "invalid value";
break;
case DLADM_STATUS_NOMEM:
s = "insufficient memory";
break;
case DLADM_STATUS_EXIST:
s = "object already exists";
break;
case DLADM_STATUS_LINKINVAL:
s = "invalid link";
break;
case DLADM_STATUS_PROPRDONLY:
s = "read-only property";
break;
case DLADM_STATUS_BADVALCNT:
s = "invalid number of values";
break;
case DLADM_STATUS_DBNOTFOUND:
s = "database not found";
break;
case DLADM_STATUS_DENIED:
s = "permission denied";
break;
case DLADM_STATUS_IOERR:
s = "I/O error";
break;
case DLADM_STATUS_TEMPONLY:
s = "change cannot be persistent";
break;
case DLADM_STATUS_TIMEDOUT:
s = "operation timed out";
break;
case DLADM_STATUS_ISCONN:
s = "already connected";
break;
case DLADM_STATUS_NOTCONN:
s = "not connected";
break;
s = "invalid configuration repository";
break;
s = "invalid MAC address";
break;
case DLADM_STATUS_KEYINVAL:
s = "invalid key";
break;
s = "invalid MAC address length";
break;
s = "invalid MAC address type";
break;
case DLADM_STATUS_LINKBUSY:
s = "link busy";
break;
case DLADM_STATUS_VIDINVAL:
s = "invalid VLAN identifier";
break;
case DLADM_STATUS_TRYAGAIN:
s = "try again later";
break;
case DLADM_STATUS_NONOTIF:
s = "link notification is not supported";
break;
case DLADM_STATUS_BADTIMEVAL:
s = "invalid time range";
break;
s = "invalid MAC address value";
break;
s = "MAC address reserved for use by underlying data-link";
break;
s = "MAC address is already in use";
break;
s = "invalid factory MAC address slot";
break;
s = "factory MAC address slot already used";
break;
s = "all factory MAC address slots are in use";
break;
s = "factory MAC address slots not supported";
break;
s = "Invalid MAC address prefix value";
break;
s = "Invalid MAC address prefix length";
break;
case DLADM_STATUS_BADCPUID:
s = "non-existent processor ID";
break;
case DLADM_STATUS_DUPCPUID:
s = "duplicate processor ID in list";
break;
case DLADM_STATUS_CPUERR:
s = "could not determine processor status";
break;
s = "processor not online";
break;
s = "too many elements specified";
break;
case DLADM_STATUS_BADRANGE:
s = "invalid range";
break;
case DLADM_STATUS_DB_NOTFOUND:
s = "database not found";
break;
s = "database parse error";
break;
s = "property parse error";
break;
s = "attribute parse error";
break;
case DLADM_STATUS_FLOW_DB_ERR:
s = "flow database error";
break;
s = "flow database open error";
break;
s = "flow database parse error";
break;
s = "flow property database parse error";
break;
s = "flow add error";
break;
s = "flow walk error";
break;
s = "a flow with identical attributes exists";
break;
s = "flow(s) with incompatible attributes exists";
break;
case DLADM_STATUS_FLOW_EXISTS:
s = "link still has flows";
break;
s = "persistent flow with the same name exists";
break;
s = "flow doesn't belong to this zone";
break;
case DLADM_STATUS_INVALID_IP:
s = "invalid IP address";
break;
s = "invalid IP prefix length";
break;
s = "invalid IP protocol";
break;
s = "invalid port number";
break;
case DLADM_STATUS_INVALID_DSF:
s = "invalid dsfield";
break;
s = "invalid dsfield mask";
break;
s = "MTU check failed, use lower MTU or -f option";
break;
case DLADM_STATUS_BADPROP:
s = "invalid property";
break;
case DLADM_STATUS_MINMAXBW:
s = "minimum value for maxbw is 10K";
break;
case DLADM_STATUS_NO_HWRINGS:
s = "request hw rings failed";
break;
case DLADM_STATUS_PERMONLY:
s = "change must be persistent";
break;
case DLADM_STATUS_OPTMISSING:
s = "optional software not installed";
break;
case DLADM_STATUS_IPTUNTYPE:
s = "invalid IP tunnel type";
break;
s = "IP tunnel type required";
break;
s = "invalid local IP tunnel address";
break;
s = "invalid remote IP tunnel address";
break;
case DLADM_STATUS_ADDRINUSE:
s = "address already in use";
break;
case DLADM_STATUS_POOLCPU:
s = "pool and cpus property are mutually exclusive";
break;
s = "invalid IB phys link";
break;
s = "port is down";
break;
s = "partition already exists";
break;
s = "PKEY is not present on the port";
break;
s = "invalid PKEY";
break;
s = "IB internal resource not available";
break;
s = "invalid PKEY table size";
break;
s = "local or remote port requires transport";
break;
s = "port has LLDP enabled";
break;
s = "port has DCB enabled";
break;
s = "LLDP is not enabled on the port";
break;
case DLADM_STATUS_DB_LONGLINE:
s = "datalink entry in database is too long";
break;
s = "cannot assign requested address";
break;
case DLADM_STATUS_MINETSBW:
s = "minimum ETS bandwidth share is 10%";
break;
s = "flows on this link must only have the attribute:\n"
" local_ip=address[/prefix_len]";
break;
s = "flows on this link must only have the attribute:\n"
" remote_ip=address[/prefix_len]";
break;
s = "flows on this link must only have the attribute:\n"
" dsfield=val[:dsfield_mask]";
break;
case DLADM_STATUS_FLOW_PROTO:
s = "flows on this link must only have the attribute:\n"
" transport={tcp|udp|sctp|icmp|icmpv6}";
break;
s = "flows on this link must only have the attributes:\n"
" transport={tcp|udp|sctp},local_port=port";
break;
s = "flows on this link must only have the attributes:\n"
" transport={tcp|udp|sctp},remote_port=port";
break;
case DLADM_STATUS_EXCLUSIVE:
s = "link is exclusively used";
break;
default:
s = "<unknown error>";
break;
}
return (buf);
}
/*
* Convert a unix errno to a dladm_status_t.
* We only convert errnos that are likely to be encountered. All others
* are mapped to DLADM_STATUS_FAILED.
*/
{
switch (err) {
case 0:
return (DLADM_STATUS_OK);
case EINVAL:
return (DLADM_STATUS_BADARG);
case EEXIST:
return (DLADM_STATUS_EXIST);
case ENOENT:
return (DLADM_STATUS_NOTFOUND);
case ENOSPC:
return (DLADM_STATUS_TOOSMALL);
case ENOMEM:
return (DLADM_STATUS_NOMEM);
case ENOTSUP:
return (DLADM_STATUS_NOTSUP);
case ENETDOWN:
return (DLADM_STATUS_NONOTIF);
case EACCES:
case EPERM:
return (DLADM_STATUS_DENIED);
case EIO:
return (DLADM_STATUS_IOERR);
case EBUSY:
return (DLADM_STATUS_LINKBUSY);
case EAGAIN:
return (DLADM_STATUS_TRYAGAIN);
case ENOTEMPTY:
return (DLADM_STATUS_FLOW_EXISTS);
case EOPNOTSUPP:
return (DLADM_STATUS_FLOW_INCOMPATIBLE);
case EALREADY:
return (DLADM_STATUS_FLOW_IDENTICAL);
case EADDRINUSE:
return (DLADM_STATUS_ADDRINUSE);
case EADDRNOTAVAIL:
return (DLADM_STATUS_ADDR_NOTAVAIL);
default:
return (DLADM_STATUS_FAILED);
}
}
{
int val;
errno = 0;
return (B_FALSE);
return (B_TRUE);
}
{
int64_t n;
errno = 0;
return (DLADM_STATUS_BADARG);
if (n < 0)
return (DLADM_STATUS_BADVAL);
switch (*endp) {
case 'k':
case 'K':
mult = 1000;
break;
case 'm':
case 'M':
case '\0':
mult = 1000000;
break;
case 'g':
case 'G':
mult = 1000000000;
break;
case '%':
/*
* percentages not supported for now,
* see RFE 6540675
*/
return (DLADM_STATUS_NOTSUP);
default:
return (DLADM_STATUS_BADVAL);
}
/* check for overflow */
return (DLADM_STATUS_BADARG);
return (DLADM_STATUS_OK);
}
/*
* Convert bandwidth in bps to a string in mpbs. For values greater
* than 1mbps or 1000000, print a whole mbps value. For values that
* have fractional Mbps in whole Kbps , print the bandwidth in a manner
* simlilar to a floating point format.
*
* bps string
* 0 0
* 100 0
* 2000 0.002
* 431000 0.431
* 1000000 1
* 1030000 1.030
* 100000000 100
*/
const char *
{
if (kbps != 0) {
if (mbps == 0)
else
kbps);
} else {
}
return (buf);
}
static int
{
int lock_fd;
LOCK_DB_PERMS)) < 0)
return (-1);
return (-1);
}
return (lock_fd);
}
static void
{
if (fd < 0)
return;
}
/*
* Given a link class, returns its class string.
*/
const char *
{
const char *s;
switch (class) {
case DATALINK_CLASS_PHYS:
s = "phys";
break;
case DATALINK_CLASS_VLAN:
s = "vlan";
break;
case DATALINK_CLASS_AGGR:
s = "aggr";
break;
case DATALINK_CLASS_VNIC:
s = "vnic";
break;
case DATALINK_CLASS_ETHERSTUB:
s = "etherstub";
break;
case DATALINK_CLASS_IPTUN:
s = "iptun";
break;
case DATALINK_CLASS_SIMNET:
s = "simnet";
break;
case DATALINK_CLASS_BRIDGE:
s = "bridge";
break;
case DATALINK_CLASS_PART:
s = "part";
break;
default:
s = "unknown";
break;
}
return (buf);
}
/*
* Given a physical link media type, returns its media type string.
*/
const char *
{
const char *s = "--";
int idx;
s = mt->media_type_str;
break;
}
}
return (buf);
}
/*
* Given a physical link media type string, returns its media type constant.
*/
{
int idx;
return (mt->media_type);
}
return (DL_OTHER);
}
{
char *db_basename;
/*
* If we are called from a boot script such as net-physical,
* it's quite likely that the root fs is still not writable.
* For this case, it's ok for the lock creation to fail since
* no one else could be accessing our configuration file.
*/
return (dladm_errno2status(EINVAL));
db_basename++;
if ((lock_fd = i_dladm_lock_db
return (dladm_errno2status(errno));
return (DLADM_STATUS_DBNOTFOUND);
return (dladm_errno2status(err));
}
if (writeop) {
db_perms)) < 0) {
return (dladm_errno2status(errno));
}
return (dladm_errno2status(errno));
}
}
goto done;
/* Set permissions on file to db_perms */
goto done;
}
/*
* Configuration files need to be owned by the 'dladm' user and
* 'netadm' group.
*/
goto done;
}
goto done;
}
return (dladm_errno2status(errno));
}
return (DLADM_STATUS_OK);
done:
if (status != DLADM_STATUS_OK)
}
return (status);
}
{
return (DLADM_STATUS_BADARG);
return (DLADM_STATUS_OK);
}
{
}
/*
* Convert priority string to a value.
*/
{
*pri = MPL_MEDIUM;
} else {
return (DLADM_STATUS_BADVAL);
}
return (DLADM_STATUS_OK);
}
/*
* Convert priority value to a string.
*/
const char *
{
const char *s;
switch (pri) {
case MPL_LOW:
s = "low";
break;
case MPL_MEDIUM:
s = "medium";
break;
case MPL_HIGH:
s = "high";
break;
default:
s = "--";
break;
}
return (buf);
}
/*
* Convert protect string to a value.
*/
{
int i;
for (i = 0; i < LPTYPES; i++) {
lp = &link_protect_types[i];
return (DLADM_STATUS_OK);
}
}
return (DLADM_STATUS_BADVAL);
}
/*
* Convert protect value to a string.
*/
const char *
{
const char *s = "--";
int i;
for (i = 0; i < LPTYPES; i++) {
lp = &link_protect_types[i];
break;
}
}
return (buf);
}
/*
*/
const char *
{
buf[0] = '\0';
return (buf);
}
{
}
const char *
{
buf[0] = '\0';
return (buf);
}
{
}
/*
* Find the set bits in a mask.
* This is used for expanding a bitmask into individual sub-masks
* which can be used for further processing.
*/
void
{
int i, c = 0;
for (i = 0; i < 32; i++) {
if (((1 << i) & mask) != 0)
list[c++] = 1 << i;
}
*cnt = c;
}
void
{
}
}
{
int len, i;
return (DLADM_STATUS_BADVAL);
if (str[0] == '\0')
return (DLADM_STATUS_OK);
return (dladm_errno2status(errno));
return (dladm_errno2status(errno));
}
for (i = 0; i < len; i++) {
char c = buf[i];
continue;
if (match) {
buf[i] = '\0';
if (*curr == '\0')
goto fail;
}
goto fail;
if (novalues)
goto fail;
} else {
goto fail;
if (c == ',')
}
}
return (DLADM_STATUS_OK);
fail:
return (DLADM_STATUS_FAILED);
}
/*
* Given a -z option value (f.e. 'zone1,zone2') the following function
* parses the option string value and returns the count of zone IDs in
* the option value and a pointer to an array of zone IDs. The caller
* must free the memory allocated for the array of zone IDs.
*/
{
char *zoneoptstr;
char *zone;
char *last;
return (DLADM_STATUS_BADARG);
do {
return (DLADM_STATUS_BADARG);
}
return (DLADM_STATUS_BADARG);
}
sizeof (zoneid_t));
if (zonelistnew == NULL) {
return (DLADM_STATUS_NOMEM);
}
zidcnt++;
return (DLADM_STATUS_OK);
}
/*
* Utility function to run filters against a given link name against
* the given search flags and optional -z zone argument values.
*/
{
/*
* Linkname checks: verify linkname length is valid, disallow zonename
* prefixed linknames in non-global zones and perform a lookup of
* datalink ID by the given linkname. If no linkname is passed then
* verify the given datalink ID and retrieve the datalink flags.
*/
linkname);
return (status);
return (status);
}
/*
* Verify datalink flags (active/persistent) match given search flags.
*/
if (!(flags & searchflags)) {
"a temporary link" : "temporarily removed");
return (DLADM_STATUS_BADARG);
}
if (zonecnt == 0)
return (DLADM_STATUS_OK);
linkname);
return (status);
}
/*
* If the user has specified a zonename prefixed linkname and has
* also specified a list of -z zone values then we have to check
* to make sure the zonename prefix is one of the -z zone arguments.
*/
"in given zone list", linkname);
return (DLADM_STATUS_BADARG);
}
/*
* If the datalink is on loan to a non-global zone and the caller
* is in the global zone we also need to check if the -z option
* string includes global zone. On loan datalinks can be viewed
* in both the global zone and in the non-global zone.
*/
return (DLADM_STATUS_OK);
}
return (DLADM_STATUS_OK);
"given zone list", linkname);
return (DLADM_STATUS_BADARG);
}
/*
* mac_propval_range_t functions. Currently implemented for only
* ranges of uint32_t elements, but can be expanded as required.
*/
/*
* Convert an array of strings (which can be ranges or individual
* elements) into a single mac_propval_range_t structure which
* allocated here but should be freed by the caller.
*/
{
int i;
char *endp;
switch (type) {
case MAC_PROPVAL_UINT32: {
/* Allocate range structure */
goto fail;
}
/* single element */
goto fail;
}
} else {
/* range of elements */
if (*endp++ != '-') {
goto fail;
}
goto fail;
}
}
}
break;
}
default:
goto fail;
}
return (DLADM_STATUS_OK);
fail:
return (status);
}
/*
* Convert a mac_propval_range_t structure into an array of elements.
*/
{
int i, j, k;
case MAC_PROPVAL_UINT32: {
k = 0;
if (k > *nelem) {
break;
}
}
}
*nelem = k;
break;
}
default:
break;
}
return (status);
}
/*
* Convert a mac_propval_range_t structure into an array of strings
* of single elements or ranges.
*/
int
{
int i;
case MAC_PROPVAL_UINT32: {
/* Write ranges and individual elements */
/* single element */
} else {
/* range of elements */
}
}
return (0);
}
default:
break;
}
return (EINVAL);
}
static int
uint32cmp(const void *a, const void *b)
{
}
/*
* Sort and convert an array of elements into a single
* mac_propval_range_t structure which is allocated here but
* should be freed by the caller.
*/
{
int i;
switch (type) {
case MAC_PROPVAL_UINT32: {
/* Allocate range structure */
return (DLADM_STATUS_NOMEM);
/* Allocate array for sorting */
return (DLADM_STATUS_NOMEM);
}
/* Copy and sort list */
for (i = 0; i < nelem; i++)
if (nelem > 1)
/* Convert list to ranges */
for (i = 1; i < nelem; i++) {
/* part of current range */
} else {
/* start a new range */
}
}
break;
}
default:
return (DLADM_STATUS_BADRANGE);
}
return (status);
}