/*
* 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 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <errno.h>
#include <getopt.h>
#include <inet/tunables.h>
#include <libdladm.h>
#include <libdliptun.h>
#include <libdllink.h>
#include <libinetutil.h>
#include <libipadm.h>
#include <locale.h>
#include <netdb.h>
#include <ofmt.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <zone.h>
typedef void cmdfunc_t(int, char **, const char *);
typedef struct cmd {
char *c_name;
const char *c_usage;
} cmd_t;
/* interface management related sub-commands */
{ "show-if", do_show_if,
"\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n" },
{ "set-ifprop", do_set_ifprop,
"\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
"<interface>" },
{ "reset-ifprop", do_reset_ifprop,
"\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>" },
{ "show-ifprop", do_show_ifprop,
"\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
"\t\t\t[-m <protocol>] [interface]\n" },
/* address management related sub-commands */
{ "create-addr", do_create_addr,
"\tcreate-addr\t[-t] -T static [-d] "
"-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
"\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever] <addrobj>\n"
"\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
"\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
{ "show-addr", do_show_addr,
"\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n" },
{ "set-addrprop", do_set_addrprop,
"\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>" },
{ "reset-addrprop", do_reset_addrprop,
"\treset-addrprop\t[-t] -p <prop> <addrobj>" },
{ "show-addrprop", do_show_addrprop,
"\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
"<addrobj>\n" },
/* protocol properties related sub-commands */
{ "set-prop", do_set_prop,
"\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" },
{ "reset-prop", do_reset_prop,
"\treset-prop\t[-t] -p <prop> <protocol>" },
{ "show-prop", do_show_prop,
"\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
" [protocol]" }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
{ 0, 0, 0, 0 }
};
/* callback functions to print show-* subcommands output */
/* structures for 'ipadm show-*' subcommands */
typedef enum {
/* name, field width, index, callback */
};
/* name, field width, index, callback */
};
/* name, field width, index, callback */
};
typedef struct show_prop_state {
const char *sps_pname;
char *sps_propval;
typedef struct show_addr_state {
typedef struct show_if_state {
typedef struct show_addr_args_s {
typedef struct show_if_args_s {
typedef enum {
typedef enum {
/* name, field width, id, callback */
};
/* name, field width, id, callback */
};
typedef struct intf_mask {
char *name;
} fmask_t;
/*
* Handle to libipadm. Opened in main() before the sub-command specific
* function is called and is closed before the program exits.
*/
/*
* Opaque ipadm address object. Used by all the address management subcommands.
*/
static char *progname;
static void die(const char *, ...);
static void die_opterr(int, int, const char *);
static void warn_ipadmerr(ipadm_status_t, const char *, ...);
static void ipadm_check_propstr(const char *, boolean_t, const char *);
static void process_misc_addrargs(int, char **, const char *, int *,
uint32_t *);
static void
usage(void)
{
int i;
gettext("usage: ipadm <subcommand> <args> ...\n"));
}
exit(1);
}
int
{
int i;
(void) textdomain(TEXT_DOMAIN);
else
progname++;
if (argc < 2)
usage();
if (status != IPADM_SUCCESS) {
die("Could not open handle to library - %s",
}
exit(0);
}
}
usage();
return (0);
}
/*
* Create an IP interface for which no saved configuration exists in the
* persistent store.
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 't':
/*
* "ifconfig" mode - plumb interface, but do not
* restore settings that may exist in db.
*/
flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
if (status != IPADM_SUCCESS) {
die("Could not create %s : %s",
}
}
/*
* Enable an IP interface based on the persistent configuration for
* that interface.
*/
static void
{
int index;
if (flags & IPADM_OPT_PERSIST)
die("persistent operation not supported for enable-if");
if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
} else if (status != IPADM_SUCCESS) {
die("Could not enable %s : %s",
}
}
/*
* Remove an IP interface from both active and persistent configuration.
*/
static void
{
if (argc != 2)
if (status != IPADM_SUCCESS) {
die("Could not delete %s: %s",
}
}
/*
* Disable an IP interface by removing it from active configuration.
*/
static void
{
int index;
if (flags & IPADM_OPT_PERSIST)
die("persistent operation not supported for disable-if");
if (status != IPADM_SUCCESS) {
die("Could not disable %s: %s",
}
}
/*
* called in from print_prop_cb() and does the job of printing each
* individual column in the 'ipadm show-*prop' output.
*/
static void
{
char *object;
if (statep->sps_ifprop) {
} else if (statep->sps_modprop) {
} else {
}
if (status != IPADM_SUCCESS) {
if (status == IPADM_PROP_UNKNOWN ||
status == IPADM_INVALID_ARG) {
} else if (status == IPADM_NOTSUP) {
} else if (status == IPADM_NOTFOUND) {
if (flags & IPADM_OPT_PERSIST) {
propval[0] = '\0';
goto cont;
} else {
object);
}
} else if (status == IPADM_ENXIO) {
/* the interface is probably disabled */
propval[0] = '\0';
goto cont;
}
return;
}
cont:
}
/*
* callback function which displays output for set-prop, set-ifprop and
* set-addrprop subcommands.
*/
static boolean_t
{
/*
* Fail retrieving remaining fields, if you fail
* to retrieve a field.
*/
return (_B_FALSE);
case IPADM_PROPFIELD_IFNAME:
break;
case IPADM_PROPFIELD_PROTO:
break;
case IPADM_PROPFIELD_ADDROBJ:
break;
case IPADM_PROPFIELD_PROPERTY:
break;
case IPADM_PROPFIELD_PERM:
break;
case IPADM_PROPFIELD_CURRENT:
break;
break;
case IPADM_PROPFIELD_DEFAULT:
break;
case IPADM_PROPFIELD_POSSIBLE:
break;
}
return (cont);
}
/*
* Callback function called by the property walker (ipadm_walk_prop() or
* ipadm_walk_proptbl()), for every matched property. This function in turn
* calls ofmt_print() to print property information.
*/
{
/*
* if an object is not found or operation is not supported then
* stop the walker.
*/
return (_B_FALSE);
return (_B_TRUE);
}
/*
* Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
* for all the properties for the specified object, relavant information, will
* be displayed. Otherwise, for the selected property set, display relevant
* information
*/
static void
{
/* allocate sufficient buffer to hold a property value */
die("insufficient memory");
/* if no properties were specified, display all the properties */
statep);
} else {
if (status == IPADM_PROP_UNKNOWN)
}
}
}
/*
* Display information for all or specific interface properties, either for a
* given interface or for all the interfaces in the system.
*/
static void
{
int option;
char *ifname;
char *protostr;
opterr = 0;
switch (option) {
case 'p':
IPADM_NORVAL) != 0)
die("invalid interface properties specified");
break;
case 'c':
break;
case 'o':
fields_str = optarg;
break;
case 'm':
if (m_arg)
die("cannot specify more than one -m");
break;
default:
break;
}
}
else
if (!m_arg)
protostr = "ip";
if (state.sps_parsable)
/* retrieve interface(s) and print the properties */
if (status != IPADM_SUCCESS)
die("Error retrieving interface(s): %s",
}
if (ifinfo)
}
}
/*
*/
static void
{
int option;
opterr = 0;
switch (option) {
case 'p':
if (p_arg)
die("-p must be specified once only");
break;
case 'm':
if (m_arg)
die("-m must be specified once only");
break;
case 't':
flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
*prop_val++ = '\0';
if (reset)
else
flags);
done:
if (status != IPADM_SUCCESS) {
if (reset)
die("reset-ifprop: %s: %s",
else
die("set-ifprop: %s: %s",
}
}
static void
{
}
static void
{
}
/*
* Display information for all or specific protocol properties, either for a
*/
static void
{
char option;
char *protostr;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'p':
if (p_arg)
die("-p must be specified once only");
IPADM_NORVAL) != 0)
die("invalid protocol properties specified");
break;
case 'c':
break;
case 'o':
fields_str = optarg;
break;
default:
break;
}
}
} else {
if (p_arg)
die("protocol must be specified when "
"property name is used");
}
if (state.sps_parsable)
else
/* handles all the errors */
}
}
/*
* Checks to see if there are any modifiers, + or -. If there are modifiers
* then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
*/
static void
{
char *p;
return;
if (p == pstr)
--p;
if (*p == '+')
*flags |= IPADM_OPT_APPEND;
else if (*p == '-')
*flags |= IPADM_OPT_REMOVE;
}
/*
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'p':
if (p_arg)
die("-p must be specified once only");
break;
case 't':
flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
*prop_val++ = '\0';
}
if (reset)
else
done:
if (status != IPADM_SUCCESS) {
if (reset)
die("reset-prop: %s: %s",
else
die("set-prop: %s: %s",
}
}
static void
{
}
static void
{
}
/* PRINTFLIKE1 */
static void
{
}
/* PRINTFLIKE1 */
static void
{
(void) putchar('\n');
}
static void
{
switch (opterr) {
case ':':
break;
case '?':
default:
break;
}
}
/* PRINTFLIKE2 */
static void
{
}
static void
{
int option;
char *val;
static char *addr_optstr[] = {
"local",
"remote",
NULL,
};
while (*addrarg != '\0') {
switch (option) {
case A_LOCAL:
die("Multiple local addresses provided");
break;
case A_REMOTE:
die("Multiple remote addresses provided");
break;
default:
if (found_mismatch)
break;
}
}
/* If only one address is provided, it is assumed a local address. */
if (found_mismatch)
else
}
/* Initialize the addrobj for static addresses. */
if (status != IPADM_SUCCESS) {
die("Error in creating address object: %s",
}
/* Set the local and remote addresses */
if (status != IPADM_SUCCESS) {
die("Error in setting local address: %s",
}
if (status != IPADM_SUCCESS) {
die("Error in setting remote address: %s",
}
}
}
static void
{
int option;
char *val;
static char *addr_optstr[] = {
"stateless",
"stateful",
NULL,
};
while (*addrarg != '\0') {
switch (option) {
case P_STATELESS:
if (stateless_arg)
die("Duplicate option");
die("Invalid argument");
else
die("Invalid argument");
break;
case P_STATEFUL:
if (stateful_arg)
die("Duplicate option");
die("Invalid argument");
else
die("Invalid argument");
break;
default:
}
}
if (!stateless_arg && !stateful_arg)
die("Invalid arguments for option -p");
/* Set the addrobj fields for addrconf */
if (stateless_arg) {
if (status != IPADM_SUCCESS) {
die("Error in setting stateless option: %s",
}
}
if (stateful_arg) {
if (status != IPADM_SUCCESS) {
die("Error in setting stateful option: %s",
}
}
}
/*
* Creates static, dhcp or addrconf addresses and associates the created
* addresses with the specified address object name.
*/
static void
{
int option;
char *cp;
opterr = 0;
switch (option) {
case 'T':
break;
case 'a':
static_arg = optarg;
break;
case 'd':
flags &= ~IPADM_OPT_UP;
break;
case 'i':
break;
case 'p':
break;
case 'w':
break;
case 't':
flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
die("invalid address object name: %s\nusage: %s",
}
/*
* Allocate and initialize the addrobj based on the address type.
*/
die("Invalid arguments for type %s\nusage: %s",
}
die("Invalid arguments for type %s\nusage: %s",
}
/* Initialize the addrobj for dhcp addresses. */
&ipaddr);
if (status != IPADM_SUCCESS) {
die("Error in creating address object: %s",
}
} else {
char *end;
die("Invalid argument");
}
if (status != IPADM_SUCCESS) {
die("Error in setting wait time: %s",
}
}
die("Invalid arguments for type %s\nusage: %s",
}
/* Initialize the addrobj for dhcp addresses. */
if (status != IPADM_SUCCESS) {
die("Error in creating address object: %s",
}
if (interface_id != NULL) {
if (status != IPADM_SUCCESS) {
die("Error in setting interface ID: %s",
}
}
if (addrconf_arg)
} else {
}
if (status == IPADM_DHCP_IPC_TIMEOUT)
else if (status != IPADM_SUCCESS)
}
/*
* Used by some address management functions to parse the command line
* arguments and create `ipaddr' address object.
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 't':
*flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
}
/*
* Remove an addrobj from both active and persistent configuration.
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'r':
break;
default:
}
}
if (status != IPADM_SUCCESS) {
die("could not delete address: %s",
}
}
/*
* Enable an IP address based on the persistent configuration for that
* IP address
*/
static void
{
int index;
if (flags & IPADM_OPT_PERSIST)
die("persistent operation not supported for enable-addr");
if (status != IPADM_SUCCESS)
}
/*
* Mark the address identified by addrobj 'up'
*/
static void
{
int index;
if (status != IPADM_SUCCESS) {
die("Could not mark the address up: %s",
}
}
/*
* Disable the specified addrobj by removing it from active cofiguration
*/
static void
{
int index;
if (flags & IPADM_OPT_PERSIST)
die("persistent operation not supported for disable-addr");
if (status != IPADM_SUCCESS) {
die("could not disable address: %s",
}
}
/*
* Mark the address identified by addrobj 'down'
*/
static void
{
int index;
if (status != IPADM_SUCCESS)
die("Could not mark the address down: %s",
}
/*
* Restart DAD for static address. Extend lease duration for DHCP addresses
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'i':
break;
default:
}
}
if (status == IPADM_DHCP_IPC_TIMEOUT)
else if (status != IPADM_SUCCESS)
}
static void
{
case AF_INET:
socklen = sizeof (struct sockaddr_in);
break;
case AF_INET6:
socklen = sizeof (struct sockaddr_in6);
break;
default:
return;
}
(NI_NOFQDN | NI_NUMERICHOST));
}
static void
{
int i;
if (is_bits) {
else
}
} else {
if (!first)
}
}
}
}
/*
* return true if the address for lifname comes to us from the global zone
* with 'allowed-ips' constraints.
*/
static boolean_t
{
return (_B_FALSE); /* from-gz only makes sense in a NGZ */
return (_B_FALSE);
if (!(zflags & ZF_NET_EXCL))
return (_B_TRUE); /* everything is from the GZ for shared-ip */
*cp = '\0';
if (status != IPADM_SUCCESS)
return (ret);
if (if_info)
return (ret);
}
static boolean_t
{
int prefixlen;
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
buf[0] = '\0';
case SA_ADDROBJ:
if (phyname)
*phyname = '\0';
} else {
}
break;
case SA_STATE:
break;
case SA_TYPE:
else
bufsize);
break;
case SA_CURRENT:
break;
case SA_PERSISTENT:
break;
case SA_ADDR:
/*
* If the address is 0.0.0.0 or :: and the origin is DHCP,
* print STR_UNKNOWN_VAL.
*/
break;
}
}
prefixlen = 0;
else
if (prefixlen > 0) {
"/%d", prefixlen);
}
/*
* Print the hostname fields if the address is not
* in active configuration.
*/
} else {
bufsize);
}
break;
}
}
/*
* For the non-persistent case, we need to show the
* currently configured addresses for source and
* destination.
*/
dstbuf);
} else {
}
break;
default:
die("invalid input");
break;
}
return (_B_TRUE);
}
/*
* Display address information, either for the given address or
* for all the addresses managed by ipadm.
*/
static void
{
int option;
char *aname;
char *cp;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'p':
break;
case 'o':
fields_str = optarg;
break;
default:
break;
}
}
die("-p requires -o");
die("Invalid address object name provided");
*cp = '\0';
}
} else {
}
if (state.sa_parsable)
if (fields_str == NULL)
/*
* Return without printing any error, if no addresses were found,
* for the case where all addresses are requested.
*/
if (status != IPADM_SUCCESS)
return;
}
continue;
}
}
if (ainfo)
die("Address object not found");
}
static boolean_t
{
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
buf[0] = '\0';
case SI_IFNAME:
break;
case SI_STATE:
break;
case SI_CURRENT:
break;
case SI_PERSISTENT:
break;
default:
die("invalid input");
break;
}
return (_B_TRUE);
}
/*
* Display interface information, either for the given interface or
* for all the interfaces in the system.
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'p':
break;
case 'o':
fields_str = optarg;
break;
default:
break;
}
}
if (state.si_parsable)
/*
* Return without printing any error, if no addresses were found.
*/
if (status != IPADM_SUCCESS) {
die("Could not get interface(s): %s",
}
}
if (if_info)
}
/*
*/
static void
{
int option;
opterr = 0;
NULL)) != -1) {
switch (option) {
case 'p':
if (p_arg)
die("-p must be specified once only");
break;
case 't':
flags &= ~IPADM_OPT_PERSIST;
break;
default:
}
}
*prop_val++ = '\0';
if (reset)
if (status != IPADM_SUCCESS) {
if (reset)
else
}
}
/*
* Sets a property on an address object.
*/
static void
{
}
/*
* Resets a property to its default value on an address object.
*/
static void
{
}
/*
* Display information for all or specific address properties, either for a
* given address or for all the addresses in the system.
*/
static void
{
int option;
char *aobjname;
char *cp;
opterr = 0;
switch (option) {
case 'p':
IPADM_NORVAL) != 0)
die("invalid interface properties specified");
break;
case 'c':
break;
case 'o':
fields_str = optarg;
break;
default:
break;
}
}
die("Invalid address object name provided");
*cp = '\0';
}
} else {
}
if (state.sps_parsable)
sizeof (state.sps_aobjname));
} else {
/*
* Return without printing any error, if no addresses were
* found.
*/
if (status == IPADM_NOTFOUND)
return;
if (status != IPADM_SUCCESS) {
die("Error retrieving address: %s",
}
if (aobjname[0] == '\0' ||
continue;
}
sizeof (state.sps_aobjname));
}
}
}
}
static void
{
if (oferr == OFMT_SUCCESS)
return;
/*
* All errors are considered fatal in parsable mode.
* NOMEM errors are always fatal, regardless of mode.
* For other errors, we print diagnostics in human-readable
* mode and processs what we can.
*/
} else {
}
}
/*
* check if the `pstr' adheres to following syntax
* - prop=<value[,...]> (for set)
* - prop (for reset)
*/
static void
{
char *nv;
if (reset) {
} else {
/* cannot have multiple 'prop=val' for single -p */
die("cannot specify more than one prop=val at "
"a time.\n%s", use);
}
}